SQL Server – Indeksy – kiedy i jak je stosować? Udostępnij na: Facebook

Autor: Jacek Włodarski

Opublikowano: 2011-06-17

  1. Wstęp
  2. Czym jest indeks?
  3. Do czego nam właściwie potrzebne indeksy?
  4. Podział indeksów
  5. Do których kolumn należy tworzyć indeksy?
  6. Tworzenie indeksów w praktyce

* * **

1.Wstęp

W tym artykule chciałbym w krótki sposób przedstawić i pokazać na przykładach wykorzystanie indeksów w bazach danych oraz wyjaśnić, dlaczego mają tak duży wpływ na wydajność wykonywanych zapytań.

2.Czym jest indeks?

Indeks jest specjalną strukturą danych wprowadzoną w celu zwiększenia prędkości wykonywania operacji na tabeli. Indeks w bazie danych jest odpowiednikiem spisu treści w książce. Po co kartkować całą książkę dla znalezienia jednej interesującej nas informacji, jeśli możemy zajrzeć do spisu treści i na jego podstawie odnaleźć stronę, na której znajduje się to, czego szukamy. Zaoszczędzimy w ten sposób cenny czas choćby dlatego, że spis treści jest zwykle zorganizowany w sposób alfabetyczny, co znacznie upraszcza wyszukanie frazy, która nas interesuje. Indeks w bazie danych wykorzystuje się przy zapytaniach typu DQL (SELECT), które mają na celu wyszukiwanie odpowiednich wartości w bazie danych. Podczas realizowania zapytania optymalizator (SQL Server) najpierw przeszukuje indeks, który jest uporządkowany, a następnie na podstawie indeksu odczytuje odpowiednie rekordy. Indeks posiada strukturę logiczną i fizyczną niezależną od tabeli, do jakiej się odwołuje. Posiada również własną przestrzeń dyskową oraz jest automatycznie utrzymywany przez system zarządzania bazą danych.

Definicja tworzenia indeksu:

CREATE INDEX name_index ON user (name);

lub

ALTER TABLE user ADD INDEX (name);

3.Do czego nam właściwie potrzebne indeksy?

Ktoś mógłby powiedzieć, że tak naprawdę SQL Server nie potrzebuje indeksów, ponieważ bez nich również otrzymamy dane, o które zapytamy. W tym momencie jednak kłania nam się słowo „wydajność” – dzięki indeksom szybciej odnajdujemy dane w tabeli. Podczas wykonywania polecenia typu DQL (SELECT*)* serwer bazy danych musi wykonać bardzo dużo operacji – wybieranie danych, sortowanie wyników itd. SQL Server może pracować z bardzo dużą ilością rekordów, a często z dziesiątkami milionów rekordów w tabeli, dlatego niezwykle ważną rolę odgrywa w nim optymalizacja wszelkiego rodzaju wyszukiwania oraz sortowania. Jak łatwo zauważyć, rekordy ułożone są w tabeli w takiej kolejności, w jakiej zostały dodane, co oznacza, że jeśli spróbujemy wyszukać w bazie danych np. sklepu ceny danego produktu, to SQL Server musi za każdym razem na nowo przetrząsać od początku do końca wszystko, co tam się znajduje. Kiedy produktów będzie parę tysięcy, może to potrwać dosyć długo. W takiej sytuacji pomocą służą nam indeksy. Indeks nałożony na pole jest niczym innym jak kopią jego zawartości, tyle że posortowaną i odpowiednio ułożoną. Teraz w momencie wyszukiwania jakiejś wartości SQL Server po prostu zajrzy do indeksów jak czytelnik do spisu treści w książce, co pozwoli mu znacznie przyspieszyć wyszukiwanie.

Bardziej obrazowo przedstawimy to w poniższym przykładzie:

