Първото нещо, което трябва да знаете, е, че индексите са начин да избегнете сканирането на цялата таблица, за да получите резултата, който търсите.
Има различни видове индекси и те са внедрени в слоя за съхранение, така че между тях няма стандарт и те също зависят от механизма за съхранение, който използвате.
InnoDB и индексът B+Tree
За InnoDB най-често срещаният тип индекс е индексът, базиран на B+Tree, който съхранява елементите в сортиран ред. Освен това не е нужно да осъществявате достъп до реалната таблица, за да получите индексираните стойности, което прави заявката ви да се връща много по-бързо.
"Проблемът" за този тип индекс е, че трябва да потърсите най-лявата стойност, за да използвате индекса. Така че, ако вашият индекс има две колони, да речем last_name и first_name, редът, в който заявявате тези полета е от голямо значение .
И така, като се има предвид следната таблица:
CREATE TABLE person (
last_name VARCHAR(50) NOT NULL,
first_name VARCHAR(50) NOT NULL,
INDEX (last_name, first_name)
);
Тази заявка ще се възползва от индекса:
SELECT last_name, first_name FROM person
WHERE last_name = "John" AND first_name LIKE "J%"
Но следният не би
SELECT last_name, first_name FROM person WHERE first_name = "Constantine"
Защото задавате заявка за first_name
колона първа и това не е най-лявата колона в индекса.
Този последен пример е още по-лош:
SELECT last_name, first_name FROM person WHERE first_name LIKE "%Constantine"
Защото сега сравнявате най-дясната част на най-дясното поле в индекса.
Хеш индексът
Това е различен тип индекс, който за съжаление поддържа само задната част на паметта. Той е светкавично бърз, но полезен само за пълни търсения, което означава, че не можете да го използвате за операции като >
, <
или LIKE
.
Тъй като работи само за бекенда на паметта, вероятно няма да го използвате много често. Основният случай, за който се сещам в момента, е този, в който създавате временна таблица в паметта с набор от резултати от друг избор и извършвате много други избирания в тази временна таблица, използвайки хеш индекси.
Ако имате голям VARCHAR
поле, можете да "емулирате" използването на хеш индекс, когато използвате B-дърво, като създадете друга колона и запишете хеш с голямата стойност върху нея. Да приемем, че съхранявате URL адрес в поле и стойностите са доста големи. Можете също така да създадете цяло число, наречено url_hash
и използвайте хеш функция като CRC32
или всяка друга хеш функция за хеширане на URL адреса, когато го вмъквате. И след това, когато трябва да направите заявка за тази стойност, можете да направите нещо подобно:
SELECT url FROM url_table WHERE url_hash=CRC32("http://gnu.org");
Проблемът с горния пример е, че след CRC32
функцията генерира доста малък хеш, в крайна сметка ще получите много колизии в хешираните стойности. Ако имате нужда от точни стойности, можете да отстраните този проблем, като направите следното:
SELECT url FROM url_table
WHERE url_hash=CRC32("http://gnu.org") AND url="http://gnu.org";
Все още си струва да се хешират нещата, дори ако номерът на сблъсък е висок, защото ще извършите само второто сравнение (низовото) срещу повтарящите се хешове.
За съжаление, използвайки тази техника, все още трябва да натиснете таблицата, за да сравните url
поле.
Приключете
Някои факти, които може да имате предвид всеки път, когато искате да говорите за оптимизация:
-
Целочисленото сравнение е много по-бързо от сравнението на низове. Може да се илюстрира с примера за емулацията на хеш индекса в
InnoDB
. -
Може би добавянето на допълнителни стъпки в процеса го прави по-бърз, а не по-бавен. Това може да се илюстрира от факта, че можете да оптимизирате
SELECT
като го разделите на две стъпки, като накарате първата да съхранява стойности в новосъздадена таблица в паметта и след това изпълни по-тежките заявки към тази втора таблица.
MySQL има и други индекси, но мисля, че B+Tree този е най-използваният някога и хеш е добре да знаете, но можете да намерите другите в Документация за MySQL .
Горещо ви препоръчвам да прочетете книгата „High Performance MySQL“, отговорът по-горе определено се основава на нейната глава за индексите.