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

demo magento

Przetestuj demo Magento 2

O technologii Magento napisaliśmy i powiedzieliśmy już wiele. Teraz możesz samodzielnie przetestować ją w praktyce. Udostępniamy Ci zupełnie darmowe demo Magento z frontendem i dostępem do panelu administracyjnego. Przetestuj je samodzielnie lub umów się na pokaz na żywo. Co zawiera demo Magento? Magento to lider oprogramowania do tworzenia sklepów internetowych B2B i systemów sprzedażowych B2B […]

Czytaj więcej
Narzędzia analityczne

Narzędzia analityczne – nie bój się ich!

W ciągu ostatniego roku badałem zarówno polski, jak i światowy rynek e-Commerce. Wykorzystując narzędzia typu Builtwith.com, odkryłem, że większość największych platform sprzedażowych korzysta z maksymalnie 14 różnych narzędzi analitycznych. Dzięki nim pozyskują informacje dotyczące zachowań klientów w ich sklepach internetowych, co stanowi bardzo ważną bazę do dalszego rozwoju.

Czytaj więcej
Magento B2B

Dlaczego sklepy Magento B2B są tak popularne?

Krajobraz rynku B2B ewoluuje. Coraz więcej firm tego sektora przenosi swoją działalność, przynajmniej częściowo, do Internetu. Według raportu B2B e-Commerce Now 2022, już 41% firm prowadzi platformy sprzedażowe. Choć na naszym polskim rynku znajdziemy jeszcze dość sporo przedsiębiorstw, które stawiają opór tej zmianie, większość z nich jednak idzie z duchem czasu i odpowiada na potrzeby […]

Czytaj więcej
Automatyczne testy aplikacji mobilnych

Automatyczne testy aplikacji mobilnych

Testy są nieodłącznym elementem wytwarzania oprogramowania. Wykonuje się je przede wszystkim w celu znalezienia błędów, sprawdzania kompatybilności i stabilności aplikacji. Dopóki aplikacja jest mała, wszystkie testy jest w stanie wykonywać tester, ale z czasem konieczna jest automatyzacja – w której tematykę chciałbym dziś Was wprowadzić. A na co to komu? Zacznę od trochę abstrakcyjnej historii. […]

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