2011-01-04 17 views
12

Jestem zdezorientowany z kolejnością wykonywania tego zapytania, proszę wyjaśnij mi to. Jestem mylony z tym, kiedy połączenie jest stosowane, wywoływana jest funkcja, nowa kolumna jest dodawana do przypadku i kiedy dodawany jest numer seryjny. Proszę wyjaśnić kolejność realizacji tego wszystkiego.Zamówienie wykonania zapytania 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)) 

Ta funkcja jest wywoływana z powyższego zapytania.

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 
+0

Poza tematem, ale najprawdopodobniej będzie o wiele lepiej wyłączyć porzucenie tego UDF i wprowadzenie logiki w linii. –

Odpowiedz

26

SQL nie ma kolejności wykonania. Jest językiem deklaratywnym. Optymalizator może dowolnie wybrać dowolną kolejność, która pozwoli uzyskać najlepszy czas wykonania. Biorąc pod uwagę każde zapytanie SQL, praktycznie niemożliwe jest, aby ktokolwiek udawał, że zna kolejność wykonywania. Jeśli dodasz szczegółowe informacje o zaangażowanym schemacie (dokładne tabele i definicje indeksów) oraz szacunkowe dane liczbowe (rozmiar danych i selektywność kluczy), wówczas można przyjąć domysły w prawdopodobnej kolejności wykonania.

Ostatecznie, jedynym prawidłowym "zamówieniem" jest ten, który opisał rzeczywisty plan wykonania. Zobacz Displaying Execution Plans by Using SQL Server Profiler Event Classes i Displaying Graphical Execution Plans (SQL Server Management Studio).

Czym innym jest jednak to, jak zapytania, podzapytania i wyrażenia wyświetlają się w "trafności". Na przykład, jeśli masz wyrażenie aliasingowe na liście projekcji SELECT, czy możesz użyć aliasu w klauzuli WHERE? Tak:

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

Czy stosowanie c alias ważne w przypadkach, gdy klauzula? Odpowiedź brzmi nie. Zapytania tworzą drzewo składniowe, a niższa gałąź drzewa nie może być odniesieniem do czegoś zdefiniowanego wyżej w drzewie. Niekoniecznie jest to kolejność "wykonania", jest to raczej problem z analizą składni. Jest to odpowiednik pisania tego kodu w C#:

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

Podobnie jak w C# ten kod nie będzie kompilować, ponieważ zmienna c jest stosowany przed zdefiniowane wyżej SELECT nie będzie skompilować poprawnie ponieważ alias c jest odniesienie niższe w drzewie, niż jest faktycznie zdefiniowane.

Niestety, w przeciwieństwie do dobrze znanych reguł analizy języka C/C#, reguły SQL dotyczące sposobu budowania drzewa zapytań są w pewnym sensie ezoteryczne. Jest krótka wzmianka o nich w Single SQL Statement Processing, ale szczegółowa dyskusja o tym, w jaki sposób są one tworzone i jaka kolejność jest ważna, a co nie, nie znam żadnego źródła. Nie mówię, że nie ma dobrych źródeł, jestem pewien, że niektóre z dobrych książek na temat SQL omawiają ten temat.

Należy pamiętać, że kolejność elementów składni nie jest zgodna z porządkiem wizualnym tekstu SQL.Na przykład klauzula ORDER BY jest zwykle ostatnia w tekście SQL, ale jako drzewo składniowe znajduje się nad wszystkim innym (sortuje dane wyjściowe zbioruSELECT, dzięki czemu znajduje się nad kolumnami WYBRANYCH) i jako takie jest jest ważne do odniesienia c alias:

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

Updated

Właściwie nie jest to: Logical Processing Order of the SELECT statement

The following steps show the logical processing order, or binding order, for a SELECT statement. This order determines when the objects defined in one step are made available to the clauses in subsequent steps. For example, if the query processor can bind to (access) the tables or views defined in the FROM clause, these objects and their columns are made available to all subsequent steps. Conversely, because the SELECT clause is step 8, any column aliases or derived columns defined in that clause cannot be referenced by preceding clauses. However, they can be referenced by subsequent clauses such as the ORDER BY clause. Note that the actual physical execution of the statement is determined by the query processor and the order may vary from this list.

  1. FROM
  2. ON
  3. JOIN
  4. WHERE
  5. GROUP BY
  6. WITH CUBE or WITH ROLLUP
  7. HAVING
  8. SELECT
  9. DISTINCT
  10. ORDER BY
  11. TOP
+0

BUt w powyższym zapytaniu, gdy moja funkcja jest wywoływana? po fatchowaniu wyniku sprzężenia wcześniejszego, jeśli przedtem to, skąd pobiera wartość parametru z, także gdy jest wykonywane "(wybierz pierwszą konwertowaną (varchar (10), eventDate, 103) z [3rdi_EventDates], gdzie EventId = 13) "i kiedy ten przypadek dla nowej kolumny jest wykonywany – NoviceToDotNet

