Почему count (*) медленный, когда объяснение знает ответ?

14

Этот запрос: select count(*) from planner_eventзанимает очень много времени для выполнения - так долго, я сдался и убил его, прежде чем он закончил. Однако, когда я бегу explain select count(*) from planner_event, я вижу столбец на выходе с количеством строк (14 м).

Почему объяснение может получить число строк мгновенно, но count (*) занимает много времени?

Benubird
источник
COUNT (*) без причины WHERE вызовет сканирование таблицы на движке InnoDB. MyISAM может доставить счет непосредственно, потому что COUNT хранится в файле de header вне таблицы.
Рэймонд

Ответы:

16

Объяснение использует ранее собранную статистику (используется оптимизатором запросов). Делать select count(*)читает КАЖДЫЙ блок данных.

Вот дешевый способ получить приблизительное количество строк:

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

Даже если вы это сделаете select count(id), это может занять очень много времени, если у вас не включен вторичный индекс id(также предполагается, idчто это ПЕРВИЧНЫЙ КЛЮЧ). Поскольку все данные (включая данные строк) хранятся в индексах B-Tree, выполнение select count(PK_COLUMN)операции I по-прежнему занимает значительное количество операций ввода-вывода (необходимо прочитать все страницы данных). Если у вас есть вторичный индекс в поле PK, он сможет выполнять меньше операций ввода-вывода для выполнения подсчета.

Кевин Ботт
источник
I_S.TABLES дает вам ту же оценку, что EXPLAINдает вам.
Рик Джеймс
Запрос отсутствует AND TABLE_SCHEMA='my_database', в противном случае вы получите несколько результатов обратно, если у вас есть таблица с таким же именем в другой базе данных.
cz
3

Explain получает число из некоторой «статистики», которая используется для оценки вещей для Оптимизатора. Это число может быть далеко от правильного - я иногда вижу, что оно более чем в 2 раза (выше или ниже), чем точное значение.

Выполнение COUNT(*)таблицы InnoDB должно сканировать таблицу, чтобы избежать неправильного подсчета записей, которые заняты вставкой / удалением другими соединениями, но еще не "зафиксированы". На самом деле, достаточно выполнить полное сканирование некоторого индекса, не обязательно всей таблицы (которая содержит PRIMARY KEY).

Сколько у вас оперативной памяти? Какова стоимость innodb_buffer_pool_size? Это могло бы помочь, если бы это было около 70% оперативной памяти.

Рик Джеймс
источник