@stfed84

Как оптимизировать Медленный запрос в MySQL?

Имеется 3 таблицы
1. Компании wmail_company
2. Заявки wmail_order
3. Счета wmail_comm_bill

Счета связаны с компаниями через заявку (wmail_comm_bill.order_id = wmail_order.id AND wmail_order.company_id = wmail_company.id)

Необходимо выявить 50 компаний у кого больше всего счетов, выполняем запрос:

SELECT wmail_company.id, wmail_company.caption,
(SELECT COUNT(*) FROM wmail_comm_bill, wmail_order WHERE wmail_comm_bill.order_id = wmail_order.id AND wmail_order.company_id = wmail_company.id) AS billcount
FROM wmail_company GROUP BY wmail_company.id ORDER BY billcount DESC LIMIT 0, 50


Он выполняется за 58.211 s - очень долго

EXPLAIN такого вида:
id? select_type? table? partitions? type? possible_keys? key? key_len? ref? rows? Extra?
1 PRIMARY wmail_company NULL ALL NULL NULL NULL NULL 6186 Using filesort
2 DEPENDENT SUBQUERY wmail_comm_bill NULL index order_id order_id 4 NULL 2158 Using index
2 DEPENDENT SUBQUERY wmail_order NULL eq_ref PRIMARY,company_id PRIMARY 4 wmail.wmail_comm_bill.order_id 1 Using where

дополнительные ключи расставлены по wmail_comm_bill.order_id, wmail_order.company_id
основные ключи id есть во всех таблицах
  • Вопрос задан
  • 2848 просмотров
Пригласить эксперта
Ответы на вопрос 5
Попробуйте через JOIN
SELECT c.id, c.caption, COUNT(*) billcount
FROM wmail_company c
    JOIN wmail_order o ON o.company_id = c.id
    JOIN wmail_comm_bill b ON b.order_id = o.id
GROUP BY c.id, c.caption ORDER BY billcount DESC LIMIT 0, 50

все нужные индексы у вас есть.
Ответ написан
@Samuel_Leonardo
А замерьте время на таком запросе
SELECT c.id, c.caption, Count(b.id) AS billcount FROM wmail_comm_bill b 
INNER JOIN wmail_order o ON b.order_id = o.id
INNER JOIN wmail_company c ON c.id = o.company_id
GROUP BY c.id
ORDER BY billcount DESC LIMIT 0, 50
Ответ написан
Комментировать
Fesor
@Fesor
Full-stack developer (Symfony, Angular)
что сразу бросается в глаза:
DEPENDENT SUBQUERY - почему бы не заменить на join?
FROM wmail_comm_bill, wmail_order - опять же join.

select com.id, com.caption, COUNT(com.id) AS billcount
FROM wmail_company com
INNER JOIN wmail_order ord ON ord.company_id = com.id
LEFT JOIN wmail_comm_bill bill ON bill.order_id=ord.id
GROUP BY com.id
ORDER BY billcount DESC
LIMIT 0 50
Ответ написан
Комментировать
KorsaR-ZN
@KorsaR-ZN
Эх, пока писал, уже опередили, раз время потратил пусть уж будет :)

SELECT 
	wc.id, 
	wc.caption,
	COUNT(wb.*) AS billcount
INNER JOIN 
	wmail_order AS wo ON wo.company_id = wc.id
INNER JOIN 
	wmail_comm_bill AS wb ON wb.order_id = wo.id
FROM
	wmail_company AS wc
GROUP BY 
	wc.id 
ORDER BY 
	billcount DESC
LIMIT 0, 50
Ответ написан
Комментировать
@stfed84 Автор вопроса
Коллеги спасибо за советы.
Тогда добавлю ... есть еще таблица wmail_comm_bill_item
это товарные позиции счета они связаны с таблицей счетов так wmail_comm_bill_item.com_bill_id = wmail_comm_bill.id
есть стоимость wmail_comm_bill_item.price_total
необходимо в том же запросе узнать не только количество счетов но и их суммы SUM(wmail_comm_bill_item.price_total)
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы