«Восемь смертных грехов» MySQL Enums

база данных MySQL
первоисточник8 Reasons Why MySQL's ENUM Data Type Is Evil

«Восемь смертных грехов» MySQL Enums

Среда, 2 марта 2011 г.

MySQLТип перечисления (ENUM)Это горячая тема для обсуждения среди программистов. На первый взгляд, мы вполне можем ограничить значения записи допустимым диапазоном через тип перечисления. Типичным примером является таблица данных с полем «Континентальные плиты»: каждая страна расположена на континентальной плите, которая вряд ли будет часто меняться. Конечно, может быть, когда-нибудь Североамериканская плита столкнется с Азиатской плитой, чтобы сформироватьСеверная Америка Азия, Но даже если ваша база данных может продолжать использоваться до этого времени, по крайней мере, вам не нужно изучать, как реконструировать вашу таблицу данных, это будет работа разработчиков в то время.

Ближе к дому. Если использование ENUM является единственным выбором, который может представить, к какой континентальной плите принадлежит страна, то мы можем перейти к следующему шагу, чтобы обсудить плюсы и минусы NoSQL, Git и SVN, а также какие фреймворки вам нравятся? вопросы. Но вот общая лучшая практика для реализации перечислений:

Comparison of ENUM vs Reference Table

ВикипедияВот как описывается реляционная таблица:

... это своего рода таблица, в которой выделяются известные данные перечисления. Например, в хранилище данных реляционной базы данных «объект» на складе может иметь поле «статус» для записи заявленной стоимости, например: «продано, зарезервировано, распродано». В минималистском дизайне базы данных эти значения будут храниться в отдельной реляционной таблице «состояние», чтобы удовлетворить парадигму (database normalization).

Следовательно, реляционные таблицы также могут удовлетворять реализации перечисления. Давайте посмотрим, каковы «восемь смертных грехов» ENUM:

1. С данными обращаются неправильно

Мужчина, женщина; Мистер, Миссис, Мисс; Африка, Азия и т. д. Эти короткие слова, которые люди используют в качестве полей типа ENUM, называютсяданные. Когда вы используете поле типа enum, технически видно, что вы берете данные (когда вы соответствуете фактическому листу данных), помещаете их в независимую позицию (база данных метаданных с точным полем определения). Это разные и ограничивающие типы данных, такие как наша обычная практика: поля значений могут хранить только целочисленные данные, или поле даты не может быть пустым — это не проблема, и это тоже очень важно. При использовании поля типа Enum мы фактически сохраняемсячасть данныхигратьэта модель данныххарактерная информация о . короче, Поля типа ENUM нарушают требование парадигмы. Это может показаться очень «академичным» или «педантичным», но отсюда и берутся следующие «преступления».

2. Изменение поля типа ENUM дорого обходится

Неизменным является то, что каждый раз, когда вы создаете поле типа ENUM, вы говорите: «Это поле нельзя изменить». Людям обычно не хватает способности учитывать общую ситуацию, а прогноз еще хуже, например, новую продуктовую линейку отдела исследований и разработок, новый план отгрузки вашей компании и столкновение Североамериканской плиты с Азиатской плитой.

使用ALTER TABLE去修改整个数据表的ENUM类型字段,是十分耗费资源的。 еслиENUM('red', 'blue', 'black')изменить наENUM('red', 'blue', 'white'), MySQL необходимо перестроить всю таблицу данных и получитьвсе данныеПроверять'black'Это недопустимое значение. MySQL действительно глуп, и он падает каждый раз, когда выУвеличиватьНовое значение ENUM делает это! (Ходят слухи, что эффективность полей типа ENUM будет рассмотрена в будущем, но у меня есть серьезные сомнения относительно ее важности.)

Полная реконструкция таблицы в небольшой таблице данных может быть не такой болезненной, но в случае массивных данных может привести к блокировке ресурсовОчень длинныйПериод времени. Если вы используете реляционную таблицу вместо поля типа ENUM, изменение коллекции перечисления — это просто вопрос использованияINSERT,UPDATEиDELETE, что смешно в сравнении.

Важно отметить, что при изменении набора перечислений для поля типа ENUM MySQL преобразует любую существующую запись, которая не существует в новом наборе перечислений, в значение''(пустой строки). С реляционными столами существует гораздо больше гибкости в изменении и удалении перечисленных коллекций (упомянутых ниже).

3. Почти невозможно добавить дополнительные свойства к связанным данным

Adding related info to a reference table

Пока никто не может быть большемудроИзмените метод поля типа ENUM, что также является нашей нормой. В нашем примере «Страна, континентальные плиты» что происходит, когда изменяется «Территория страны»? Мы не ожидали этого свойства, но оно должно быть там. Используя дизайн реляционной таблицы, мы можем легко расширить таблицу данных «континентальной плиты», добавляя в нее данные и поля, которые мы хотим, различными способами. ПЕРЕЧИСЛЕНИЕ? Хватит говорить.

