Jak dodać indeksy do tabel MySQL?

407

Mam bardzo dużą tabelę MySQL z około 150 000 wierszy danych. Obecnie, kiedy próbuję uruchomić

SELECT * FROM table WHERE id = '1';

kod działa poprawnie, ponieważ pole ID jest indeksem podstawowym. Jednak w przypadku ostatniego rozwoju projektu muszę przeszukać bazę danych według innego pola. Na przykład:

SELECT * FROM table WHERE product_id = '1';

To pole nie było wcześniej indeksowane; Jednak dodałem jeden, więc mysql teraz indeksuje pole, ale kiedy próbuję uruchomić powyższe zapytanie, działa ono bardzo wolno. Zapytanie EXPLAIN ujawnia, że ​​nie ma indeksu dla pola product_id, gdy już go dodałem, w wyniku czego zapytanie zajmuje od 20 minut do 30 minut, aby zwrócić pojedynczy wiersz.

Moje pełne wyniki WYJAŚNIJ to:

| id | select_type | table | type | possible_keys| key  | key_len | ref  | rows  | Extra       |
+----+-------------+-------+------+--------------+------+---------+------+-------+------------------+
|  1 | SIMPLE      | table | ALL  | NULL         | NULL | NULL    | NULL |157211 | Using where |
+----+-------------+-------+------+--------------+------+---------+------+-------+------------------+

Warto zauważyć, że właśnie spojrzałem, a pole ID jest przechowywane jako INT, natomiast pole PRODUCT_ID jest przechowywane jako VARCHAR. Czy to może być przyczyną problemu?

Michał
źródło
1
Czy możesz opublikować pełne EXPLAINwyniki? Czy jesteś pewien, że to nie ma indeksu? Czy jest tam indeks, ale MySQL decyduje się go nie używać?
VoteyDisciple,
169
Duży stół miałby 150 000 000 rekordów. Bardzo duży stół ma 15 000 000 000 rekordów. Tabela średniej wielkości ma 150 000. Dla przyszłego odniesienia.
usumoio,
4
Pamiętaj, że „LUB” może spowodować, że MySql nie będzie używać indeksów. Miałem zapytanie z 3 OR. Każdy przeglądał indeks i działał w 15 ms. Wszystko trwało od 25 sekund do limitu czasu. Zrobiłem więc 3 zapytania i UNION je razem, zajęło to również 15 ms na 500 000 wierszy.
Leif Neland,
Zastanów się, jaki typ danych przechowujesz. Wydajność może ulec zmianie w zależności od porównywanego typu danych. Jak powiedziałeś PRODUCT_ID jest typem danych VARCHAR, spróbuj zmienić go na INT i zindeksować kolumnę.
gilbertdim

Odpowiedzi:

606
ALTER TABLE `table` ADD INDEX `product_id_index` (`product_id`)

Nigdy nie porównuj integerz stringsMySQL. Jeśli idtak int, usuń cytaty.

zerkms
źródło
Indeks został już dodany przy użyciu tego dokładnego kodu SQL, ale wygląda na to, że nie został on „zastosowany” do danych, a zapytanie EXPLAIN pokazuje, że nie ma indeksu dla pola.
Michael
1
Chcesz sprawdzić indeks przy pomocy SHOW CREATE TABLE, czy już to zrobiłeś?
Wrikken
33
Użyj SHOW INDEXES FROM YOURTABLE dev.mysql.com/doc/refman/5.0/en/show-index.html, aby sprawdzić, czy indeksy zostały dodane
Timo Huovinen
6
Dzisiaj miałem dokładny problem, który opisuje @ Michael, a rozwiązaniem było: „Nigdy nie porównuj liczb całkowitych z łańcuchami w mysql”. Dziękuję Ci.
user12345,
@ Wrikken Dodałem mój indeks i użyłem polecenia POKAŻ INDEKSY Z TWOJEGO TABELI. Pojawia się, ale nie wydaje mi się, żeby był używany podczas przeszukiwania mojej tabeli. Czy muszę zmieniać zapytanie wyboru podczas korzystania z indeksu?
Ced
147
ALTER TABLE TABLE_NAME ADD INDEX (COLUMN_NAME);
pabloferraz
źródło
96
W MySQL, jeśli używasz ALTER TABLE tbl ADD INDEX (col)zamiast ALTER TABLE tbl ADD INDEX col (col), a następnie przy użyciu ALTER TABLE tbl ADD INDEX (col)więcej niż jeden raz będzie utrzymywać dodanie wskaźników nazwanych col_2, col_3... za każdym razem. Podczas korzystania z ALTER TABLE tbl ADD INDEX col (col)2 raz da ERROR 1061 (42000): Duplicate key name 'col'.
Abhishek Oza
82

Możesz użyć tej składni, aby dodać indeks i kontrolować rodzaj indeksu (HASH lub BTREE).

create index your_index_name on your_table_name(your_column_name) using HASH;
or
create index your_index_name on your_table_name(your_column_name) using BTREE;

Możesz dowiedzieć się o różnicach między indeksami BTREE i HASH tutaj: http://dev.mysql.com/doc/refman/5.5/en/index-btree-hash.html

Hieu Vo
źródło
1
Hash przekonwertowany na btree, gdy widzę używanie indeksów show.
RN Kushwaha
1
Jakie będą ustawienia domyślne z Hash i BTree, jeśli ich nie podam?
Bhavuk Mathur
2
@RNKushwaha, ponieważ InnoDB i MyIsam nie obsługują HASH, AFAIK, obsługują je tylko silniki pamięci i NDB
Hieu Vo
60

Warto zauważyć, że wiele indeksów pól może znacznie poprawić wydajność zapytań. Tak więc w powyższym przykładzie zakładamy, że ProductID to jedyne pole do wyszukiwania, ale w zapytaniu było powiedzone ProductID = 1 AND Category = 7, wtedy pomaga indeks wielu kolumn. Osiąga się to dzięki:

ALTER TABLE `table` ADD INDEX `index_name` (`col1`,`col2`)

Dodatkowo indeks powinien być zgodny z kolejnością pól zapytań. W moim rozszerzonym przykładzie indeks powinien wynosić (ProductID, Category), a nie na odwrót.

Antony
źródło
1
Ładne, wyraźne nazewnictwo indeksu pozwala na łatwe odwrócenie.
Sam Berry,
Czy możesz podać źródło the index should match the order of the query fields?
Bishwas Mishra
58

Można dodać indeksy dwóch typów: kiedy zdefiniujesz klucz podstawowy, MySQL domyślnie przyjmie go jako indeks.

Wyjaśnienie

Klucz podstawowy jako indeks

Rozważ, że masz tbl_studenttabelę i chcesz student_idjako klucz podstawowy:

ALTER TABLE `tbl_student` ADD PRIMARY KEY (`student_id`)

Powyższa instrukcja dodaje klucz podstawowy, co oznacza, że ​​indeksowane wartości muszą być unikalne i nie mogą mieć wartości NULL.

Podaj nazwę indeksu

ALTER TABLE `tbl_student` ADD INDEX student_index (`student_id`)

Powyższa instrukcja utworzy zwykły indeks o student_indexnazwie.

Utwórz unikalny indeks

ALTER TABLE `tbl_student` ADD UNIQUE student_unique_index (`student_id`)

Tutaj student_unique_indexjest nazwa indeksu przypisana do student_id i tworzy indeks, dla którego wartości muszą być unikalne (tutaj można zaakceptować null).

Opcja pełnego tekstu

ALTER TABLE `tbl_student` ADD FULLTEXT student_fulltext_index (`student_id`)

Powyższa instrukcja utworzy nazwę indeksu pełnotekstowego student_fulltext_index, dla której potrzebujesz MyISAM Mysql Engine.

Jak usunąć indeksy?

DROP INDEX `student_index` ON `tbl_student`

Jak sprawdzić dostępne indeksy?

SHOW INDEX FROM `tbl_student`
Jazzzzzz
źródło
17

Mówisz, że masz indeks, wyjaśnienie mówi inaczej. Jeśli jednak tak naprawdę robisz, możesz kontynuować:

Jeśli masz indeks w kolumnie, a MySQL postanawia go nie używać, może to dlatego, że:

  1. W zapytaniu MySQL znajduje się inny indeks, który można uznać za bardziej odpowiedni, i może on używać tylko jednego. Rozwiązaniem jest zwykle indeks obejmujący wiele kolumn, jeśli ich normalna metoda wyszukiwania ma wartość większą niż jedna kolumna.
  2. MySQL decyduje, że istnieje wiele pasujących wierszy, i uważa, że ​​skanowanie tabel jest prawdopodobnie szybsze. Jeśli tak nie jest, czasem ANALYZE TABLEpomaga.
  3. W bardziej złożonych zapytaniach decyduje się nie używać go w oparciu o wyjątkowo inteligentne i przemyślane voodoo w planie zapytań, które z jakiegoś powodu po prostu nie spełnia twoich bieżących wymagań.

W przypadku (2) lub (3) możesz nakłonić MySQL do użycia indeksu według sytax podpowiedzi indeksu , ale jeśli to zrobisz, upewnij się, że wykonałeś kilka testów w celu ustalenia, czy rzeczywiście poprawia ono wydajność korzystania z indeksu podczas jego podpowiedzi .

Wrikken
źródło