Dlaczego jest to potrzebne?
Gdy dane są przechowywane na dyskowych urządzeniach magazynujących, są przechowywane jako bloki danych. Te bloki są dostępne w całości, co czyni je operacją dostępu do dysku atomowego. Bloki dyskowe mają strukturę podobną do list połączonych; oba zawierają sekcję danych, wskaźnik do lokalizacji następnego węzła (lub bloku) i oba nie muszą być przechowywane w sposób ciągły.
Z uwagi na fakt, że wiele rekordów można posortować tylko na jednym polu, możemy stwierdzić, że wyszukiwanie w polu, które nie jest posortowane, wymaga wyszukiwania liniowego, które wymaga N/2
dostępu do bloków (średnio), gdzie N
jest liczba bloków, które stół się rozciąga. Jeśli to pole jest polem niekluczowym (tzn. Nie zawiera unikatowych wpisów), należy przeszukać cały obszar tabel przy dostępie do N
bloku.
Natomiast z posortowanym polem można zastosować wyszukiwanie binarne, które ma log2 N
dostęp do bloków. Ponieważ dane są sortowane według pola niekluczowego, reszta tabeli nie musi być przeszukiwana pod kątem duplikatów, gdy tylko zostanie znaleziona wyższa wartość. Zatem wzrost wydajności jest znaczny.
Co to jest indeksowanie?
Indeksowanie to sposób sortowania wielu rekordów w wielu polach. Utworzenie indeksu dla pola w tabeli tworzy kolejną strukturę danych, która przechowuje wartość pola i wskaźnik do rekordu, którego dotyczy. Ta struktura indeksu jest następnie sortowana, umożliwiając na nim wyszukiwanie binarne.
Minusem indeksowania jest to, że indeksy te wymagają dodatkowego miejsca na dysku, ponieważ indeksy są przechowywane razem w tabeli za pomocą silnika MyISAM, plik ten może szybko osiągnąć limity rozmiaru bazowego systemu plików, jeśli wiele pól w tej samej tabeli jest indeksowanych .
Jak to działa?
Po pierwsze, nakreślmy przykładowy schemat tabeli bazy danych;
Nazwa pola Typ danych Rozmiar na dysku
id (klucz podstawowy) Unsigned INT 4 bajty
firstName Char (50) 50 bajtów
lastName Char (50) 50 bajtów
emailAddress Char (100) 100 bajtów
Uwaga : zamiast varchar zastosowano char, aby umożliwić dokładny rozmiar wartości dysku. Ta przykładowa baza danych zawiera pięć milionów wierszy i jest nieindeksowana. Wydajność kilku zapytań zostanie teraz przeanalizowana. Są to zapytania przy użyciu identyfikatora (posortowane pole klucza) i zapytania przy użyciu firstName (nieposortowane pole nieposortowane).
Przykład 1 - pola posortowane a nieposortowane
Biorąc pod uwagę naszą przykładową bazę danych r = 5,000,000
rekordów o ustalonym rozmiarze, dających rekordową długość R = 204
bajtów, i są one przechowywane w tabeli za pomocą silnika MyISAM, który używa domyślnej wielkości B = 1,024
bajtów bloku . Czynnikiem blokującym tabelę byłyby bfr = (B/R) = 1024/204 = 5
rekordy na blok dysku. Całkowita liczba bloków potrzebnych do utrzymania tabeli to N = (r/bfr) = 5000000/5 = 1,000,000
bloki.
Liniowe wyszukiwanie w polu id wymagałoby średniego N/2 = 500,000
dostępu do bloku, aby znaleźć wartość, biorąc pod uwagę, że pole id jest polem kluczowym. Ponieważ jednak pole id jest również posortowane, można przeprowadzić wyszukiwanie binarne wymagające średniego log2 1000000 = 19.93 = 20
dostępu do bloku. Natychmiast widzimy, że jest to drastyczna poprawa.
Teraz pole firstName nie jest sortowane ani kluczowe, więc wyszukiwanie binarne jest niemożliwe, a wartości nie są unikalne, dlatego tabela będzie wymagała wyszukiwania do końca dokładnego N = 1,000,000
dostępu do bloku. Jest to sytuacja, którą indeksowanie ma poprawić.
Biorąc pod uwagę, że rekord indeksu zawiera tylko indeksowane pole i wskaźnik do rekordu oryginalnego, jest oczywiste, że będzie mniejszy niż rekord wielu pól, na który wskazuje. Zatem sam indeks wymaga mniejszej liczby bloków dysku niż oryginalna tabela, co wymaga mniejszego dostępu do bloków w celu iteracji. Schemat indeksu w polu firstName przedstawiono poniżej;
Nazwa pola Typ danych Rozmiar na dysku
firstName Char (50) 50 bajtów
(wskaźnik zapisu) Specjalne 4 bajty
Uwaga : Wskaźniki w MySQL mają długość 2, 3, 4 lub 5 bajtów w zależności od wielkości tabeli.
Przykład 2 - indeksowanie
Biorąc pod uwagę naszą przykładową bazę danych r = 5,000,000
rekordów z indeksem długości rekordu R = 54
bajtów i przy użyciu domyślnego rozmiaru B = 1,024
bajtów bloku . Czynnikiem blokującym indeks byłyby bfr = (B/R) = 1024/54 = 18
rekordy na blok dysku. Całkowita liczba bloków wymaganych do przechowywania indeksu to N = (r/bfr) = 5000000/18 = 277,778
bloki.
Teraz wyszukiwanie przy użyciu pola firstName może wykorzystać indeks do zwiększenia wydajności. Pozwala to na binarne wyszukiwanie indeksu ze średnią log2 277778 = 18.08 = 19
dostępów blokowych. Aby znaleźć adres rzeczywistego rekordu, który wymaga dalszego dostępu do bloku w celu odczytu, przynosząc całkowitą liczbę 19 + 1 = 20
dostępów do bloku, daleko od 1.000.000 dostępów do bloku wymaganych do znalezienia dopasowania FirstName w tabeli nieindeksowanej.
Kiedy należy go używać?
Biorąc pod uwagę, że utworzenie indeksu wymaga dodatkowego miejsca na dysku (277,778 dodatkowych bloków w stosunku do powyższego przykładu, wzrost o ~ 28%) oraz że zbyt wiele indeksów może powodować problemy wynikające z ograniczeń wielkości systemów plików, należy starannie rozważyć wybór właściwego pola do indeksowania.
Ponieważ indeksy są używane tylko do przyspieszenia wyszukiwania pasującego pola w rekordach, oczywiste jest, że pola indeksujące używane tylko do danych wyjściowych byłyby po prostu stratą miejsca na dysku i czasu przetwarzania podczas wykonywania operacji wstawiania lub usuwania, a zatem należy unikać. Biorąc pod uwagę charakter wyszukiwania binarnego, ważna jest liczność lub niepowtarzalność danych. Indeksowanie na polu o liczności 2 spowoduje podzielenie danych na pół, podczas gdy liczność na 1000 zwróci około 1000 rekordów. Przy tak niskiej liczności skuteczność zmniejsza się do sortowania liniowego, a optymalizator kwerendy uniknie użycia indeksu, jeśli liczność jest mniejsza niż 30% liczby rekordów, skutecznie czyniąc indeks stratą miejsca.