我写了个存储过程,数据量一大速度就巨低,qianwt,在哪里?帮帮我,分不够再加 (100分)

P

panjf

Unregistered / Unconfirmed
GUEST, unregistred user!
有两个表,
主表:T_EngWWord和从表:T_EngWInfo,他们由WordID列关联,我通过这个存储过程向里面
追加数据。
CREATE PROCEDURE AddWord

@Word VARCHAR(50),
@POS VARCHAR(8),
@Mean VARCHAR(500),
@TAG INT,
@Prof VARCHAR(12)

AS

DECLARE @WID bigint /*WordID*/
DECLARE @Count INT

BEGIN TRAN
/*判断词库中是否包含新单词*/
SELECT @Count = COUNT(*) FROM dbo.T_EngWWord
WHERE EWord = @Word

IF @Count = 0
BEGIN
INSERT INTO dbo.T_EngWWord(EWord)
VALUES (@Word)
END
/*得到单词的ID*/
SELECT @WID = WordID FROM dbo.T_EngWWord
WHERE EWord = @Word

SELECT @Count = COUNT(*) FROM dbo.T_EngWInfo
WHERE (WordID = @WID) and (WordMean = @Mean) and (WordPos = @Pos) and (Prof = @prof)

/*判断是否包含此解释*/
IF @Count = 0
BEGIN
INSERT INTO dbo.T_EngWInfo(WordID, WordPos, WordMean, MeanTag, Prof, Orig_CAT)
VALUES (@WID, @Pos, @Mean, @Tag, @Prof, 1)
END
ELSE
BEGIN
UPDATE dbo.T_EngWInfo
SET Orig_CAT = 1
WHERE (WordID = @WID) and (WordMean = @Mean) and (WordPos = @Pos) and (Prof = @prof)
END

/*处理出错信息*/
IF @@ERROR != 0
BEGIN
ROLLBACK TRAN
PRINT'插入出错'
RETURN
END
COMMIT TRAN
GO
 
在经常作为查询条件的字段加上索引
 
建议将赋值类语句(如 SELECT @?? = ?? FROM dbo....) 放在BEGIN TRAN ... COMMIT TRAN
的外面.
自己改了试试吧
 
索引已经加了,
TO:smallbs
只能挪出第一个,可没多大用
 
将一个BEGIN TRAN ... COMMIT TRAN改成两个
INSERT INTO dbo.T_EngWWord(EWord) VALUES (@Word) //这里放一个
下面的插入和修改语句再放一个(用变量来控制它是否执行)
另外,测试一下类似 SELECT @Count = COUNT(*) FROM 。。和 SELECT @Count = COUNT(EWord) FROM 。。
之间在效率上有什么不同 ?
 
SELECT @Count = COUNT(*) FROM
速度稍快,

[red]还是不行,我还是说说我的意图吧,诸位看了上面的过程可能就有了先入为主的印象[/red]
[blue]执行这个存储过程添加一条单词的信息,先判断主表有没有这个单词,如果有了就
得到它的ID,在向从表添加词性、意义等信息,
WordID,WordMean,WordPos,Prof是一个唯一索引,如果从表已经有这些信息了,则将
Orig_CAT设为真[/blue]
不知诸位这个功能怎么实现?
 
CREATE PROCEDURE AddWord

@Word VARCHAR(50),
@POS VARCHAR(8),
@Mean VARCHAR(500),
@TAG INT,
@Prof VARCHAR(12)

AS

DECLARE @WID bigint /*WordID*/
DECLARE @Count INT

SELECT @WID = WordID FROM dbo.T_EngWWord WHERE EWord = @Word
//没找到
if @@ROWCOUNT = 0
BEGIN
INSERT INTO dbo.T_EngWWord(EWord) VALUES (@Word)
SELECT @WID = @@IDENTITY//假如WordID是自动增长列可以这样用
END

UPDATE dbo.T_EngWInfo
SET Orig_CAT = 1
WHERE (WordID = @WID) and (WordMean = @Mean) and (WordPos = @Pos) and (Prof = @prof)

//没发现
if @@ROWCOUNT = 0
INSERT INTO dbo.T_EngWInfo(WordID, WordPos, WordMean, MeanTag, Prof, Orig_CAT)
VALUES (@WID, @Pos, @Mean, @Tag, @Prof, 1)
END
GO
 
谢谢,似乎速度稍快些了,还很慢,难道是我表结构建的有问题?
 
to: qianwt
用事务和不用事务执行这段代码又什么不同吗?
 
to panjf:
没有什么不同,不过你这里用事务干吗呢,没有什么意义
在表T_EngWWord中对EWord字段建唯一索引,
create unique index EngWWord_index on T_EngWWord(EWord)
在表T_EngWInfo中对WordID,WordMean,WordPos,Prof四个字段建唯一索引,
create unique index T_EngWInfo_index on T_EngWInfo(WordID,WordMean,WordPos,Prof)
建过索引速度应该会快很多。



表结构问题:
T_EngWWord中EWord已经是唯一的了,为什么不用EWord做主键,而用自动增长列WordID呢,
主外键自然也可以用EWord来关联呀,你这样就多花了查找WordID的时间,
 
请问有多慢?
我用interbase作类似的更新, 200,000条纪录的表, 每均可处理 1200rows/sec
(用PIII 600, 64M, Win2K Prof., Firebird 1.5)

是否该表有很多index, foreign key要同时更新吗?
 
to qianwt:
谢谢你的提醒,让偶茅塞顿开,请问
如果不用事务,两个用户同时执行这个存储过程不会冲突吗?
什么时候改用事务呢?
那几个索引已经建了。
另外我的机器是PII400,384M内存,当有两个用户同时用这个存储过程插入大量数据时速度
就变得极慢,是我的cpu太差了吗?
 
看两个用户的EWord是否一样,假如一样后面的修改会覆盖前面的修改,
你这里并发操作本身就是合理的,你也不是修改后的值与修改前的值有关,
你用事务同样解决不了并发操作的问题,
 
速度的问题与很多问题有关,CPU是一个方面吧
用SQL语句对数据库操作,速度本来就不是很快(特别是数据量大)
除非你用OLEDB来对SQL SERVER操作,可以提高2-1000倍(书上看来的)
你用DTS导数据和通过程序一条一条插入就可以看出效果了
 
你的意思是不用存储过程,用程序 + ADO吗?
 
不是ADO,就是另外一种访问SQL SERVER的方法,
我没有用过,不过网上的这些资料应该比较多.
 
好的,非常感谢你
 
顶部