具有意外索引扫描的慢查询

时间:2010-03-17 23:25:53

标签: sql performance indexing

我有这个问题:

SELECT *
FROM sample
   INNER JOIN test ON sample.sample_number = test.sample_number
   INNER JOIN result ON test.test_number = result.test_number
   WHERE sampled_date BETWEEN '2010-03-17 09:00' AND '2010-03-17 12:00'

这里最大的表是RESULT,包含11.1M记录。左边的2个表格大约是1M。

此查询运行缓慢(超过10分钟)并返回大约800条记录。执行计划在所有11M记录上显示聚集索引扫描(通过它的PRIMARY KEY(result.result_number,实际上不参与查询))。 RESULT.TEST_NUMBER是一个群集主键。

如果我改变2010-03-17 09:00到2010-03-17 10:00 - 我得到大约40条记录。它执行300毫秒。和计划显示索引搜索(在result.test_number索引上)

如果我将SELECT子句中的*替换为result.test_number(用索引覆盖) - 那么在第一种情况下也会变快。这指向了硬盘IO问题,但没有说明改变计划。

那么,有什么想法吗?

更新 sampled_date在表格样本中并由索引覆盖。 此查询中的其他字段:test.sample_number也由index和result.test_number覆盖。

更新2: 显然比sql server在任何原因都不想使用索引。

我做了一个小实验:我用结果删除INNER JOIN,选择所有test.test_number然后再做

SELECT * FROM RESULT WHERE TEST_NUMBER IN (...)

这当然很快。但我无法得到有什么不同,以及为什么查询优化器选择这种不恰当的方式来选择第一种情况下的数据。

更新3: 在备份数据库并使用新名称还原到数据库之后 - 即使在更多范围内,这两个请求也可以按预期快速运行...

所以 - 是否有任何特殊的命令来清理或优化,可能与此相关? : - (

3 个答案:

答案 0 :(得分:7)

有几件事要尝试:

  • 更新统计信息
  • 在查询中添加有关使用哪个索引的提示(在SQL Server中,您可以在指定表后指出WITH (INDEX(myindex))
编辑:您注意到复制数据库使其工作,这告诉我索引统计信息已过期。您可以定期使用UPDATE STATISTICS mytable更新它们。

使用EXEC sp_updatestats更新整个数据库。

答案 1 :(得分:0)

我要做的第一件事是指定我想要的确切列,并查看问题是否仍然存在。我怀疑你需要所有三个表中的所有列。

听起来很难从结果表中获取所有行。一排多大?查看表中所有数据的大小,并将其除以行数。右键单击表格 - >属性...,存储选项卡。

尝试将where子句放入子查询中以强制它首先执行此操作?

SELECT *
FROM 
    (SELECT * FROM sample 
     WHERE sampled_date 
     BETWEEN '2010-03-17 09:00' AND '2010-03-17 12:00') s
     INNER JOIN test ON s.sample_number = test.sample_number
     INNER JOIN result ON test.test_number = result.test_number

如果您期望少量样本

,这可能会更好
SELECT *
FROM sample
   INNER JOIN test ON sample.sample_number = test.sample_number
   INNER JOIN result ON test.test_number = result.test_number
WHERE sample.sample_ID in (
    SELECT sample_ID
    FROM sample
    WHERE sampled_date BETWEEN '2010-03-17 09:00' AND '2010-03-17 12:00'
)

答案 2 :(得分:0)

如果您执行SELECT *,则需要表格中的所有数据。表的数据位于聚簇索引中 - 聚簇索引的叶节点数据页。

所以如果你想要所有这些数据页面,并且因为你加入了1 mio。行到11兆。行(11个中的1个对SQL Server不是非常有选择性),使用索引查找行,然后对找到的每个行的实际数据页进行书签查找,可能效率不高,因此SQL Server使用聚簇索引扫描。

所以简而言之:只选择你真正需要的那些行!因此,您可以为SQL Server提供使用索引的机会,在那里进行搜索,并找到必要的数据。

如果您只选择三列,四列,则SQL Server将查找并使用包含这些列的索引的可能性比您要求所有相关表中的所有数据要高得多。

另一种选择是尝试找到表达子查询的方法,例如使用例如一个公用表表达式,它将从两个较小的表中获取数据,并进一步减少该行数,并加入对主表的希望非常小的结果。如果你有一个只有40或800个结果的小结果集(而不是两个表每行1个mio。),那么SQL Server可能更倾向于使用Clustered Index Seek并在40或800行上进行书签查找,而不是而不是进行完整的聚集索引扫描。

相关问题