Przetwarzanie zapytań T-SQL może być rozpatrywane ze strony logicznej i fizycznej. Strona logiczna jest konceptualną reprezentacją zapytania która wyjaśnia jaki jest poprawny wynik działania zapytania. Strona fizyczna jest to sposób przetwarzania zapytania przez silnik bazodanowy. Proces fizyczny musi produkować taki sam wynik jak proces logiczny. Aby osiągnąć ten cel silnik bazodanowy potrafi stosować optymalizację. Optymalizacja może zmienić kolejność kroków przetwarzania logicznego lub je przekształcić - lecz tylko pod warunkiem, że na końcu wyprodukuje taki sam wynik.

T-SQL jako deklaratywny język English-like

T-SQL jako język wzorowany na standardzie SQL jest językiem deklaratywnym o strukturze wzorowanej na języku angielskim. Jest językiem deklaratywnym ponieważ deklarujemy tylko wynik jaki chcemy uzyskać a silnik bazy danych odpowiada za to w jaki sposób fizycznie uzyskać taki wynik. Mówiąc o logicznym przetwarzaniu danych nie bierzemy pod uwagę zagadnień wydajnościowych, logika przetwarzania definiuje tylko poprawność zapytania. Optymalizacja natomiast wymaga zrozumienia mechanizmów fizycznych które biorą udział w przetwarzaniu danych. Ponieważ T-SQL jest wzorowany na języku angielskim to instrukcje które w nim piszemy są ułożone w szyku logicznym tego języka. W języku angielskim pytamy o obiekty docelowe przed podaniem lokalizacji z której mają być one dostarczone jak w przykładzie:

SELECT shipperid, phone FROM Sales.Shippers;

Pierw zapytaliśmy o obiekty shipperid i phone za pomocą instrukcji SELECT po czym podaliśmy lokalizację w której mają one być znalezione za pomocą instrukcji FROM. Logiczna interpretacja takiego zapytania wymaga innej kolejności przetwarzania. Np aby wydać instrukcję w kolejnych krokach należało by wydać polecenie:

FROM Sales.Shipper SELECT shipperid, phone

Fazy logicznego przetwarzania zapytania

Podstawową klauzulą służącą do pobierania danych w T-SQL jest klauzula SELECT. Poniżej przedstawiona jest kolejność zapisu zapytania T-SQL

  1. SELECT
  2. FROM
  3. WHERE
  4. GROUP BY
  5. HAVING
  6. ORDER BY

Logiczna kolejność przetwarzania zapytania przez silnik bazy danych jest inna. Zaczyna się od podania lokalizacji za pomocą instrukcji FROM. Poniżej zapisana jest kolejność przetwarzania logicznego:

  1. FROM
  2. WHERE
  3. GROUP BY
  4. HAVING
  5. SELECT
  6. ORDER BY

Każda faza działa na jednej lub wielu tabelach wejściowych i zwraca wirtualną tabelę na wyjściu. Tabela wyjściowa każdej fazy jest tabelą wejściową fazy która po niej następuje. Są to operacje na relacjach które zwracają wynik relacyjny. Jeżeli używamy klauzuli ORDER BY to wynik nie jest relacyjny. Rozważmy kolejność logicznego przetwarzania poniższego zapytania:

SELECT country, YEAR(hiredate) AS yearhired, COUNT(*) AS numemployees FROM HR.Employees WHERE hiredate >= '20030101' GROUP BY country, YEAR(hiredate) HAVING COUNT(*) > 1 ORDER BY country , yearhired DESC;

1. Faza klauzuli FROM

W klauzuli FROM wybierane są tabele z których chcemy pobrać wyniki oraz operatory które służą do interakcji między wieloma tabelami jak np JOIN. Jeżeli potrzebujemy zapytać o dane z jednej tabeli jak na przykładzie wystarczy napisać nazwę tabeli wejściowej w klauzuli. Na wyjściu tej fazy powstaje tabela wynikowa która zawiera wszystkie wiersze z tabeli wejściowej. W  przypadku tego zapytania jest to dziewięć wierszy tabeli HR.Employees.

empid hiredate country ------ ----------- -------- 1 2002-05-01 USA 2 2002-08-14 USA 3 2002-04-01 USA 4 2003-05-03 USA 5 2003-10-17 UK 6 2003-10-17 UK 7 2004-01-02 UK 8 2004-03-05 USA 9 2004-11-15 UK

2. Filtrowanie danych w fazie klauzuli WHERE

W tej fazie wiersze otrzymane na wejściu z klauzuli FROM są poddawane filtrowaniu na podstawie predykatu zapisanego w klauzuli WHERE. Tylko wiersze które w wyniku przeliczenia działania predykatu dają w wyniku TRUE są zwracane. W naszym zapytaniu filtrujemy wiersze dla pracowników zatrudnionych po 01-02-2003. Predykat spełnia sześć wierszy i one zostają zwrócone jako wynik.

