Dlaczego liczba (*) jest powolna, gdy wyjaśnienie zna odpowiedź?

14

To zapytanie: select count(*) from planner_eventuruchamia się bardzo długo - tak długo poddałem się i zabiłem, zanim się skończyło. Jednak po uruchomieniu explain select count(*) from planner_eventwidzę kolumnę na wyjściu z liczbą wierszy (14 m).

Jak wyjaśnienie może natychmiast uzyskać liczbę wierszy, ale liczenie (*) zajmuje dużo czasu?

Benubird
źródło
COUNT (*) bez przyczyny GDZIE spowoduje skanowanie tabeli w silniku InnoDB. MyISAM może dostarczyć liczbę bezpośrednio, ponieważ COUNT jest zablokowany w pliku nagłówka poza tabelą.
Raymond Nijland

Odpowiedzi:

16

Wyjaśnij używa wcześniej zebranych statystyk (używanych przez optymalizator zapytań). Wykonywanie select count(*)odczytu KAŻDEGO bloku danych.

Oto tani sposób na uzyskanie szacunkowej liczby wierszy:

select TABLE_ROWS FROM INFORMATION_SCHEMA.TABLES where TABLE_NAME='planner_event';

Nawet jeśli tak select count(id), może to potrwać bardzo długo, chyba że masz dodatkowy indeks id(zakładając, że idjest to KLUCZ PODSTAWOWY). Ponieważ wszystkie dane (w tym dane wiersza) są przechowywane w indeksach B-drzewa, wykonywanie a select count(PK_COLUMN)nadal stanowi znaczną ilość operacji we / wy (należy odczytać wszystkie strony danych). Jeśli masz indeks wtórny w polu PK, będzie mógł wykonać mniejszą liczbę operacji we / wy, aby wykonać zliczanie.

Kevin Bott
źródło
I_S.TABLES daje ci to samo oszacowanie, które EXPLAINdaje ci.
Rick James
Brakuje zapytania AND TABLE_SCHEMA='my_database', w przeciwnym razie otrzymasz wiele wyników z powrotem, jeśli masz tabelę o tej samej nazwie w innej bazie danych.
cz
3

Wyjaśnij pobiera liczbę z niektórych „statystyk”, które są używane do oszacowania rzeczy dla Optymalizatora. Ta liczba może być daleka od prawidłowej - czasami widzę, że jest ona większa niż współczynnik 2 (wyższy lub niższy) niż dokładna wartość.

Wykonanie COUNT(*)na tabeli InnoDB musi zeskanować tabelę, aby uniknąć błędnego zliczania rekordów, które są zajęte wstawianiem / usuwaniem przez inne połączenia, ale jeszcze nie „zatwierdzone”. W rzeczywistości wystarczy wykonać pełne skanowanie jakiegoś indeksu, niekoniecznie całej tabeli (która zawiera PRIMARY KEY).

Ile masz pamięci RAM? Jaka jest wartość innodb_buffer_pool_size? Może to pomóc, gdyby było to około 70% pamięci RAM.

Rick James
źródło