Хранение значений enum в базе данных

#sql-server #database-design #enums

#sql-сервер #база данных-дизайн #перечисления

Вопрос:

К вашему сведению: я явно имею в виду SQL Server 2000-8 и C #. Итак, СУБД с поддержкой enum, такие как MySQL, не являются предметом моего вопроса.

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

  1. Сохраните enum как int в db и извлеките значение enum (или атрибут описания enum с использованием отражения) в коде:
    это подход, который я обычно использую. Проблема в том, что когда я пытаюсь выполнить запрос из базы данных в SSMS, извлеченные данные трудно понять.

  2. Сохраните перечисление как строку (varchar) в базе данных и преобразуйте обратно в int в коде.
    На самом деле, это может быть лучшим решением. Но (не смейтесь!) это кажется неправильным. Я не уверен насчет минусов. (За исключением большего пространства в БД, что обычно приемлемо) Итак, что-нибудь еще против этого подхода?

  3. Создайте отдельную таблицу в db, которая синхронизирована с определением enum в коде, и установите связь внешнего ключа между вашей основной таблицей и таблицей enum.
    Проблема в том, что когда другое значение enum должно быть добавлено позже, необходимо обновить и код, и базу данных. Кроме того, могут быть опечатки, которые могут быть проблемой!

Итак, в общем случае, когда мы можем принять накладные расходы на БД во 2-м решении, каков наилучший способ хранения значений enum в БД? Существует ли общее определенное правило шаблона проектирования по этому поводу?
Спасибо.

Ответ №1:

Определенного правила проектирования (о котором я знаю) не существует, но я предпочитаю подход № 1.

  1. Это подход, который я предпочитаю. Это просто, и перечисления обычно достаточно компактны, чтобы я начал запоминать, что означают цифры.
  2. Это более читабельно, но может помешать рефакторингу или переименованию ваших значений перечисления, когда вы захотите. Вы теряете некоторую свободу своего кода. Внезапно вам нужно подключить администратора базы данных (в зависимости от того, где / как вы работаете) просто для изменения значения перечисления или страдать с этим. Синтаксический анализ enum также оказывает некоторое влияние на производительность, поскольку в игру вступают такие вещи, как Locale, но, вероятно, незначительное.
  3. Какую проблему это решает? Где-то в таблице все еще есть нечитаемые числа, если только вы не хотите добавить накладные расходы на объединение. Но иногда это тоже правильный ответ, в зависимости от того, как используются данные.

РЕДАКТИРОВАТЬ: У Криса в комментариях был хороший момент: если вы все-таки перейдете к числовому подходу, вам следует явно присвоить значения, чтобы вы могли также изменить их порядок. Например:

 public enum Foo
{
     Bar = 1,
     Baz = 2,
     Cat = 9,
     //Etc...
}
  

Комментарии:

1. Хм, вы правы. № 2 вызывает проблемы, если мы хотим переименовать значения enum. 1 Спасибо!

2. Номер 1 вызывает проблемы, если вы когда-либо измените порядок своих перечислений.

3. @Chris: Тогда явно определите значения.

4. @Крис Морган: Вот почему я никогда не определяю перечисления, не определив их int значение явно.

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

Ответ №2:

Одна идея, которую я видел раньше, которая является вашим вариантом 3 более или менее

  • Таблица в базе данных (для внешних ключей и т.д.)
  • Соответствующее перечисление в клиентском коде
  • Проверка при запуске (через вызов базы данных), чтобы убедиться, что они совпадают

Таблица database table может иметь ограничение trigger или check для уменьшения риска изменений. У него не должно быть никаких разрешений на запись, поскольку данные привязаны к выпуску клиентского кода, но это добавляет фактор безопасности на случай сбоев администратора базы данных

Если у вас есть другие клиенты, читающие код (что очень распространено), то в базе данных есть полные данные.

Комментарии:

1. Как насчет join накладных расходов? Стоит ли оно того?

2. @Kamyar: ОБЪЕДИНИТЬ служебные данные в database engine? Вы издеваетесь надо мной, верно?

3. не вызывает ли это накладных расходов? Во многих статьях рекомендуется использовать меньше соединений. (До тех пор, пока это не очень сильно повредит нормализации) например: sql-server-performance.com/2007/database-design