+0

Jedynym sposobem na znalezienie tego jest sprawdzenie rzeczywistego planu wykonania. –

+4

Istnieje * DROGA * zbyt wiele odpowiedzi w Internecie/SO, które mówią: "Optymalizatory SQL to magia - nikt nie wie, jak dane zapytanie zostanie wykonane". Ale jak sobie uświadomiłeś, nie jest to prawdą! Tak, optymalizator robi przypadkowe rzeczy - ale oczywiście jest * trochę * kolejność wykonywania klauzul. Albo jak możesz kiedykolwiek polegać na zapytaniu? Przenieś aktualizację na górę, aby osoby, które szukają odpowiedzi, nie widziały twojej niewłaściwej odpowiedzi u góry, a następnie opuściły wątek ... – mmcrae

24

Zapytania są zazwyczaj przetwarzane w następującej kolejności (serwer SQL). Nie mam pojęcia, czy inne RDBMS robią to w ten sposób.

FROM [MyTable] 
    ON [MyCondition] 
    JOIN [MyJoinedTable] 
WHERE [...] 
GROUP BY [...] 
HAVING [...] 
SELECT [...] 
ORDER BY [...] 
+2

To jest poprawna odpowiedź, ale ma tak mało głosów ... – mmcrae

+0

Zgadzam się! Krótkie i słodkie wyjaśnienie. Mój pomysł na tę odpowiedź. –

+0

Tak, odpowiedź oznaczona jako poprawna wprowadza trochę w błąd –

2

"Zamówienie wykonania" jest prawdopodobnie złym modelem mentalnym dla zapytań SQL. Trudno napisać jedno zapytanie, które w rzeczywistości zależy od kolejności wykonania (jest to dobre). Zamiast tego powinieneś pomyśleć o wszystkich sprzężeniach i klauzulach, które zdarzają się jednocześnie (prawie jak szablon).

Powiedziałeś, że możesz uruchomić wyświetlanie Execution Plans, które powinno dać ci wgląd w to.

Ponieważ jednak nie jest jasne, dlaczego chcesz znać kolejność wykonywania, domyślam się, że próbujesz uzyskać model mentalny dla tego zapytania, dzięki czemu możesz go w jakiś sposób naprawić. W ten sposób "przetłumaczyłbym" twoje zapytanie, chociaż dobrze sobie radziłem z tego rodzaju analizą, jest tam trochę szarego obszaru z dokładnością.

i gdzie KLAUZULA

  • Dajcie mi wszyscy uczestnicy imprez wiersze. from [3rdi_EventParticipants

  • dać mi również wszystkie wiersze zdarzeń Zapis które odpowiadają uczestnicy imprez wiersze na SignUpID inner join 3rdi_EventSignup] as ES on EP.SignUpId = ES.SignUpId

  • ale tylko Event 13 EP.EventId = 13

  • I tylko wtedy, gdy identyfikator użytkownika ma zapis w role użytkowników stół gdzie id rola nie jest w 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 CLA UŻYWAJ

  • Dla każdego z wierszy dać mi unikatowy identyfikator Row_number() OVER(ORDER BY (SELECT 1)) AS 'Serial Number',

  • Uczestnicy imię EP.FirstName

  • uczestników Nazwisko Ep.LastName

  • Nazwa Rezerwacja Rola GetBookingRoleName

  • Go spojrzenie w datach zdarzeń i dowiedzieć się, co pierwszy EVENTDATE gdzie eventid = 13, który można znaleźć (select top 1 convert(varchar(10),eventDate,103)from [3rdi_EventDates] where EventId=13) as EventDate

  • końcu przetłumaczyć GetBookingRoleName w kategorii.Nie mam tabelę dla tego więc będę ją map ręcznie (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

więc kilka notatek tutaj. Nie zamawiasz przez nic, gdy wybierzesz TOP. Powinieneś chyba mieć na zamówienie. Można to równie łatwo umieścić w klauzuli "z", np.

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 
3

SQL jest językiem deklaratywnym, co oznacza, że ​​informuje silnik SQL, co ma robić, a nie w jaki sposób. Jest to przeciwieństwo do języka imperatywnego, takiego jak C, w którym sposób robienia czegoś jest jasno określony.

Oznacza to, że nie wszystkie instrukcje będą wykonywane zgodnie z oczekiwaniami. Na szczególną uwagę zasługują wyrażenia boolowskie, które mogą nie być oceniane od lewej do prawej, jak napisano. Na przykład, poniższy kod nie jest gwarantowana wykonać bez dzielenia przez zero błędu:

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

Powodem tego jest optymalizator kwerendy wybiera najlepszą (najbardziej wydajne) sposób wykonać instrukcję. Oznacza to, że na przykład wartość może być ładowana i filtrowana przed zastosowaniem predykatu przekształcającego, co powoduje błąd. Zobacz drugi link powyżej na przykład

Zobacz: here i here.

Powiązane problemy