Данные конфигурации: таблица из одной строки в сравнении с таблицей имя-значение-пара

64

Допустим, вы пишете приложение, которое может быть настроено пользователем. Для хранения этих «данных конфигурации» в базе данных обычно используются два шаблона.

  1. Таблица однорядные

      CompanyName  |  StartFullScreen  |  RefreshSeconds  |  ...
    ---------------+-------------------+------------------+--------
      ACME Inc.    |        true       |       20         |  ...
    
  2. Имя-значение пары таблица

      ConfigOption   |   Value
    -----------------+-------------
     CompanyName     | ACME Inc.
     StartFullScreen | true (or 1, or Y, ...)
     RefreshSeconds  | 20
     ...             | ...
    

Я видел оба варианта в дикой природе, и оба имеют очевидные преимущества и недостатки, например:

  • Таблицы из одной строки ограничивают количество возможных вариантов конфигурации (поскольку количество столбцов в строке обычно ограничено). Каждый дополнительный параметр конфигурации требует изменения схемы БД.
  • В таблице «имя-значение-пара» все «строково типизировано» (вы должны закодировать / декодировать параметры Boolean / Date / etc.).
  • (многое другое)

Есть ли в сообществе разработчиков консенсус относительно того, какой вариант предпочтительнее?

Heinzi
источник
2
Нет причин, по которым «вертикальный» подход не может иметь разные типы данных. Добавьте столбец типа int, float и text в каждой строке. Сохраните / загрузите значения из него, используя специфические для типа функции, такие как 'SaveConfigInt (' field ', n)'
GrandmasterB
4
Есть отличный вопрос StackOverflow, спрашивающий об этом, и лучший ответ дает плюсы и минусы обоих подходов. stackoverflow.com/questions/2300356/…
Кевин - Восстановить Монику
1
Подход 3: одна колонка / одна строка с простым форматом обмена данными, таким как JSON или YAML. Сочетает в себе преимущества обоих подходов.
Schlamar
как насчет использования таблицы из одной строки со сложными данными, содержащими xml / json, таких как <config> <CompanyName> ACME Inc. </ CompanyName> <StartFullScreen> true </ StartFullScreen> 20 <RefreshSeconds> </ RefreshSeconds> </ config> и проверить объект на бизнес-уровне?
Джон
1
@Джон: Хорошая идея, если нужны иерархические структуры. Если это не так, это просто вариант 2 с добавленной сложностью.
Хайнци

Ответы:

15

Я лично предпочитаю однорядные таблицы для большинства вещей. Хотя это правда, что он менее гибкий, если только вы не ожидаете динамического поведения, вполне допустимо добавлять дополнительные столбцы позже, если вам это нужно. В некотором смысле, это эквивалент использования словаря / карты для хранения пар имя-значение по сравнению с наличием членов класса при программировании. Конечно, это не идеальная метафора, но многие из преимуществ и недостатков параллельны, когда вы думаете об этом.

Так вы бы использовали словарь / карту над учениками? Вероятно, нет, если у вас не было оснований полагать, что объем представляемых данных полностью адаптируем, как если бы у вас была таблица пар имя-значение.

Нил
источник
Что делать, если данные для хранения определяются пользователем? т.е. подумайте о пользовательском интерфейсе, в котором пользователь может создать «поле», указав метку поля, тип данных, которые он будет содержать и т. д. Это будет означать выполнение операторов DDL из кода. Вы все еще выбрали бы вариант 1?
Деваналист
1
@devanalyst Нет, если данные могут меняться от компонента к компоненту, не имеет смысла пытаться создать статическую таблицу для ее представления. В этом случае было бы лучше использовать второй вариант.
Нил
12

Как правило, я бы пошел с вариантом 2, но у меня было бы несколько столбцов для обеспечения типа данных

ConfigOption   |   textValue    |   DateValue   |   NumericValue

Вариант 1 обладает дополнительным преимуществом, благодаря которому вы можете очень легко «поменять» все конфигурации, добавив Activeстолбец.

Идиоты
источник
Если вы собираетесь разрешить отключение конфигураций (для варианта 1), по крайней мере, сделайте это activatedOnотметкой времени, чтобы вы могли определить, когда она была активирована. И если вы переходите к варианту 2 ... что произойдет, если в итоге значения будут храниться в нескольких столбцах (или это оракул, где (по-видимому) нулевые и пустые строки эквивалентны)?
Заводная муза
1
@ X-Zero, хранение нескольких конфигураций обычно выполняется в целях тестирования, но отметка времени не повредит. Техническое обслуживание конфигурации, вызов для получения значения будет знать, какой столбец проверять, если вы действительно хотите, вы можете добавить столбец для типа данных ... Но я думаю, что это уже
неубедительно
5
схема EATV (Entity-Attribute-Type-Value) нарушает третью нормальную форму; столбец Тип только косвенно связан с первичным ключом таблицы через столбец Значение, который описывает столбец Тип. Кроме того, хранение и создание динамических типов не решает много проблем; если метод GetConfigValue () может вернуть любой тип, он должен вернуть Object (или каким-либо образом получить ожидаемый тип), который все еще должен оцениваться во время выполнения.
KeithS
5
Каждый раз, когда вариант 1 был реализован в программном обеспечении, которое я видел, его пришлось преобразовать в вариант 2. Вариант 2 легче поддерживать с течением времени, просто требуется больше времени для правильной реализации в первый раз. Вариант 1 является быстрым и простым в реализации, но обслуживание с течением времени ужасно, если ваше программное обеспечение не является крошечным и не имеет возможности расти.
Джимми Хоффа
8

