MySQL 查询优化 - 现有查询运行速度太慢



我正在尝试优化以下查询,但它对我来说运行得很慢:

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的输出: id: 1 select_type: SIMPLE table: trans_email partitions: NULL type: ALL possible_keys: trans_id key: NULL key_len: NULL ref: NULL rows: 769970 filtered: 10.00 Extra: Using where; Using temporary; Using filesort *************************** 2. row *************************** id: 1 select_type: SIMPLE table: trans partitions: NULL type: eq_ref possible_keys: PRIMARY,fk_trans_company,co_del_drft_type,co_drft_del_utc key: PRIMARY key_len: 4 ref: trans_email.trans_id rows: 1 filtered: 5.00 Extra: Using where *************************** 3. row *************************** id: 1 select_type: SIMPLE table: email_statuses partitions: NULL type: ref possible_keys: email_statuses_trans_email_id_foreign key: email_statuses_trans_email_id_foreign key_len: 4 ref: trans_email.id rows: 2 filtered: 100.00 Extra: NULL 3 rows in set, 1 warning (0.00 sec)

据我所知,一切都被正确索引。(请注意,trans_email.type_id实际上是一个布尔值,因此尚未编制索引。

您可以使用 LEFT JOIN,尽管您需要在 WHERE 的连接表中有一个非 NULL 字段。

如果 LEFT JOIN 为trans生成一个 NULL 行,则`trans`.`company_id` = 1不能为 true,因此 LEFT JOIN 产生的任何额外行(与内部 JOIN 相比(都不会在最终结果中被接纳。

使用 LEFT JOIN,您至少生成 769970 行(即trans_email中每行至少一行(,然后将它们修剪为 25 行。如果你有一个内部 JOIN,你会立即从你的主索引减少到 50 行(假设布尔列的分布大致相等(,然后根据布尔条件减少到 25 行。

编辑:更改另一个左联接(email_statuses一个(实际上会改变你的结果,除非你的email_statuses表中有完整的覆盖,一旦另一个左联接消失,它应该不会真正影响你的运行时,所以请随意保留左联接原样。

因此 - 试试这个(只有一个词更瘦(:

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

最新更新