1

我们有一个大表,我们称之为“数据”,有大约 20 亿行,数据按日期、位置、名称进行索引。每行都有一个“分数”。

我们还有一个表格,其中包含该表格中所有不同的日期。

如果我运行这样的查询:

SELECT  AVG(score)
    FROM  Data d
    WHERE  d.date IN (
        SELECT  today
            FROM  dates dt
            WHERE  dt.today > '2020-01-01'
              AND  dt.today <  '2020-06-01'
              AND  d.location = 'Location1');

此查询会在几秒钟后返回。如果我然后运行相同的查询,但查找按名称分组的平均分数,则查询需要几分钟。IE

SELECT  d.name, AVG(score)
    FROM  Data d
    WHERE  d.date IN (
        SELECT  today
            FROM  dates dt
            WHERE  dt.today > '2020-01-01'
              AND  dt.today <  '2020-06-01'
              AND  d.location = 'Location1')
            GROUP BY  .d.name;

不同名称的数量是几十万,有什么技术可以提高这样的查询速度吗?

4

2 回答 2

2

首先试试这个。

 CREATE INDEX data_name_score ON Data (location, date, name, score);

这个复合 覆盖索引应该会加速您的查询。对于您的大小的表,创建需要一些时间。(运行它一夜之间,也许?)

为什么此索引会提高您的查询性能?将索引视为索引所有列中所有值的排序列表。

  1. MySQL 可以随机访问索引以查找第一个相关行......location您选择的第一行并且date在您提到的范围内。

  2. 然后,它可以按顺序逐步遍历索引,而根本不回溯表,以满足查询。name并且score在索引中。

  3. 当它逐步遍历索引时,你瞧,索引项的顺序是处理GROUP BY. 它遇到with valuescore的所有值,然后遇到 的所有分数,依此类推。不需要一个内部表,其中每个不同的名称都有一行。nameab

    请注意,如果您说MAX(score)的不是AVG(score)您的查询,则可以通过所谓的松散索引扫描来满足。这些速度几乎快得惊人,甚至比您的查询将使用的紧密索引扫描还要快。

其次,像这样简化您的查询。

SELECT d.name, AVG(score) avgscore 
  FROM Data d
 WHERE d.location = 'Location1'
   AND d.date >= '2020-01-01'
   AND d.date < '2020-06-01'
 GROUP BY d.name;

MySQL 应该能够通过对我建议的索引进行范围扫描来满足您的查询。

而且,请注意,许多单列索引通常对性能有害,除非它们与您必须执行的实际查询相匹配。几个单列索引等同于多列索引。

至于为什么没有索引你的查询会很慢,你可以用EXPLAIN让 MySQL 告诉你它是如何满足查询的。它可能必须检查表中的大部分 gigarow 以过滤您想要的并生成结果。

于 2020-10-22T22:09:22.383 回答
0
  • 缺少右括号。

  • 使用JOIN dates ...,而不是IN ( SELECT ... )

  • 1 月 1 日是故意遗漏的吗?

于 2020-10-22T22:42:01.133 回答