【问题标题】:Optimize mysql query for date group优化mysql查询日期组
【发布时间】:2016-07-23 21:51:41
【问题描述】:

这是我的桌子:

CREATE TABLE IF NOT EXISTS `test_dates` (
  `date` date NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE IF NOT EXISTS `test_log` (
  `id` int(10) unsigned NOT NULL,
  `timest` datetime NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

ALTER TABLE `test_dates`
  ADD PRIMARY KEY (`date`);

ALTER TABLE `test_log`
  ADD PRIMARY KEY (`id`),
  ADD KEY `emissione` (`timest`);

我有这个查询来计算每个日期的日志:

SELECT d.date, COUNT(l.id) 
FROM test_dates d
LEFT JOIN test_log l ON l.timest>=d.date AND l.timest<d.date + INTERVAL 1 DAY 
GROUP BY d.date

test_dates 表在日期列中编入索引,test_log 表在时间列中编入索引。

但是在解释这个查询时,我得到了查询类型“ALL”和 NULL 键。

+-----+--------------+--------+-------------+--------+----------------+----------+----------+------+--------+-----------+------------------------------------------------+--+
| id  | select_type  | table  | partitions  | type   | possible_keys  |   key    | key_len  | ref  | rows   | filtered  |                     Extra                      |  |
+-----+--------------+--------+-------------+--------+----------------+----------+----------+------+--------+-----------+------------------------------------------------+--+
|  1  | SIMPLE       | d      | NULL        | index  | PRIMARY        | PRIMARY  | 3        | NULL |   705  | 100.00    | Using index                                    |  |
|  1  | SIMPLE       | l      | NULL        | ALL    | emissione      | NULL     | NULL     | NULL | 98256  | 100.00    | Range checked for each record (index map: 0x2) |  |
+-----+--------------+--------+-------------+--------+----------------+----------+----------+------+--------+-----------+------------------------------------------------+--+

为什么mysql不能使用表索引?

日志表大约有100000行,查询很慢。

【问题讨论】:

  • 大概是查询慢了?至少,有关查询性能的问题需要针对所有相关表(最好也是样本数据)的 CREATE 语句以及 EXPLAIN 的结果。

标签: mysql optimization indexing


【解决方案1】:

尝试将其作为相关子查询运行:

SELECT d.date,
       (SELECT COUNT(l.id) 
        FROM log l 
        WHERE l.timest >= d.date AND l.timest < d.date + INTERVAL 1 DAY 
       ) as cnt
FROM dates d;

在使用GROUP BY 的索引时,MySQL 不是很好。有时使用子查询可以显着提高性能。您的表具有正确的索引。

【讨论】:

  • 工作测试(MySQL 5.6.26):没有区别。在家测试(MariaDB 10.0.19):巨大的差异。也许 MySQL 5.7 和 MariaDB 10 一样好。
  • 我确认我用mysql 5.6.26测试过
【解决方案2】:

如果索引和相关子查询不适合您,您更好的选择可能是更新日期表并添加摘要计数列。然后,当您在日志表中执行插入操作时,将相关日期的日期表中的计数器加 1。如果还没有这样的记录,则添加一个并将其计数设置为 1,因为它是一条新记录。

然后,您需要做的就是根据日期范围从您的日期表中选择一个 sum(),而不要查看详细信息。一旦为可能的审查选择了给定日期,您就可以查询基础数据。

【讨论】:

    【解决方案3】:

    把它转过来。首先在第二张表上做一个高效的GROUP BY(见下面的子查询),然后填写缺失的天数(外部查询):

    SELECT  date,
            IFNULL(log.ct, 0) AS ct
        FROM  
          ( SELECT  DATE(timest) AS date,
                    COUNT(*) AS ct
                FROM  test_log 
                GROUP BY date
          ) AS log
        RIGHT JOIN  test_dates AS d  USING(date);
    

    如果要限制日期范围,请在子查询和外部查询中添加WHERE 子句。

    【讨论】:

      猜你喜欢
      • 2011-07-07
      • 1970-01-01
      • 1970-01-01
      • 2023-01-28
      • 1970-01-01
      • 2021-06-22
      • 1970-01-01
      • 2012-05-19
      • 2011-06-25
      相关资源
      最近更新 更多