我有一个巨大的表格,在某些列x
上具有更小的数字(按数量级)不同的值。
我需要像SELECT DISTINCT x FROM hugeTable
那样进行查询,我想要相对较快地执行此操作。
我做了CREATE INDEX hugeTable_by_x ON hugeTable(x)
之类的事情,但出于某种原因,即使输出很小,查询执行速度也不快。查询计划显示97%的时间花在hugeTable_by_x
的索引扫描上,估计的行数等于整个表的大小。接下来是哈希匹配操作。
由于我在列x
上创建了索引,我不能指望此查询运行得非常快吗?
请注意,我使用的是Microsoft SQL Server 2005.
答案 0 :(得分:22)
这可能不是索引问题,而是数据设计问题之一。准确归一化。您需要查询字段的不同值,甚至愿意添加索引这一事实强烈表明该字段应该规范化为具有(小)连接键的单独表。然后通过扫描更小的查找外表来立即获得不同的值。
更新
作为解决方法,您可以通过“distinct”字段在聚合上创建indexed view。 COUNT_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
条件,JOINS
和ORDER BY
条款产生更大的影响。
答案 5 :(得分:0)
根据您对执行计划的描述,我认为这是最好的执行。
索引扫描读取存储的整个索引(不是按索引顺序),HASH MATCH执行不同的操作。
您的问题可能还有其他方法。在SQL Server中,我想到了索引视图。但是,这可能会让你在该桌面上的写作受到重创。
答案 6 :(得分:0)
如果列x的基数较低,则创建本地位图索引将使性能提高很多倍。
答案 7 :(得分:-1)