Чем плох MySQL. в избранное  новое всё   подписка   модер. 
От: Maxim S. Shatskih mvp 
Дата: 16.07.07 16:06
Оценка:45 (10)
MySQL может использовать один из двух основных низкоуровневых движков — InnoDB или MyISAM.

InnoDB вроде как развитый. Только медленнее MyISAM раза в 2.5 — 3, а уж если сравнивать MySQL 4.0 c MSSQLServer 7 (делал такое году в 2004) на одинаковом железе — то Microsoft будет быстрее примерно втрое на паттерне "куча мелких апдейтов".

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

Теперь о MyISAM.

1. Только table-level locking. Чудовищные тормоза в апликации. Все ждут, пока кто-то один внесет изменения. Крайне забавно, например, для форумного движка со всеми сообщениями в одной таблице.
2. Отсутствие средства автовосстановления целостности по логу транзакций при старте базы. У MSSQLServer это было с рождения — с начала 90х. После крахов реально пропадают строки из таблиц. Лично видел.
3. Отсутствие полноценных средств бэкапа. Их всего два а) остановить демона, и скрутить базы в tgz б) mysqldump, который не бэкап, а экспорт в текст на языке SQL, и который — урааа! — накладывает лок длительностью во всю операцию.
4. Отвратительная имплементация ORDER BY, см. файл filesort.cc. Что они делают? выгружают ключи к результату (а то и сам результат) в _2 временных файла_, которые даже не являются MyISAMовскими таблицами. Аллоцируют временный буфер в памяти, нарезают его на кусочки, потом покусочечно читают туда первый временный файл, и пишут во второй, делая по ходу merge sort. В пределах кусочков используется qsort.

Почему это отвратительно? ну, то, что файлы растут, что при работе с ними используются обычные кэширующие syscalls — это полбеды. Беда в другом. Беда в аллокации этого самого sort_buffer на каждый запрос с ORDER BY. Если юзерей у системы много, а размер буфера велик — то реально исчерпать все 3GB юзерского адресного пространства во FreeBSD и получить облом в malloc(). Более того, там явно стоит цикл вида "а если malloc обломался — то пробуем буфер в 2 раза меньше".

Естественно, при такой нагрузке на heap malloc() начинает обламываться не только в filesort, но и в любом другом месте. И тут вступает в силу пятый пункт:

5. Некоторые обломы malloc() не проверяются в коде, и приводят к краху mysqld по сигналу 11.

Что, в свою очередь по пункту 2 иногда приводит к исчезновению строк из таблиц.

Как ORDER BY сделан в нормальных базах данных? SELECT INTO во временную таблицу с индексом, и потом SELECT уже из нее. Временная таблица создается в том же page cache, что и основная база данных, при этом у этих страниц ставится атрибут "слив на диск в последнюю очередь", что бережет disk IO. При исполнении ORDER BY не используется malloc() больших размеров.

Да, можно уменьшить в конфиге параметр sort_buffer_size. И получить стабильные тормоза раза в 4 медленнее, зато практически без крахов.

Насколько я понимаю, этот же движок сортировки используется и для InnoDB. В исходниках есть почти такой же код, который специфичен для MyISAM — но он используется в CREATE INDEX, а не в ORDER BY.

Выводы:
— при разработке приложений под MySQL нужно думать о том, как обойти эту проблему с ORDER BY, вплоть до выгрузки результата в таблицу (на деле временную) с индексом по атрибуту сортировки.
— иначе — на единицах гигабайт базы и сотнях пользователей — крах за крахом.
— обязательны "узкие композиты" при использовании таблиц с BLOBами, нужно добиваться того, чтобы EXPLAIN SELECT показывал Using index — т.е. полное неприкосновение к самой таблице с полным исполнением запроса по композиту.
— возможно, имеет смысл на коленке сделанный table partitioning.

Повторю еще раз — для приложений с ощутимой нагрузкой и ощутимыми размерами базы _нужно принимать специальные меры при разработке приложения, чтобы обойти MySQL misdesigns_.
Занимайтесь LoveCraftом, а не WarCraftом!