У меня была похожая проблема на позапрошлой неделе с запросом, который занял целую вечность. При написании этого запроса я попытался применить некоторые из вещей, извлеченных из другого запроса, но это занимает очень много времени, чтобы выполнить.
При выполнении двух отдельных частей запроса требуется 2 минуты каждая для завершения, что приемлемо, хотя быстрее было бы намного лучше.
Вот мой запрос:
SELECT
x.entityCode 'Entity Code'
, x.nnd_volume 'Latest Brand Volume'
, maxDate 'Last Action Date'
, x.Brand 'Brand Description'
, (SELECT
ROUND(((SELECT (MAX(A.line_value * B.pack_volume))
FROM master_data.brand_master B
WHERE A.brand_code = B.brand_code
AND A.brand_code = B.brand_code)
/ --THIS IS NOT A BUG, JUST TRYING TO CLEARLY INDICATE THE TWO SELECTS BEING DIVIDED AND CALCULATED
(SELECT C.case_volume
FROM master_data.brand_master C
WHERE A.brand_code = C.brand_code
AND A.brand_code = C.brand_code)),2) 'brand_volume'
FROM am_lines.brand_module A
WHERE A.action_date BETWEEN DATE(DATE_SUB(CURDATE(), INTERVAL 28 DAY))
AND DATE(DATE_SUB(CURDATE(), INTERVAL 0 DAY))
AND A.entity_code = x.entityCode
AND A.brand_code = x.brandCode
GROUP BY A.entity_code, A.brand
) 'Max Brand (28 Days)'
FROM
(SELECT
BBM.entity_code AS entityCode
, MAX(action_date) AS maxDate
, brand AS Brand
, brand_code AS brandCode
, ROUND(((SELECT (BBM.line_value * B.pack_volume)
FROM master_data.brand_master B
WHERE BBM.brand_code = B.brand_code AND BBM.brand_code = B.brand_code)
/ --THIS IS NOT A BUG, JUST TRYING TO CLEARLY INDICATE THE TWO SELECTS BEING DIVIDED AND CALCULATED
(SELECT C.box_volume
FROM master_data.brand_master C
WHERE BBM.brand_code = C.brand_code AND BBM.brand_code = C.brand_code)),2) 'brand_volume'
FROM
am_lines.brand_module BBM
WHERE
line_field_id IN (3154, 3655)
AND action_date BETWEEN DATE(DATE_SUB(CURDATE(), INTERVAL 28 DAY)) AND DATE(DATE_SUB(CURDATE(), INTERVAL 0 DAY))
GROUP BY
-- action_date
entity_code
, brand_code) AS X
GROUP BY
x.entityCode
, x.brand;
Примерные данные (объем упаковки и объем коробки — это просто справочная таблица, которая показывает общие единицы в упаковке / коробке и используется для расчета, и поэтому я не включил ее в примерные данные):
entity_code | action_date| brand | line_value
------------+------------+----------+-----------
108792 |2016-12-07 |brand 001 | 25
108793 |2016-12-08 |brand 002 | 36
108795 |2016-12-06 |brand 003 | 10
108796 |2016-12-05 |brand 004 | 55
108795 |2016-12-13 |brand 001 | 5
108792 |2016-12-14 |brand 003 | 2
108793 |2016-12-14 |brand 005 | 15
108796 |2016-12-16 |brand 006 | 25
ТЕКУЩИЕ РЕЗУЛЬТАТЫ, КОТОРЫЕ РАБОТАЮТ:
- Каждый запрос Select выполняется в течение нескольких минут (не более 2) и дает
желаемый результат. - Action_date и line_field_id индексируются.
- Добавление индекса в entity_code замедляет таблицу по неизвестной причине.
ТЕКУЩИЕ ПРОБЛЕМЫ / ЖЕЛАЕМЫЙ РЕЗУЛЬТАТ:
- Выполнение всего запроса как одного занимает вечность, более 2
несколько часов. - Каждое предприятие будет продавать / Держать акции ряда брендов. Мне нужно определить максимальное удержание акций в 28-дневном цикле, а также в месяц (столбец максимальное удержание 28 дней в желаемом наборе).
- Мне нужно будет также показать последнюю неделю фондового холдинга (столбец бренд Холдинг в желаемом наборе).
ПРЕДСТАВЛЕНИЕ НАБОРА ЖЕЛАЕМЫХ РЕЗУЛЬТАТОВ:
entity_code | Last Date | brand holding | Max Holding (28 Days) |Brand
------------+------------+------------------+-----------------------+----------+
108792 |2016-12-27 |10 | 25 |Brand 001
108792 |2016-12-27 |36 | 36 |Brand 002
108792 |2016-12-27 |5 | 10 |Brand 003
108792 |2016-12-27 |25 | 55 |Brand 004
108792 |2016-12-27 |4 | 5 |Brand 005
108783 |2016-12-15 |80 | 80 |Brand 001
108783 |2016-12-15 |36 | 41 |Brand 002
108783 |2016-12-15 |12 | 12 |Brand 003
108783 |2016-12-15 |8 | 11 |Brand 004
108783 |2016-12-15 |20 | 90 |Brand 005
План запроса (store_code совпадает с кодом сущности, я просто переименовал его в целях публикации):
Я настроил свой индекс на action_date и line_field_id.
Позвольте мне дать вам несколько советов. Если их недостаточно, давайте начнем сначала.
JOINs
.CURDATE
не имеет времени, поэтому не нужно преобразовывать вDATE
:DATE(DATE_SUB(CURDATE(), INTERVAL 28 DAY))
—>(CURDATE() - INTERVAL 28 DAY)
(SELECT ROUND...
возвращается только одна строка? ВозможноGROUP BY
то излишне?brand
, иногдаbrand_code
; это «ошибка»?Индексы:
Дополнения
VARCHAR
для значений, с которыми необходимо произвести вычисления, напримерMAX(A.line_value * B.pack_volume)
.(255)
дальшеVARCHAR
, используйте «разумные» максимальные длины.PRIMARY KEY
на любом InnoDB столе.line_field_id IN (3154, 3655)
withVARCHAR(900)
prevent reasonable optimizations, могут привести к «неправильным» результатам.(Я не буду рассматривать этот вопрос дальше, пока, по крайней мере, типы данных не будут «исправлены».)