我有以下查询:
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_time
是 datetime
或 date
。然后,您应该将条件表示为字符串。相反,使用 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/