Det första du måste veta är att index är ett sätt att undvika att skanna hela tabellen för att få det resultat du letar efter.
Det finns olika typer av index och de är implementerade i lagringslagret, så det finns ingen standard mellan dem och de beror också på vilken lagringsmotor du använder.
InnoDB och B+Tree-indexet
För InnoDB är den vanligaste indextypen det B+Tree-baserade indexet, som lagrar elementen i en sorterad ordning. Du behöver inte heller komma åt den verkliga tabellen för att få de indexerade värdena, vilket gör att din fråga återkommer mycket snabbare.
"Problemet" med den här indextypen är att du måste fråga efter värdet längst till vänster för att använda indexet. Så om ditt index har två kolumner, säg efternamn och förnamn, är ordningen du frågar efter dessa fält mycket av. .
Så med tanke på följande tabell:
CREATE TABLE person (
last_name VARCHAR(50) NOT NULL,
first_name VARCHAR(50) NOT NULL,
INDEX (last_name, first_name)
);
Den här frågan skulle dra fördel av indexet:
SELECT last_name, first_name FROM person
WHERE last_name = "John" AND first_name LIKE "J%"
Men följande skulle inte
SELECT last_name, first_name FROM person WHERE first_name = "Constantine"
Eftersom du frågar efter first_name
kolumnen först och det är inte kolumnen längst till vänster i indexet.
Det här sista exemplet är ännu värre:
SELECT last_name, first_name FROM person WHERE first_name LIKE "%Constantine"
För nu jämför du den högra delen av fältet längst till höger i indexet.
Hashindexet
Detta är en annan indextyp som tyvärr bara stöder minnesbackend. Det är blixtsnabbt men bara användbart för fullständiga sökningar, vilket innebär att du inte kan använda det för operationer som >
, <
eller LIKE
.
Eftersom det bara fungerar för minnesbackend kommer du förmodligen inte att använda det så ofta. Det huvudsakliga fallet jag kan komma på just nu är att du skapar en tillfällig tabell i minnet med en uppsättning resultat från en annan markering och utför många andra val i den här temporära tabellen med hjälp av hashindex.
Om du har en stor VARCHAR
fältet kan du "emulera" användningen av ett hashindex när du använder ett B-Tree, genom att skapa en annan kolumn och spara en hash av det stora värdet på den. Låt oss säga att du lagrar en url i ett fält och värdena är ganska stora. Du kan också skapa ett heltalsfält som heter url_hash
och använd en hashfunktion som CRC32
eller någon annan hashfunktion för att hasha webbadressen när den infogas. Och sedan, när du behöver fråga efter detta värde, kan du göra något så här:
SELECT url FROM url_table WHERE url_hash=CRC32("http://gnu.org");
Problemet med exemplet ovan är att eftersom CRC32
funktionen genererar en ganska liten hash, du kommer att sluta med många kollisioner i de hashade värdena. Om du behöver exakta värden kan du åtgärda det här problemet genom att göra följande:
SELECT url FROM url_table
WHERE url_hash=CRC32("http://gnu.org") AND url="http://gnu.org";
Det är fortfarande värt att hasha saker även om kollisionstalet är högt eftersom du bara utför den andra jämförelsen (strängen) mot de upprepade hasharna.
Tyvärr, med den här tekniken, måste du fortfarande gå i tabellen för att jämföra url
fältet.
Avsluta
Några fakta som du kan tänka på varje gång du vill prata om optimering:
-
Heltalsjämförelse är mycket snabbare än strängjämförelse. Det kan illustreras med exemplet om emulering av hashindex i
InnoDB
. -
Om du lägger till ytterligare steg i en process kanske det går snabbare, inte långsammare. Det kan illustreras av det faktum att du kan optimera en
SELECT
genom att dela upp det i två steg, göra det första lagra värden i en nyskapad tabell i minnet och sedan köra de tyngre frågorna på den andra tabellen.
MySQL har andra index också, men jag tror att B+Tree är det mest använda någonsin och hash-en är en bra sak att veta, men du kan hitta de andra i MySQL-dokumentation .
Jag rekommenderar dig starkt att läsa boken "High Performance MySQL", svaret ovan var definitivt baserat på dess kapitel om index.