【问题标题】:Can I optimize a SELECT DISTINCT x FROM hugeTable query by creating an index on column x?我可以通过在列 x 上创建索引来优化 SELECT DISTINCT x FROM hugeTable 查询吗?
【发布时间】:2011-08-23 20:24:03
【问题描述】:

我有一个巨大的表,在某些列 x 上的不同值的数量要少得多(按数量级)。

我需要做一个类似SELECT DISTINCT x FROM hugeTable 的查询,而且我想相对快一点。

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

既然我在x 列上创建了一个索引,我不能指望这个查询运行得很快吗?

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

【问题讨论】:

  • 您好,您要索引的列是“int”字段吗?表上索引的想法是让系统映射出该索引在模型中的位置,然后使其更容易检索。如果这个字段除了只是一个值之外没有任何相关性,它真的不会有太大的区别,因为它仍然需要扫描表。
  • 如果在hugeTablex=1 中有1000 行,那么hugeTable_by_x 仍然必须在x=1 的叶级别中包含对这些行的1000 个引用。如果这些引用很广泛(hugeTable 的聚类键是什么?),索引本身就会很大。
  • 请注意,我也试过SELECT x FROM hugeTable GROUP BY x,它给出了完全相同的查询计划。

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


【解决方案1】:

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

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

【讨论】:

    【解决方案2】:

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

    索引通常对WHERE 条件、JOINSORDER BY 子句有更大的影响。

    【讨论】:

    • 它并不真正“必须扫描索引中的每个值”。在内部,它可以执行一系列搜索(例如二进制搜索)来查找值的连续变化。
    【解决方案3】:

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

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

    可能还有其他方法可以解决您的问题。在 SQL Server 中,我想到了索引视图。但是,这可能会给您在该表上的写入带来很大的影响。

    【讨论】:

      【解决方案4】:

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

      更新
      作为一种解决方法,您可以通过“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);
      

      【讨论】:

      • 虽然您所说的绝对正确,但您所说的情况可能正是为什么要完成SELECT DISTINCT,作为规范化过程的一部分。例如,我们有一个系统,它从一组下载的 FTP 文件中引入数据馈送。该数据根本没有标准化。这是我们流程精确功能的一半,即在我们将数据加载到系统中时对其进行规范化。例如,我们有一个查询(伪代码),例如INSERT INTO NORMALIZEDVALUELIST (NAME) SELECT DISTINCT SOMEFIELD FROM UNNORMALIZEDSOURCE WHERE <SOMEFIELD NOT IN NORMALIZEDVALUELIST(NAME)>
      • 关于解决方法,随着时间的推移,通过 CRUD 操作维护此索引视图的 CPU 成本会不会高于原始表上的简单索引?然后发布的其他一些解决方法可能是更好的选择。
      • 索引视图确实增加了写入操作的成本。如果只有几个不同的值并且表很大,我认为它实际上可能比列上的索引便宜。如果没有别的,索引视图占用的磁盘空间比索引占用的磁盘空间要少得多。所以答案是“视情况而定”。
      • 您好,答案很好,但示例 SQL 将无法按原样运行。创建视图时,您需要命名所有列。目前count_big(*) 列没有名称,因此会出错。我建议使用count_big(*) as kount 之类的东西,只是给它一个名字并让视图定义编译。
      【解决方案5】:

      如果您事先知道这些值并且在 x 列上有一个索引(或者如果每个值都可能在整个表的 seq 扫描中快速出现),那么单独查询每个值会快得多:

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

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

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

      【讨论】:

        【解决方案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)
        

        【讨论】:

          【解决方案7】:

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

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

          https://stackoverflow.com/a/29286754/538763(引用了多种解决方法)

          其他答案说您可以规范化这将解决您的问题,但即使其规范化的 SQL Server 仍然喜欢执行扫描以查找组中的 max()。解决方法:

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

          【讨论】:

            【解决方案8】:

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

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2013-02-28
              • 1970-01-01
              • 2012-02-23
              • 2018-01-05
              • 2013-04-11
              • 2021-11-12
              • 2019-06-26
              • 2018-01-12
              相关资源
              最近更新 更多