Разница в производительности между Innodb и Myisam в Mysql - PullRequest
8 голосов
/ 30 марта 2012

У меня есть таблица mysql с более чем 30 миллионами записей, которые изначально хранились в myisam.Вот описание таблицы:

describe_table

Я бы запустил следующий запрос к этой таблице, который обычно занимал бы около 30 секунд.Я бы каждый раз менял @eid, чтобы избежать кэширования базы данных или диска.

select count(fact_data.id) 
    from fact_data 
    where fact_data.entity_id=@eid 
        and fact_data.metric_id=1

Затем я преобразовал эту таблицу в innoDB, не внося никаких других изменений, и после этого один и тот же запрос теперь возвращается ниже секунды каждый раззапустите запрос.Даже когда я случайно установил @eid, чтобы избежать кеширования, запрос возвращается менее чем за секунду.

Я исследовал различия между двумя типами хранилищ, чтобы попытаться объяснить резкое улучшение производительности, но ничего не смог придумать.Фактически, многое из того, что я прочитал, указывает на то, что Myisam должен быть быстрее.

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

Ответы [ 3 ]

15 голосов
/ 30 марта 2012

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

MyISAM исторически считался более быстрым, чем InnoDB, но для последних версий InnoDB это справедливо для гораздо меньшего набора вариантов использования. MyISAM обычно быстрее для сканирования таблиц только для чтения. В большинстве других случаев я нахожу InnoDB быстрее. Часто в разы быстрее. Блокировки таблиц являются смертельным звеном для MyISAM в большинстве случаев использования MySQL.

MyISAM кэширует индексы в своем ключевом буфере. Возможно, вы установили слишком маленький буфер ключей, чтобы он эффективно кэшировал индекс для вашей довольно большой таблицы.

MyISAM зависит от ОС для кэширования данных таблицы из файлов .MYD в кеше диска ОС. Если в операционной системе недостаточно памяти, она начнет выгружать свой дисковый кеш. Это может заставить его продолжать чтение с диска.

InnoDB кэширует как индексы, так и данные в своем собственном буфере памяти. Вы можете указать ОС не использовать ее дисковый кеш, если для innodb_flush_method установлено значение O_DIRECT, хотя это не поддерживается в OS X.

InnoDB обычно буферизует данные и индексы на страницах по 16 КБ. В зависимости от того, как вы меняете значение @eid между запросами, возможно, он уже кэшировал данные для одного запроса из-за чтения диска с предыдущего запроса.

Убедитесь, что вы создали индексы одинаково. Используйте объяснение, чтобы проверить, использует ли MySQL индекс. Так как вы включили вывод команды description вместо show create table или show indexers, я не могу сказать, является ли entity_id частью составного индекса. Если бы это была не первая часть составного индекса, он бы не использовался.

Если вы используете относительно современную версию MySQL, перед запуском запроса выполните следующую команду:

установить профилирование = 1;

Это включит профилирование запросов для вашего сеанса. После выполнения запроса выполните

показывать профили;

Это покажет вам список запросов, для которых доступны профили. Я думаю, что он сохраняет последние 20 по умолчанию. Предполагая, что ваш запрос был первым, запустите:

показать профиль для запроса 1;

Затем вы увидите продолжительность каждого этапа выполнения запроса. Это чрезвычайно полезно для определения того, что (например, блокировки таблиц, сортировка, создание временных таблиц и т. Д.) Вызывает медленный запрос.

6 голосов
/ 30 марта 2012

Моим первым подозрением будет то, что исходная таблица MyISAM и / или индексы со временем фрагментируются, что приводит к медленному снижению производительности. Таблица InnoDB не будет иметь такой же проблемы, так как вы создали ее со всеми данными, уже находящимися в ней (так что все они будут последовательно храниться на диске).

Вы можете проверить эту теорию, перестроив таблицу MyISAM. Самый простой способ сделать это - использовать «нулевой» оператор ALTER TABLE:

ALTER TABLE mytable ENGINE = MyISAM;

Затем проверьте производительность, чтобы убедиться, что она лучше.

Другая возможность была бы, если бы сама база данных просто настраивалась на производительность InnoDB, а не MyISAM. Например, InnoDB использует innodb_buffer_pool_size parameter, чтобы узнать, сколько памяти должно быть выделено для хранения кэшированных данных и индексов в памяти. Но MyISAM использует параметр key_buffer. Если ваша база данных имеет большой пул буферов innodb и небольшой буфер ключей, то производительность InnoDB будет лучше, чем производительность MyISAM, особенно для больших таблиц.

1 голос
/ 18 февраля 2013

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

...