Sql 查询速度慢,索引扫描意外

Sql 查询速度慢,索引扫描意外,sql,performance,indexing,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,它包含1110万

我有一个疑问:

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,它包含1110万条记录。左边的两张桌子大约1米

此查询运行缓慢(超过10分钟),并返回大约800条记录。执行计划时,将对所有11M记录进行聚集索引扫描(在其主键上(result.result\u number,实际上不参与查询))。 RESULT.TEST_编号是群集主键

如果我把2010-03-17 09:00改为2010-03-17 10:00,我会得到大约40条记录。它执行300毫秒。计划显示索引搜索(超过结果测试编号索引)

若我将SELECT子句中的*替换为result.test_number(包含索引),那个么在第一种情况下,所有这些都会变快。这指出了硬盘IO的问题,但并没有澄清计划的变化

有什么想法吗

更新: 抽样日期在表样本中,并包含在索引中。 此查询中的其他字段:test.sample\u number也包含在索引和result.test\u number中

更新2: 显然比sql server在任何方面都不想使用索引

我做了一个小实验:我用result删除内部连接,选择所有test.test\u编号,然后执行

SELECT * FROM RESULT WHERE TEST_NUMBER IN (...)
当然,这很快就能奏效。但我不知道有什么区别,为什么查询优化器在第一种情况下选择这样不合适的方式来选择数据

更新3: 备份数据库并使用新名称还原到数据库后,这两个请求的工作速度与预期一样快,甚至在更大的范围内


那么-是否有任何与此相关的用于清理或优化的特殊命令-(

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

听起来好像很难从结果表中取出所有行。行有多大?看看表中所有数据有多大,然后除以行数。右键单击表->属性…,存储选项卡

尝试将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'
)

如果执行
选择*
,则需要表中的所有数据。表的数据位于聚集索引中-聚集索引的叶节点位于数据页中


因此,如果您想要所有这些数据页,并且由于您要将1百万行加入到11百万行中(11个中的1个对于SQL Server不是很有选择性),使用索引查找行,然后对找到的每一行的实际数据页进行书签查找,可能效率不高,因此SQL Server使用聚集索引扫描


长话短说:只选择您真正需要的行!这样,SQL Server就有机会使用索引,在那里进行搜索,并找到必要的数据

如果只选择三、四列,那么SQL Server找到并使用包含这些列的索引的可能性要比从所有相关表中获取所有数据的可能性大得多


另一种选择是尝试找到一种表达子查询的方法,例如使用公共表表达式,从两个较小的表中获取数据,并进一步减少行数,然后将希望非常小的结果与主表连接。如果您的结果集很小,只有40或800个结果(而不是两个各有1百万行的表),那么SQL Server可能更倾向于使用聚集索引查找,并在40或800行上进行书签查找,而不是进行完整的聚集索引扫描。

尝试以下几点:

  • 更新统计数据
  • 向查询中添加有关要使用的索引的提示(在SQL Server中,您可以在指定表后使用(index(myindex)))
编辑:您注意到复制数据库使其正常工作,这告诉我索引统计信息已过时。您可以定期使用类似于
updatestatistics mytable
的内容更新它们


使用
EXEC sp\u updatestats
更新整个数据库。

是否有一个仅在采样日期上的索引?您使用的是什么SQL server?采样日期在哪个表中?当然是采样日期在样本中。当然,它也包含索引(计划中此索引的索引搜索始终是)。SQL 2000。“采样日期上有索引吗?”我不明白这一点:-(是否有一个索引的唯一列是SAMPLE\u date?是的。有一个索引只包含SAMPLE.Sampled\u date(并且没有其他索引包含此字段的最左侧部分)尝试选择“x”而不是选择*。它有多快?可能是返回的数据量。如果是数据量(800行)如果出现问题,请尝试对结果1进行分页。结果表中已包含索引。问题,而不是示例2.800 vs 40(相应的第一次和第二次查询)。如果我指定了与RESULT.TEST_编号不同的任何字段(从…中选择RESULT.NAME)例如,我得到一个缓慢的查询,并计划使用聚集索引扫描此查询得到相同的结果(也很慢)。但即使在10-12小时的时间间隔内,速度也很慢。请检查行的大小,请参见上文。还要查看在上午9点到10点的时间范围内是否有大量数据。最后一次查询不会有帮助,因为正如我所说的,问题在于结果,而不是样本“因此,如果您仍然想要所有这些数据页,并且由于您要将1百万行加入11百万行”我将把大约20行(日期范围限制)加入到带有索引的11百万行中。无论如何,这并不能解释为什么更改范围会稍微改变计划。为什么sql可以将索引用于20行而不能使用到800行因此,长话短说:只选择您真正需要的行!这样,SQL Server就有机会使用索引,在那里进行搜索,并找到必要的数据。”因此,如果我枚举所有需要的20个字段