我正在尝试优化以下查询,但对我而言,它的运行速度非常慢:
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
实际上是布尔值,因此没有被索引。)
答案 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