我有一个简单的select语句需要很长时间才能运行,但是在同一个表上使用相同WHERE子句运行count(*)会在不到一秒的时间内返回。
此查询运行很长时间(1小时+):
SELECT col1
, col2
, col3
FROM Table
WHERE RowInsertDate >= @SomeStartDate
AND RowInsertDate < @SomeEndDate
但是这个查询在不到一秒的时间内就会出现:
SELECT count(*)
FROM Table
WHERE RowInsertDate >= @SomeStartDate
AND RowInsertDate < @SomeEndDate
该表有3400万行,其中包含ID列和用于主键的地理区域(北,南,东,西)列。列&#39; RowInsertDate&#39;是行插入表中的日期。上述查询的预期结果是“没有行”,&#39;和&#39; 0&#39;分别
此表的聚簇索引是(ID,geoRegion)ASC。该表在RowInsertDate ASC上还有一个非聚集索引。
我不知道从哪里开始。有没有人遇到过这个?
答案 0 :(得分:1)
运行select count(*)
SQL Server只能计算索引中的行数。当您运行select col1,col2,col3
时,对于索引中找到的每一行,SQL Server必须获取聚簇索引键值(ID,geoRegion,存储在索引中),然后使用该聚簇索引搜索从表中找到的所有行关键值。
如果SQL Server认为对聚簇索引执行所有查找将更有效,那么SQL Server也可以决定进行聚簇索引扫描(或其他)。您可以查看查询计划中发生的情况。
为了使查询更快,您可能需要考虑将您需要选择的列添加到RowInsertDate中,无论是包含列还是普通列。这当然只有在列数相对较小时才会有意义(或者表的更新不会很多)。
答案 1 :(得分:0)
虽然您可以查看执行计划,但我很确定这是典型的BOOKMARK LOOKUP问题。它耗费资源并且耗时。一种解决方案是创建一个COVERING INDEX来处理它。
这两个查询的执行时间不同,因为它们完全不同。
当然,您还应该检查列(col1,col2,col3)的数据类型。
除此之外,您还可以设置NOCOUNT ON。希望它有所帮助。
答案 2 :(得分:0)
如果ID是唯一的(例如身份),那么我建议您单独使用PK群集。额外的列必须携带额外的数据进行查找。
我和我希望geoRegion是一个字节。如果是varchar,那么你所需的音量是你的10倍。这是相同内存量的索引的1/10。
如果上面没有修复它,那么在索引
中添加包含这些列CREATE NONCLUSTERED INDEX IX_Table_RowInsertDate
ON Table (RowInsertDate)
INCLUDE (col1, col2, col3);
答案 3 :(得分:-2)
由于查询非常简单。我认为你缺少的是一个nolock:
SELECT col1
, col2
, col3
FROM Table (nolock)
WHERE RowInsertDate >= @SomeStartDate
AND RowInsertDate < @SomeEndDate