Порядок выполнения SQL-запроса
Я смущен порядком выполнения этого запроса, пожалуйста, объясните мне это.
Я смущен, когда приложение применяется, вызывается функция, добавляется новый столбец и когда добавляется серийный номер. Пожалуйста, объясните порядок выполнения всего этого.
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 [email protected] and R.RoleId not in(1,2)
else
Select @RoleName= RoleName From Roles where RoleId = @BookingId
return @RoleName
end
Ответы
Ответ 1
SQL не имеет порядка выполнения. Является декларативным языком. Оптимизатор может выбирать любой заказ, который, по его мнению, подходит для обеспечения наилучшего времени выполнения. Учитывая любой SQL-запрос, в принципе невозможно никому притворяться, что знает порядок выполнения. Если вы добавите подробную информацию о связанной схеме (точное определение таблиц и индексов) и оцененные мощности (размер данных и селективность ключей), тогда можно предположить, что вероятный порядок выполнения.
В конечном счете, единственным правильным "порядком" является тот, который описан в фактическом плане выполнения. См. Отображение планов выполнения с помощью классов событий профилировщика SQL Server и Отображение графических планов выполнения (SQL Server Management Studio).
Совершенно другое дело, так это то, как запросы, подзапросы и выражения проецируют себя на "достоверность". Например, если у вас есть выражение с псевдонимом в списке проекции SELECT, можете ли вы использовать псевдоним в предложении WHERE? Вот так:
SELECT a+b as c
FROM t
WHERE c=...;
Используется ли псевдоним c
в предложении where? Ответ - нет. Запросы формируют дерево синтаксиса, а нижняя ветвь дерева не может ссылаться на что-то определенное выше в дереве. Это не обязательно порядок выполнения, это больше проблема синтаксического разбора. Это эквивалентно написанию этого кода в С#:
void Select (int a, int b)
{
if (c = ...) then {...}
int c = a+b;
}
Так же, как и в С#, этот код не будет компилироваться, потому что используется переменная c
до того, как будет определена, SELECT выше не будет скомпилирован должным образом, потому что псевдоним c
ссылается ниже в дереве, чем на самом деле определено.
К сожалению, в отличие от хорошо известных правил синтаксического анализа языка C/С#, правила SQL, как построено дерево запросов, как-то эзотеричны. Существует краткое упоминание о них в Обработка отдельных SQL-запросов, но подробное обсуждение того, как они созданы, и какой порядок действителен, а что нет, Я не знаю ни одного источника. Я не говорю, что нет хороших источников, я уверен, что некоторые из хороших книг SQL там охватывают эту тему.
Обратите внимание, что порядок дерева синтаксиса не соответствует визуальному порядку текста SQL. Например, предложение ORDER BY обычно является последним в тексте SQL, но в качестве дерева синтаксиса оно находится выше всего остального (он сортирует вывод SELECT, поэтому он сидит выше столбцов SELECTed, так сказать) и как таковой есть действителен для ссылки на псевдоним c
:
SELECT a+b as c
FROM t
ORDER BY c;
Обновление
На самом деле есть следующее: Логическая обработка порядка инструкции SELECT
Следующие шаги показывают логические порядок обработки или порядок привязки, для оператора SELECT. Этот заказ определяет, когда объекты, определенные в один шаг предоставляется в последующих шагах. Для Например, если процессор запросов может привязывать (доступ) к таблицам или представлениям определенные в предложении FROM, эти объекты и их столбцы сделаны доступный для всех последующих шагов. И наоборот, поскольку предложение SELECT представляет собой этап 8, любые псевдонимы столбцов или производные столбцы, определенные в этой статье на предыдущие статьи. Однако они могут быть на которые ссылаются последующие статьи как предложение ORDER BY. Обратите внимание, что фактическое физическое исполнение оператор определяется запросом процессор и порядок могут отличаться от этот список.
- С
- ON
- JOIN
- WHERE
- GROUP BY
- С CUBE или WITH ROLLUP
- HAVING
- SELECT
- DISTINCT
- ЗАКАЗАТЬ
- TOP
Ответ 2
Запросы обычно обрабатываются в следующем порядке (SQL Server). Я понятия не имею, работают ли другие СУБД таким образом.
FROM [MyTable]
ON [MyCondition]
JOIN [MyJoinedTable]
WHERE [...]
GROUP BY [...]
HAVING [...]
SELECT [...]
ORDER BY [...]
Ответ 3
SQL - это декларативный язык, означающий, что он говорит движку SQL, что делать, а не как. Это противоречит императивному языку, такому как C, в котором, как что-то делать, четко изложено.
Это означает, что не все операторы будут выполняться так, как ожидалось. Особо следует отметить булевские выражения, которые могут не оцениваться слева направо, как написано. Например, следующий код не может выполняться без деления на нулевую ошибку:
SELECT 'null' WHERE 1 = 1 OR 1 / 0 = 0
Причиной этого является оптимизатор запросов, который выбирает лучший (наиболее эффективный) способ выполнения инструкции. Это означает, что, например, значение может быть загружено и отфильтровано до применения предиката преобразования, вызвавшего ошибку. См. Вторую ссылку выше для примера
Смотрите: здесь и здесь.
Ответ 4
"Порядок выполнения", вероятно, является плохой ментальной моделью для SQL-запросов. Его трудно написать один запрос, который фактически зависит от порядка исполнения (это хорошо). Вместо этого вы должны думать обо всех соединениях и о том, где предложения происходят одновременно (почти как шаблон)
Сказав, что вы можете запустить отображение Планы выполнения, которое должно дать вам представление об этом.
Однако, поскольку неясно, почему вы хотите знать порядок выполнения, я предполагаю, что вы пытаетесь получить ментальную модель для этого запроса, чтобы вы могли каким-то образом ее исправить. Вот как я буду "переводить" ваш запрос, хотя я хорошо справился с таким анализом, там какая-то серая область с точной точностью.
FROM AND WHERE CLAUSE
-
Дайте мне все строки участников мероприятия. 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 (
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))
SELECT CLAUSE
-
Для каждой строки введите уникальный идентификатор
Row_number() OVER(ORDER BY (SELECT 1)) AS 'Serial Number',
-
Участники Имя EP.FirstName
-
Участники Фамилия Ep.LastName
-
Имя роли бронирования GetBookingRoleName
-
Перейдите в поле "События" и узнайте, что первое событие Event, где находится 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)
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