пятница, 26 сентября 2008 г.

Не используйте MyISAM (MyISAM vs InnoDB)

Прочитав большое количество отзывов и рекомендаций про работу InnoDB и MyISAM, я обнаружил пример, который меня убедил, что MyISAM следует использовать предварительно подумав 10 раз. А для повседневной разработки стоит использовать только InnoDB.

Краткое сравнение:
  • InnoDB поддерживает внешние ключи и транзакции и потому поддерживает целостность данных. MyISAM не делает ничего из перечисленного.
  • InnoDB устойчив к отключению питания. MyISAM может потерять данные при отключении питания.
  • InnoDB требует для хранения информации больше дискового пространства чем MyISAM.
  • Производительность InnoDB практически не уступает MyISAM (бенчмарки). Стоит также учесть, что при соотношении запросов 10 выборок на одну запись MyISAM может выигрывать в производительности (рассмотрение этого вопроса выходит за рамки данной заметки, материал легко найти в интернете)
  • InnoDB несколько хуже масштабируется (для подавляющего большинства проектов это не требуется).
  • У InnoDB есть несколько серьёзных и в то же время забавных ограничений (ограничения).

А теперь позвольте привести пример, который повёрг меня в сильный ступор.

Пример:

mysql> CREATE TABLE t (a INT NOT NULL, UNIQUE(a) ) ENGINE=MyISAM;
Query OK, 0 rows affected (0.01 sec)

mysql> INSERT INTO t values (5), (6);
Query OK, 2 rows affected (0.00 sec)
Records: 2 Duplicates: 0 Warnings: 0

mysql> select * from t;
+---+
| a |
+---+
| 5 |
| 6 |
+---+
2 rows in set (0.00 sec)

mysql> update t set a = 1;
ERROR 1062 (23000): Duplicate entry '1' for key 1
mysql> select * from t;
+---+
| a |
+---+
| 1 |
| 6 |
+---+
2 rows in set (0.00 sec)


Как видно, что при использовании MyISAM малейшая ошибка может вызвать полную потерю информации. Можно даже с уверенностью утверждать, что целостность данных будет нарушена. С InnoDB такого бы не произошло. Для себя я сделал вывод, что при разработке следует использовать InnoDB, но не злоупотреблять её преимуществами, ибо всегда есть вероятность того, что придётся переходить на MyISAM в целях оптимизации.

P.S. А вообще, не стоит использовать MySQL, лучше использовать PostgreSQL, но эту тему я раскрою несколько позже.

21 комментарий:

Sergey комментирует...
Этот комментарий был удален автором.
Анонимный комментирует...

Ужас. Автор, как можно что-то советовать, ничего в этом не понимая? Где потеря информации? MyISAM отработал корректно, и не какая целостность, не будет нарушена.

Alexxz комментирует...

Вы считаете, что если в результате выполнения запроса изменились не все строки а только половина, причём не известно какая, то это нормальное поведение БД?

Unknown комментирует...

вполне нормальное поведение, жаль что оно не соответствовало Вашим ожиданиям :).
если Вам нужна транзакционность - используйте другой engine. нужна скорость, и Вы готовы ради нее изучить специфику работы таких нетипичных случаев - выбирайте MyISAM. Проекты разные и MySQL дает возможность выбора.

Unknown комментирует...

если отправлять в бд неправильные запросы, то и результат будет "не известно какой". это не проблема типа таблицы.

Анонимный комментирует...

Мда уж. Действительно.
Какие делаете запросы такие и получаете результаты и не нужно винить в этом движок.
update t set a = 1;
Вы захотели присвоить всем элементам столбца a значение 1, но т.к. поле является UNIQUE то было изменено только первая строка.

Анонимный комментирует...

И что, очень часто приходится изменять "по ошибке" ключевое поле? Чаще всего по ошибке или DELETE выполняется с неправильным WHERE, или в UPDATE меняется какое-то другое поле. И что от этого спасет?
P.S. Предпочитаю MyISAM - хотя бы за то что я четко знаю что каждая таблица лежит в отдельном файле и в случае каких-нибудь сбоев не потеряю всю базу целиком, максимум пару таблиц.

Alexxz комментирует...

"Предпочитаю MyISAM - хотя бы за то что я четко знаю что каждая таблица лежит в отдельном файле и в случае каких-нибудь сбоев не потеряю всю базу целиком, максимум пару таблиц." Для этого придумали опцию innodb_file_per_table, а также регулярные бекапы. Кроме того нарушение целостности MyISAM таблицы при отключении питания более вероятное событие, чем у InnoDB.

Анонимный комментирует...

автор конечно отжег! ржунимагу! тупо позор! это же надо написать такую лажу!
Оба движка имеют и преимущества и недостатки, но так тупо "пиарить" один из них, приводя абсурдные аргументы...
Сразу можно поставить вопрос о компетентности автора!
Извечная дилема - "безопасность И объёмы данных + потери в быстродействии" против "производительности И вероятности потерять данные при сбоях". Выбирайте сами кому что а зависимости от поставленных задач. Но табу вроде "Не используйте MyISAM..." быть не должно

