我有一个问题,为什么有些SQL(在SQL Server 2005上运行)的行为是这样的。具体来说,我在更新期间进行了一次更改以减少锁争用,并且在我认为不会的情况下似乎正在工作。为什么SQL更新顶部显然减少锁定,即使没有记录更新?
原始代码:
我们有这样的更新语句,这是被应用到表300多万条记录:
UPDATE USER WITH (ROWLOCK)
SET Foo = 'N', Bar = getDate()
WHERE ISNULL(email, '') = ''
AND Foo = 'Y'
正如你可能已经猜到,这似乎锁定USER表一段时间。即使使用ROWLOCK提示,针对USER运行查询和更新的其他作业也会阻塞,直到完成此操作。这对于这个特定的应用程序来说是不可接受的,所以我认为我会通过让update语句一次只更新100条记录来应用我读到的一个技巧。这会让其他查询有机会偶尔进入桌面。
改进代码:
DECLARE @LOOPAGAIN AS BIT;
SET @LOOPAGAIN = 1;
WHILE @LOOPAGAIN = 1
BEGIN
UPDATE TOP (100) USER WITH (ROWLOCK)
SET Foo = 'N', Bar = getDate()
WHERE ISNULL(email, '') = ''
AND Foo = 'Y'
IF @@ROWCOUNT > 0
SET @LOOPAGAIN = 1
ELSE
SET @LOOPAGAIN = 0
END
这并获得成功。我们的更新完成了其工作,其他查询能够获得表格。一切都是幸福与光明。
谜:
我明白这是如何提高性能时有它不得不更新表中的许多记录。每完成100次更新后,通过循环快速运行,就可以让其他查询有机会进入桌面。神秘的是,即使没有受到更新影响的记录,此循环也具有相同的效果!
第二次运行我们的原始查询时,它只会运行一小部分时间(比如说30秒左右),但是在那段时间内它会锁定表,即使没有记录被更改。但是,将查询放在循环中的“TOP(100)”子句中,尽管无需执行任务就花了很长时间,但是它为其他查询释放了空间!
我对此很惊讶。谁能告诉我:
- 如果我刚才说的是,在所有的清晰,
- 为什么第二个代码块允许其他的查询在表中获取,即使没有被更新的记录?
我认为在它意识到没有要更新的行之前,仍然需要对表进行“SELECT”操作。 – 2009-11-10 20:32:43
在什么事务隔离级别下? – 2009-11-10 21:18:25