Mamy tysiąc wartości posortowanych rosnąco, a nas interesują rekordy z zakresu od 600 do 700. Jeśli rekordy są posortowane rosnąco, SQL Server może zacząć od środkowego rekordu tego zbioru i sprawdzić, czy znaleziona wartość jest mniejsza, czy większa od podanego zakresu. Naturalnie, jeśli wartość środkowego elementu jest mniejsza od podanego zakresu, przeszukuje tylko późniejsze rekordy (również przez wyszukiwanie połówkowe w nowym zbiorze, stanowiącym połowę zbioru poprzedniego), jeśli wartość tego elementu jest większa od podanego zakresu, SQL Server szuka jedynie w rekordach wcześniejszych. Jeśli z kolei poszukiwana wartość mieści się w podanym zakresie, porusza się w obu kierunkach, dopóki nie wypadnie poza założony zakres. W sytuacji, gdy nie byłoby posortowanej tablicy, musiałby najpierw albo ją posortować, albo przejrzeć wszystkie wartości w celu wyodrębnienia tych, które go interesują. (Rys. 1. Przykład binarnego wyszukiwania elementu numer 13 w zbiorze uporządkowanym 15-elementowym.)

1. Przykład binarnego wyszukiwania elementu numer 13 w zbiorze uporządkowanym 15-elementowym.

 

A zatem co zyskaliśmy?

Dzięki posortowaniu rekordów SQL Server na wstępie odrzucił całe mnóstwo rekordów, które nie pasują do naszego zapytania. Dodatkowo mamy zrealizowaną automatycznie funkcję sortowania, bez uruchamiania jakiejkolwiek funkcji sortującej.

A więc czy możemy wnioskować, że indeksy należy stosować „na wszelki wypadek” wszędzie, gdzie to tylko możliwe?

Niestety, nie do końca. To dlatego, że ceną za udogodnienia, jakie oferuje nam indeks, jest zwiększenie rozmiarów bazy, gdyż indeks również potrzebuje trochę miejsca. Przestrzeń dyskowa jest z kolei kluczowym aspektem podczas projektowania bazy danych. A zatem już na początku została obalona postawiona teza o popieraniu rozrzutności podczas indeksowania danych. Należy się zastanowić, na których polach indeks będzie nam potrzebny, a na których jest zwyczajnie zbędny. W tym momencie pomocne będzie środowisko SQL Server, które udzieli nam diagnostycznej informacji o wykonywaniu zapytania, na podstawie której przekonamy się, czy wykorzystał on nasze indeksy. Wystarczy zapytanie SELECT poprzedzić słowem EXPLAIN, a odpowiedź na nasze pytanie mamy gotową.

Ale czy w praktyce robi to jakąkolwiek różnicę?

Wyobraźmy sobie zapytanie, które ma wybrać dane z 15 tabel, z których największa ma np. milion rekordów. Przypuszczam, że operacja wyszukiwania będzie trwała ok. 5 minut. Po założeniu indeksu na tej największej tabeli czas wykonywania zapytania może się skrócić nawet o 10 razy.

4. Podział indeksów

Już na początku warto zaznaczyć, że będzie to nie lada wyczyn, ponieważ indeksy można podzielić praktycznie ze względu na wszystko! No… może prawie wszystko J.

Z punktu widzenia liczby wskazań indeksu do pliku danych rozróżnia się:

  • Indeks gęsty (dense) – zawiera wpis dla każdej wartości klucza wyszukiwania, czyli dla każdego rekordu.
  • Indeks rzadki (sparse) – posiada wpis jedynie dla niektórych wartości wyszukiwania (np. bloków).

Ze względu na liczbę poziomów mówimy o indeksach jednopoziomowych oraz wielopoziomowych. Wyszukanie danych z wykorzystaniem indeksu jednopoziomowego wymaga przeszukania pliku indeksu. Z wykorzystaniem znalezionych rekordów indeksu następuje odczytanie rekordów danych. Należy zwrócić uwagę, że plik indeksu jest przeszukiwany algorytmem połowienia binarnego, ponieważ jest to plik uporządkowany. Algorytm ten nie należy do efektywnych. Z tego względu wprowadzono indeksy wielopoziomowe, których efektywność przeszukiwania jest większa.

Ze względu na charakterystykę atrybutu indeksowego SQL Server obsługuje trzy rodzaje indeksów jednopoziomowych:

**Rys.2.  Indeks główny (podstawowy).

Indeks główny (Primary index) – zwany także podstawowym, jest założony na kluczu podstawowym pliku uporządkowanego i zawiera jeden klucz dla każdego bloku dyskowego. Pierwszy z rekordów danego bloku nazywamy rekordem zaczepienia lub rekordem kotwiczącym. Należy on do grupy indeksów rzadkich.

Zalety: Mniejszy rozmiar niż plik oryginalny oraz możliwe przeszukiwanie przez połowienie binarne.

