ROW_NUMBER () OVER (РАЗДЕЛЕНИЕ ПО ЗАКАЗУ B). Perfomance при использовании вместе с «WITH AS» и «WHERE» для ограничения результата? - PullRequest
0 голосов
/ 02 августа 2020

Наша таблица называется «продукты».

Мы хотели бы получить из каждой «productLine» 3 продукта наивысшего «amountInStock».

Этот запрос работает, и это общепринятый подход:

WITH inventory
AS (SELECT 
       productLine,
       productName,
       quantityInStock,
       ROW_NUMBER() OVER (
          PARTITION BY productLine 
          ORDER BY quantityInStock DESC) row_num
    FROM 
       products
   )
SELECT 
   productLine,
   productName,
   quantityInStock
FROM 
   inventory
WHERE 
   row_num <= 3;

Я сомневаюсь, будет ли приведенный выше пример быстрым с таблицей из нескольких миллионов или миллиардов строк. Похоже, что он будет go по всей таблице, прежде чем ограничит результат до WHERE row_num <= 3; </p>

Если описанный выше метод медленный для больших таблиц, есть ли лучший подход?

Я использую MySQL 8 +

Ответы [ 2 ]

1 голос
/ 02 августа 2020

Во-первых, любой вопрос о производительности необходимо проверить на ваших данных и в вашей среде.

Во-вторых, номер строки должен присвоить значение всем строкам. Он должен использовать индекс, если он доступен, поэтому он должен иметь разумную производительность.

Производительность по таким запросам непростая, если учесть крайности:

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

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

SELECT p.*
FROM products p
WHERE p.quantityInStock <= (SELECT p2.quantityInStock
                            FROM products p2
                            WHERE p2.productline = p.productline
                            ORDER BY p2.quantityInStock DESC
                            LIMIT 1 OFFSET 2
                           );

Правильный индекс находится на products(productline, quantityInStock desc).

Примечание. Вышеизложенное предполагает, что каждая «продуктовая линейка» включает как минимум три продукта. Также предполагается, что количества уникальны, поэтому в вашем запросе он больше похож на rank(), чем на row_number(). Обе эти проблемы можно решить.

0 голосов
/ 04 августа 2020

Я хотел бы добавить к замечательному и умному (как всегда) решению, предоставленному одним из лучших майнеров данных, Гордоном Линоффом.

Я изменил второй запрос, чтобы он оставил место для фантазии и убрал предположение, что каждая линейка продуктов имеет ограничение «минимум 3 продукта»!

SELECT p.*
FROM products p
WHERE p.quantityInStock IN (SELECT * FROM (SELECT p2.quantityInStock
                            FROM products p2
                            WHERE p2.productline = p.productline
                            ORDER BY p2.quantityInStock DESC
                            LIMIT 3) AS T 
                           );

Я не знаю, насколько эффективно вышеприведенное решение, но похоже на предыдущие logi c. Как и предположил Гордон, решение предполагает «относительно небольшое количество продуктовых линий» и практически неограниченное количество продуктов.

Еще раз, спасибо Гордону и спасибо.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...