060 SQL FIZYCZNA STRUKTURA BAZY DANYCH Prof. dr hab. Marek Wisła
Struktura tabeli Data dane LOB - Large Objects (bitmapy, teksty) Row-Overflow zawiera dane typu varchar, varbinary http://msdn.microsoft.com/en-us/library/ms189051(v=sql.105).aspx
Fizyczna struktura bazy danych Dane zapisywane są w 8-KB ciągłych obszarach zwanych stronami (page) numerowanymi automatycznie od 0 do n. Pojedynczy wiersz tabeli nie może być zapisany na kilku stronach, ale na jednej stronie może być zapisanych kilka wierszy. Strony łączone są w 64 KB zakresy (extent), a więc w jeden zakres wchodzi kolejne 8 stron. W jednym zakresie może znajdować się kilka (małych) tabel. Kolejność zapisu wierszy na stronach nie jest w żaden sposób uporządkowana, chyba że został utworzony indeks klastrowany (clustered).
Strona - page Każda strona rozpoczyna się od 96 B nagłówka, w którym zapisywane są dane systemowe: numer strony, typ strony, ilość wolnego miejsca na stronie. identyfikator obiektu, do którego należy ta strona.
Zapis wierszy na stronie Dane wierszy są zapisywane na stronie w sposób ciągły zaczynając od pierwszego bajta po nagłówku. Tablica przesunięć (offset) wierszy umieszczona jest na końcu strony, każdy wiersz umieszczony na stronie posiada jeden wpis w tabeli przesunięć. W tabeli przesunięć zapisywana jest odległość w bajtach początku wiersza od początku strony. Kolejność wpisów w tabeli przesunięć jest przeciwna do kolejności wierszy na stronie.
Zapis wierszy > 8KB Jeden wiersz nie może być zapisany na kilku stronach, jednak część danych wiersza może zostać przeniesiona do osobnej tabeli. Maksymalny rozmiar wiersza to 8,060 bajtów (8 KB), jednak z pominięciem danych zapisywanych w kolumnach typu Text/Image. Od SQL Serwer 2005, to ograniczenie zostało rozszerzone o kolumny o zmiennej długości typu varchar, nvarchar, varbinary i sql_variant. Jeśli wiersz przekracza 8,060 bajtów, SQL Server automatycznie przenosi jedną lub kilka wartości z kolumn o zmiennej długości na strony w ROW_OVERFLOW_DATA allocation unit, rozpoczynając od kolumny o największej długości. W miejsce przeniesionej wartości wpisywany jest 24 bajtowy wskaźnik w IN_ROW_DATA allocation unit na oryginalnej stronie. Jeśli wskutek kolejnej operacji zostanie zmniejszona wielkość wiersza, SQL Server automatycznie przeniesie dane z powrotem na stronę.
Podział stron Próba dodania nowego wiersza do pełnej strony powoduje wstawienie nowej strony i zapis wiersza na nowej stronie http://sqlblogcasts.com/blogs/tonyrogerson/archive/2007/06/28/what-is-a-page-split-what-happens-whydoes-it-happen-why-worry.aspx
Podział stron Z tego powodu strony często zawierają puste miejsca. Jest to niekorzystne z punktu widzenia ilości przestrzeni dyskowej zajmowanej przez bazę danych, ale może być korzystne w przypadku wstawiania danych w wolne miejsca (np. w przypadku korzystania z indeksu grupującego). Przykład podziału stron
Typy zakresów Zakres jest jednorodny (uniform), gdy wszystkie strony tego zakresu przynależą tylko do jednego obiektu. Zakres jest mieszany (mixed), gdy jego strony przynależą do różnych obiektów. Każda z ośmiu stron może należeć do innego obiektu.
INDEKSY
Indeksy Indeks zawiera posortowaną (logicznie) kopię zbioru wartości jednej lub kilku kolumn z danej tabeli. Z każdą wartością w indeksie jest związana specjalna wartość, wskazująca, gdzie fizycznie można znaleźć wiersz, z którego ta wartość pochodzi. Ponieważ indeks jest zbiorem posortowanym, SZBD potrafi szybko znaleźć właściwą wartość i odpowiadający jej wiersz tabeli
Indeksy Indeks może być określony dla kolumny (kolumn) klucza głównego lub dla innej (innych) kolumn często wykorzystywanych w kryteriach wyszukiwania. Indeks jest strukturą danych zwiększającą szybkość wykonywania operacji wyszukiwania. Indeksy spowalniają operacje wstawiania, usuwania i modyfikacji danych.
Zasady programowania Zwiększenie czasu wykonywania operacji spowodowane koniecznością uaktualniana wielu indeksów może być istotne tylko w przypadku wykonywania masowych operacji wstawiania lub aktualizowania danych. W pozostałych przypadkach (jedno lub kilkukrotnego wstawiania/aktualizowania danych) czas uaktualniania indeksów jest praktycznie niezauważalny. Z tego powodu dodanie indeksu do tabeli może być zdecydowanie korzystne dla użytkowników skracając czas potrzebny na uzyskanie danych z tabel.
Indeks klastrowany (CLUSTERED) Zwykle wiersze tabeli zapisywane są na stronach w przypadkowej kolejności. Jeśli jednak w tabeli został zdefiniowany indeks klastrowany, wiersze są zapisywane dokładnie w takiej kolejności, jaka wynika z wartości klucza użytego w indeksie. Ponieważ wiersze w bazie danych są fizycznie posortowane, indeksy klastrowane są bardzo wydajnym sposobem wyszukiwania wierszy. Tabela może posiadać tylko jeden indeks klastrowany. Każdy indeks klastrowany musi być unikalny.
Indes klastrowany http://msdn.microsoft.com/enus/library/ms177443(v=sql.105).aspx
Indeks nieklastrowany Opcja indeksu NONCLUSTERED (nieklastrowany) jest standardową wartością każdego indeksu i nie musi być specyfikowana podczas tworzenia indeksu. Wiersze w tabeli pozbawionej indeksu klastrowanego są zapisywane w bazie danych w przypadkowy sposób. W takim przypadku tabela przypomina stertę (heap) na którym składowane są dane. Indeksy nieklastrowane mają strukturę niezależną od wierszy tabeli. Indeks nieklastrowany zawiera swój klucz (kolumny) indeksu oraz wskaźnik do wiersza w którym znajdują się dane.
Indeks unikalny (UNIQUE) Indeks klastrowany musi być unikalny. Natomiast indeksy nieklastrowane nie muszą być unikalne. Jeśli jednak dane składowane w kolumnie (lub kliku kolumnach) indeksu mają być unikalne, podczas definiowania indeksu można użyć opcji UNIQUE
Indeks nieklastrowany http://msdn.microsoft.com/enus/library/ms177484(v=sql.105).aspx
Tworzenie indeksu CREATE [UNIQUE CLUSTERED NONCLUSTERED] INDEX nazwa-indeksu ON nazwa-tabeli (nazwa-kolumny [ASC DESC] {, nazwa-kolumny [ASC DESC]}); Zapytanie tworzy indeks o podanej nazwie dla tabeli o podanej nazwie, określony dla kolumn o podanych nazwach CLUSTERED indeks klastrowany. Można utworzyć tylko 1 indeks klastrowany i 249 indeksów nieklastrowanych. UNIQUE wymusza niepowtarzalność wartości danych w kolumnach tworzących indeks.
Zasady programisty Indeks klastrowany powinien być tworzony dla kolumny (rzadziej: kilku kolumn) według której użytkownicy najczęściej przeszukują dane. Indeksy powinny być zakładane na kolumnach, z których: wykorzystywane są do łączenia tabel (klauzule FROM i JOIN) - w szczególności optymalne są złączenia po kombinacjach PRIMARY KEY FOREIGN KEY, wykorzystywane są do wyszukiwania danych w klauzuli WHERE, wykorzystywane są do grupowania danych w klauzuli GROUP BY wykorzystywane są do sortowania tabeli w klauzuli ORDER BY
Usuwanie indeksu DROP INDEX nazwa-indeksu ON nazwa-tabeli {,nazwa-indeksu ON nazwa-tabeli} Przy pomocy komendy DROP INDEX można usunąć tylko te indeksy, które zostały założone komendą CREATE INDEX.
Usuwanie PRIMARY KEY ALTER TABLE nazwa-tabeli DROP CONSTRAINT nazwa-primary-key Usuwanie indeksu opartego na kluczu własnym można wykonać jedynie poprzez usunięcie węzła integralności.
OPTYMALIZACJA
Optymalizacja Zapytania, podobnie jak pozostałe komendy T-SQL, przed skompilowaniem i wykonaniem są optymalizowane przez wewnętrzny proces Sewera SQL - Query Optimizer. Celem Query Optimizera jest znalezienie najszybszego sposobu wykonania zapytania. Decyzje podejmowane są na podstawie ilości operacji wejścia-wyjścia oraz ilości obliczeń mających być wykonanych przez procesor niezbędnych do wykonania zapytania. Query Optimizer szacuje koszt operacji wejścia-wyjścia na podstawie: struktury tabel, do których odwołuje się zapytanie i istniejących na tych tabelach indeksów. kosztu operacji złączenia tabelach źródłowych. istniejących lub tworzonych dynamicznie przez Query Optimizera statystyk opisujących dane źródłowe. metainformacji opisujących fizyczną strukturę tabel, w których zapisane są żądane dane.
Statystyki Ponieważ Query Optimizer oblicza koszt wykonania instrukcji na podstawie statystyk, nieaktualne lub nieadekwatne statystki spowodują utworzenie nieefektywnego planu jej wykonania. Wynikiem optymalizacji jest znalezienie takiego sposobu wykonania zapytania: który operuje na najmniejszej z możliwych liczby wierszy i w związku z tym wymaga odczytania najmniejszej liczby stron (8 KB spójnych bloków danych). którego całkowity czas przeprowadzania jest najkrótszy.
Statystyki [SET SHOWPLAN_TEXT ON SET SHOWPLAN_ALL ON GO] SET STATISTICS IO ON SET STATISTICS TIME ON Zapytanie-SQL Query Analyzer pozwala na wyświetlenie statystyk związanych z czasem (SET STATISTICS TIME) i liczbą operacji wejściawyjścia (opcja SET STATISTICS IO). Ponadto możemy wyświetlić opracowany przez Query Optimizer plan wykonania instrukcji (opcja SET SHOWPLAN_TEXT lub SET SHOWPLAN_ALL).
Statystyki Table 'MojaTabela'. Scan count 1, logical reads 79, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0. scan count - ilość odwołań do tabeli źródłowej. logical reads - ilość stron danych odczytanych z pamięci podręcznej. physical reads ilość stron danych odczytanych z dysku. Ta liczba nigdy nie jest większa od liczby stron odczytanych z pamięci podręcznej. Na podstawie tych dwóch wartości można obliczyć współczynnik trafień: współczynnik trafień = (logical reads physical reads) / logical reads, read-ahead reads określa liczbę stron umieszczoną w pamięci podręcznej, lob Large object.
Statystyki Argumenty wywołania operacji Koszt wykonania operacji i jego szacunkowy udział w koszcie wykonania instrukcji (Cost), Koszt wykonania operacji i operacji przez nią wywołanych (Subtree cost), Ilość wykonania operacji w ramach instrukcji (Number of executes), Ilość zwróconych przez operację wierszy (Row count), Szacunkową wielkość zwróconych przez operację wierszy (Estimated row size), Szacunkowy koszt operacji wejściawyjścia przeprowadzonych przez operację (I/O cost), Szacunkowy koszt wykorzystania zasobów procesora przez operację (CPU cost).