Ostatnia aktualizacja:

1 września 2025

Opublikowano:

20 czerwca 2017

MySQL – EXPLAIN – jak używać i jak czytać

MySQL – EXPLAIN – jak używać i jak czytać

W dzisiejszym wpisie będę omawiał użycie polecenia EXPLAIN w MySQL. Dowiemy się jak używać tego polecenia. W jakich sytuacjach może być przydatne, a także jak interpretować otrzymywane odpowiedzi. Dyrektywa EXPLAIN powoduje, że zamiast wykonywać zadane zapytanie zostaną wyświetlone informacje na temat planu wykonania danego zapytania. Do wersji MySQL 5.6.3 możliwe było użycie EXPLAIN tylko do zapytań SELECT. Najnowsze wersje MySQL wspierają dyrektywę EXPLAIN również z zapytaniami UPDATE, INSERT, REPLACE.

W tym artykule dowiesz się:
  1. Jak użyć polecenia <code>EXPLAIN</code>?
  2. Jak czytać wyniki?
  3. Podsumowanie

W treści będę używał tabel z aplikacji Redmine, bo używamy tego narzędzia w firmie.

Jak użyć polecenia <code>EXPLAIN</code>?

Użycie polecenia EXPLAIN jest bardzo proste i polega na poprzedzeniu zapytania dyrektywą EXPLAIN. Najprostszy przykład użycia EXPLAIN to: EXPLAIN SELECT 1\G, dzięki któremu uzyskujemy następujący wynik:

*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: NULL
         type: NULL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: NULL
        Extra: No tables used

Jak czytać wyniki?

Przyjrzyjmy się poszczególnym elementom otrzymanego wyniku.

Kolumna ID

Kolumna id zawiera numer zapytania, którego dotyczy. W naszym pierwszym przykładzie było oczywiście pojedyncze zapytanie dlatego mamy tylko jeden wiersz w odpowiedzi o id = 1. W przypadku zapytań z podzapytaniami, podzapytania w dyrektywie FROM oraz zapytań z dyrektywą UNION podzapytania numerowane są (zazwyczaj) w kolejności ich występowania w zapytaniu. Przykładowo dla podzapytania:  EXPLAIN SELECT (SELECT 1 FROM issues) FROM journals\G otrzymujemy

*************************** 1. row ***************************
           id: 1
  select_type: PRIMARY
        table: journals
         type: index
possible_keys: NULL
          key: index_journals_on_user_id
      key_len: 4
          ref: NULL
         rows: 33843
        Extra: Using index
*************************** 2. row ***************************
           id: 2
  select_type: SUBQUERY
        table: issues
         type: index
possible_keys: NULL
          key: issues_project_id
      key_len: 4
          ref: NULL
         rows: 6704
        Extra: Using index

Dla podzapytania pochodnego EXPLAIN SELECT id FROM (SELECT * FROM issues) AS DERIVED\G otrzymujemy:

*************************** 1. row ***************************
           id: 1
  select_type: PRIMARY
        table: &lt;derived2&gt;
         type: ALL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 6704
        Extra: NULL
*************************** 2. row ***************************
           id: 2
  select_type: DERIVED
        table: issues
         type: ALL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 6704
        Extra: NULL

Dla zapytania z dyrektywą UNION EXPLAIN SELECT 1 UNION SELECT 1\G otrzymujemy

*************************** 1. row ***************************
           id: 1
  select_type: PRIMARY
        table: NULL
         type: NULL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: NULL
        Extra: No tables used
*************************** 2. row ***************************
           id: 2
  select_type: UNION
        table: NULL
         type: NULL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: NULL
        Extra: No tables used
*************************** 3. row ***************************
           id: NULL
  select_type: UNION RESULT
        table: &lt;union1,2&gt;
         type: ALL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: NULL
        Extra: Using temporary

