Оптимизация / Исправление Запросов

У меня была похожая проблема на позапрошлой неделе с запросом, который занял целую вечность. При написании этого запроса я попытался применить некоторые из вещей, извлеченных из другого запроса, но это занимает очень много времени, чтобы выполнить.

При выполнении двух отдельных частей запроса требуется 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 совпадает с кодом сущности, я просто переименовал его в целях публикации):
План запроса (store_code совпадает с кодом сущности, я просто переименовал его в целях публикации):

Я настроил свой индекс на action_date и line_field_id.

Показать создать изображение таблицы:
Введите описание изображения здесь

1 ответ

  1. Позвольте мне дать вам несколько советов. Если их недостаточно, давайте начнем сначала.

    • Многие подзапросы, которые у вас есть, не нужны; Вы были бы лучше JOINs.
    • CURDATE не имеет времени, поэтому не нужно преобразовывать вDATE: DATE(DATE_SUB(CURDATE(), INTERVAL 28 DAY))—> (CURDATE() - INTERVAL 28 DAY)
    • Пожалуйста, используйте какой-то отступ, чтобы помочь дифференцировать вложенные запросы.
    • Какие гарантии, что (SELECT ROUND...возвращается только одна строка? Возможно GROUP BYто излишне?
    • Иногда вы используетеbrand, иногда brand_code; это «ошибка»?
    • Добавьте индексы ниже; я не могу сказать, какие из них были бы лучшими.

    Индексы:

    INDEX(action_date, entity_code, brand_code)
    INDEX(line_field_id, action_date)
    INDEX(entity_code, brand, action_date)
    

    Дополнения

    • Не используйте VARCHARдля значений, с которыми необходимо произвести вычисления, например MAX(A.line_value * B.pack_volume).
    • Не используйте слепо (255)дальшеVARCHAR, используйте «разумные» максимальные длины.
    • Есть PRIMARY KEYна любом InnoDB столе.
    • Несовпадающие типы, такие как line_field_id IN (3154, 3655)with VARCHAR(900)prevent reasonable optimizations, могут привести к «неправильным» результатам.

    (Я не буду рассматривать этот вопрос дальше, пока, по крайней мере, типы данных не будут «исправлены».)