Порядок выполнения SQL-запроса - PullRequest
24 голосов
/ 04 января 2011

Я запутался с порядком выполнения этого запроса, пожалуйста, объясните мне это. Меня смущает, когда применяется соединение, вызывается функция, добавляется новый столбец с регистром и когда добавляется серийный номер Пожалуйста, объясните порядок выполнения всего этого.

select Row_number() OVER(ORDER BY (SELECT 1))  AS 'Serial Number', 
    EP.FirstName,Ep.LastName,[dbo].[GetBookingRoleName](ES.UserId,EP.BookingRole) as RoleName,  
    (select top 1 convert(varchar(10),eventDate,103)from [3rdi_EventDates] where EventId=13) as EventDate,
    (CASE [dbo].[GetBookingRoleName](ES.UserId,EP.BookingRole)  
            WHEN    '90 Day Client' THEN 'DC'
            WHEN    'Association Client'  THEN  'DC'
            WHEN    'Autism Whisperer'    THEN  'DC'
            WHEN    'CampII'             THEN   'AD' 
            WHEN    'Captain'              THEN 'AD' 
            WHEN    'Chiropractic Assistant' THEN 'AD'
            WHEN    'Coaches'               THEN 'AD'
            END) as Category from [3rdi_EventParticipants] as EP  
    inner join [3rdi_EventSignup] as ES on EP.SignUpId = ES.SignUpId  
    where EP.EventId = 13
    and userid in (  
    select distinct userid from userroles  
    --where roleid not in(6,7,61,64) and roleid not in(1,2))  
    where roleid not in(19, 20, 21, 22) and roleid not in(1,2))

Эта функция вызывается из вышеприведенного запроса.

CREATE function [dbo].[GetBookingRoleName]  
(  
 @UserId as integer,
 @BookingId as integer
)  
RETURNS varchar(20)  
as  
begin  
declare @RoleName varchar(20)  

if @BookingId = -1
Select Top 1 @RoleName=R.RoleName From UserRoles UR inner join Roles R on UR.RoleId=R.RoleId Where UR.UserId=@UserId and R.RoleId not in(1,2)  
else
Select @RoleName= RoleName From Roles where RoleId = @BookingId

return @RoleName  
end

Ответы [ 5 ]

43 голосов
/ 04 января 2011

SQL не имеет порядка выполнения. Это декларативный язык. Оптимизатор может выбрать любой заказ, который он считает подходящим для обеспечения наилучшего времени исполнения. При любом запросе SQL никто не может притвориться, что знает порядок выполнения. Если вы добавите подробную информацию об используемой схеме (точное определение таблиц и индексов) и предполагаемую мощность (размер данных и селективность ключей), тогда можно получить догадку в вероятном порядке выполнения.

В конечном счете, единственный правильный «порядок» - это тот, который описан в фактическом плане выполнения. См. Отображение планов выполнения с использованием классов событий SQL Server Profiler и Отображение графических планов выполнения (SQL Server Management Studio) .

Совершенно иная вещь - как запросы, подзапросы и выражения проецируют себя в 'validity'. Например, если у вас есть псевдоним в списке проекции SELECT, можете ли вы использовать псевдоним в предложении WHERE? Как это:

SELECT a+b as c
FROM t
WHERE c=...;

Допустимо ли использование псевдонима c в предложении where? Ответ - нет. Запросы формируют синтаксическое дерево, и нижняя ветвь дерева не может быть ссылкой на что-то определенное выше в дереве. Это не обязательно порядок «исполнения», это скорее проблема синтаксического разбора. Это эквивалентно написанию этого кода на C #:

void Select (int a, int b)
{
   if (c = ...) then {...}
   int c = a+b;
}

Так же, как в C #, этот код не будет компилироваться, так как переменная c используется до того, как определена, вышеупомянутый SELECT не будет компилироваться должным образом, потому что на псевдоним c в дереве ссылаются ниже, чем фактически определено.

К сожалению, в отличие от хорошо известных правил синтаксического анализа языка C / C #, правила SQL о том, как строится дерево запросов, несколько эзотеричны. Они кратко упоминаются в Обработка единого оператора SQL , но подробно обсуждается, как они создаются, а какой порядок действителен, а какой нет, я не знаю ни одного источника. Я не говорю, что нет хороших источников, я уверен, что некоторые из хороших книг по SQL освещают эту тему.

Обратите внимание, что порядок синтаксического дерева не соответствует визуальному порядку текста SQL. Например, предложение ORDER BY обычно является последним в тексте SQL, но как синтаксическое дерево оно располагается над всем остальным (сортирует output в SELECT, поэтому оно находится, так сказать, над столбцами SELECTed). ) и как таковой является действительным для ссылки на c псевдоним:

SELECT a+b as c
FROM t
ORDER BY c;

Обновлено

На самом деле это так: Порядок логической обработки оператора SELECT

