我有一个运行缓慢的更新查询(请参阅下面的第一个查询)。我在PhoneStatus表和PhoneID列上创建了一个名为IX_PhoneStatus_PhoneID的索引。 Table PhoneStatus包含2000万条记录。当我运行以下查询时,不使用索引并使用聚簇索引扫描,反过来更新运行缓慢。
UPDATE PhoneStatus
SET RecordEndDate = GETDATE()
WHERE PhoneID = 126
如果我执行以下查询(包括新的FROM),我仍然会遇到与未使用的索引相同的问题。
UPDATE PhoneStatus
SET RecordEndDate = GETDATE()
FROM Cust_Profile.PhoneStatus
WHERE PhoneID = 126
但是,如果我添加HINT以强制在FROM上使用索引,它就可以正常工作,并且会使用Index Seek。
UPDATE PhoneStatus
SET RecordEndDate = GETDATE()
FROM Cust_Profile.PhoneStatus WITH(INDEX(IX_PhoneStatus_PhoneID))
WHERE PhoneID = 126
有谁知道为什么第一个查询不会使用索引?
更新
在包含2000万条记录的表中,每个phoneID最多可以显示10次
BarDev
答案 0 :(得分:5)
20M表中有多少个不同的PhoneID?如果条件where PhoneID=126
不够有选择性,您可能会点击索引tipping point。如果此查询和访问条件非常频繁,则PhoneID是群集索引最左侧密钥的良好候选。
答案 1 :(得分:2)
看看Is an index seek always better or faster than an index scan? 有时搜索和扫描将完全相同。
索引可能会被忽略,因为您的统计信息可能过时或索引的selectivity
太低而SQL Server认为扫描会更好
启用统计信息,查看有和没有搜索的查询之间是否存在任何差异
SET STATISTICS io ON
UPDATE PhoneStatus
SET RecordEndDate = GETDATE()
WHERE PhoneID = 126
UPDATE PhoneStatus
SET RecordEndDate = GETDATE()
FROM Cust_Profile.PhoneStatus WITH(INDEX(IX_PhoneStatus_PhoneID))
WHERE PhoneID = 126
现在看一下回来的读物
答案 2 :(得分:2)
Pablo是正确的,只有当SQL Server认为这将更有效地运行查询时,它才会使用索引。但是有2000万行应该知道使用索引。我想你只需要更新数据库的统计数据。
请填写更多信息,请参阅http://msdn.microsoft.com/en-us/library/aa260645(SQL.80).aspx。
答案 3 :(得分:1)
SQLServer(或任何其他SQL Server产品),如果没有强制使用任何索引。它将使用它,如果它认为将有助于更有效地运行查询。
因此,在您的情况下,SQLServer认为它不需要使用IX_PhoneStatus_PhoneID
,并且通过使用其聚簇索引可能会获得更好的结果。但这可能是错误的,这就是索引提示的含义:让服务器知道它可以通过使用其他索引做得更好。
如果最近创建并填充了您的表,则可能是统计数据有些过时的情况。所以你可能想要强制statistic update。
答案 4 :(得分:0)
重申:
SQL将接受您的查询并尝试找出如何在不进行操作的情况下完成工作 整个桌子。对于非聚集索引,数据可能如下所示:
PhoneStatus PhoneID
A 124
A 125
A 126
B 127
C 128
C 129
C 130
etc.
问题是,SQL将首先检查第一列,之前检查值 第二栏由于更新中未指定第一列,因此SQL 不能通过索引搜索树“快捷”到相关条目,因此必须扫描整个表。 (不,SQL不够聪明,不能说“呃,我只是检查一下 第二列首先“,是的,他们这样做是对的。”
由于非聚集索引不会使查询更快,因此默认为表 扫描 - 并且由于存在聚簇索引,这意味着它将成为聚簇索引扫描。 (如果聚集索引在PhoneId上,那么您的查询会有最佳性能,但我猜这不是这种情况。)
使用提示时,会强制使用非聚集索引,这样会更快 而不是全表扫描如果该表的列数远多于索引(其中 基本上只有两个),因为要筛选的数据要少得多。