Indeksy MySQL - jakie są najlepsze praktyki?

208

Od jakiegoś czasu korzystam z indeksów w bazach danych MySQL, ale nigdy się o nich właściwie nie dowiedziałem . Zasadniczo umieszczam indeks na dowolnych polach, które będę wyszukiwał lub wybrał za pomocą WHEREklauzuli, ale czasami nie wydaje się on tak czarno-biały.

Jakie są najlepsze praktyki dotyczące indeksów MySQL?

Przykładowe sytuacje / dylematy:

  • Jeśli tabela ma sześć kolumn i wszystkie można przeszukiwać, czy powinienem indeksować je wszystkie, czy nie?

  • Jakie są negatywne skutki indeksowania?

  • Jeśli mam kolumnę VARCHAR 2500, którą można przeszukiwać z części mojej witryny, czy powinienem ją zindeksować?

Haroldo
źródło
5
Prawdopodobnie powinieneś ponownie wyznaczyć pytanie. Wybór indeksów jest ważną częścią optymalizacji dowolnego modelu bazy danych. I z mojego punktu widzenia niezwiązanego z php.
VGE

Odpowiedzi:

242

Zdecydowanie powinieneś poświęcić trochę czasu na czytanie na temat indeksowania, jest dużo na ten temat napisanych i ważne jest, aby zrozumieć, co się dzieje.

Mówiąc ogólnie, indeks narzuca porządek w wierszach tabeli.

Dla uproszczenia wyobraź sobie, że tabela to tylko duży plik CSV. Ilekroć wiersz jest wstawiany, jest wstawiany na końcu . Tak więc „naturalne” uporządkowanie tabeli to tylko kolejność wstawiania wierszy.

Wyobraź sobie, że masz załadowany plik CSV w bardzo podstawowej aplikacji do obsługi arkuszy kalkulacyjnych. Cały ten arkusz kalkulacyjny wyświetla dane i numeruje wiersze w kolejności sekwencyjnej.

Teraz wyobraź sobie, że musisz znaleźć wszystkie wiersze o wartości „M” w trzeciej kolumnie. Biorąc pod uwagę to, co masz dostępne, masz tylko jedną opcję. Skanujesz tabelę sprawdzając wartość trzeciej kolumny dla każdego wiersza. Jeśli masz dużo wierszy, ta metoda („skanowanie tabeli”) może zająć dużo czasu!

Teraz wyobraź sobie, że oprócz tej tabeli masz indeks. Ten konkretny indeks jest indeksem wartości w trzeciej kolumnie. Indeks zawiera wszystkie wartości z trzeciej kolumny, w pewnej znaczącej kolejności (powiedzmy alfabetycznie), a dla każdej z nich zawiera listę numerów wierszy, w których pojawia się ta wartość.

Teraz masz dobrą strategię znajdowania wszystkich wierszy, w których wartość trzeciej kolumny to „M”. Na przykład możesz przeprowadzić wyszukiwanie binarne ! Podczas gdy skanowanie tabeli wymaga spojrzenia na N wierszy (gdzie N jest liczbą wierszy), wyszukiwanie binarne wymaga jedynie spojrzenia na wpisy indeksu log-n, w najgorszym przypadku. Wow, to na pewno o wiele łatwiejsze!

Oczywiście, jeśli masz ten indeks i dodajesz wiersze do tabeli (na końcu, ponieważ tak działa nasza tabela pojęciowa), musisz aktualizować indeks za każdym razem. Robisz więc trochę więcej pracy, pisząc nowe wiersze, ale oszczędzasz mnóstwo czasu, gdy czegoś szukasz.

Ogólnie rzecz biorąc, indeksowanie tworzy kompromis między wydajnością odczytu a wydajnością zapisu. Bez indeksów wstawianie może być bardzo szybkie - silnik bazy danych po prostu dodaje wiersz do tabeli. Podczas dodawania indeksów silnik musi aktualizować każdy indeks podczas wykonywania wstawiania.

Z drugiej strony odczyty stają się znacznie szybsze.

Mam nadzieję, że obejmuje to pierwsze dwa pytania (jak odpowiedzieli inni - musisz znaleźć właściwą równowagę).