Alexxz комментирует...

Уважаемый аноним. Производительность InnoDB уже давно поднялась до MyISAM (за исключением нескольких специфических случаев). Рекомендую вам обновить свои знания в этой области прежде чем кричать то, что было актуально лет 6-7 назад (пройдите хотя бы по ссылке из статьи). Единственное преимущество, которое осталось у MyISAM - FULLTEXT индексы, которые не так уж часто на практике используются.

Александр комментирует...

Херня реально, лучше бы автор привел бы примеры когда нужно использовать myisam, а когда innoDb

nazar-pc комментирует...

Всё абсолютно правильно отработало, вы просто не поняли того, что написали.
Писали от транзакциях? Так вот MyISAM их не имеет (тоже писали), потому он изменил первую запись, а когда наткнулся на ошибку - прекратил работу, но отката не делал (нет такой возможности в MyISAM).

А непонимание работы/не желание разобраться не делает виноватым в этом движок БД!

Alexxz комментирует...

Уважаемый, nazar-pc. Я не говорил, что что-то работает неправильно. Я прекрасно понимаю, почему так происходит. Однако, такое поведение движка БД не является очевидным.

Анонимный комментирует...

Ахаха, молодчага, собрался сбить все столбы вдоль дороги, сбил первый, а до второго не доехал. Теперь возмущается, почему первый столб назад не встал.

А если серьезно, первое значение изменилось на 1 и ошибки не вызвало, а изменить остальные значения на 1 не удалось, потому что сам же прописал полю уникальность.

Анонимный комментирует...

>Вы считаете, что если в результате выполнения запроса изменились не все строки а только половина, причём не известно какая, то это нормальное поведение БД?

И не половина, а только одна, все остальные неудачно пытаются продублировать уникальное значение.

Alexxz комментирует...

>И не половина, а только одна, все остальные неудачно пытаются продублировать уникальное значение.
С точки зрения целостности данных, нет разницы один элемент или десять. Целостность как таковая нарушена.

Анонимный комментирует...

Мдя... действительно, автор, Вы написали громкий заголовок и абсурдный аргумент под ним. Так делать нельзя;)
Теперь давайте вернемся к вопросам оптимизации. Сравним процедурный/модульный подход в программировании с объектно-ориентированным... При желании, написать большой проект можно с любым подходом, но объектно-ориентированный будет значительно быстрее написан. В то же время при "классическом" программировании можно будет написать проект более производительный (оптимизированный), но в то же время будет больше вероятность нарушения каких-либо правил (типа целостности данных). Та же ситуация и в базах данных. Оба движка очень популярны именно потому, что не перекрывают работу друг друга, а направлены в разные направления. Вы можете писать оптимизированный код с более низкоуровневым подходом, но на Вас ложится тяжелый груз: обеспечение целостности данных!!! Либо можете целостность данных взять из движка и писать на более высоком уровне, проигрывая в производительности:)

Анонимный комментирует...

Мдя... действительно, автор, Вы написали громкий заголовок и абсурдный аргумент под ним. Так делать нельзя;)
Теперь давайте вернемся к вопросам оптимизации. Сравним процедурный/модульный подход в программировании с объектно-ориентированным... При желании, написать большой проект можно с любым подходом, но объектно-ориентированный будет значительно быстрее написан. В то же время при "классическом" программировании можно будет написать проект более производительный (оптимизированный), но в то же время будет больше вероятность нарушения каких-либо правил (типа целостности данных). Та же ситуация и в базах данных. Оба движка очень популярны именно потому, что не перекрывают работу друг друга, а направлены в разные направления. Вы можете писать оптимизированный код с более низкоуровневым подходом, но на Вас ложится тяжелый груз: обеспечение целостности данных!!! Либо можете целостность данных взять из движка и писать на более высоком уровне, проигрывая в производительности:)

Eisebio комментирует...

Делаем намеренный "fatal error" в сценарии PHP и после это появится статья "Не используйте PHP" ? )))

Анонимный комментирует...

забавная статья..
автор, ошибка преднамеренная, нельзя ее использовать как аргумента, так как виновник программист, а не MyISAM
Но и поведение не очевидно - согласен, все распинаются что очевидно и какие они умные.. но не согласен с ними. Думаю, субд могла бы выдать ошибку еще перед попыткой выполнить запрос, и не нарушать целостность.. но что если написать set = rand()? тогда без транзакции никак, потому разработчики и не стали заморачиваться над этим в myisam

Анонимный комментирует...

Вы считаете, что если в результате выполнения запроса изменились не все строки а только половина, причём не известно какая, то это нормальное поведение БД?

От неправильных запросов движки не обязаны спасать.
По хорошему нужно было добавить строку и тогда все сработало вполне ожидаемо.
Но движек не будет виноват если кто-то по ошибке добавит ';' после первой строчки.

update t set a=1
Order by a Limit 1;