Wady: Wysoki koszt modyfikacji danych

**Rys.3.  Indeks zgrupowany.

Indeks zgrupowany (Clustered index) – jest założony na atrybucie niebędącym kluczem podstawowym pliku uporządkowanego (nieunikatowym) porządkującym pliku uporządkowanego. Indeks zawiera jeden klucz dla każdej wartości atrybutu. Posiada dwa pola – pierwsze ma ten sam typ co pole klastrowania, drugie – wskaźnik. Indeks zawiera wpis do każdej odrębnej wartości klastrowania oraz wskaźnik na pierwszy blok, do którego ona należy. Należy do grupy indeksów rzadkich.

Zalety: Mniejszy rozmiar niż plik oryginalny, możliwe przeszukiwanie przez połowienie binarne.
Wady: Wysoki koszt modyfikacji danych.

Indeks niezgrupowany (Nunclustered index) – jest zakładany na pole, które ma unikatowe wartości w każdym rekordzie lub które nie jest polem klucza i posiada powtarzające się wartości. Plik indeksu niezgrupowanego jest uporządkowany i posiada dwa pola – jedno jest tego typu co wybrane pole niebędące polem uporządkowania pliku (pole indeksujące), drugie  –wskaźnikiem na blok lub rekord. Dla jednego pliku może być wiele indeksów drugorzędnych. Należy do grupy indeksów zagęszczonych. Wskaźniki we wpisach indeksu są wskaźnikami na bloki.

 Jest on zakładany na atrybucie indeksowym pliku danych, który nie jest atrybutem porządkującym tego pliku. Każdy rekord pliku danych posiada swój odpowiednik w rekordzie indeksu. Stąd indeks wtórny jest indeksem gęstym. Rekord indeksu wtórnego składa się z dwóch pól – wartości pola indeksowego i wskaźnika albo do rekordu albo do bloku danych zawierającego ten rekord.

**Rys.4.  Indeks niezgrupowany.

 

Indeksy wielopoziomowe – dla pierwszego poziomu tworzymy indeks podstawowy i nazywamy go indeksem drugiego poziomu. Analogicznie dla poziomu drugiego, gdzie tworzy się indeks poziomu trzeciego. Indeksy wielopoziomowe można konstruować z wykorzystaniem indeksów podstawowych, wtórnych i zgrupowanych, pod warunkiem jednak, że indeks pierwszego poziomu ma różne wartości i rekordy stałej długości.

**Rys.5. Indeksy wielopoziomowe.

Jedną z fundamentalnych koncepcji indeksu wielopoziomowego jest struktura VSAM (Virtual Sequential Access Method). Koncepcyjnie struktura ta jest zbudowana z dwóch poziomów. Poziom pierwszy indeksuje cylindry. Rekordy indeksu na tym poziomie zawierają pary wartości – poszukiwany klucz i adres do indeksu ścieżki dyskowej. Poziom drugi indeksuje ścieżki. Jego rekordy zawierają pary wartości – poszukiwany klucz i adres ścieżki. Jak widać, jest to struktura silnie związana z zastosowanym sprzętem komputerowym. Indeks na pierwszym poziomie adresuje bloki danych. Każdy rekord tego indeksu zawiera wartość pola indeksowego i adres bloku danych, w którym ta wartość się znajduje. Rekordy tego indeksu są przechowywane w pliku uporządkowanym zgodnie z wartościami klucza indeksu pierwszego poziomu. Rekordy indeksu drugiego poziomu zawierają adresy bloków indeksu pierwszego poziomu.

Tworzenie indeksu