Еще одна замечательная гибкость — это простота расширения реляционных таблиц. Простое битовое поле флага может указать, доступно ли это «значение перечисления». Так что, если ваша компания не планирует продавать черные украшения, вы можете просто поставить «черный»is_discontinuedПросто сделайте отметку в поле. И вы все еще можете запросить проданные цветав то же времяЧерные украшения, которые вы все еще можете заказать эти статистики могут посчитать о! Enum, вы любите попробовать?

4. Очень хлопотно получить все возможные значения ENUM

Очень распространенным требованием является отображение данных, существующих в базе данных, в перетаскиваемом списке, например:

выберите цвет:

красный синий черный

Если эти значения хранятся в таблице данных под названием «цвета», все, что вам нужно сделать, это:SELECT * FROM colors, чтобы данные можно было динамически отображать в перетаскиваемом списке. Вы можете добавлять или изменять цвета в таблице соотношений цветов, и параметры цвета для вашего классного заказа будут автоматически обновляться, что удивительно. (Перевод: пример здесь должен быть эквивалентен: «С помощью фонового управления вы можете ограничить параметры определенного типа данных для внешних пользователей». Такая функция.)

Вернуться на Enum: Как вы получаете все перечисленные значения? Конечно, вы можете использовать значения Enum Go с отчетливым запросом (перевод: enum Query, который не совпадает с значением данных друг друга, равна уникальности запроса enum, используя отчетливый), но это только вернет толькоОн действительно используется и существует в необязательном значении поля ENUM таблицы данных.Значения ENUM, а не все возможные значения. Вы также можете запросить INFORMATION_SCHEMA и проанализировать возвращенные данные с помощью кода, чтобы найти все значения, которые вы хотите для ENUM, но это совершенно избыточно. На самом деле, я так и не нашел элегантного и нативного SQL-способа получить все значения полей типа ENUM.

5. Ограниченная оптимизация, обеспечиваемая полями типа ENUM.

Обычно оправданные причины использования ENUM не более чем слово «оптимизация», такие как повышение производительности, упрощение модели и высокая читабельность.