Przykład z UNION jest najciekawszym jak do tej pory. Możemy zobaczyć, że MySQL zawsze kopiuje wyniki zapytania UNION do tabeli tymczasowej, a następnie z tabeli tymczasowej zwraca nam otrzymany rezultat. Stąd mamy 3, a nie 2 wiersze w ostatnim wyniku.

Kolumna SELECT_TYPE

W kolumnie select_type otrzymujemy informacje o tym jakiego typu jest dane zapytanie. Możliwe wartości to: SIMPLESUBQUERYDERIVEDUNIONUNION RESULT oraz PRIMARY:

  • PRIMARY zostaje oznaczona najbardziej zewnętrzna składowa w badanym zapytaniu;
  • SIMPLE otrzymujemy jeżeli nie mamy żadnych podzapytań w danym zapytaniu;
  • SUBQUERY to podzapytania, które występują w klauzuli;
  • SELECT zapytania pierwotnego;
  • DERIVED to podzapytania w klauzuli FROM zapytania pierwotnego;
  • Typ UNION otrzymują drugie i kolejne części zapytania UNIONUNION RESULT (jak już wcześniej wspomniałem) jest efektem pracy MySQL – zwraca rezultat z tymczasowej tabeli w przypadku zapytań z UNION.

Kolumna TABLE

Kolumna table mówi o tym jakiej tabeli dotyczy dane zapytanie. Odczytując wartości z tej kolumny możemy zobaczyć jaką kolejność optymalizator zapytań MySQL zdecydował się zastosować do danego zapytania. Nie musi to być kolejność zgodna z kolejnością w zapytaniu.

Przykładowo: EXPLAIN SELECT i.id FROM journals j INNER JOIN issues i ON i.id = j.journalized_id INNER JOIN projects p ON i.project_id = p.id\G – otrzymujemy

*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: p
         type: index
possible_keys: PRIMARY
          key: index_projects_on_lft
      key_len: 5
          ref: NULL
         rows: 116
        Extra: Using index
*************************** 2. row ***************************
           id: 1
  select_type: SIMPLE
        table: i
         type: ref
possible_keys: PRIMARY,issues_project_id
          key: issues_project_id
      key_len: 4
          ref: xcoding_redmine.p.id
         rows: 47
        Extra: Using index
*************************** 3. row ***************************
           id: 1
  select_type: SIMPLE
        table: j
         type: ref
possible_keys: journals_journalized_id,index_journals_on_journalized_id
          key: index_journals_on_journalized_id
      key_len: 4
          ref: xcoding_redmine.i.id
         rows: 3
        Extra: Using index

Możemy zauważyć, że w kolumnie table otrzymaliśmy aliasy zastosowane w zapytaniu (nie mamy nazwy tabeli projects, ale alias p). Kolejność zastosowana przez MySQL jest inna niż w zapytaniu i odpowiada drzewu wykonywania zapytania. W przypadku gdy zapytanie dotyczy tabel tymczasowych możemy zobaczyć np. table: <union1,2> tak jak w przykładzie z UNION. Oznacza to, że jest to tabela tymczasowa z podzapytań o ID 1 i ID 2 z planu wykonywania zapytania. Możemy też zobaczyć np. table: . Będzie to oznaczało, że to zapytanie korzysta z wyniku zapytania w podzapytaniu o ID 2.

Kolumna TYPE

Kolumna type pokazuje w jaki sposób MySQL musi przetworzyć wiersze w tabeli.

  • ALL – oznacza, że należy przeskanować wszystkie wiersze w tabeli,
  • INDEX – MySQL musi przeskanować wszystkie wiersze w tabeli, ale może wykonać to w porządku w jakim jest przechowywane w indeksie, co może zaoszczędzić czas wykonywania zapytania gdyż nie trzeba go już sortować (ale dalej musimy uzyskać dostęp do pełnej tabeli na dysku),
  • RANGE – MySQL może użyć indeksu do przeszukania tylko potrzebnych w danym zapytaniu wartości,
  • REF – MySQL może przeszukać jedynie indeks do znalezienia potrzebnych wartości. Może występować przypadek REF_OR_NULL gdzie potrzebny jest jeszcze dodatkowy dostęp do pobrania wartości odpowiadających NULL,
  • EQ_REF – MySQL zadecydował do użycia indeksu głównego lub unikalnego do zwrócenia wartości. Jest to bardzo szybki dostęp, bo przy natrafieniu na wartość MySQL może ją zwrócić bez szukania dalszych, także dopasowanych wartości,
  • CONST – zazwyczaj występuje w przypadku użycia w klauzuli WHERE wartości z indeksu głównego tabeli.

