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

时间:2018-10-24 09:39:34

标签: mysql sql

我正在尝试优化以下查询,但对我而言,它的运行速度非常慢:

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实际上是布尔值,因此没有被索引。)

1 个答案:

答案 0 :(得分:1)

尽管在WHERE的联接表中需要一个非NULL字段,但仍使用LEFT JOIN。

如果LEFT JOIN为`trans`.`company_id` = 1产生NULL行,则

trans不能为真,因此LEFT JOIN产生的多余行(与内部JOIN相比)都不会被接受。

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

编辑:更改另一个LEFT JOIN(email_statuses一个)实际上会改变您的结果,除非您在email_statuses表中具有完全的覆盖范围,并且它实际上不会对运行时产生太大影响,其他LEFT JOIN消失后,请随时保留该LEFT JOIN。

因此-试试这个(只有一个词苗条):

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