Оптимизация запросов MySQL - существующий запрос выполняется слишком медленно - PullRequest
0 голосов
/ 24 октября 2018

Я пытаюсь оптимизировать следующий запрос, но он работает очень медленно для меня:

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 на самом деле является bool, и поэтому не был проиндексирован.)

1 Ответ

0 голосов
/ 24 октября 2018

Вы используете LEFT JOIN, хотя вам требуется не-NULL поле в объединенной таблице в WHERE.

`trans`.`company_id` = 1 не может быть истинным, если LEFT JOIN создает строку NULL для trans, поэтому нетиз дополнительных строк, созданных LEFT JOIN (по сравнению с внутренним JOIN), будут допущены к конечному результату.

При использовании LEFT JOIN вы создаете не менее 769970 строк (т. е. как минимум по одной на строку в trans_email).), затем вы обрезаете их до 25. Если вместо этого у вас был внутренний JOIN, вы бы сразу сократили до 50-ти строк (при условии примерно равного распределения логического столбца) только из основного индекса, а затем урезали до 25 с помощью логического значения.условие.

РЕДАКТИРОВАТЬ: Изменение другого ЛЕВОГО СОЕДИНЕНИЯ (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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...