我有一张大约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 子句中的查询,这将是我实际使用中的一个小得多的列表。
由于
答案 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
。
此外,检查数据库排序规则以查看它是否与实例排序规则匹配。确保没有硬盘性能问题。