Порядок выполнения предложения в SQL

Этот вопрос не о порядке казни. Речь идет только о ORDER BY.

В стандартном исполнении есть:

  • ОТ
  • ГДЕ
  • СГРУППИРОВАТЬ ПО
  • НАЛИЧИЕ
  • ВЫБЕРИТЕ
  • ЗАКАЗАТЬ ПО
  • ВЕРХ

РЕДАКТИРОВАТЬ :Этот вопрос был более или менее проблемой " Применяет ли SQL Server оценку короткого замыкания при выполнении выражений ORDER BY? " Ответ: ИНОГДА! Я просто не нашел разумной причины, почему. См. Правка #4.

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

DECLARE @dt18YearsAgo AS DATETIME = DATEADD(YEAR,-18,GETDATE());
SELECT
  Customers.Name
FROM
  Customers
WHERE
  Customers.DateOfBirth > @dt18YearsAgo
ORDER BY
  Contacts.LastName ASC, --STATEMENT1
  Contacts.FirstName ASC, --STATEMENT2
  (
   SELECT
     MAX(PurchaseDateTime)
   FROM
     Purchases
   WHERE
     Purchases.CustomerID = Customers.CustomerID
  ) DESC --STATEMENT3

Это не настоящее утверждение, которое я пытаюсь выполнить, а просто пример. Есть три оператора ORDER BY. Третье утверждение используется только в редких случаях, когда фамилия и имя совпадают.

Если нет повторяющихся фамилий, не выполняет ли SQL Server операторы ORDER BY #2 и #3? И, по логике, если нет повторяющихся фамилий и имен, делает ли SQL Server примечание к выполнению инструкции #3.

Это действительно для оптимизации. Чтение из таблицы Purchases должно быть только последним средством. В случае моего приложения было бы неэффективно читать каждое отдельное «PurchaseDateTime» из группы «Покупки» по «CustomerID».

Пожалуйста, сохраните ответ, связанный с моим вопросом, а не с предложением, таким как создание индекса для CustomerID, PurchaseDateTime в покупках. Настоящий вопрос заключается в том, пропускает ли SQL Server ненужные операторы ORDER BY?

Изменить :По-видимому, SQL Server всегда будет выполнять каждый оператор, пока есть одна строка. Даже с одной строкой это даст вам ошибку деления на ноль:

DECLARE @dt18YearsAgo AS DATETIME = DATEADD(YEAR,-18,GETDATE());
SELECT
  Customers.Name
FROM
  Customers
WHERE
  Customers.DateOfBirth > @dt18YearsAgo
ORDER BY
  Contacts.LastName ASC, --STATEMENT1
  Contacts.FirstName ASC, --STATEMENT2
  1/(Contacts.ContactID - Contacts.ContactID) --STATEMENT3

Редактировать2 :По-видимому, это не дает делить на ноль:

DECLARE @dt18YearsAgo AS DATETIME = DATEADD(YEAR,-18,GETDATE());
SELECT
  Customers.Name
FROM
  Customers
WHERE
  Customers.DateOfBirth > @dt18YearsAgo
ORDER BY
  Contacts.LastName ASC, --STATEMENT1
  Contacts.FirstName ASC, --STATEMENT2
  CASE WHEN 1=0
    THEN Contacts.ContactID
    ELSE 1/(Contacts.ContactID - Contacts.ContactID)
  END --STATEMENT3

Хорошо,первоначальный ответ на мой вопрос - ДА, он выполняется, но что приятно, так это то, что я могу остановить выполнение с помощью правильного CASE WHEN

Редактировать 3 :Мы можем остановить выполнение оператора ORDER BY с правильным CASE WHEN. Хитрость, я думаю, заключается в том, чтобы выяснить, как правильно его использовать. CASE WHEN даст мне то, что я хочу, а именно выполнение короткого замыкания в инструкции ORDER BY. Я сравнил план выполнения в SSMS, и в зависимости от инструкции CASE WHEN таблица Purchases вообще не сканируется, ДАЖЕ ХОТЯ это четко видимая инструкция SELECT/FROM:

DECLARE @dt18YearsAgo AS DATETIME = DATEADD(YEAR,-18,GETDATE());
SELECT
  Customers.Name
FROM
  Customers
WHERE
  Customers.DateOfBirth > @dt18YearsAgo
ORDER BY
  Contacts.LastName ASC, --STATEMENT1
  Contacts.FirstName ASC, --STATEMENT2
  CASE WHEN 1=0
    THEN
    (
     SELECT
       MAX(PurchaseDateTime)
     FROM
       Purchases
     WHERE
       Purchases.CustomerID = Customers.CustomerID
    )
    ELSE Customers.DateOfBirth
  END DESC

Редактировать 4 :Теперь я совсем запутался. Вот пример @Lieven

WITH Test (name, ID) AS
(SELECT 'Lieven1', 1 UNION ALL SELECT 'Lieven2', 2)

SELECT * FROM Test ORDER BY name, 1/ (ID - ID)

Это не приводит к делению на ноль, а это означает, что SQL Server фактически выполняет оценку короткого замыкания в НЕКОТОРЫХ таблицах, в частности, созданных с помощью команды WITH.

Попытка сделать это с помощью переменной TABLE:

DECLARE @Test TABLE
(
    NAME nvarchar(30),
    ID int
);
INSERT INTO @Test (Name,ID) VALUES('Lieven1',1);
INSERT INTO @Test (Name,ID) VALUES('Lieven2',2);
SELECT * FROM @Test ORDER BY name, 1/ (ID - ID)

приведет к ошибке деления на ноль.

5
задан Peter Mortensen 15 January 2013 в 19:59
поделиться