CREATE [UNIQUE] [CLUSTERED] [NONCLUSTERED] INDEX nazwa_indeksu
ON {tabela/widok} (kolumna [Asc/Desc] [,…n])
[With <opcja _indeksu>[…n]]
<opcja indeksu>::=
{PAD_INDEX| 
           FILLFACTOR = współczynnik_wypełnienia
           IGNORE_DUP_KEY|
           DROP_EXISTING|
STATISTIC_NO_RECOMPUTE|
SORT_IN_TEMPDB
}
Argumenty polecenia CREATE INDEX
Argument Wyjaśnienie
UNIQUE Nie dopuszcza się występowania dwóch takich samych wierszy. Jeśli mimo wszystko zajdzie taka sytuacja, to indeks nie zostanie utworzony.
CLUSTREAD / NONCLUSTREAD Określenie sposobu tworzenia indeksu. Można utworzyć tylko 1 indeks klastrowy i 249 nieklastrowych. Domyślnie – indeksy nieklastrowe
Nazwa_indeksu Określa nazwę tworzonego indeksu
tabela | widok Nazwa tabeli lub perspektywy (widoku) na podstawie, na której ma zostać utworzony indeks
Kolumna Nazwa kolumny lub kolumn (gdy ma być to indeks złożony)
ASC \ DESC Określenie sposobu sortowania indeksu (rosnąco –ASC, malejąco – DESC), domyślnie indeks jest posortowany rosnąco
ON grupa_plików Określa grupę plików, w których indeks ma być tworzony
PAD_INDEX Określa, że powinna być zostawiona przestrzeń dla przyszłych aktualizacji indeksów (przydaje się np. przy atrybutach typu varchar)
FILLFACTOR = współczynnik wypełnienia Określa, jaki procent bloku ma zostać zapełniony
IGNORE_DUP_KEY Używany z klauzulą UNIQUE. Jeśli nie będzie klauzuli IGNORE_DUP_KEY, i wystąpi próba dodania indeksu o istniejącej wartości – to indeks nie zostanie utworzony, jeśli natomiast tworzymy indeks z klauzulą IGONRE_DUP_KEY, to w tej samej sytuacji zdublowany klucz zostanie odrzucony, ale indeks zostanie utworzony.
DROP EXISTING Używany do ponownego tworzenia istniejących indeksów, przy tworzeniu indeksów1) klastrowych można odczuć wzrost wydajności, ponieważ tworzą się na nowo indeksy nieklastrowe
STATISTICS_NO_RECOMPUTE Oznacza, ze statystyki indeksu nie mają być na bieżąco uaktualniane
SORT IN TEMPDE Oznacza, że bezpośrednie wyniki sortowania mają być przechowywane w bazie tempdb, jeśli baza ta znajduje się na innym dysku, niż baza z danymi użytkownika, to znacznie zwiększa to wydajność

**Tab.1. Argumenty polecenia CREATE INDEX.

Niezależnie od tego, czy indeksy są zgrupowane, czy niezgrupowane, najczęściej tworzone są w formie drzew zbalansowanych. Gwarantuje to logarytmiczny (względem rozmiaru) czas wykonywania podstawowych operacji takich jak wstawianie, wyszukiwanie czy usuwanie elementów. Balanced Binary Trees (B-drzewa) zapewniają szybki dostęp do danych, gdyż  rekordy o podobnych kluczach są grupowane. Balansowanie drzewa jest kluczową jego własnością. Stan drzewa jest przez cały czas kontrolowany, a gałęzie są w razie potrzeby modyfikowane tak, aby do przejścia przez drzewo w celu odnalezienia jakiejś wartości i dotarcie do konkretnego rekordu wymagało tylko kilku dostępów do strony. W indeksie zgrupowanym dane są przechowywane we właściwej kolejności, np. jak w encyklopedii. Indeks niezgrupowany jest oddzielnym obiektem bazy danych, wskazującym poszczególne wiersze w tabeli, ale bez uwzględnienia sposobu zapisania wiersza. Odpowiednikiem tego typu indeksu jest indeks znajdujący się na końcu niektórych książek.

Rys. 6. Przykład binarnego drzewa zbalansowanego i niezbalansowanego.

Rys. 7.  B-tree.

B-tree składa się z korzenia (Root), z gałęzi zawierających dodatkowe informacje oraz liści (Leaf), które zawierają pozycje przechowywane w porządku, którym odpowiadają zaindeksowane dane. Liczba indeksowanych wierszy na stronie jest zależna od miejsca wymaganego przez kolumny zdefiniowane w indeksie. Na przykład, w indeksie jest zdefiniowana kolumna 4-bajtowa int. Będzie ona miała piętnaście razy więcej pozycji niż kolumna zdefiniowana jako char(60), która wymaga 60-bajtów miejsca. Jedna strona w SQL może ważyć 8192 bajty, a mieszczą się w niej dane o wadze 8060 bajtów. Jeżeli budujemy indeks oparty na kolumnie zawierającej znakowy typ danych char(60), każdy wiersz na stronie będzie wymagał 60 bajtów miejsca, to również oznacza ze 60 bajtów będzie zawierał każdy wiersz w indeksie. Jeżeli jest tylko 100 wierszy danych, zajmują one 6000 bajtów. Dane te zmieszczą się na jednej stronie, więc indeks będzie miał jedną stronę Root, jak również stronę Leaf.

