První věc, kterou musíte vědět, je, že indexy jsou způsob, jak se vyhnout skenování celé tabulky, abyste získali výsledek, který hledáte.
Existují různé druhy indexů a jsou implementovány ve vrstvě úložiště, takže mezi nimi neexistuje žádný standard a také závisí na úložném enginu, který používáte.
InnoDB a index B+Tree
Pro InnoDB je nejběžnějším typem indexu index založený na B+Tree, který ukládá prvky v seřazeném pořadí. Také nemusíte přistupovat ke skutečné tabulce, abyste získali indexované hodnoty, díky čemuž se váš dotaz vrátí mnohem rychleji.
"Problém" tohoto typu indexu spočívá v tom, že pro použití indexu je nutné zadat dotaz na hodnotu zcela vlevo. Pokud tedy váš index obsahuje dva sloupce, řekněme last_name a first_name, velmi záleží na pořadí dotazu na tato pole. .
Takže s ohledem na následující tabulku:
CREATE TABLE person (
last_name VARCHAR(50) NOT NULL,
first_name VARCHAR(50) NOT NULL,
INDEX (last_name, first_name)
);
Tento dotaz by využil index:
SELECT last_name, first_name FROM person
WHERE last_name = "John" AND first_name LIKE "J%"
Ale následující by ne
SELECT last_name, first_name FROM person WHERE first_name = "Constantine"
Protože se ptáte na first_name
sloupec první a není to sloupec úplně vlevo v indexu.
Tento poslední příklad je ještě horší:
SELECT last_name, first_name FROM person WHERE first_name LIKE "%Constantine"
Protože nyní porovnáváte pravou část pole zcela vpravo v indexu.
Hash index
Toto je jiný typ indexu, který bohužel podporuje pouze paměťový backend. Je bleskurychlý, ale užitečný pouze pro úplné vyhledávání, což znamená, že jej nemůžete použít pro operace jako >
, <
nebo LIKE
.
Vzhledem k tomu, že funguje pouze pro paměťový backend, pravděpodobně jej nebudete používat příliš často. Hlavní případ, který mě právě napadá, je ten, že vytvoříte dočasnou tabulku v paměti se sadou výsledků z jiného výběru a provedete spoustu dalších výběrů v této dočasné tabulce pomocí hash indexů.
Pokud máte velký VARCHAR
pole, můžete "emulovat" použití hash indexu při použití B-stromu vytvořením dalšího sloupce a uložením hash velké hodnoty do něj. Řekněme, že ukládáte adresu URL do pole a hodnoty jsou poměrně velké. Můžete také vytvořit celočíselné pole s názvem url_hash
a použijte hashovací funkci jako CRC32
nebo jakákoli jiná hashovací funkce pro hashování adresy URL při jejím vkládání. A pak, když potřebujete dotaz na tuto hodnotu, můžete udělat něco takového:
SELECT url FROM url_table WHERE url_hash=CRC32("http://gnu.org");
Problém s výše uvedeným příkladem je, že od CRC32
Funkce generuje poměrně malý hash, skončíte s mnoha kolizemi v hašovaných hodnotách. Pokud potřebujete přesné hodnoty, můžete tento problém vyřešit takto:
SELECT url FROM url_table
WHERE url_hash=CRC32("http://gnu.org") AND url="http://gnu.org";
Stále stojí za to věci hašovat, i když je číslo kolize vysoké, protože provedete pouze druhé porovnání (řetězcové) s opakovanými hašemi.
Bohužel při použití této techniky je stále potřeba trefit se do tabulky, abyste mohli porovnat url
pole.
Zabalit
Některá fakta, která můžete vzít v úvahu pokaždé, když budete chtít mluvit o optimalizaci:
-
Porovnání celých čísel je mnohem rychlejší než porovnání řetězců. Lze to ilustrovat na příkladu emulace hash indexu v
InnoDB
. -
Možná, že přidáním dalších kroků do procesu je proces rychlejší, nikoli pomalejší. Lze to ilustrovat tím, že můžete optimalizovat
SELECT
rozdělením do dvou kroků, přičemž první ukládá hodnoty do nově vytvořené tabulky v paměti a poté provádí těžší dotazy na této druhé tabulce.
MySQL má i jiné indexy, ale myslím si, že ten B+Tree je nejpoužívanější a ten hash je dobré vědět, ale ty ostatní najdete v Dokumentace MySQL .
Vřele vám doporučuji, abyste si přečetli knihu „High Performance MySQL“, výše uvedená odpověď byla rozhodně založena na její kapitole o indexech.