Всем известно, что в таблицах, которые используют InnoDB в качестве движка, такие запросы SELECT COUNT(*) FROM mytable
очень неточны и очень медленны, особенно когда таблица становится больше и когда во время выполнения этого запроса происходят постоянные вставки / удаления строк.
Как я понял, InnoDB не сохраняет количество строк во внутренней переменной, что является причиной этой проблемы.
Мой вопрос: почему это так? Будет ли так сложно хранить такую информацию? Это важная информация, которую нужно знать во многих ситуациях. Единственная трудность, которую я вижу, если такой внутренний счет будет реализован, - это когда транзакции задействованы: если транзакция не совершена, вы считаете количество строк, вставленных ею, или нет?
PS: я не специалист по БД, я просто тот, у кого MySQL простое хобби. Так что, если я просто спросил что-то глупое, не будь чрезмерно критичен: D.
SELECT COUNT(*) FROM ...
запросы точны. Если вы предпочитаете, phpMyAdmin можно настроить так, чтобы он всегда использовал точное количество строк за счет скорости. Дополнительная информация: stackoverflow.com/questions/11926259/…Ответы:
Я согласен с @RemusRusanu (+1 за его ответ)
SELECT COUNT(*) FROM mydb.mytable
в InnoDB ведет себя как механизм хранения транзакций. Сравните это с MyISAM.MyISAM
Если
mydb.mytable
это таблица MyISAM, запускSELECT COUNT(*) FROM mydb.mytable;
аналогичен запускуSELECT table_rows FROM information_schema.table WHERE table_schema = 'mydb' AND table_name = 'mytable';
. Это вызывает быстрый поиск количества строк в заголовке таблицы MyISAM.InnoDB
Если
mydb.mytable
это таблица InnoDB, вы получаете мешанину вещей, происходящих. У вас есть MVCC, регулирующий следующее:Запрос InnoDB для подсчета таблицы требует навигации по этим зловещим вещам. На самом деле, никто никогда не узнает,
SELECT COUNT(*) from mydb.mytable
учитывает ли повторяемое чтение только считанные или непрочитанные чтения.Вы можете попытаться немного стабилизировать ситуацию, включив innodb_stats_on_metadata .
Согласно документации MySQL на innodb_stats_on_meta_data
Отключение может дать или не дать вам более стабильный счет с точки зрения настройки планов EXPLAIN. Это может повлиять на производительность
SELECT COUNT(*) from mydb.mytable
либо в хорошем, либо в плохом смысле, либо не повлиять вообще. Попробуйте и посмотрите !!!источник
Для начала нет такой вещи, как «текущий счетчик» для хранения в переменной. Подобный запрос
SELECT COUNT(*) FROM ...
зависит от текущего уровня изоляции и всех параллельных ожидающих транзакций. В зависимости от уровня изоляции, запрос может видеть или не видеть строки, вставленные или удаленные в ожидании незавершенных транзакций. Единственный способ ответить - подсчитать строки, которые видны для текущей транзакции.Обратите внимание, что я даже не коснулся еще более острого вопроса о параллельных транзакциях, которые начинаются или заканчиваются во время подсчета. Не говоря уже об откатах ...
источник
COUNT(*)
запросы редко бывают необходимы в реальности и, как правило, являются результатом неопытности разработчика (считайте строки, прежде чем мы их выберем!) Или плохого дизайна приложения.SELECT COUNT(*)
, добавьте неоптимизированнуюWHERE
таблицу, и у вас будет несколько пользователей, которые ставят БД на колени для нескольких сомнительно полезных счетчиков статистики.Хотя теоретически было бы возможно вести точный подсчет количества строк для данной таблицы с помощью InnoDB, это будет стоить большого количества блокировок, что отрицательно скажется на производительности. Это также будет отличаться в зависимости от уровня изоляции.
MyISAM уже выполняет блокировку на уровне таблицы, поэтому никаких дополнительных затрат там нет.
Мне редко требуется количество строк для таблицы, хотя я использую COUNT (*) совсем немного. У меня вообще есть предложение WHERE. Используя эффективный индекс для небольшого набора результатов, я считаю, что они достаточно быстрые.
Я не согласен с тем, что подсчет является неточным. Подсчеты представляют собой снимок данных, и я всегда находил их точными.
Короче говоря, MySQL предоставляет вам возможность реализовать это для InnoDB. Вы можете сохранить счетчик и увеличивать / уменьшать его после каждого запроса. Тем не менее, более простым решением, вероятно, является переход на MyISAM.
источник