5. Do których kolumn należy tworzyć indeksy?

O wyborze indeksu decyduje optymalizator kwerend określający, które (ewentualnie) indeksy będą najbardziej użyteczne.

Warto również w tym punkcie określić, czym jest selektywność indeksu. Jest to nic innego, jak parametr określający, czy indeks na określonych kolumnach może być przydatny. Wartość tego parametru wyliczamy ze wzoru:

 

gdzie:
S – selektywnośc;
U – liczba unikalnych wartości dla kolumny;
W – liczba wszystkich wierszy w kolumnie;

Jeśli wartość selektywności indeksu wynosi mniej niż 85%, SQL Server raczej nie będzie z niego korzystał.

  • Indeksy, z wyjątkiem grupujących, w pewnych sytuacjach mogą wydłużać czas operacji wstawiania i modyfikowania danych.
  • Indeks grupujący powinien być tworzony dla kolumny, według której użytkownicy często sortują dane odczytywane z tabeli lub dla kolumn przechowujących wartości, na podstawie których zwracane są zbiory danych.

Dla indeksów niezgrupowanych odpowiednimi kandydatami są kolumny, które:

– przechowują wartości częściej odczytywane, niż modyfikowane,

– wykorzystywane są do łączenia lub wyszukiwania danych,

– przechowują różnorodne wartości.

W praktyce indeksy tworzymy dla:

  • Kolumn z ograniczeniem PRIMARY KEY.
  • Kolumn z ograniczeniem FOREIGN KEY oraz kolumn wykorzystywanych przy łączeniu tabel.
  • Kolumn przechowujących dane wykorzystywane jako argument wyszukiwania.
  • Kolumn przechowujących często sortowane dane.

Nie ma natomiast możliwości, aby założyć indeks dla kolumn przechowujących dane typu bit, txt, ntext, image.

Indeksy możemy podzielić na takie, które zakładamy na jedną kolumnę, lub takie, gdy zakładamy go na wiele kolumn równocześnie. Warto zauważyć, że założenie indeksów na wiele kolumn nie jest równoważne założeniu wielu indeksów na pojedynczych kolumnach.

Innym podziałem jest podział na indeksy unikalne oraz „normalne”. Jak sama nazwa wskazuje, każda wartość w indeksie unikalnym musi być inna – stosowane np. do zapewnienia unikalności kluczy głównych. Normalne, czyli najprościej mówiąc nieunikalne, tzn. takie, dla których wartości w indeksie mogą się powtarzać. Te drugie stanowią najczęstsze kryterium stosowania indeksów.

6. Tworzenie indeksów w praktyce

Dotąd mówiliśmy o teorii tworzenia indeksów. A jak wygląda tworzenie indeksu w praktyce?

Indeksy możemy tworzyć od razu, już na etapie tworzenia tabeli, lub stworzyć indeksy do istniejącej tabeli. Zobaczmy zatem, jak wygląda to dla poszczególnych przypadków.

  • Tworzenie indeksów przy tworzeniu tabeli:
CREATE TABLE nazwa_tabeli (
kolumna1 INT,
kolumna2 INT,
UNIQUE indeks_unikalny (kolumna1),
INDEX indeks_zwykly (kolumna2)
)
  • Tworzenie indeksów w istniejącej tabeli:
ALTER TABLE nazwa_tabeli
ADD UNIQUE indeks_unikalny (kolumna1),
ADD INDEX indeks_zwykly (kolumna2)

Możemy też użyć słowa CREATE jak w przykładzie pierwszym. W jednej komendzie tworzony jest tylko jeden indeks, zatem należy wydać dwie komendy, aby dodać indeks unikalny oraz indeks zwykły:

CREATE UNIQUE INDEX indeks_unikalny ON nazwa_tabeli (kolumna1)
CREATE INDEX indeks_zwykly ON nazwa_tabeli (kolumna2)

