Как оптимизировать мой sql-запрос за 2 минуты и 25 секунд - PullRequest
0 голосов
/ 29 октября 2018

У меня есть таблица с данными 3 ГБ (она будет увеличиваться), и мне нужно отобразить общий объем продаж, топ-категорию и топ-продукт (максимальное вхождение в столбце). Ниже приведен запрос, который дает мне вышеупомянутый результат:

select t.category, 
       sum(t.sale) sales,
        (select product 
        from demo 
        where  category = t.category
        group by product
        order by count(*) desc
        limit 1) top_product
from demo t
group by t.category

Приведенный выше запрос занимает около 2 минут и 25 секунд. Я не мог найти способ оптимизировать это. Есть ли другой способ, который кто-то мог бы рекомендовать?

Пример таблицы:

category  product    sale 
C1         P1        10
C2         P2        12
C3         P1        14
C1         P2        15
C1         P1        02
C2         P2        10
C2         P3        22
C3         P1        01
C3         P2        27
C3         P3        02

Выход:

category  Top product   Total sales 
    C1         P1        27
    C2         P2        44
    C3         P1        44

Ответы [ 2 ]

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

Решение для взлома только в MySQL использует GROUP_CONCAT в сочетании с вложенными функциями SUBSTRING_INDEX, чтобы получить первый элемент в строке с упорядоченными запятыми.

Это не идеальный подход ; но это уменьшит количество необходимых подзапросов и может быть эффективным для вашего особого случая.

Вам также нужно будет использовать SET SESSION group_concat_max_len = @@max_allowed_packet;.

Мы в основном определяем продажи и количество случаев для комбинации продукта и категории. Этот набор результатов затем используется как Производная таблица , и мы используем хак Group_concat() для определения продукта с максимальным количеством в категории.

SET SESSION group_concat_max_len = @@max_allowed_packet;

SELECT 
  dt.category, 
  SUM(dt.sale_per_category_product) AS total_sales, 
  SUBSTRING_INDEX(
    SUBSTRING_INDEX(
      GROUP_CONCAT(dt.product ORDER BY dt.product_count_per_category DESC)
                    , ','
                    , 1
                   )
                 , ','
                 , -1
                ) AS top_product 
FROM 
(
  SELECT 
    category, 
    product, 
    SUM(sale) AS sale_per_category_product, 
    COUNT(*) AS product_count_per_category 
  FROM demo 
  GROUP BY category, product 
) AS dt 
GROUP BY dt.category 

Схема (MySQL v5.7)

| category | total_sales | top_product |
| -------- | ----------- | ------------|
| C1       | 27          | P1          |
| C2       | 44          | P2          |
| C3       | 44          | P1          |

Просмотр на БД Fiddle

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

Ваш запрос может быть написан так:

SELECT g1.category, g1.sum_sale, g2.product
FROM (
    SELECT category, SUM(sale) AS sum_sale
    FROM demo
    GROUP BY category
) AS g1
INNER JOIN (
    SELECT category, product, COUNT(*) AS product_count
    FROM demo
    GROUP BY category, product
) AS g2 ON g1.category = g2.category
INNER JOIN (
    SELECT category, MAX(product_count) AS product_count_max
    FROM (
        SELECT category, product, COUNT(*) AS product_count
        FROM demo
        GROUP BY category, product
    ) AS x
    GROUP BY category
) AS g3 ON g2.category = g3.category AND g2.product_count = g3.product_count_max

Обычно он пытается найти максимальное количество (*) для каждой категории и на основании этого вычисляет продукт. Это может принести пользу от соответствующих индексов.

...