【问题标题】:MySQL count(DISTINCT) very slow - better with subqueries?MySQL count(DISTINCT) 非常慢 - 子查询更好?
【发布时间】:2017-03-23 07:26:09
【问题描述】:

我有一张平桌,大约有 10mio 行,每行有 15 列。 索引设置为 column_1、column_2、column_3 和 my_time。

  SELECT    Date(my_time) my_time, 
            count(DISTINCT column_1) c_c1, 
            count(DISTINCT column_2) c_c2 
    FROM    `table_name` 
   WHERE    `column_3` in (10,11,100,50,213,756) 
     AND    Date(my_time) > '2016-09-01' 
     AND    Date(my_time) < '2016-09-30' 
GROUP BY    Date(my_time) 
ORDER BY    Date(my_time) ASC

结果大约需要 20-30 秒。

有谁知道,如何改进这个查询,也许是子查询? 如果是子查询,能否给我一个示例查询,如何提高性能?

谢谢!

【问题讨论】:

  • 发送EXPLAIN 并将其发布在您的答案中。
  • 尝试更改为 my_time BETWEEN '2016-09-01 00:00:00' AND '2016-09-30 23:59:59'
  • id: 1 select_type: SIMPLE table: table_name type: ALL possible_keys: my_time,column_3 key: NULL key_len: NULL ref: NULL rows: .... Extra: Using where;使用文件排序

标签: mysql select count subquery distinct


【解决方案1】:

如果 MySQL 支持函数索引,我们可以坚持使用 Date(my_time) 并为您的查询创建此索引:

create index idx_speedy on table_name(column_3, Date(my_time), column_1, column_2);

由于 MySQL 不支持这一点,您可以决定创建一个生成的列

alter table table_name add my_date date generated always as ( Date(my_time) );

创建索引

create index idx_speedy on table_name(column_3, my_date, column_1, column_2);

并相应地重写您的查询:

  SELECT    my_date, 
            COUNT(DISTINCT column_1) AS c_c1, 
            COUNT(DISTINCT column_2) AS c_c2 
    FROM    table_name 
   WHERE    column_3 in (10, 11, 100, 50, 213, 756) 
     AND    my_date BETWEEN '2016-09-02' AND '2016-09-29' 
GROUP BY    my_date 
ORDER BY    my_date ASC;

如果我没记错的话,这是从 MySQL 5.7.6 开始提供的。

【讨论】:

    【解决方案2】:

    您可能可以使用适当的索引来加快速度:

    create index idx_speedy on table_name(column_3, my_time);
    

    或者更好的是覆盖索引:

    create index idx_speedy on table_name(column_3, my_time, column_1, column_2);
    

    为了更好地利用索引,请尽量避免在 where 子句中的列上使用函数,即避免出现Date(my_time)

      SELECT    Date(my_time) my_time, 
                COUNT(DISTINCT column_1) AS c_c1, 
                COUNT(DISTINCT column_2) AS c_c2 
        FROM    table_name
       WHERE    column_3 in (10, 11, 100, 50, 213, 756) 
         AND    my_time >= '2016-09-02' 
         AND    my_time < '2016-09-30' 
    GROUP BY    Date(my_time) 
    ORDER BY    Date(my_time) ASC;
    

    【讨论】:

    • 这应该会加快查询速度。但我认为您还应该有一个单独的INDEX my_time 来加快ORDER BY 子句
    • 很遗憾没有改善。解释现在向我展示:id:1 select_type:SIMPLE table:table_name type:index possible_keys:my_time,column_3,speed_idx key:speed_idx key_len:173 ref:NULL rows:....额外:使用where,使用索引,使用filesort
    • 太糟糕了,我认为这与给定表格一样快。 @jussius:不,这无济于事;排序不是在my_time 上完成,而是在Date(my_time) 上完成,而且无论如何my_time 已经在我的索引中。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-06-30
    • 2021-09-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多