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


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 / і т.д.).
  • (набагато більше)

Чи існує консенсус у спільноті розвитку щодо того, який варіант є кращим?


2
Немає причин, що "вертикальний" підхід не може мати різні типи даних. Додайте стовпчик int, float та text у рядку. Збережіть / завантажте з нього значення, використовуючи функції, характерні для типу, наприклад, 'SaveConfigInt (' field ', n)'
GrandmasterB

4
З цього питання виникає відмінне запитання StackOverflow, а найвища відповідь дає плюси і мінуси обом підходам. stackoverflow.com/questions/2300356/…
Кевін

1
Підхід 3: Один стовпчик / одиночний рядок з простим форматом обміну даними, як JSON або YAML. Поєднує переваги обох підходів.
шламар

як щодо використання однорядкової таблиці зі складними даними, що містять xml / json, такі як <config> <CompanyName> ACME Inc. </CompanyName> <StartFullScreen> true </StartFullScreen>20<RefreshSeconds></RefreshSeconds> </config> і перевірити об'єкт у бізнес-шарі?
Джон

1
@John: Гарна ідея, якщо потрібні ієрархічні структури. Якщо їх немає, це просто варіант 2 з додатковою складністю.
Хайнзі

Відповіді:


15

Я особисто віддаю перевагу однорядним столам для більшості речей. Хоча це правда, що вона менш гнучка, якщо ви не очікуєте динамічної поведінки, цілком прийнятно додавати додаткові стовпці пізніше, якщо вам потрібно. У певному сенсі це еквівалент використання словника / карти для утримання пар імен-значень проти наявності членів класу при програмуванні. Зрозуміло, це не ідеальна метафора, але багато переваг і недоліків паралельно, коли ви думаєте про це.

Отже, ви б використовували словник / карту над учасниками класу? Напевно, немає, якщо у вас не було підстав вважати, що кількість представлених даних є цілком пристосованим, подібно до того, щоб мати таблицю пар імен-значення.


Що робити, якщо дані, що зберігаються, визначені користувачем? тобто подумайте про інтерфейс користувача, де користувач може створити "поле", вказавши мітку поля, тип даних, який він буде містити тощо. Це означатиме виконання DDL-операторів з коду. Ви б все-таки пішли з варіантом 1?
devanalyst

1
@devanalyst Ні, якщо дані можуть змінюватися від компонента до компонента, тоді не було б сенсу намагатися створити статичну таблицю для її представлення. У такому випадку краще використовувати другий варіант.
Ніл

12

Я зазвичай перейду з варіантом 2, Але я маю декілька стовпців для застосування типу даних

ConfigOption   |   textValue    |   DateValue   |   NumericValue

Варіант 1 Має додаткову перевагу, що ви можете легко «поміняти місцями» цілі конфігурації, додавши Activeстовпець.


Якщо ви збираєтесь дозволити відключення конфігурацій (для варіанту 1), принаймні зробіть це activatedOnчасовою позначкою, щоб ви могли сказати, коли вона була активована. І якщо ви збираєтесь з варіантом 2 ... що станеться, якщо в кінцевому підсумку зберігаються значення в декількох стовпцях (або це оракул, де (мабуть) нуль і порожня рядок еквівалентні)?
Завод-Муза

1
@ X-Zero, зберігання декількох конфігурацій зазвичай робиться для тестування, але часова марка не може зашкодити. Конфігурація технічного обслуговування, виклик, щоб отримати значення, буде знати, який стовпець перевірити, якщо ви дійсно хотіли, ви можете додати стовпець для типу даних .. Але я думаю, що це закінчилося вбивством ...
Morons

5
схема EATV (Entity-Attribute-Type-Value) порушує третю нормальну форму; стовпець "Тип" лише опосередковано пов'язаний з первинним ключем таблиці, через стовпець "Значення", який описує стовпець "Тип". Крім того, динамічне зберігання та інстанція не дуже вирішує проблеми; якщо метод GetConfigValue () може повернути будь-який тип, він повинен повернути Object (або йому якось задати очікуваний тип), який все одно повинен бути оцінений під час виконання.
KeithS