Для меня, если вы идете в один ряд или EAV, зависит от того, как вы хотите их использовать.

Сила EAV в том, что новые данные могут быть добавлены без изменений в структуре. Это означает, что если вам нужно новое значение конфигурации, вы просто добавляете его в таблицу и извлекаете его там, где хотите, в коде, и вам не нужно добавлять новое поле в запрос домена, схемы, сопоставления, запросов DAL. , и т.д.

Его недостаток в том, что он имеет только самую незначительную структуру, требующую от вас пессимистического отношения к данным. Каждое использование любого значения конфигурации должно ожидать, что значение не будет присутствовать или не в правильном формате, и вести себя соответственно, когда это не так. Значение config не может быть разборчиво в double, либо в int, либо в char. Это может быть ноль. может не быть строки для значения вообще. Обходные пути обычно требуют наличия единого действительного значения «по умолчанию» для всех значений конфигурации определенного типа в коде ( крайне редко; чаще всего значение по умолчанию столь же проблематично для потребления кода, как и вообще никакого), или сохраняйте жестко закодированный словарь значений по умолчанию (который должен меняться при каждом добавлении нового столбца, что делает основное преимущество хранилища EAV довольно спорным).

Один широкий ряд в значительной степени противоположен. Вы сопоставляете его с одним экземпляром объекта конфигурации с полем / свойством для каждого существующего значения конфигурации. Вы точно знаете, какого типа должны быть эти значения во время компиляции, и вы «быстро терпите неудачу» в DAL, если столбец конфигурации не существует или не имеет значения правильного типа, что дает вам одно место для поиска исключений на основе по поиску конфигурации / проблемы с гидратацией.

Основным недостатком является то, что для каждого нового значения требуется структурное изменение; новый столбец БД, новый столбец в DAL (сопоставление или SQL-запросы / SP), новый столбец домена, все необходимое для правильного тестирования использования.

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

Короче говоря, схема EAV для хранения конфигурации действительно не решает проблему, которую она намеревается решить, и большинство обходных путей для проблем, которые она представляет, нарушают DRY.

Keiths
источник
3

Специально для значений конфигурации, я бы сказал - перейти с одной строки. Если вы сейчас не проходите разработку, как часто эти столбцы будут меняться?

Вероятно, лучше всего защитить тип данных значений , а не код для расширяемости, который вы вряд ли будете иметь во время простоя между большими (r) выпусками. Кроме того, добавление или удаление одного столбца является почти самой простой миграцией. Я не вижу головной боли при создании новой опции конфигурации.

Кроме того, вы сказали, что «пользователи» могут настроить эти параметры, не ограничивая их. Это конфигурации для каждого пользователя? Если это так, я буду еще сильнее утверждать, что параметры конфигурации должны быть в столбцах - по одной строке на пользователя. Это сэкономит много головных болей обслуживания позже.

Izkata
источник
2

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

Если ваши клиенты не могут обработать фрагменты JSON, найдите новых клиентов.

gnasher729
источник
1

Однорядные плюсы: хорошо определены. Минусы: изменение конфигурации может быть проблемой. Миграция БД и т.д ..

Entity-Value Pros: Супер гибкий, поддерживает развитие вашей конфигурации. Минусы: ссылочная целостность? Дополнительные проверки в вашем коде, чтобы увидеть, существует ли свойство, прежде чем вы можете что-либо сделать с ним.

Я бы взял подход 2, поддержанный нереляционной БД, такой как Монго. Если есть что-то, в чем вы можете быть уверены, это изменится.

JVXR
источник
1

Используйте оба!

Разберитесь, какие параметры могут иметь несколько экземпляров, и какие параметры являются общими.

Однорядная таблица (конфигурации)

  id  |  company_name  |  start_fullscreen  |  refresh_seconds  |  ...
------+----------------+--------------------+-------------------+-------
  4   |  ACME Inc.     |  true              |  20               |  ...

Таблица имя-значение-пара (параметры)

  name             |  value          | update_time  
-------------------+-----------------+--------------
  generic_option_1 |  Option 1 Value | timestamp    
  generic_option_2 |  Option 2 Value | timestamp    
  generic_option_3 |  Option 3 Value | timestamp    
  configuration    |  4              | timestamp    
  ...              |  ...            | ...          

Я думаю, что это более гибко.

Эндрю Лука
источник