Затем смотрим на производительность. В неоптимизированной базе данных можно делать много странных и преувеличенных вещей, но в большинстве случаев это не влияет на производительность, пока данные не достигнут определенного масштаба, а обычно наши продукты далеки от этого масштаба. Следует отметить, что, поскольку разработчики баз данных стремятся сделать свои проекты достижимымиполная парадигма, и будет рассматриваться только в том случае, если у вас есть проблемы с производительностьюАнтипарадигма. Если вы обеспокоены замедлением, вызванным использованием реляционных таблиц, вы можете проверить производительность различных методов на том же этапе, прежде чем рассмотреть его. Не думайте, что реляционный запрос будет узким местом, оно может не быть иногда. (Ссылаться наevidence to support that ENUM isn't always appreciably faster than alternatives.)

Еще одно утверждение о способе оптимизации ENUM заключается в том, что ENUM может эффективно уменьшить количество внешних ключей таблиц данных в базе данных. Нельзя отрицать, что использование внешних ключей равнозначно соединению множества разных ящиков линиями, а в больших системах разработка парадигмы может уменьшить границы человеческого понимания и требования к сложным запросам. Но зачем мы разрабатываем модель, зачем мы абстрагируем модель, чтобы понять ее. Попробуйте создать новую диаграмму модели данных или диаграмму ER и проигнорируйте некоторые мелкие детали и реляционные таблицы. Иногда использование ENUM делает точно так же, какэто выглядит так просто, но на самом деле вам нужно иметь в виду неявную реляционную таблицу, поэтому нетэто выглядит так просто.

6. Значения ENUM нельзя напрямую повторно использовать в других листах данных

Когда вы создаете поле ENUM со значением (в таблице данных), вы не можете повторно использовать этот ENUM непосредственно в других таблицах данных. При наличии реляционной таблицы одну и ту же форму приложения можно повторно использовать в нескольких других таблицах данных. При изменении одних данных в реляционной таблице отреагируют и другие таблицы данных.

A reference table can easily be linked to multiple tables

Разделение полей типа ENUM позволит вам повторно использовать одно и то же значение ENUM в нескольких таблицах данных (требуется согласованность).

7. Поля типа ENUM имеют очевидные подводные камни

Предположим, вы установили поле "цвет"ENUM('blue', 'black', 'red'), когда ты хочешьINSERTОдна строка данных, но поле «цвет»'purple'MySQL изменит недопустимое значение''(пустая строка). Нет проблем с этим, но если мы используем таблицу с отношениями внешнего ключа, то мы можем из-за надежности данных и более надежных.

Точно так же MySQL связывает индексы перечисления со значениями ENUM и неправильно вызывает индексы вместо используемых значений ENUM, и наоборот.

Давайте представим:

CREATE TABLE test (foobar ENUM('0', '1', '2'));

mysql> INSERT INTO test VALUES ('1'), (1);
Query OK, 2 rows affected (0.00 sec)
Records: 2  Duplicates: 0  Warnings: 0

mysql> SELECT * FROM test;
+--------+
| foobar |
+--------+
| 1      |
| 0      |
+--------+
2 rows in set (0.00 sec)

Мы вставили '1' (нить), и случайно вставил 1 (Нет цитаты, числовые). MySQL 会将我们地数值型数据当作是枚举索引去处理(并没有错,但会令人混淆),根据索引可知,ENUM字段的第一个值为 0 。 (译:枚举索引由 1 开始)

8. ENUM не переносим

Тип ENUM не является стандартом SQL, он принадлежит MySQL, и другие СУБД могут не иметь встроенной поддержки.PostgreSQL, MariaDBDrizzle(Последние два являются ответвлениями MySQL), я знаю только, что эти три поддерживают ENUM. Если кто-то собирается мигрировать базу данных, то он потратит больше шагов на то, чтобы разобраться с вашими "тонкими" полями ENUM, полагаю, он вас "полюбит больше". Если (этот человек) ты, Вы можете найти себя «достаточно умным» в то время. Вообще говоря, миграции баз данных происходят не так уж часто, а поскольку все предполагают, что в процессе миграции базы данных что-то пойдет не так, это становится «восьмым смертным грехом».

Когда уместно использовать ENUM:

1. Когда вам нужно хранить точные неизменяемые значения

Континентальные плиты — лучший пример, и определение очень точное. Другим распространенным примером является титул: мистер, миссис, мисс или покерная масть: бубны, трефы, червы, пики. Однако даже в этих примерах иногда нужно расширить диапазон значений (например, когда кому-то нужно, чтобы вы называли «Доктор Чен» вместо «Мистер Чен», или когда вам нужна карта-джокер в игре в покер).

2. Вам никогда не нужно хранить дополнительную связанную информацию

Вернемся к примеру с игрой в карты. Игра в покер, подходящая для всех возрастов, основывается на правилах, согласно которым трефы и пики — черные, а бубны и черви — красные (например, уке). Что, если нам нужно связать дополнительную информацию для мастей, например, цвет? Если мы используем реляционные таблицы, то нам нужно только добавить поля в реляционную таблицу, тривиальное дело. Если мы используем ENUM для представления мастей, нам трудно точно представить связь между мастями и цветами, поэтому мы можем добиться этой ассоциации только на прикладном уровне.

3. Количество значений ENUM больше, чем2и меньше чем20Кусок

Если ваше значение Enum равно двум, выабсолютно нормальноЗамените ENUM более эффективным TINYINT(1) или более эффективным BIT(1) (MySQL 5.0.3 и выше). Например:gender ENUM('male', 'female')можно преобразовать в:is_male BIT(1), Когда у вас есть только два варианта, вполне возможно использовать логическое значениеtrue/false, в сочетании с ключевым словом "есть" в имени поля для различения. Что касается предела 20, то да, ENUM может вместить до 65535 значений, но, пожалуйста, не пытайтесь. Более двадцати значений могут стать громоздкими, а более 50 должны быть сложными в управлении и использовании.

Если вы все равно используете ENUM:

1. Не используйте числовые типы для значений ENUM

Enum определяется кактип персонажаДанные существуют по какой-то причине. не то что ты используешьЧисловойНеправильно хранить числа в типе поля, но есть достаточно свидетельств того, что внутренний механизм MySQL использует числа для ссылки на индексы (см. пункт 7 выше). В любом случае, не храните числа в ENUM, хорошо?

2. Рассмотрите возможность использования строгого режима

Включение строгого режима, по крайней мере, сообщите об ошибке, если вы внесите не существующее значение enum. В противном случае появляется предупреждение, и значение устанавливается в пустую строку""(индекс перечисления равен 0). Расшифровка: если вы установите IGNORE, ошибки все равно будут игнорироваться.

в заключении

Выполняйте значимые действия с точки зрения разработки и сопровождения и рассматривайте возможность оптимизации при возникновении проблем с производительностью — вообще говоря, вопрос о том, использовать ли реляционные таблицы или использовать типы ENUM, является спорным.

Неоспоримым фактом является злоупотребление узкими местами производительности (концепция). Разработчики тратят много времени, думая об этом, беспокоясь о (например) скорости некритического кода. Эти требования к эффективности оказывают большое негативное влияние на отладку и обслуживание. Мы должны игнорировать эту небольшую часть эффективности и взять (достичь)97%(Эффективность) Преждевременная оптимизация — корень всех зол.

Хотя мы не должны отказываться от оптимизации этого3%(Эффективность), но отличный разработчик не должен слепо довольствоваться этой целью (перевод: относится к стремлению к высокой эффективности и должен знать код ключа для обработки кода ключа. Но это также должно выполняться при условии понимания кода. -Donald Knuth


komlenic.com is the weblog/playground of Chris Komlenic, a full stack developer and generalist living in central Pennsylvania.