mysql - 使用日期范围和连接优化 MySQL 查询

标签 mysql query-optimization

我有以下查询:

SELECT COUNT(*)
  FROM datum d

  JOIN datum_type dt
    ON dt.datum_id = d.id
   AND dt.type_id = '3' 

 WHERE d.added_time >=  DATE_FORMAT(CURDATE(), '%Y-%m')
   AND d.added_time <   DATE_FORMAT(CURDATE() + INTERVAL 1 MONTH, '%Y-%m')

在d.id(PRIMARY)、d.added_time、dt.datum_id、dt.type_id上​​有索引

目前的解释计划是:

+----+-------------+-------+--------+--------------------+---------+---------+-------------+--------+-------------+
| id | select_type | table |  type  |   possible_keys    |   key   | key_len |     ref     |  rows  |    Extra    |
+----+-------------+-------+--------+--------------------+---------+---------+-------------+--------+-------------+
|  1 | SIMPLE      | dt    | ref    | type_id,datum_id   | type_id |       1 | const       | 602628 |             |
|  1 | SIMPLE      | d     | eq_ref | PRIMARY,added_time | PRIMARY |       8 | dt.datum_id |      1 | Using where |
+----+-------------+-------+--------+--------------------+---------+---------+-------------+--------+-------------+

由于我们有相当长一段时间的数据记录,它似乎首先使用 datum.id PRIMARY 加入类型,然后扫描每个加入的行以查看 datum.added_time 是否在范围内。

我尝试使用 added_time 索引,但解释计划是:

+----+-------------+-------+-------+------------------+------------+---------+------+---------+--------------------------+
| id | select_type | table | type  |  possible_keys   |    key     | key_len | ref  |  rows   |          Extra           |
+----+-------------+-------+-------+------------------+------------+---------+------+---------+--------------------------+
|  1 | SIMPLE      | d     | index | added_time       | added_time |       4 | NULL | 6195194 | Using where; Using index |
|  1 | SIMPLE      | dt    | ref   | type_id,datum_id | datum_id   |       8 | d.id |       1 | Using where              |
+----+-------------+-------+-------+------------------+------------+---------+------+---------+--------------------------+  

这几乎与 datum.added_time 范围内有这么多不同 datum_type.type_id 的 datum_types 一样长。

是否有某种索引组合可以加快速度?

最佳答案

让我假设 added_timedatetimedate。然后,您应该将条件表示为字符串。相反,使用 date 常量:

SELECT COUNT(*)
FROM datum d JOIN
     datum_type dt
     ON dt.datum_id = d.id AND
        dt.type_id = '3' 
WHERE d.added_time >= DATE_SUB(CURDATE(), INTERVAL DAY(CURDATE()) - 1 DAY) AND
      d.added_time < DATE_ADD(DATE_SUB(CURDATE(), INTERVAL DAY(CURDATE()) - 1 DAY), INTERVAL 1 MONTH);

这可以利用 datum(added_time, id)datum_type(datum_id, type_id) 上的索引。

如果没有来自 datum_type 的重复记录(用于计数),我建议您将查询重写为:

SELECT COUNT(*)
FROM datum d
WHERE d.added_time >= DATE_SUB(CURDATE(), INTERVAL DAY(CURDATE()) - 1 DAY) AND
      d.added_time < DATE_ADD(DATE_SUB(CURDATE(), INTERVAL DAY(CURDATE()) - 1 DAY), INTERVAL 1 MONTH) AND
      EXISTS (SELECT 1
              FROM datum_type dt
              WHERE dt.datum_id = d.id AND dt.type_id = '3'
             );

如果 type_id 是一个整数,那么您应该去掉单引号。在 SQL 中混合不同的数据类型会混淆优化并阻止索引的使用。

关于mysql - 使用日期范围和连接优化 MySQL 查询,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36332510/

相关文章:

mysql - 我不确定我是否有正确的索引或者我是否可以提高我在 MySQL 中的查询速度?

php - 优化 SQL 查询

sql - 需要大量时间的生产 Hadoop 查询

mysql - 如何向 codeigniter 中的所有订阅者发送时事通讯图像

mysql - 是否可以查看数据库索引的底层树?

mysql - 使用 3 个大表从 MySQL 进行高效(PHP?)过滤

MySql查询优化帮助

java - 使用Java的PreparedStatement将数组传递给SQL查询

mysql - 更新期间对每个最后插入 ID 执行

sql - 从可能为空的多个表优化 SQL 查询