Twój trzeci scenariusz jest nieco bardziej skomplikowany. Jeśli używasz LIKE, mechanizmy indeksowania zazwyczaj pomogą zwiększyć szybkość odczytu do pierwszego „%”. Innymi słowy, jeśli wybierasz GDZIE kolumna JAK „foo% bar%”, baza danych użyje indeksu, aby znaleźć wszystkie wiersze, w których kolumna zaczyna się od „foo”, a następnie musisz przeskanować ten pośredni zestaw wierszy, aby znaleźć podzbiór który zawiera „pasek”. WYBIERZ ... GDZIE kolumna JAK „% bar%” nie może korzystać z indeksu. Mam nadzieję, że rozumiesz dlaczego.

Wreszcie, musisz zacząć myśleć o indeksach w więcej niż jednej kolumnie. Koncepcja jest taka sama i zachowuje się podobnie jak w LIKE - zasadniczo, jeśli masz indeks na (a, b, c), silnik będzie nadal korzystał z indeksu od lewej do prawej tak dobrze, jak to możliwe. Tak więc wyszukiwanie w kolumnie a może korzystać z indeksu (a, b, c), tak jak w przypadku (a, b). Jednak silnik musiałby wykonać pełny skan tabeli, jeśli szukałeś GDZIE b = 5 ORAZ c = 1)

Mam nadzieję, że pomoże to rzucić nieco światła, ale muszę powtórzyć, że najlepiej jest spędzić kilka godzin na szukaniu dobrych artykułów, które wyjaśniają te rzeczy dogłębnie. Dobrym pomysłem jest również przeczytanie dokumentacji konkretnego serwera bazy danych. Sposób, w jaki wskaźniki są implementowane i używane przez planistów zapytań, może się znacznie różnić.

timdev
źródło
10
Co z FULLTEXTindeksami? Czy mogą pomóc w takich warunkach LIKE '%bar%'?
Septagram,
2
@Septagram - FULLTEXTmoże pomóc w tym zapytaniu, jeśli bar jest „słowem”. FULLTEXTobsługuje słowa, a nie dowolne podciągi (jak to LIKErobi).
Rick James
@timdev wyraźnie, w jakiej części udzielono odpowiedzi na pierwsze pytanie? Mogę wykryć drugie i trzecie pytanie, na które udzielono odpowiedzi w pierwszej i drugiej części (przed i po Mam nadzieję, że obejmuje to pierwsze dwa pytania ) waszej cennej odpowiedzi
Manuel Jordan,
1
@ManuelJordan - Nie ma prostej odpowiedzi na pierwsze pytanie. To zależy od tego, jak chcesz zrównoważyć kompromisy w kontekście przewidywanego (lub nawet lepszego, zaobserwowanego) użycia.
timdev,
57

Sprawdź prezentacje, takie jak More Mastering the Art of Indexing .

Aktualizacja 12/2012: Opublikowałem nową prezentację: Jak projektować indeksy, naprawdę . Przedstawiłem to w październiku 2012 r. Na ZendCon w Santa Clara, aw grudniu 2012 r. W Percona Live London.

Projektowanie najlepszych indeksów to proces, który musi odpowiadać zapytaniom uruchamianym w Twojej aplikacji.

Trudno jest zalecić ogólne reguły dotyczące tego, które kolumny najlepiej indeksować, czy też należy indeksować wszystkie kolumny, żadnych kolumn, które indeksy powinny obejmować wiele kolumn itp. Zależy to od zapytań, które należy uruchomić.

Tak, istnieje pewien narzut, więc nie powinieneś niepotrzebnie tworzyć indeksów. Ale powinieneś utworzyć indeksy, które przyniosą korzyści dla zapytań, które musisz szybko uruchomić. Obciążenie indeksu jest zwykle znacznie większe niż jego korzyść.

W przypadku kolumny VARCHAR (2500) prawdopodobnie chcesz użyć indeksu FULLTEXT lub indeksu prefiksów:

CREATE INDEX i ON SomeTable(longVarchar(100));