5
Кожен раз, коли варіант 1 був реалізований у програмному забезпеченні, яке я бачив, його потрібно було перетворити на варіант 2. Варіант 2 легше підтримувати в часі, просто потрібно більше часу, щоб правильно вперше здійснити його. Варіант 1 швидкий і простий у здійсненні, але технічне обслуговування з часом жахливе, якщо ваше програмне забезпечення крихітне, без шансів на зростання.
Джиммі Хоффа

8

Для мене, чи ви ходите однорядно або EAV, залежить від того, як ви їх хочете споживати.

Потужність EAV полягає в тому, що нові дані можна додавати без зміни структури. Це означає, що якщо ви хочете нове значення конфігурації, ви просто додаєте його до таблиці та витягаєте його там, де ви хочете його в коді, і вам не потрібно додавати нове поле до домену, схеми, відображення, запитів DAL тощо.

Його недолік полягає в тому, що він має лише найпростішу структуру, що вимагає від вас поводження з даними песимістично. Кожне використання будь-якого значення конфігурації повинно очікувати, що значення не буде чи не у належному форматі, і поводитись відповідно, коли воно не є. Значення конфігурації може не піддаватися подвійному чи інертному чи знаковому знакам. Це може бути недійсним. взагалі може не бути рядка для значення. Шляхи цього зазвичай вимагають існування єдиного дійсного значення "за замовчуванням" для всіх значень конфігурацій певного типу коду ( вкрай рідко; частіше значення за замовчуванням настільки ж проблематичне для використання коду, як і взагалі жодного) або зберігайте твердокодированний словник значень за замовчуванням (який потрібно змінювати щоразу, коли додається новий стовпець, що робить основну перевагу зберігання EAV досить суперечливою).

Один широкий ряд - це навпаки. Ви зіставляєте його в одному екземплярі об'єкта Конфігурація з полем / властивістю для кожного існуючого значення конфігурації. Ви точно знаєте, який тип цих значень повинен бути під час компіляції, і ви «швидко провалюєтесь» у DAL, якщо стовпчик конфігурації не існує або не має значення належного типу, що дає вам одне місце для вилучення винятків на основі про проблеми з конфігурацією / гідратацією.

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

Правильна ситуація, в якій використовувати будь-яке з них, - це ситуація, в якій недоліки пом'якшуються. Для мене більшість ситуацій для кодування конфігурації вимагають реалізації однорядного. Це головним чином тому, що якщо ви вводите абсолютно нове значення конфігурації, яке регулює поведінку певної частини вашої програми, вам вже доведеться змінити код, щоб використовувати нове значення конфігурації; чому б не перескочити на об’єкт config та додати значення, яке буде використано?

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


3

Зокрема, для значень конфігурації я б сказав - перейдіть з одним рядком. Якщо ви зараз не займаєтеся розробкою, як часто ці колонки все-таки змінюватимуться?

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

Крім того, ви сказали, що "користувачі" можуть налаштувати ці параметри, не надаючи обмеження. Чи налаштовані вони на кожного користувача? Якщо це так, я ще сильніше заперечую, що параметри конфігурації повинні бути в стовпцях - один рядок на користувача. Це позбавить від головного болю від технічного обслуговування пізніше.


2

Якщо ваші клієнти можуть обробляти фрагменти JSON (це не лише масиви та словники, але й прості рядки, числа, булеві значення, нульові значення), ви можете мати багаторядкову таблицю з назвою опції та значенням рядка, що містить JSON. Це дозволяє також зберігати структуровані значення, і код для їх обробки вже повинен бути там.

Якщо ваші клієнти не можуть обробити фрагменти JSON, знайдіть нових клієнтів.


1

Плюси одного ряду: чітко визначено. Мінуси: Зміна конфігурації може бути болем. Міграція БД тощо.

Плюси сутності та вартості: Супер гнучка, підтримує еволюцію вашої конфігурації. Мінуси: референтна цілісність? Більше перевіряє ваш код, щоб побачити, чи існує ресурс, перш ніж ви можете зробити що-небудь на ньому.

Я б взяв підхід 2, підкріплений нереляційним db, як Монго. Якщо є щось, в чому ви можете бути впевнені, його зміна.


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    
  ...              |  ...            | ...          

Я думаю, що це гнучкіше.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.