我可以通过在列x上创建索引来优化SELECT DISTINCT x FROM hugeTable查询吗?

时间:2011-05-12 05:54:16

标签: sql sql-server-2005 tsql indexing query-optimization

我有一个巨大的表格,在某些列x上具有更小的数字(按数量级)不同的值。

我需要像SELECT DISTINCT x FROM hugeTable那样进行查询,我想要相对较快地执行此操作。

我做了CREATE INDEX hugeTable_by_x ON hugeTable(x)之类的事情,但出于某种原因,即使输出很小,查询执行速度也不快。查询计划显示97%的时间花在hugeTable_by_x的索引扫描上,估计的行数等于整个表的大小。接下来是哈希匹配操作。

由于我在列x上创建了索引,我不能指望此查询运行得非常快吗?

请注意,我使用的是Microsoft SQL Server 2005.

8 个答案:

答案 0 :(得分:22)

这可能不是索引问题,而是数据设计问题之一。准确归一化。您需要查询字段的不同值,甚至愿意添加索引这一事实强烈表明该字段应该规范化为具有(小)连接键的单独表。然后通过扫描更小的查找外表来立即获得不同的值。

更新
作为解决方法,您可以通过“distinct”字段在聚合上创建indexed viewCOUNT_BIG是索引视图中允许的聚合:

create view vwDistinct
with schemabinding
as select x, count_big(*)
from schema.hugetable
group by x;

create clustered index cdxDistinct on vwDistinct(x);

select x from vwDistinct with (noexpand);

答案 1 :(得分:6)

SQL Server没有实现任何工具来直接寻找索引中的下一个不同的值,一路上跳过重复项。

如果您有许多重复项,那么您可以使用递归CTE来模拟这一点。该技术来自here。 (“使用递归CTE的超快速DISTINCT”)。例如:

with recursivecte as (
  select min(t.x) as x
  from hugetable t
  union all
  select ranked.x
  from (
    select t.x,
           row_number() over (order by t.x) as rnk
    from hugetable t
    join recursivecte r
      on r.x < t.x
  ) ranked
  where ranked.rnk = 1
)
select *
from recursivecte
option (maxrecursion 0)

答案 2 :(得分:2)

如果您事先知道这些值并且列x上有索引(或者如果每个值很可能在整个表的seq扫描中快速显示),则单独查询每个值要快得多:

select vals.x
from [values] as vals (x)
where exists (select 1 from bigtable where bigtable.x = vals.x);

继续使用exists()将执行与有效值一样多的索引查找。

您编写它的方式(如果事先不知道值,这是正确的),查询引擎将需要读取整个表并散列聚合该混乱以提取值。 (这使得索引毫无用处。)

答案 3 :(得分:1)

没有。但是有一些解决方法(不包括规范化):

一旦索引到位,那么可以在SQL中实现优化器可以自动执行的操作:

https://stackoverflow.com/a/29286754/538763(引用多个变通方法)

其他答案说你可以规范化哪个可以解决你的问题,但即使其规范化的SQL Server仍然喜欢执行扫描以找到组内的max()。解决方法:

https://dba.stackexchange.com/questions/48848/efficiently-query-max-over-multiple-ranges?rq=1

答案 4 :(得分:0)

在索引字段上执行SELECT DISTINCT时,索引扫描是有意义的,因为执行仍然必须扫描整个表的索引中的每个值(假设没有WHERE子句,似乎你的例子是这样的。)

索引通常会对WHERE条件,JOINSORDER BY条款产生更大的影响。

答案 5 :(得分:0)

根据您对执行计划的描述,我认为这是最好的执行。

索引扫描读取存储的整个索引(不是按索引顺序),HASH MATCH执行不同的操作。

您的问题可能还有其他方法。在SQL Server中,我想到了索引视图。但是,这可能会让你在该桌面上的写作受到重创。

答案 6 :(得分:0)

如果列x的基数较低,则创建本地位图索引将使性能提高很多倍。

答案 7 :(得分:-1)

可能。虽然不能保证 - 但这完全取决于查询。

我建议您阅读Gail Shaw撰写的这篇文章(part 1part 2)。