Zauważ, że konwencjonalny indeks nie może pomóc, jeśli szukasz słów, które mogą znajdować się w środku tego długiego varchara. W tym celu użyj indeksu pełnotekstowego.

Bill Karwin
źródło
3
Dziękuję bardzo. slideshare.net/matsunobu/… był bardzo pomocny.
Bishal Paudel
1
Doskonała prezentacja slideshare.net/billkarwin/how-to-design-indexes-reale
Manuel Jordan
1
Niesamowita prezentacja (ta z 2012 roku), naprawdę zrozumiała cały sens indeksów.
DarkteK
46

Nie powtórzę niektórych dobrych rad z innych odpowiedzi, ale dodam:

Wskaźniki złożone

Możesz tworzyć indeksy złożone - indeks, który zawiera wiele kolumn. MySQL może korzystać z nich od lewej do prawej . Więc jeśli masz:

Table A
Id
Name
Category
Age
Description

jeśli masz indeks złożony, który zawiera Imię / Kategorię / Wiek w tej kolejności, poniższe klauzule WHERE użyją tego indeksu:

WHERE Name='Eric' and Category='A'

WHERE Name='Eric' and Category='A' and Age > 18

ale

WHERE Category='A' and Age > 18

nie użyłby tego indeksu, ponieważ wszystko musi być używane od lewej do prawej.

Wyjaśnić

Użyj wyjaśnienia / wyjaśnienia rozszerzonego, aby zrozumieć, jakie indeksy są dostępne dla MySQL, a które faktycznie wybiera. MySQL użyje tylko JEDNEGO klucza na zapytanie .

EXPLAIN EXTENDED SELECT * from Table WHERE Something='ABC'

Dziennik powolnych zapytań

Włącz dziennik wolnych zapytań, aby zobaczyć, które zapytania działają wolno.

Szerokie kolumny

Jeśli masz szeroką kolumnę, w której NASTĘPNE rozróżnienie występuje w pierwszych kilku znakach, możesz użyć tylko pierwszych N znaków w indeksie. Przykład: mamy kolumnę ReferenceNumber zdefiniowaną jako varchar (255), ale w 97% przypadków numer referencyjny to 10 znaków lub mniej. Zmieniłem indeks, aby patrzeć tylko na pierwsze 10 znaków i całkiem poprawiłem wydajność.

Eric J.
źródło
Mam pytanie dotyczące ostatniej części. Czytałem gdzieś, że jeśli tworzysz kolumnę za pomocą VARCHAR, zawsze powinieneś ustawić ją na 255. Teraz powiedziałeś, że indeks ustawiony na tego typu kolumnę może ograniczać się do oglądania tylko pierwszych 10 znaków. Jak dokładnie możesz to zrobić?
AlexioVay
20

Jeśli tabela ma sześć kolumn, a wszystkie z nich można przeszukiwać, powinienem indeksować je wszystkie lub żadną z nich

Czy szukasz pola po polu, czy niektóre wyszukiwania wykorzystują wiele pól? Które pola są najczęściej wyszukiwane? Jakie są typy pól? (Indeks działa lepiej na INTach, na przykład na VARCHAR). Czy próbowałeś użyć EXPLAIN w zapytaniach, które są uruchamiane?

Jakie są pozytywne skutki indeksowania

AKTUALIZACJE i WSTAWKI będą wolniejsze. Istnieją również dodatkowe wymagania dotyczące miejsca do przechowywania, ale w dzisiejszych czasach jest to zwykle nieistotne.

Jeśli mam kolumnę VARCHAR 2500, którą można przeszukiwać z części mojej witryny, powinienem ją zindeksować

Nie, chyba że jest to UNIKALNE (co oznacza, że ​​jest już zindeksowane) lub wyszukujesz tylko dokładne dopasowania w tym polu (nie używając wyszukiwania pełnotekstowego LIKE lub mySQL).

Zasadniczo umieszczam indeks na dowolnych polach, które będę wyszukiwał lub wybrał za pomocą klauzuli WHERE

Normalnie indeksowałbym najczęściej wyszukiwane pola, a następnie INTs / BOOLEANs / ENUMs zamiast pól, które są VARCHARS. Nie zapominaj, że często musisz utworzyć indeks dla pól połączonych zamiast indeksu dla pojedynczego pola. Użyj WYJAŚNIJ i sprawdź wolny dziennik.

