Optimize mysql query for date group

微笑、不失礼 提交于 2020-02-04 01:24:13

问题


This my tables:

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`);

I have this query to count logs per date:

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

table test_dates is indexed in date colum and test_log table is indexed in timest column.

But explaining this query I got query type "ALL" and NULL key.

+-----+--------------+--------+-------------+--------+----------------+----------+----------+------+--------+-----------+------------------------------------------------+--+
| 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) |  |
+-----+--------------+--------+-------------+--------+----------------+----------+----------+------+--------+-----------+------------------------------------------------+--+

Why mysql cannot use table indexes?

Log tables has about 100000 rows and the query is very slow.


回答1:


Try running this as a correlated subquery:

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;

MySQL is not very good when using indexes with GROUP BY. Sometimes using a subquery can be a significant boost to performance. Your table has the correct indexes.




回答2:


If the index and correlated sub-query are not working for you, your better option may be to update your dates table and add a summary count column. Then, when you do an insert into your logs table, you add 1 to your counter in the dates table for the date in question. If no such record exists yet, add one and set its count to 1 since it is a new record.

Then, all you would need to do is select a sum() from your dates table based on the date range and never look at the details. Once a given date IS selected for possible review, then you could query the underlying data.




回答3:


Turn it around. First do an efficient GROUP BY on the second table (see subquery, below), then fill in the missing days (outer query):

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);

If you want to limit the date range, add a WHERE clause in both the subquery and the outer query.



来源:https://stackoverflow.com/questions/36401234/optimize-mysql-query-for-date-group

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!