COUNT(*) для таблиц InnoDB — перевод с MySQL Performance Blog

Меня давно интересовало, что за откровения таятся в блоге Петра Зайцева и Вадима Ткаченко посвященному оптимизации работы с MySQL. Сложность в том, что он на английском, а времени на то, чтобы не просто прочитать, а понять все тонкости нет.

С этого поста я начинаю переводить и размещать в блоге различные материалы оттуда, а также с других англоязычных ресурсов посвященных веб-разработке.

----------

Оригинал: COUNT(*) for Innodb Tables (MySQL Performance Blog).
Автор: Петр Зайцев.

----------

Я считаю, самое важное замечание при переходе с MyISAM на Innodb — предупреждение о том, что Innodb очень медлителен при обработке запросов COUNT(*). Но есть одна деталь, которую часто упускают из виду — это относится только к запросам COUNT(*) без оператора WHERE.

Таким образом, если ваш запрос выглядит как SELECT COUNT(*) FROM USER, он будет обрабатываться быстрее в таблицах MyISAM (MEMORY и некоторых других), потому что будет просто прочитано сохраненное в таблице значение количества строк. В Innodb при этом необходимо выполнить полное сканирование таблицы или индекса, потому что в этом типе таблиц не предусмотрен такой счётчик. Это так же не может быть решено заведением простого счётчика, так как разные транзакции могут видеть разное количество записей в таблице.

Если запрос выглядит так: SELECT COUNT(*) FROM IMAGE WHERE USER_ID=5, то он одинаково будет выполнятся над таблицами MyISAM и Innodb — путем сканированием индексного ряда. Он может быть выполнен как быстрее, так и медленнее как для MyISAM, так и для Innodb. Все зависит от структуры таблицы.

На практике чаще всего приходится иметь дело с запросами второго типа, поэтому это не такая страшная проблема, как кажется на первый взгляд. Обычно счётчик числа строк нужен для программ администрирования, которые могут отображать его в статистике таблицы, также его можно использовать в статистике приложения, чтобы показывать сообщения вида «У нас 123345 пользователей, которые закачали 1344656 изображений», но это можно легко устранить.

Так что помните — Innodb медлителен не для ВСЕХ зопросов COUNT(*), а только для очень специфических запросов COUNT(*) без оператора WHERE. Хотя это не значит, что я не хочу, чтобы это исправили — на самом деле это очень раздражает.

----------

Теги: , , ,

Еще по теме

Posted on марта 12, 2008 
Filed Under Проектирование и разработка сайтов

Комментарии

Всего комментариев: 18

  1. FX Poster - марта 12, 2008 17:00

    Хехе. У меня такие же проблемы — вижу, что новый пост, интересно, но быстренько «просмотреть» его не получается, т.к. он на английском, нужно вчитываться. Так что начинание поддерживаю полностью! Спасибо!

  2. Артём Майнас - марта 12, 2008 18:24

    У меня вообще какой-то страх перед MySQL и всем, что с ним связано. Сейчас пытаюсь его преодалеть и научиться нормально работать с такими базами.

  3. FX Poster - марта 12, 2008 18:26

    Зря. Ничего сложного там нет, если особо не лезть в дебри оптимизации работы БД.

  4. Денис Болтиков - марта 12, 2008 18:57

    Артём Майнас, основы и правда просты. Я их тоже раньше не понимал, потом пришлось делать проект и разобрался за пару дней. Попробуй посмотреть соответствующий онлайн-курс на INTUIT.

    Вопрос в другом, а оно тебе надо? У тебя много других достоинств.

  5. Денис Болтиков - марта 12, 2008 19:00

    Случайно удалил комметарий по делу от одного из читателей :( Извиняюсь, не туда нажал мышкой.

    Было про то, что запрос с COUNT(id) ложит базу с таблицей «news» за 7 секунд. Если ты еще читаешь, то повтори его пожалуйста.

    Ну и сразу советы. Замени COUNT(id) на COUNT(*). Проверь есть ли индекс по полю по которому идет выборка и используется ли этот индекс в запросе.

    Мысли про мемкеш тоже должна помочь :)

  6. kikaha - марта 12, 2008 19:25

    Кармический батончик тебе в панамку за перевод! У меня с этим блогом та же ситуация — никак время не выберу сесть и вкусно прочитать , а в ридере только глазами пробегаю ... спасибо за перевод еще раз, ждем остальных статей!

  7. dkrnl - марта 12, 2008 19:29

    SELECT COUNT(`id`) FROM `news` WHERE `type`=1;

    новостей ~18 000, архив за 6 лет.

    Все индексы есть,  Работает иногда 7> секунд.

    Канешно мемкэшед выход, но не совсем, ведь какотой запрос всеравно будет считать за тоже не приемлимое время. И хорошо если этот запрос от бота, а не от человека. (:

    Да и динамика новостей такая что кеш «протухает» в среднем через час.

    Думаю передалать на inodb + доп. таблица со счетчиками для каждего type и тригеры.

    Вот только не ясный момент — как долго будут работать тригеры, и в какое время. Если после коммита то получится большой лаг — для редактора новостей. Или же по инициативие бд... надо пробывать.

  8. Vadim Voituk - марта 12, 2008 21:32

    Автору удаленного комментария рекомендую прочесть небольшой сравнительный тестик

    voituk.kiev.ua/2006/07/27...count-statement/

  9. Vadim Voituk - марта 13, 2008 00:37

    @dkrnl: А можно explain запроса (дабы не захламлять ветку) выслать на емайл vadim.voituk на gmail.com?

    Какой средний размер строки таблицы news?

    Когда последний раз был optimize table?

    Я конечно ни на что не намекаю, но у меня подобный запрос редко 7 секунд выполняется на 18 млн записей :)

  10. Денис Болтиков - марта 13, 2008 13:11

    Да, для 18 тысяч записей такой запрос выполняется непозволительно долго.

  11. Дима - марта 18, 2008 00:16

    недавно столкнулся с такой же ситуацией

  12. Eugene - марта 28, 2008 16:43

    Vadim Voituk, спасибо за тестик. Наглядно и понятно все.

    Всем юзать count(*) :)

  13. TYUS - июля 21, 2008 09:26

    Денис, а еще будут посты об оптимизации мускул?

    Сам вот недавно столкнулся с такой проблемой.

  14. Ванько - августа 13, 2008 04:10

    Читал в оригинале этот пост, и блог в целом почитываю :) Полезностей куча.

  15. MLMовка - декабря 22, 2008 23:02

    Может быть немного не в тему, но по MySQL у меня проблема перевода базы с одного хостинга на другой. Делая бэкап/рестор — получаются одни вопросики :(

    Кто-нибудь может помочь?

  16. Денис Болтиков - декабря 23, 2008 00:01

    Проблема в кодировках. посмотри в какой кодировке данные лежат в таблицах, в какой ты сохраняешь, в какой кодировке новая базы и в какой ты туда загружаешь данные.

  17. MLMовка - января 6, 2009 00:30

    оригинал в koi8, база в utf8

  18. Денис Болтиков - января 6, 2009 00:59

    Ну вот, при экспорте в новую базу укажи, что данные хранятся в koi и все пройдет нормально.

Комментарии закрыты.

Тема Vertigo Blue Theme от Brian Gardner.
Движок WordPress.

Рейтинг блогов