【问题标题】:is there something faster than "having count" for large tables?对于大桌子,有什么比“计数”更快的吗?
【发布时间】:2010-10-23 13:30:35
【问题描述】:

这是我的查询:

select word_id, count(sentence_id) 
from sentence_word 
group by word_id 
having count(sentence_id) > 100;

表 sentenceword 包含 3 个字段,wordid、sentenceid 和一个主键 id。 它有 350k+ 行。 这个查询需要高达 85 秒,我想知道(希望,祈祷?)有一种更快的方法可以找到所有超过 100 个句子 ID 的单词 ID。

我试过去掉 select count 部分,只是做“有 count(1)”,但都没有加快速度。

如果您能提供任何帮助,我将不胜感激。谢谢!

【问题讨论】:

  • 这是与 MySQL 的(并使用 HeidiSQL 作为客户端访问它)
  • 另一个烦人的澄清...(对不起):数据在不断变化。每天大约 10k 插入行和约 5k 删除行。所以我认为这使得存储或缓存结果不可能

标签: sql count query-optimization having


【解决方案1】:

如果经常执行该查询,并且该表很少更新,您可以保留一个带有单词 ID 和相应句子计数的辅助表——除此之外很难想到任何进一步的优化!

【讨论】:

    【解决方案2】:

    如果您还没有,请在 sentence_id、word_id 上创建一个复合索引。

    【讨论】:

    • 我相信该索引的正确列顺序是 (word_id, sentence_id)。
    • @Irina C:我刚刚在 SQL Server 上使用索引列进行了双向测试,尽管执行计划不同,但逻辑 IO 的数量是相同的。
    【解决方案3】:

    您的查询很好,但需要一些帮助(索引)才能获得更快的结果。

    我手头没有资源(或无法访问 SQL),但我会尽量从记忆中帮助您。

    从概念上讲,回答该查询的唯一方法是计算所有共享相同 word_id 的记录。这意味着查询引擎需要一种快速的方法来查找这些记录。如果没有 word_id 上的索引,数据库唯一能做的就是一次遍历表一条记录,并保持运行它找到的每个不同 word_id 的总数。这通常需要一个临时表,并且在扫描整个表之前不能发送任何结果。不好。

    有了 word_id 上的索引,它仍然需要遍历表,所以你会认为它没有多大帮助。但是,SQL 引擎现在可以计算每个 word_id 的计数,而无需等到表的末尾:它可以分派行和 word_id 的值的计数(如果它通过您的where 子句),或者丢弃该行(如果没有);这将导致服务器上的内存负载降低,可能会导致部分响应,并且不再需要临时表。第二个方面是并行性。通过 word_id 上的索引,SQL 可以将作业分成块并使用单独的处理器内核并行运行查询(取决于硬件功能和现有工作负载)。

    这可能足以帮助您查询;但你必须尝试看看:

    CREATE INDEX someindexname ON sentence_word (word_id)
    

    (T-SQL 语法;您没有指定您使用的 SQL 产品)

    如果这还不够(或根本没有帮助),还有其他两种解决方案。

    首先,SQL 允许您使用索引视图和其他机制预先计算 COUNT(*)。我手头没有详细信息(而且我不经常这样做)。如果您的数据不经常更改,那么您会获得更快的结果,但会增加复杂性和一些存储空间。

    此外,您可能需要考虑将查询结果存储在单独的表中。仅当数据从不更改或按精确的时间表更改(例如,在凌晨 2 点刷新数据期间),或者如果更改很少并且您可以在几个小时内忍受不完美的结果(您必须安排定期数据刷新);这在道德上相当于穷人的数据仓库。

    确定适合您的方法的最佳方法是运行查询并查看查询计划,其中包含或不包含上述候选索引。

    【讨论】:

    • 感谢您的帮助!事实上,所有相关字段都已编入索引......但只需将查询更改为 count(*) 而不是 count(sentence_id) 就是答案!日日夜夜。所以似乎就是这样。我认为出于某种原因,我认为带有特定字段的 count() 比使用 * 更有效,但现在这似乎是一个愚蠢的假设。将进行更多检查以确认这是问题所在。
    【解决方案4】:

    计数(sentence_id) > 100;

    这有问题...表格有重复的单词/句子对,或者没有。

    如果确实有重复的单词/句子对,您应该使用此代码来获得正确答案:

    HAVING COUNT(DISTINCT Sentence_ID) > 100
    

    如果表中没有重复的词/句对...那么你不应该计算 sentence_ids,你应该只计算行数。

    HAVING COUNT(*) > 100
    

    在这种情况下,您可以在 仅 word_id 上创建索引,以获得最佳性能。

    【讨论】:

    • 令人惊讶的是,像 * 这样简单的东西是 85 秒查询和字面上 0.3 秒之间的差异!谢谢大家-
    【解决方案5】:

    令人惊讶的是,有一种更快的方法可以在大型数据集上实现这一目标:

    SELECT totals.word_id, totals.num 
      FROM (SELECT word_id, COUNT(*) AS num FROM sentence_word GROUP BY word_id) AS totals
     WHERE num > 1000;
    

    【讨论】:

      猜你喜欢
      • 2017-04-03
      • 2015-07-20
      • 2011-11-07
      • 1970-01-01
      • 1970-01-01
      • 2013-12-11
      • 2011-04-13
      • 2013-12-02
      • 2013-05-17
      相关资源
      最近更新 更多