Příkaz EXPLAIN je nástroj pro analýzu dotazů. S jeho pomocí lze získat informace, jakým způsobem je konkrétní dotaz zpracován.
Spuštění je jednoduché – stačí přidat klíčové slovo
EXPLAIN
před dotaz. Výsledkem je, že MySQL vrátí informace
o zpracovaném dotazu, namísto aby jej skutečně provedl.
Od MySQL 5.6.3 lze EXPLAIN
spustit pro
SELECT
, DELETE
, INSERT
,
REPLACE
a UPDATE
.
Ve starších verzích jej lze spustit pouze pro SELECT
.
EXPLAIN SELECT u.jmeno, o.nazev, uk.jmeno AS kamarad
FROM uzivatele AS u
LEFT JOIN uzivatele AS uk ON uk.id = u.nejlepsi_kamarad_id
JOIN obce AS o ON o.id = u.obec_id
WHERE u.pohlavi = 'muz'
ORDER BY u.datum_narozeni
SQL 1 – Ukázka příkazu
EXPLAIN
Výstupem je tabulka s neměnným počtem sloupců a variabilním počtem řádků.
id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
---|---|---|---|---|---|---|---|---|---|
1 | SIMPLE | u | ref | pohlavi_datum_narozeni | pohlavi_datum_narozeni | 1 | const | 1683 | Using index condition; Using where; |
1 | SIMPLE | o | eq_ref | PRIMARY | PRIMARY | 3 | obec_id | 1 | |
1 | SIMPLE | uk | eq_ref | PRIMARY | PRIMARY | 3 | nejlepsi_kamarad_id | 1 | Using where; |
Tabulka 1 – Ukázka výstupu příkazu
EXPLAIN
Jak můžete vidět v tabulce 1, jedna tabulka v dotazu odpovídá
jednomu řádku ve výstupu. Všiměte si, že se tabulka uzivatele
objevila ve výstupu vícekrát, jelikož se k ní přistupuje dvakrát.
Později uvidíte, že jako samostatné tabulky zahrnuje MySQL do výstupu i subdotazy či dočasné tabulky.
Pořadí řádků je určeno posloupností v jakém MySQL zpracovává jednotlivé části dotazu. To nemusí vždy korespondovat s pořadím v samotném SQL dotazu, viz. pořadí tabulek v SQL 1 a pořadí řádků v tabulce 1.
Mějte na paměti že výsledky nemusí být
vždy přesné a úplné. Některé statistické výpočty jsou pouze
přibližné odhady, zároveň EXPLAIN
neuvádí veškeré
informace, např. o triggerech apod.
Jedná se o číslo, které identifikuje jednotlivé SELECT
y
v dotazu. Číslování je posloupné podle pozice v dotazu, tzn. čím
dříve se objeví SELECT
v dotazu, tím menší má
id
.
V prvním příkladu byly všechny řádky označeny jako id
1,
jelikož se v dotazu vyskytoval jediný SELECT
. V dalším
příkladě níže je již druhý SELECT
v subdotazu označen jako
id
2.
EXPLAIN SELECT u.jmeno, o.nazev, ( SELECT 1 FROM staty LIMIT 1 ) AS const
FROM uzivatele AS u
JOIN obce AS o ON o.id = u.obec_id
WHERE u.pohlavi = 'muz'
ORDER BY u.datum_narozeni
SQL 2 – Druhý SELECT
v dotazu
id | select_type | table | … |
---|---|---|---|
1 | PRIMARY | u | … |
1 | PRIMARY | o | … |
2 | SUBQUERY | staty | … |
Tabulka 2 – Tabulky uzivatele
a
obce
jsou označeny s id
1
, jelikož se
k nim přistupuje v rámci prvního SELECT
u v dotazu. Subdotaz
označený jako const
se vyskytuje v dotazu až jako druhý, je
proto označen jako id
2
.
Jak už název naznačuje, tento sloupec označuje typ SELECT
u.
Může nabývat následujících hodnot:
Hodnota | Popis |
---|---|
SIMPLE | Jednoduchý SELECT . V dotazu se nevyskytuje žádný subdotaz či UNION . |
PRIMARY | Označení pro první, nejkrajněší SELECT , v připadě, že se v dotazu vyskytuje subdotaz či UNION . |
SUBQUERY | Subdotaz v klauzuli SELECT . |
DERIVED | Subdotaz v klauzuli FROM . Tento typ subdotazu ukládá MySQL do dočacné tabulky. |
UNION | Druhý a další posloupný SELECT v UNION u. |
UNION RESULT | Výsledek UNION u. Jedná se o dočasnou anonymní tabulku s výsledky ze všech SELECT ů v UNION u. Jelikož se v dotazu nevyskytuje žádný SELECT do této tabulky, je id UNION RESULT u NULL . |
DEPENDENT | Jako DEPENDENT mohou být označeny SUBQUERY a UNION . Jedná se o SELECT y, které závisejí na datech z vnějšího dotazu. |
UNCACHEABLE | Také jako UNCACHEABLE mohou být označeny pouze SUBQUERY a UNION . UNCACHEABLE označuje dotaz jehož výsledek nemůže být cachován. |
Hodnota tohoto sloupce je obvykle jednoznačná. Je to název či alias
tabulky, ke které se přistupuje. Výjímku tvoří pouze přístup
k anonymním dočasným tabulkám, které jsou výsledkem
SELECT
u typu DERIVED
či UNION
.
Přistupuje-li se k dočasné tabulce vzniklé ze SELECT
u typu
DERIVED
, objeví se jako hodnota tohoto sloupce ve formě
<derivedN>
, kde N je id
DERIVED
SELECT
u.
EXPLAIN SELECT u.jmeno, o.nazev
FROM uzivatele AS u
JOIN ( SELECT * FROM obce WHERE stat_id > 10 LIMIT 5 ) AS o ON o.id = u.obec_id
WHERE u.pohlavi = 'muz'
ORDER BY u.datum_narozeni
SQL 3 – Dotaz se subdotazem v klauzily
FROM
id | select_type | table | … |
---|---|---|---|
1 | PRIMARY | u | … |
1 | PRIMARY | … | |
2 | DERIVED | obce | … |
Tabulka 3 – JOIN
uje se tabulka
vzniklá ze subdotazu, proto se na druhém řádku jako hodnota table objevuje
<derived2>
. 2
odkazuje k id
SELECTU
, jehož výsledkem tato anonymní dočasná tabulka
vznikla.
V případě dočasné tabulky vzniklé jako výsledek UNION
u,
označené jako UNION RESULT
, se jako hodnota tohoto sloupce
objeví <unionN,M>
. Kde N a M jsou id
jednotlivých SELECT
ů v UNION
u.
EXPLAIN SELECT u.jmeno, u.prijmeni, u.email
FROM uzivatele AS u
WHERE u.pohlavi = 'muz'
AND u.datum_narozeni > '1990-01-01'
UNION SELECT u.jmeno, u.prijmeni, u.email
FROM uzivatele AS u
WHERE u.pohlavi = 'muz'
AND u.datum_narozeni < '1990-01-01'
SQL 4 – Dotaz s UNION
em
id | select_type | table | … |
---|---|---|---|
1 | PRIMARY | u | … |
2 | UNION | u2 | … |
NULL | UNIONRESULT | … |
Tabulka 4 – V UNION
u jsou dva
SELECT
y, ve výstupu označené jako 1
a
2
. Výsledky obou SELECT
ů MySQL uloží do dočasné
tabulky, ta se objevuje jako třetí řádek ve výstupu. Jelikož se k ní
nepřistupuje žádným SELECT
em, je hodnota id
NULL
. <union1,2>
jako hodnota table odkazuje na
SELECT
y ze kterých výsledek vznikl (SELECT
id
1
a 2
).
Tento sloupec může nabývat několika definovaných hodnot. Udávájí jakým způsobem MySQL přistupuje do tabulky.
Hodnota | Popis |
---|---|
ALL | Table scan. MySQL musí projít celou tabulku, od prvního řádku až k poslednímu. |
index | Totéž co ALL , s tím rozdílem že MySQL přistupuje k řádkům tabulky v pořadí podle indexu. Jde tedy o získání všech řádků seřazených podle indexu. |
range | MySQL přistupuje do tabulky podle indexu pouze v určitém rozsahu. Obvykle jde o filtrování indexovaného sloupce operátory > , < , BETWEEN , apod. |
ref | Jde o porovnání neunikátního indexu s jednou hodnotou. Opět tedy musí MySQL přistoupit k více řádkům tabulky, nicméně oproti range se již index neporovnává vůči rozsahu odnot, nýbrž vůči jedné hodnotě. |
eq_ref | MySQL porovnává při JOIN ování unikátní index s jednou určitou hodnotou. |
const | Nejlepší možný způsob přístupu do tabulky. Podobně jako u eq_ref je výstupem nanejvíš jeden řádek. |
NULL | MySQL vůbec do tabulky nepřistupuje. Výsledek dotazu je známý již ve fázi optimalizace. |
Jde o indexy, které MySQL vyhodnotilo jako užitečné pro zeefektivnění přístupu do tabulky.
Sloupec s názvem indexu, který byl pro dotaz využit.
Použitý index nemusí vždy korespondovat se seznamem v
possible_keys
. Prakticky to velmi často znamená, že je ve snaze
co nejvíce zvýšit efektivitu dotazu využit tzv. covering
index, který sice nemusí pomoci účelně nalézt požadované řádky,
nicméně výrazně urychluje jejich získání.
Velikost použitého indexu v bajtech.
Obsahem jsou názvy sloupců odkazující tabulky, které byly využity pro porovnání s použitým indexem.
EXPLAIN SELECT u.jmeno, u.prijmeni, u.email
FROM uzivatele AS u
WHERE u.pohlavi = 'muz'
AND u.datum_narozeni = '1990-01-01'
SQL 5 – Ukázka filtrování v dotazu dvěma konstantami
… | possible_keys | key | key_len | ref | … |
---|---|---|---|---|---|
… | pohlavi_datum_narozeni | pohlavi_datum_narozeni | 4 | const,const | … |
Tabulka 5 – V případě, že se index
porovnává s konstantami (nikoliv s hodnotami z jiných tabulek), objeví se
v ref
hodnota const
.
Odhad počtu řádků tabulky, které bude nutno přečíst k nalezení všech požadovaných řádků.
EXPLAIN SELECT *
FROM `uzivatele`
WHERE 1
LIMIT 10
SQL 6 – Dotaz s LIMIT
em
… | rows | … |
---|---|---|
… | 5006 | … |
Tabulka 6 – rows
je
nejnepřesnější sloupec EXPLAIN
u. V tomto případě je hodnota
rows
5006, ačkoliv MySQL přečte díky LIMIT
u pouze
10 řádků.
Sloupec Extra
obsahuje některé dodatečné informace.
Seznam a popis všech možných hodnot naleznete v manuálu.
Hodnota | Popis |
---|---|
Using index | MySQL všechna potřebná data získá již z indexu (tzv. covering index). Nemusí tedy přistupovat do tabulky, což dotaz velmi zrychluje, často až o řády. |
Using filesort | Po získání všech požadovaných řádku z tabulky se provádí ještě dodatečné řazení. |
Using temporary | MySQL musí vytvořit dočasnou tabulku s výsledkem dotazu, na kterou poté aplikuje dodatečné operace, např. řazení apod. |