powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / MySQL [игнор отключен] [закрыт для гостей] / (MySQL) Оптимизация запроса (16 сек)
6 сообщений из 6, страница 1 из 1
(MySQL) Оптимизация запроса (16 сек)
    #38964219
halfhope
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Всем доброго времени суток.

Нужна помощь в оптимизации запроса (MySQL). Это запрос на кол-во аттрибутов у отфильтрованных товаров. В нем есть 3 подзапроса из таблиц (product_special, product_discount, product_to_category). Сам запрос выполняется ~17 сек. Если первые два подзапроса убрать, то работает относительно быстро (0.7 сек).

С механизмом работы mysql знаком плохо, поэтому не знаю как правильно решить задачу(и вообще не знаю). EXPLAIN показал, что тормоза из-за создания временных таблиц (Use temporary). Пробовал реализовать Full Outer Join к таблицам product_special и product_discount посредством двух запросов и UNION ALL, но возвращает 0 строк, до конца так и не разобрался.


Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
SELECT count(*) AS total,
       p2a.attribute_id,
       trim(p2a.text) AS 'text'
FROM product p
LEFT JOIN
  (SELECT product_id,
          price,
          customer_group_id,
          date_start,
          date_end
   FROM product_special
   WHERE customer_group_id = '1'
     AND (date_start = '0000-00-00'
          OR date_start < '2015-05-03 16:03:00')
     AND (date_end = '0000-00-00'
          OR date_end > '2015-05-03 16:03:00')
   GROUP BY product_id) ps ON (ps.product_id = p.product_id)
LEFT JOIN
  (SELECT product_id,
          price
   FROM product_discount
   WHERE customer_group_id = '1'
     AND quantity = '1'
     AND (date_start = '0000-00-00'
          OR date_start < '2015-05-03 16:03:00')
     AND (date_end = '0000-00-00'
          OR date_end > '2015-05-03 16:03:00')
   GROUP BY product_id) pd2 ON (pd2.product_id = p.product_id)

LEFT JOIN product_to_store p2s ON(p.product_id=p2s.product_id)
LEFT JOIN product_attribute p2a ON (p2a.product_id=p.product_id)
INNER JOIN
  (SELECT category_id,
          product_id
   FROM product_to_category
   WHERE category_id = '60') p2c ON(p.product_id=p2c.product_id)
WHERE p.status = '1'
  AND p.date_available <= '2015-05-03 16:03:00'
  AND p2s.store_id =0
  AND p2a.language_id='2'
  AND COALESCE( pd2.price,  ps.price , p.price) >=105781
  AND COALESCE( pd2.price,  ps.price , p.price) <=1039600
GROUP BY p2a.attribute_id,
         trim(p2a.text)


Ссылка на дамп БД с таблицами (unpacked 18Mb).
...
Рейтинг: 0 / 0
(MySQL) Оптимизация запроса (16 сек)
    #38964300
Arhat109
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
halfhope,

Приведите планы всех подзапросов отдельно, особенно первого и общий план - тоже не помешает.

Варианты из ХШ:
1. Первый подзапрос идет "без индексов";
2. Первый подзапрос материализуется (большая выборка = запись на диск)
...
Рейтинг: 0 / 0
(MySQL) Оптимизация запроса (16 сек)
    #38964618
halfhope
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Еще раз повторю запрос, отформатировал с комментариями
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
SELECT 
	count(*) AS total, 
	p2a.attribute_id, 
	trim(p2a.text) AS 'text' 
FROM 
	product p /* начало первого подзапроса */
	LEFT JOIN (
		SELECT 
			product_id, 
			price, 
			customer_group_id, 
			date_start, 
			date_end 
		FROM 
			product_special 
		WHERE 
			customer_group_id = '1' 
			AND (
				date_start = '0000-00-00' 
				OR date_start < '2015-05-03 16:03:00'
			) 
			AND (
				date_end = '0000-00-00' 
				OR date_end > '2015-05-03 16:03:00'
			) 
		GROUP BY 
			product_id
	) ps ON (ps.product_id = p.product_id) /* конец первого подзапроса */
	/* начало второго подзапроса */
	LEFT JOIN (
		SELECT 
			product_id, 
			price 
		FROM 
			product_discount 
		WHERE 
			customer_group_id = '1' 
			AND quantity = '1' 
			AND (
				date_start = '0000-00-00' 
				OR date_start < '2015-05-03 16:03:00'
			) 
			AND (
				date_end = '0000-00-00' 
				OR date_end > '2015-05-03 16:03:00'
			) 
		GROUP BY 
			product_id
	) pd2 ON (pd2.product_id = p.product_id) /* конец второго подзапроса */
	LEFT JOIN product_to_store p2s ON(p.product_id = p2s.product_id) 
	LEFT JOIN product_attribute p2a ON (p2a.product_id = p.product_id) 
	/* начало третьего подзапроса */
	INNER JOIN (
		SELECT 
			category_id, 
			product_id 
		FROM 
			product_to_category 
		WHERE 
			category_id = '60'
	) p2c ON(p.product_id = p2c.product_id) 
	/* конец третьего подзапроса */
WHERE 
	p.status = '1' 
	AND p.date_available <= '2015-05-03 16:03:00' 
	AND p2s.store_id = 0 
	AND p2a.language_id = '2' 
	AND COALESCE(pd2.price, ps.price, p.price) >= 105781 
	AND COALESCE(pd2.price, ps.price, p.price) <= 1039600 
GROUP BY 
	p2a.attribute_id, 
	trim(p2a.text)



EXPLAIN первого:


Кстати, чем меньше элементов в этой таблице (product_special) тем меньше скорость выполнения общего запроса. По отдельности они все быстрые.

Второго:



Третьего:



Общий:



Результаты профилирования общего запроса:

...
Рейтинг: 0 / 0
(MySQL) Оптимизация запроса (16 сек)
    #38964653
Фотография Akina
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
А что Вы хотите? Вы справа приматываете к таблице пухлые неиндексированные подзапросы - ясен пень оно не помещается в памяти и оттого льётся на диск.

Вот Вам реально нужно именно ЛЕВОЕ связывание? и именно в НАЧАЛЕ цепи считывания таблиц? Я вижу, что данные этих подзапросов используются исключительно в секции WHERE. А часть выгребаемых полей вообще нахрен не нужна...

В общем, перепишите свой запрос, руководствуясь строгой логикой и здравым смыслом - и он если и не взлетит, то уж подпрыгнет стопудово.
...
Рейтинг: 0 / 0
(MySQL) Оптимизация запроса (16 сек)
    #38965362
Arhat109
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
halfhope,

ХШ оказался прав на все 100%. Что можно сделать?

1. Внести в секции ON левых джойнов из секции WHERE все "их" условия. То бишь какую табличку лепите, от той coalesce и пришейте. Константы можно и повторить, на скорость движения они не влияют..
2. Перенести внутренний join в начало сборки. Все "левые" джойны должны пришиваться "апосля".

Собственно в секции WHERE у вас должно остаться ровно то, что относится к основной табличке и внутренним объединениям (этим - пофиг)...

пробуйте. :)
...
Рейтинг: 0 / 0
(MySQL) Оптимизация запроса (16 сек)
    #38965364
Arhat109
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Arhat109,

Это "кроме" или дополнительно к тому, что Вам уже посоветовали...
...
Рейтинг: 0 / 0
6 сообщений из 6, страница 1 из 1
Форумы / MySQL [игнор отключен] [закрыт для гостей] / (MySQL) Оптимизация запроса (16 сек)
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]