Jak łatwo zauważyć, bez trudu można dodać do jednej tabeli wiele indeksów. Z tego co widać, w pojedynczej tabeli może istnieć wiele indeksów. Niemniej istnieje również możliwość utworzenia indeksów na kilku kolumnach jednocześnie.

Przypadek, kiedy dwa różne indeksy tworzymy na dwóch różnych kolumnach, znamy już w zasadzie z poprzedniego przykładu, jednak – jak się przekonamy w przykładzie poniżej – również dla dwóch indeksów zwykłych składnia będzie wyglądała podobnie:

CREATE INDEX indeks_imie ON osoby (imie)
CREATE INDEX indeks_nazw ON osoby (nazwisko)

W przypadku kiedy naszym celem jest utworzenie jednego indeksu na dwóch kolumnach, wystarczy zastosować zapis jak w poniższym przykładzie:

CREATE INDEX indeks_imie_nazw ON osoby (imie, nazwisko)

Dwa powyższe przykłady mogą wydawać się podobne, jednak występuje pomiędzy nimi zasadnicza różnica. Rozważmy, jak zostanie zinterpretowany przez system SQL Server poniższy przykład:

SELECT * FROM osoby WHERE imie='Jan' AND nazwisko='Kowalski'
  • Jeśli tabela posiada dwa różne indeksy, każdy na pojedynczej kolumnie, baza danych wykona to zapytanie w następujących krokach:
  1. wyszuka wszystkie rekordy, gdzie występuje imie = Jan;
  2. wyszuka wszystkie rekordy, gdzie występuje nazwisko = Kowalski;
  3. obliczy część wspólną zbiorów rekordów z pierwszego i drugiego kroku, i zwróci ją jako wynik zapytania.
  • W drugim przypadku, tzn. kiedy indeks jest nałożony na kolumnach (imię, nazwisko), baza danych może wyszukać potrzebne dane w jednym kroku. Sprawdzi równocześnie wartości w polach „imię” i „nazwisko”.

Warto również zauważyć, że w momencie gdy nałożymy jeden indeks na kilka kolumn, to zostanie on użyty nie tylko wtedy, kiedy warunek znajdujący się w zapytaniu będzie zawierał wszystkie kolumny uwzględnione przez indeks, ale również dla warunków, które zawierają dowolną ilość kolumn z tych, które zostały uwzględnione przy tworzeniu indeksu.

Przykład: Mamy indeks utworzony w tabeli na kolumnach (imie, nazwisko, pesel). W tym przypadku indeks zostanie użyty dla warunku wyszukiwania, we wszystkich kombinacjach wspomnianych kolumn, np.:

  • imie, nazwisko, pesel
  • nazwisko, imie
  • imie, pesel
  • imie itd.

Kolejność warunków w zapytaniu nie ma tutaj najmniejszego znaczenia. Baza danych najpierw wyszuka zaznaczone przez nas warunki, a następnie dopiero je przestawi, aby pasowały do kolejności zaznaczonej w utworzonym indeksie.

Jeśli nie wiesz, jakich zapytań wyszukujących będziesz używał w czasie zapytań, tzn. czy będziesz wyszukiwał tylko po imieniu, tylko po numerze pesel, czy też zarówno po imieniu, jak i po nazwisku, warto zastosować uniwersalną opcję utworzenia indeksów, która obsłuży jednocześnie wszystkie przypadki:

CREATE INDEX indeks_imie_nazw ON osoby (imie, nazwisko)
CREATE INDEX indeks_nazw ON osoby (nazwisko)

Należy przeanalizować zapytania, które są wykonywane, i na tej podstawie podjąć decyzję gdzie i jakie indeksy utworzyć. Na pewno indeksy należy utworzyć dla kluczy głównych (unikalne) oraz dla kluczy obcych, gdyż po tych polach często się wyszukuje. Ponadto często się zdarza, że podczas oznaczania pola jako klucz obcy baza danych wymaga indeksu na nim.

Czy muszę nadawać nazwy indeksom, które tworzę?

Nazwy indeksów nie są obowiązkowe. W przypadku gdy ich nie określisz, baza danych sama sobie utworzy nazwy. Warto jest je jednak nadawać, ponieważ przy większej ich ilości, lub nawet po upływie pewnego czasu, trudno ci będzie się zorientować, który indeks do czego służy.

 

Podsumowanie

W tym artykule nauczyliśmy się, kiedy i jak właściwie stosować indeksy w bazie danych.