Przykładowo: EXPLAIN SELECT id FROM issues WHERE id = 7555\G – otrzymujemy:

************************* 1. row *************************
           id: 1
  select_type: SIMPLE
        table: issues
         type: const
possible_keys: PRIMARY
          key: PRIMARY
      key_len: 4
          ref: const
         rows: 1
        Extra: NULL
  • NULL – oznacza, że wartość może być określona już na etapie optymalizacji zapytania. Najczęstszym przykładem jest wartość maksymalna z pola, które jest zaindeksowane w danej tabeli.

Kolumna POSSIBLE_KEYS

Ta kolumna mówi o tym, które indeksy mogą być użyte przy obliczaniu wyniku zapytania. Jest tworzona na początku procesu optymalizacji dlatego lista może być dość długa i nie być pomocna przy analizie całości zapytania (jak w przykładzie wyjaśniającym kolumnę TABLE).

Kolumna KEY

Kolumna key wskazuje, który indeks będzie użyty przez MySQL podczas wykonywania zapytania. Możliwa jest sytuacja, w której mamy pustą kolumnę possible_keys, ale i tak zostanie użyty indeks.

Przykładowo: EXPLAIN SELECT id FROM issues\G – otrzymujemy:

*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: issues
         type: index
possible_keys: NULL
          key: issues_project_id
      key_len: 4
          ref: NULL
         rows: 6704
        Extra: Using index

Kolumna KEY_LEN

Kolumna key_len podaje informacje ile bajtów indeksu zostanie użytych przez MySQL podczas wykonywania zapytania. Szczególnie przydatna może być w przypadku wielokolumnowych indeksów. Informacja o ilości użytych bajtów może powiedzieć jaka część indeksu została użyta (do wersji MySQL 5.5 może zostać użyta tylko lewa część indeksu lub jego całość). W przypadku gdy indeks obejmuje kolumny tekstowe należy też brać pod uwagę charset jaki jest w nich użyty. Podawana tutaj informacja zawsze oznacza maksymalną wielkość indeksu (lub jego części), bez względu na to, czy obecnie wypełnione w tabeli wartości wymagają aż tak dużej ilości pamięci do ich przechowania.

Kolumna REF

Ta kolumna informuje o tym które kolumny z indeksów podany w kolumnie key zostaną użyte podczas wykonywania zapytania (patrz przykład z kolumny table).

Kolumna ROWS

Kolumna rows podaje informacje ile średnio rekordów w bazie danych będzie należało przejrzeć żeby wydobyć dane niezbędne w zapytaniu. Jeżeli mamy do czynienia ze złożonym zapytaniem to informacja dotyczy pojedynczego wykonania pętli dla JOIN. Informacje te mogą być mocno nieprecyzyjne.

Przykładowo zapytanie: SELECT * FROM issues LIMIT 1\G zwróci wyniki już po znalezieniu pierwszego rekordu, a wynik jest następujący (w tabeli jest 6704 rekordów):

*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: issues
         type: ALL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 6704
        Extra: NULL

Kolumna EXTRA

Najważniejsze wartości jakie mogą pojawić się w tej kolumnie:

  • Using index – podczas wykonywania zapytania użyty będzie indeks zamiast odczytu bezpośrednio z tabeli
  • Using where – MySQL będzie musiał przefiltrować wyniki otrzymane z silnika bazy danych. Często jest to informacja, którą warto przemyśleć pod kątem stworzenia nowego (lub modyfikacji istniejących) indeksów.
  • Using temporary – MySQL użyje tabeli tymczasowej do sortowania wyników
  • Using filesort – wymagane będzie użycie sortowania po wyciągnięciu danych z bazy zamiast wyciągnięcia ich w wymaganym porządku

