T-SQL.Что лучше: присоединяйтесь, затем группа или группа, затем присоединяйтесь - PullRequest
1 голос
/ 23 марта 2019

У меня есть 2 таблицы:

Заказ:

IdProduct (what is ordered - FK to Product table)
Price  (what is the total price for offer)
Piece  (i.e. count - how many products are ordered?) 

Продукт :

Id
Name

И там2 оператора SQL, которые возвращают продукты по лучшей цене за единицу:

Оператор № 1:

SELECT 
    p.Name,
    MIN (Price / Piece) AS MinPrice
FROM 
    [ORDER] o
JOIN 
    Product p ON IdProduct = p.Id
GROUP BY
    p.Name

Оператор № 2:

SELECT p.Name, t.MinPrice 
FROM
    (SELECT IdProduct, MIN(Price/Piece) AS MinPrice 
     FROM [Order] 
     GROUP BY IdProduct) t 
JOIN 
    Product p ON p.Id = t.IdProduct

Я изучил планы выполненияв Microsoft SQL Server Management Studio они выглядят очень похоже, хотя у меня есть несколько наблюдений:

  1. Почему в первом плане используется инструкция [order by name]?Его выходные данные имеют названия продуктов, которые упорядочены "asc", даже если я не использую инструкцию заказа T-SQL

  2. Этот неявный "порядок по имени asc" замедляет первый sql.Когда я добавляю "order by name asc" ко второму sql - они становятся идентичными по стоимости плана выполнения.

  3. Я думаю, что sql # 2 должен превзойти # 1 из-за:

    a).Он группируется по PK (то есть целому числу), а не по имени (с типом столбца nvarchar, более того, он не индексируется) b).Он объединяет таблицы только после того, как первая группа сгруппирована, что должно максимизировать производительность (по сравнению с объединением полных 2 таблиц, как это ожидается для первого sql), но планы выполнения, тем не менее, показывают одинаковую оценочную стоимость выполнения.

Какой оператор SQL вы бы предпочли и почему?Может быть, у вас есть собственная версия оператора SQL?

1 Ответ

0 голосов
/ 24 марта 2019

Лично я предпочел бы утверждение 2. Моя причина сильно отличается от того, что вы ожидаете.

Вы поняли, что ваши 2 утверждения не созданы, чтобы возвращать одинаковые результаты?

Первый запрос NOT группирует записи по продуктам, группирует их по названию продукта. В большинстве БД столбцы с именем name никогда не бывают уникальными. Следовательно, 2 GROUP BY не эквивалентны (может быть, ваши тестовые данные получаются , чтобы сделать 2 одинаковых результата, но здесь играет только удача).

Вот что должно было быть написано:

SELECT 
    p.Name,
    MIN (Price / Piece) AS MinPrice
FROM 
    [ORDER] o
JOIN 
    Product p ON IdProduct = p.Id
GROUP BY
    IdProduct, p.Name /* GROUP BY PK on Product */

ИМХО, второй синтаксис - хорошая защита от такого рода ошибок. Я советую, это тот, который вы используете.
Это избавит вас от некоторых хлопот, когда вы будете работать с устаревшей БД с более 100 таблицами вместо двух таблиц, которые вы создали и заполнили самостоятельно, не говоря уже о том, что 1-й оператор может долгое время работать правильно, пока, наконец, Product.name не перестанет работать. уникальный.

Кстати, неявный order by намекал, что он не использует столбец PK. Это не замедляет ваш запрос. Это заказ записи в рамках подготовки к GROUP BY


PS: чтобы ответить на ваш вопрос о производительности, ваше второе утверждение против того, о котором я писал, должно быть очень похожим (спасибо планировщику запросов).
Я иногда видел, как 1-е утверждение было значительно медленнее, но никогда значительно быстрее 2-го (если существуют исключения, они достаточно редки, чтобы я их пропустил).

PPS: поскольку вы агрегируете данные из Product, добавление WHERE в поле из Order может усложнить работу.
Боюсь, что именно такие вещи вы должны пробовать каждый раз, когда разрабатывается новый запрос.

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