empid hiredate country ------ ----------- -------- 4 2003-05-03 USA 5 2003-10-17 UK 6 2003-10-17 UK 7 2004-01-02 UK 8 2004-03-05 USA 9 2004-11-15 UK

Typowym błędem osób które nie rozumieją kolejności przetwarzania logicznego jest użycie aliasów kolumn zdefiniowanych w klauzuli SELECT, która jest rozpatrywana później niż WHERE.

3. Grupowanie wierszy w fazie klauzuli GROUP BY

W tej fazie definiowane są grupy dla niepowtarzających się kombinacji wartości w grupowanych elementach z tabeli wejściowej. Każdy wiersz jest przypożątkowywany grupie bazując na definicji grupowania. W zapytaniu przykładowym grupy tworzone są dla każdej kombinacji kraju i roku zatrudnienia. Dla sześciu wierszy otrzymanych z fazy WHERE zostaną stworzone cztery grupy:

group group detail detail detail country YEAR(hiredate) empid country hiredate -------- -------------- ------ ------- ---------- UK 2003 5 UK 2003-10-17 6 UK 2003-10-17 UK 2004 7 UK 2004-01-02 9 UK 2004-11-15 USA 2003 4 USA 2003-05-03 USA 2004 8 USA 2004-03-05

Do grupy UK, 2003 pasują dwa wiersze otrzymane z poprzedniej fazy (z pracownikiem nr 5 i 6), dla grupy UK, 2004 również dwa wiersze (7 i 9), pozostałe grupy posiadają po jednym wierszu. W ostatecznym wyniku fazy grupowania otrzymujemy jeden wiersz reprezentujący każdą grupę, dlatego wyrażenia niegrupujące są ograniczone. Wyrażenia użyte w tej fazie muszą gwarantować jedną wartość dla każdej grupy.  Jeżeli chcemy w liście wynikowej tej fazy otrzymać wartości które biorą udział w grupowaniu to nie ma problemu ponieważ gwarantują one jedną wartość dla grupy. Natomiast dla kolumn z poza wyrażenia GROUP BY (np empid), trzeba użyć funkcji agregujących jak MAX, MIN COUNT itp które gwarantują jeden wynik dla grupy.

4. Filtrowanie zgrupowanych wierszy w fazie HAVING

W tej fazie wiersze są filtrowane na podstawie predykatu jak w fazie WHERE, lecz w tej fazie dzieje się to już na całych grupach. Tylko grupy które w wyniku działania predykatu dają TRUE zostają wynikiem działania tej fazy.  W zapytaniu został użyty predykat COUNT(*) > 1, co oznacza wy-filtrowanie tylko tych grup które mają więcej niż jednego pracownika.

group group detail detail detail country YEAR(hiredate) empid country hiredate -------- -------------- ------ ------- ---------- UK 2003 5 UK 2003-10-17 6 UK 2003-10-17 UK 2004 7 UK 2004-01-02 9 UK 2004-11-15

 5. Faza SELECT

Faz ta jest przetwarzana prawie na końcu pomimo tego, że jest zapisywana jako pierwsza. Faza SELECT posiada dwa główne kroki. Pierwszym krokiem jest przeliczenie wyrażeń w liście klauzuli SELECT i stworzenie atrybutów wynikowych. Krok ten dotyczy również dodania nazw atrybutom jeżeli są one wynikiem wyrażenia. Drugim krokiem jest usunięcie duplikatów jeżeli SELECT zawiera klauzulę DISTINCT.  W przykładowym zapytaniu nie ma klauzuli DISTINCT więc ten krok zostaje pominięty.

country yearhired numemployees -------- ---------- ------------ UK 2003 2 UK 2004 2

Faza ta zwraca wynik relacyjny który nie gwarantuje kolejności wyników. Aby wyniki były uporządkowane trzeba użyć klauzuli ORDER BY która sprawia, że wynik jest nierelacyjny.

6. Kolejność zwracanych wyników w fazie klauzuli ORDER BY

Ta faza odpowiada za uporządkowanie wyników w określonej kolejności. Kolejność ustalona jest w liście klauzuli ORDER BY. Nasze zapytanie ma zostać zaprezentowane najpierw w kolejności krajów, później malejąco wg roku zatrudnienia.

country yearhired numemployees -------- ---------- ------------ UK 2004 2 UK 2003 2

Klauzula ORDER BY pozwala na użycie aliasów użytych w klauzuli SELECT ponieważ występuje później w kolejności logicznej przeważania. Istnieją jeszcze klauzule filtrujące ilość danych wynikowych jak TOP i OFFSET-FETCH. Przetwarzane są one na samym końcu i mogą być traktowane jako faza 7.

Podsumowanie

  • T-SQL jest językiem deklaratywnym w którym instrukcje pisane są bazując na strukturze i kolejności języka angielskiego.
  • Przetwarzanie logiczne zapytania jest konceptualną interpretacją kolejności wykonywania zadań prowadzących do otrzymania poprawnego wyniku.