Podsumowanie

Dyrektywa EXPLAIN jest pierwszym narzędziem po jakie powinniśmy sięgnąć w przypadku problemów z wydajnością zapytań SQL lub po prostu w procesie optymalizacji zapytań. Pozwala ona zrozumieć jak MySQL będzie przetwarzał zapytanie, dostarcza informacji o użytych indeksach (lub ich braku) , kolejności przetwarzania podzapytań czy łączenia elementów z wielu tabel.

Mam nadzieję, że wyjaśnione w artykule składowe polecenia EXPLAIN zachęcą do zapoznania się bardziej dogłębnie z możliwościami tej dyrektywy i przyczynią się do zwiększenia szybkości działania Waszych baz danych.

Ostatnia aktualizacja:

1 września 2025

Opublikowano:

20 czerwca 2017

W tym artykule dowiesz się:
  1. Jak użyć polecenia <code>EXPLAIN</code>?
  2. Jak czytać wyniki?
  3. Podsumowanie

Polecane artykuły

Aplikacja hybrydowa

Czym jest aplikacja hybrydowa?

Zastanawiacie się, czym jest aplikacja hybrydowa, do czego służy, jak ją stworzyć i jak z niej korzystać? W dzisiejszym artykule postaram się przybliżyć Wam ten temat. Jak dzielimy rodzaje aplikacji? Zacznijmy od samego początku. Aplikacje mobilne dzielą się na trzy typy: aplikacje natywne, aplikacje webowe, aplikacje hybrydowe. Hybrydowe aplikacje mobilne są połączeniem rozwiązań aplikacji natywnych […]

Czytaj więcej
Podłączenie Firebase do Androida

Podłączenie Firebase do projektu Android

Projekt Firebase to narzędzie analityczne dla aplikacji mobilnych (zarówno Android jak i iOS) pozwalające na darmowe skorzystanie z wielu modułów. Moduły od Firebase Dodawanie projektu do Firebase Android Studio Zakładam, że jesteśmy już zalogowani do konsoli Firebase (https://console.firebase.google.com/). Klikamy “Utwórz nowy projekt” i wypełniamy podstawowe dane dla naszego projektu. Po chwili mamy utworzony projekt, który możemy podpiąć […]

Czytaj więcej
Hosting Prestashop

Hosting dla sklepu na Prestashop – na co zwracać uwagę?

Wybór odpowiedniego hostingu dla sklepu internetowego opartego na Prestashop jest kluczowym elementem sukcesu w e-Commerce. To potężna i elastyczna platforma, ale aby w pełni wykorzystać możliwości wdrożenia Prestashop, potrzebujesz odpowiedniego środowiska hostingowego. W tym artykule omówimy, jaki hosting wybrać, aby Twój sklep działał płynnie, szybko i niezawodnie. Dlaczego wybór hostingu jest tak ważny? Hosting to […]

Czytaj więcej
Kiedy Magento nie jest dla Ciebie dobrym rozwiązaniem?

Kiedy Magento nie będzie dla Ciebie dobrym rozwiązaniem?

Jest pewna praktyka wśród agencji e-Commerce, która budzi nasz autentyczny gniew. Mowa o wciskaniu na siłę klientowi technologii, w której akurat dana firma się specjalizuje. A decyzja o wyborze platformy powinna być motywowana wyłącznie potrzebami i możliwościami biznesowymi klienta agencji. Dlatego dziś pójdziemy pod prąd i pokażemy Ci przypadki, w których wdrożenie Magento, naszej flagowej […]

Czytaj więcej

Skontaktuj się z nami

Opowiedz nam o swoich ambicjach związanych z e-commerce i pozwól nam wspólnie je zrealizować.

Skontaktuj się z nami