在SQL Server 2005中的巨大表上使用“not in”进行更新

时间:2011-03-25 16:31:30

标签: sql-server indexing

我有一张大约115k行的表格。像这样:

Table: People
Column: ID PRIMARY KEY INT IDENTITY NOT NULL
Column: SpecialCode NVARCHAR(255) NULL
Column: IsActive BIT NOT NULL

最初,我有一个像这样定义的索引:

PK_IDX (clustered) -- clustered index on primary key
IDX_SpecialCode (non clustered, non-unique) -- index on the SpecialCode column

我正在做这样的更新:

Update People set IsActive = 0 
Where SpecialCode not in ('...enormous list of special codes....')

这个庞大的列表基本上是表中99%的用户。

此更新在我的服务器上永久 。作为测试,我将“not in”子句中的特殊代码列表修剪为表中1%的用户,并且我的执行计划最终使用PK_IDX索引上的INDEX SCAN而不是IDX_SpecialCode索引。以为它会用。

所以,我想也许我需要修改IDX_SpecialCode,以便它包含“IsActive”列。我这样做了,我仍然看到执行计划默认为PK_IDX索引扫描,我的查询仍然需要很长时间才能运行。

那么 - 更正确地更新这种性质的方法是什么?我有来自更新的排除的用户列表,但是试图避免从数据库中加载所有员工的特殊代码,过滤掉我的应用程序端不在我的列表中的那些代码,然后运行我的 in 子句中的查询,这将是我实际使用中的一个小得多的列表。

由于

4 个答案:

答案 0 :(得分:3)

如果您有要排除的员工,为什么不用这些PK_ID填充索引表并执行:

Update People 
set IsActive = 0 
Where NOT EXISTS (SELECT NULL
                  FROM lookuptable l
                  WHERE l.PK = People.PK)

您正在获取索引扫描,因为SQL Server并不愚蠢,并且意识到只查看整个表而不是一次检查100个不同的条件更有意义。如果您的统计信息是最新的,则优化器会知道IN语句覆盖了多少表,如果它认为表更快,则会执行表或聚簇索引扫描。

答案 1 :(得分:1)

使用NOT子句时,将忽略SQL-Server索引。这就是为什么你看到执行计划忽略你的索引。 < - 参考:第6页.MCTS考试70-433数据库开发SQL 2008(我现在正在阅读)

可能值得一看全文索引,虽然我不知道是否会发生同样的事情(我还没有访问一个设置为目前测试的框)

HTH

答案 2 :(得分:0)

是否有任何方法可以使用您希望排除的用户的ID而不是代码 - 即使在索引值上,比较ID也可能比字符串更快。

答案 3 :(得分:0)

我认为问题出在SpecialCode NVARCHAR(255)上。 Sql Server中的字符串比较非常慢。请考虑更改您的查询以使用ID。而且,尽量避免使用NVarchar。如果不关心Unicode,请改用Varchar

此外,检查数据库排序规则以查看它是否与实例排序规则匹配。确保没有硬盘性能问题。