我正在尝试优化以下查询,但它对我来说运行速度非常慢:
SELECT `trans_email`.*
, `email_statuses`.`recipient`, `email_statuses`.`status_id`, `email_statuses`.`message`, `email_statuses`.`status_received_at`
, `trans`.`doc`
FROM `trans_email`
LEFT JOIN `email_statuses` ON `trans_email`.`id` = `email_statuses`.`trans_email_id`
LEFT JOIN `trans` ON `trans_email`.`trans_id` = `trans`.`id`
WHERE `trans_email`.`type_id` = 0 AND `trans`.`company_id` = 1
ORDER BY `email_statuses`.`status_received_at` DESC
LIMIT 25 OFFSET 0
25 rows in set (4.87 sec)
这是EXPLAIN
的输出:
编号:1
选择类型:简单
表:trans_email
分区:NULL
类型:全部
可能的键:trans_id
键:空
key_len: NULL
引用:空
行:769970
过滤:10.00
额外:使用地点;使用临时的;使用文件排序
************************** 2. 行 ****************** ******
编号:1
选择类型:简单
表:反式
分区:NULL
类型:eq_ref
可能的键:主、fk_trans_company、co_del_drft_type、co_drft_del_utc
关键:主要
key 长度:4
引用:trans_email.trans_id
行数:1
过滤:5.00
额外:使用地点
************************** 3. 行 ****************** ******
编号:1
选择类型:简单
表:电子邮件状态
分区:NULL
类型:引用
possible_keys: email_statuses_trans_email_id_foreign
键:email_statuses_trans_email_id_foreign
key 长度:4
引用:trans_email.id
行数:2
过滤:100.00
额外:空
3 行一组,1 次警告(0.00 秒)
据我所知,所有内容都已正确索引。 (请注意,trans_email.type_id
实际上是一个 bool 值,因此尚未编入索引。)
最佳答案
尽管您在 WHERE 的连接表中需要非 NULL 字段,但您仍使用 LEFT JOIN。
如果 LEFT JOIN 为trans
生成 NULL 行,则 `trans`.`company_id` = 1
不能为 true,因此 LEFT JOIN 不会生成任何额外行(与内部 JOIN 相比)将在最终结果中被接受。
使用 LEFT JOIN,您至少会生成 769970 行(即 trans_email
中的每行至少一行),然后将它们削减到 25。如果您有一个内部 JOIN,您将立即从主索引中减少到 50 行(假设 bool 列分布大致相等),然后根据 bool 条件减少到 25 行。
编辑:更改另一个 LEFT JOIN(email_statuses
之一)实际上会更改您的结果,除非您在 email_statuses
表中完全覆盖,并且它不应该一旦另一个 LEFT JOIN 消失,确实会影响您的运行时,所以请随意保留该 LEFT JOIN 原样。
因此 - 试试这个(只有一个词更 slim ):
SELECT `trans_email`.*
, `email_statuses`.`recipient`, `email_statuses`.`status_id`, `email_statuses`.`message`, `email_statuses`.`status_received_at`
, `trans`.`doc`
FROM `trans_email`
JOIN `email_statuses` ON `trans_email`.`id` = `email_statuses`.`trans_email_id`
LEFT JOIN `trans` ON `trans_email`.`trans_id` = `trans`.`id`
WHERE `trans_email`.`type_id` = 0 AND `trans`.`company_id` = 1
ORDER BY `email_statuses`.`status_received_at` DESC
LIMIT 25 OFFSET 0
关于MySQL 查询优化 - 现有查询运行速度太慢,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52965734/