Pete
źródło
11

Wydajne ładowanie danych : Indeksy przyspieszają pobieranie, ale spowalniają wstawianie i usuwanie, a także aktualizacje wartości w indeksowanych kolumnach. Oznacza to, że indeksy spowalniają większość operacji związanych z pisaniem. Dzieje się tak, ponieważ zapisywanie wiersza wymaga zapisu nie tylko wiersza danych, ale także zmian w indeksach. Im więcej indeksów ma tabela, tym więcej trzeba wprowadzić zmian i tym większy jest średni spadek wydajności. Większość tabel otrzymuje wiele odczytów i mało zapisów, ale w przypadku tabeli z wysokim odsetkiem zapisów koszt aktualizacji indeksu może być znaczny.

Unikaj indeksów : jeśli nie potrzebujesz konkretnego indeksu, aby zapytania działały lepiej, nie twórz go.

Miejsce na dysku : Indeks zajmuje miejsce na dysku, a wiele indeksów zajmuje odpowiednio więcej miejsca. Może to spowodować szybsze osiągnięcie limitu rozmiaru tabeli niż w przypadku braku indeksów. W miarę możliwości unikaj indeksów.

Na wynos: nie przekreślaj indeksu

Srikar Doddi
źródło
5

Ogólnie indeksy pomagają przyspieszyć wyszukiwanie w bazie danych, co ma tę wadę, że wykorzystuje dodatkowe miejsce na dysku i spowalnia INSERT/ UPDATE/ DELETEzapytania. Użyj EXPLAINi przeczytaj wyniki, aby dowiedzieć się, kiedy MySQL używa twoich indeksów.

Jeśli tabela ma sześć kolumn i wszystkie można przeszukiwać, czy powinienem indeksować je wszystkie, czy nie?

Indeksowanie wszystkich sześciu kolumn nie zawsze jest najlepszą praktyką.

(a) Czy zamierzasz skorzystać z którejkolwiek z tych kolumn podczas wyszukiwania określonych informacji?

(b) Jaka jest selektywność tych kolumn (ile różnych wartości jest przechowywanych, w porównaniu do całkowitej liczby rekordów w tabeli)?

MySQL używa optymalizatora opartego na kosztach, który próbuje znaleźć „najtańszą” ścieżkę podczas wykonywania zapytania. A pola o niskiej selektywności nie są dobrymi kandydatami.

Jakie są pozytywne skutki indeksowania?

Już odpowiedziano: dodatkowe miejsce na dysku, niższa wydajność podczas wstawiania - aktualizacji - usuwania.

Jeśli mam kolumnę VARCHAR 2500, którą można przeszukiwać z części mojej witryny, czy powinienem ją zindeksować?

Wypróbuj indeks FULLTEXT .

Anax
źródło
4

1/2) Indeksy przyspieszają niektóre operacje wyboru, ale spowalniają inne operacje, takie jak wstawianie, aktualizowanie i usuwanie. Może to być równowaga.

3) użyj indeksu pełnotekstowego lub może sfinksa

Paul Creasey
źródło
Aby temu zapobiec slow down other operations like insert, update and deletes, możesz użyć opcji START TRANSACTION; YOUR CODE HERE; COMMIT Które mogą pomóc uniknąć slowing downinnych operacji, ponieważ tylko raz sprawdzi ograniczenia. Zastrzeżenie: W przypadku korzystania REPLACE INTOi twój SQL_MODE<> STRICT_ALL_TABLESOR będzie ignorować wymienić na wkładkę i duplikatów. TRADITIONALBulk Load
JayRizzo
Transakcje nie są obsługiwane we wszystkich silnikach MySQL. AFAIK, transakcje spowalniają operacje DB, nawet jeśli są one używane tylko pośrednio. To, co musimy zaprojektować w oparciu o rzeczywistą wydajność, to jakiś półautomatyczny sposób profilowania (pomiaru wydajności) różnych opcji optymalizacji, w tym indeksów i transakcji.
David Spector,