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ą WHERE
klauzuli, 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ć?
mysql
indexing
query-optimization
Haroldo
źródło
źródło
Odpowiedzi:
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ć.
źródło
FULLTEXT
indeksami? Czy mogą pomóc w takich warunkachLIKE '%bar%'
?FULLTEXT
może pomóc w tym zapytaniu, jeślibar
jest „słowem”.FULLTEXT
obsługuje słowa, a nie dowolne podciągi (jak toLIKE
robi).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:
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.
źródło
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:
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:
ale
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 .
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ść.
źródło
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?
AKTUALIZACJE i WSTAWKI będą wolniejsze. Istnieją również dodatkowe wymagania dotyczące miejsca do przechowywania, ale w dzisiejszych czasach jest to zwykle nieistotne.
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).
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.
źródło
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
źródło
Ogólnie indeksy pomagają przyspieszyć wyszukiwanie w bazie danych, co ma tę wadę, że wykorzystuje dodatkowe miejsce na dysku i spowalnia
INSERT
/UPDATE
/DELETE
zapytania. UżyjEXPLAIN
i przeczytaj wyniki, aby dowiedzieć się, kiedy MySQL używa twoich indeksów.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.
Już odpowiedziano: dodatkowe miejsce na dysku, niższa wydajność podczas wstawiania - aktualizacji - usuwania.
Wypróbuj indeks FULLTEXT .
źródło
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
źródło
slow down other operations like insert, update and deletes
, możesz użyć opcjiSTART TRANSACTION;
YOUR CODE HERE;
COMMIT
Które mogą pomóc uniknąćslowing down
innych operacji, ponieważ tylko raz sprawdzi ograniczenia. Zastrzeżenie: W przypadku korzystaniaREPLACE INTO
i twójSQL_MODE
<>STRICT_ALL_TABLES
OR będzie ignorować wymienić na wkładkę i duplikatów.TRADITIONAL
Bulk Load