Следующие шаги показывают логическое заказ на обработку или обязательный заказ, для оператора SELECT. Этот заказ определяет, когда объекты, определенные в один шаг сделан доступным для пункты в последующих шагах. За Например, если обработчик запросов может привязка (доступ) к таблицам или представлениям определенные в предложении FROM, эти объекты и их столбцы сделаны доступно для всех последующих шагов. И наоборот, потому что предложение SELECT это шаг 8, любые псевдонимы столбцов или производные столбцы, определенные в этом пункте не может быть ссылка на предыдущий статьи. Тем не менее, они могут быть ссылки на последующие пункты, такие как как предложение ORDER BY. Обратите внимание, что фактическое физическое исполнение утверждение определяется запросом процессор и порядок могут отличаться от этот список.

  1. FROM
  2. ON
  3. ГДЕ
  4. GROUP BY
  5. С КУБОМ или С РОЛЛАПОМ
  6. HAVING
  7. SELECT
  8. DISTINCT
  9. ЗАКАЗАТЬ ПО
  10. TOP
39 голосов
/ 04 января 2011

Запросы обычно обрабатываются в следующем порядке (SQL Server).Я понятия не имею, делают ли другие РСУБД так.

FROM [MyTable]
    ON [MyCondition]
  JOIN [MyJoinedTable]
 WHERE [...]
 GROUP BY [...]
HAVING [...]
SELECT [...]
 ORDER BY [...]
5 голосов
/ 04 января 2011

SQL - это декларативный язык, то есть он говорит движку SQL, что делать, а не как. Это контрастирует с императивным языком, таким как C, на котором ясно изложено, как сделать что-то.

Это означает, что не все операторы будут выполняться должным образом. Особо следует отметить логические выражения, которые могут не оцениваться слева направо, как написано. Например, следующий код не гарантированно выполняется без ошибки деления на ноль:

SELECT 'null' WHERE 1 = 1 OR 1 / 0 = 0

Причина этого в том, что оптимизатор запросов выбирает лучший (наиболее эффективный) способ выполнения оператора. Это означает, что, например, значение может быть загружено и отфильтровано до применения предиката преобразования, что вызывает ошибку. См. Вторую ссылку выше для примера

См .: здесь и здесь .

2 голосов
/ 04 января 2011

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

При этом вы можете запустить отображение Планов выполнения , которые должны дать вам представление о нем.

Однако, поскольку неясно, почему вы хотите знать порядок выполнения, я предполагаю, что вы пытаетесь получить мысленную модель для этого запроса, чтобы вы могли каким-то образом исправить ее. Вот как я бы «перевел» ваш запрос, хотя я хорошо справился с таким анализом, но есть некоторая серая область с его точностью.

ОТ И ГДЕ ОГОВОРКА

  • Дайте мне все строки участников мероприятия. from [3rdi_EventParticipants

  • Также предоставьте мне все строки регистрации событий, которые соответствуют строкам участников события в SignUpID inner join 3rdi_EventSignup] as ES on EP.SignUpId = ES.SignUpId

  • Но только для события 13 EP.EventId = 13

  • И только если идентификатор пользователя имеет запись в таблице ролей пользователя, где идентификатор роли не находится в 1,2,19,20,21,22 userid in (<br> select distinct userid from userroles<br> --where roleid not in(6,7,61,64) and roleid not in(1,2))<br> where roleid not in(19, 20, 21, 22) and roleid not in(1,2))

ВЫБРАТЬ КЛАУЗУ

  • Для каждой из строк дайте мне уникальный идентификатор Row_number() OVER(ORDER BY (SELECT 1)) AS 'Serial Number',

  • Участники Имя EP.FirstName

  • Фамилия участников Ep.LastName

  • Название роли бронирования GetBookingRoleName

  • Пойдите, посмотрите в Даты событий и выясните, какая первая EventDate, где EventId = 13, вы найдете (select top 1 convert(varchar(10),eventDate,103)from [3rdi_EventDates] where EventId=13) as EventDate

  • Наконец, переведите GetBookingRoleName в категорию. У меня нет таблицы для этого, поэтому я сопоставлю ее вручную (CASE [dbo].[GetBookingRoleName](ES.UserId,EP.BookingRole)<br> WHEN '90 Day Client' THEN 'DC' WHEN 'Association Client' THEN 'DC' WHEN 'Autism Whisperer' THEN 'DC' WHEN 'CampII' THEN 'AD' WHEN 'Captain' THEN 'AD' WHEN 'Chiropractic Assistant' THEN 'AD' WHEN 'Coaches' THEN 'AD' END) as Category

Итак, пара замечаний здесь. Вы ничего не заказываете, когда выбираете TOP. Вы, вероятно, должны иметь заказ там. Вы также можете легко вставить это в пункт from, например,

from [3rdi_EventParticipants] as EP  
    inner join [3rdi_EventSignup] as ES on EP.SignUpId = ES.SignUpId,   
       (select top 1 convert(varchar(10),eventDate,103)
       from [3rdi_EventDates] where EventId=13
       Order by eventDate) dates
1 голос
/ 04 ноября 2018

Для оценки текста запроса существует логический порядок, но ядро ​​базы данных может выбирать, в каком порядке выполнять компоненты запроса, основываясь на том, что является наиболее оптимальным. Логический порядок разбора текста приведен ниже. Именно поэтому, например, вы не можете использовать псевдоним из предложения SELECT в предложении WHERE. Что касается процесса разбора запроса, псевдоним еще не существует.

  1. FROM

  2. ON

  3. OUTER

  4. WHERE

  5. GROUP BY

  6. CUBE | ROLLUP

  7. HAVING

  8. SELECT

  9. DISTINCT

  10. ЗАКАЗАТЬ ПО

  11. TOP

См. документацию Microsoft (см. «Порядок логической обработки оператора SELECT») для получения дополнительной информации об этом.

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