尽管有索引,但使用group by查询的distinct计数太慢

hgqdbh6s  于 2021-06-23  发布在  Mysql
关注(0)|答案(3)|浏览(337)

我有以下查询,统计每周每个区域的船只数量:

SELECT zone, 
    DATE_FORMAT(creation_date, '%Y%u') AS date, 
    COUNT(DISTINCT vessel_imo) AS vessel_count 
  FROM vessel_position
  WHERE zone IS NOT NULL
   AND creation_date >= DATE_SUB(CURDATE(), INTERVAL 12 MONTH)
  GROUP BY zone, date;

这个表有大约4000万行。这方面的执行计划是:

+----+-------------+-----------------+------------+-------+--------------------+------+---------+------+----------+----------+------------------------------------------+
| id | select_type | table           | partitions | type  | possible_keys      | key  | key_len | ref  | rows     | filtered | Extra                                    |
+----+-------------+-----------------+------------+-------+--------------------+------+---------+------+----------+----------+------------------------------------------+
|  1 | SIMPLE      | vessel_position | NULL       | range | creation_date,zone | zone | 5       | NULL | 21190904 |    50.00 | Using where; Using index; Using filesort |
+----+-------------+-----------------+------------+-------+--------------------+------+---------+------+----------+----------+------------------------------------------+

vessel_imo , zone 以及 creation_date 每个索引。主键是复合键( vessel_imo , creation_date ).
当我查看查询配置文件时,我可以看到我花了大量时间 Creating sort index .
我能做些什么来进一步改进这个查询吗?

ftf50wuq

ftf50wuq1#

假设数据一旦插入,就不会更改,然后构建并维护一个摘要表。
该表将有三列:区域、周和该周的计数。在每周开始时,只构建前一周的行(每个区域一行;跳过 NULL ). 然后构建一个针对该表的查询——它将非常快,因为它将获取更少的行。
与此同时 INDEX(creation_date, zone, vessel_imo) 作为二级索引,将使每周任务的效率合理(大约是当前查询的52倍)。

ffx8fchx

ffx8fchx2#

设置@mystartdate=date\u sub(curdate(),间隔12个月);
选择区域,日期格式(创建日期,“%y%u”)作为日期,计数(不同的容器\u imo)作为容器计数,从容器位置创建日期>=@mystartdate和区域>0按区域,日期分组;
可能提供结果在较短的时间内,请张贴您的比较时间第二次运行的每一个(旧的和建议的)
请张贴新的解释选择…以确认创建日期的索引现在使用。
除非旧的数据被允许改变,为什么你要收集12个月的历史,1个多月前的数字是不会改变的。

6vl6ewon

6vl6ewon3#

这取决于筛选条件的选择性以及表结构。过滤条件是否选择了20%的行,5%,1%,0.1%?
如果你的答案不到5%,那么以下索引可能会有所帮助:

create index ix1_date_zone on vessel_position (creation_date, zone);

如果您的表有许多和/或重列,则此选项可能仍然很慢,具体取决于筛选条件的选择性。
否则,您可以尝试使用更昂贵的索引,以避免使用表并执行以下操作:

create index ix2_date_zone_imo on vessel_position 
  (creation_date, zone, vessel_imo);

这个索引的维护成本更高——读取 insert , update , delete 排成一排——但对你的孩子来说会更快 select .
两种选择都可以尝试,并根据您的需要选择最好的。

相关问题