简单的选择查询运行速度非常慢,但在运行速度相同的表上选择count(*)

时间:2016-08-16 16:43:21

标签: sql sql-server tsql

我有一个简单的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上还有一个非聚集索引。

我不知道从哪里开始。有没有人遇到过这个?

4 个答案:

答案 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