Коли ви починаєте переходити до "визначених користувачем полів", як це часто зустрічається в трекерах помилок, керуванні ресурсами клієнтів та подібних бізнес-інструментах, це те, що вони не підкріплені таблицею з мільйонними полями (якщо вони є, то ймовірно, це проблема своє).
Замість цього ви знайдете проекти таблиць значення атрибутів сутності та пов'язаний інструмент адміністрування для управління дійсними атрибутами.
Розглянемо наступну таблицю:
+ -------------- +
| річ |
| -------------- |
| id |
| тип |
| desc |
| attr1 |
| attr2 |
| attr3 |
| attr4 |
| attr5 |
+ -------------- +
Це після того, як ви додали кілька атрибутів. Замість того , щоб attr1
робити вигляд , що читає artist
або tracks
або genre
або будь-які атрибути речі є. І замість 5, що робити, якщо це було 50. Очевидно, що це не піддається управлінню. Також потрібно оновити модель та перерозподілити додаток для обробки нового поля. Не ідеально.
Тепер розглянемо таку структуру таблиці:
+ -------------- + + --------------- + + ------------- +
| річ | | thing_attr | | attr |
| -------------- | | --------------- | | ------------- |
| id | <--- + | thing_id (fk) | +> | id |
| тип | | attr_id (fk) | + - + | назва |
| desc | | значення | | |
+ -------------- + + --------------- + + ------------- +
У вас є ваша річ з її основними полями. У вас є ще дві таблиці. Один з атрибутами. Кожне поле - це рядок у attr
таблиці. А потім є thing_attr
сторона із закордонними клавішами, що відносяться до thing
столу та attr
столу. Тоді у цьому полі є значення, у якому ви зберігаєте незалежно від значення поля для цієї сутності.
А тепер у вас є структура, в якій таблицю attr можна оновлювати під час виконання, а нові поля можна додавати (або видаляти) на льоту, без істотного впливу на загальну програму.
Запити трохи складніші, і перевірка також стає складнішою (або фанкі, що зберігаються, або всі клієнтські сторони). Це торгівля дизайном.
Розглянемо також ситуацію, коли одного дня вам потрібно зробити міграцію, і ви повернетесь до програми, щоб побачити, що зараз є півдесятка або більше атрибутів, ніж схема, яку ви спочатку розповсюджували. Це спричиняє потворні міграції та оновлення, коли таблиця значення атрибутів суб'єкта господарювання при правильному використанні може бути чистішою. (Не завжди, але може бути.)
Чи є недоліки просто змінити схему під час виконання? Якщо користувач вважає, що річ потребує нового атрибута, просто динамічно додайте стовпчик до таблиці?
Якщо ви працюєте з відповідним ароматизатором бази даних nosql, ви, ймовірно, могли б це зробити (зауважте, що відповідний аромат nosql для цього, ймовірно, буде сховищем ключових значень , а це - таблиця EAV для реляційних, описаних вище) без зайвих клопотів. Однак це стосується всіх компромісів для nosql, які описані в інших місцях дуже докладно.
Якщо ви замість цього працюєте на реляційній базі даних - вам потрібно мати схему. Додавання стовпця динамічно означає, що деякі підмножини наступних речей є істинними:
- Ви займаєтесь програмуванням метабаз. Замість того, щоб мати можливість чітко відобразити цей стовпець у цьому полі за допомогою хорошого ORM, ви, ймовірно, робите такі речі, як,
select *
а потім робите якийсь складний код, щоб дізнатися, що саме є даними (див . ResultSetMetaData Java ), а потім зберігаєте їх у карті ( або якийсь інший тип даних - але не непогані поля в коді). Це викидає неабияку безпеку типу та друку, яку ви маєте при традиційному підході.
- Ви, ймовірно, відмовилися від ORM. Це означає, що ви пишете raw sql для всього коду, а не дозволяєте системі виконувати роботу за вас.
- Ви кинули робити чисті оновлення. Що відбувається, коли клієнт додає поле з одним ім'ям, яке також використовує ваша наступна версія? На сайті сватання оновлення, яке хоче додати
hasdate
поле для зберігання часової позначки, вже визначене як hasdate
з булевим для успішного матчу ... і ваше оновлення перерветься.
- Ви довіряєте, що клієнт не порушує систему, використовуючи якесь зарезервоване слово, яке також порушує ваші запити ... десь.
- Ви прив'язали себе до однієї марки БД. DDL різних баз даних відрізняються. Типи баз даних - найпростіший приклад цього.
varchar2
проти text
тощо. Ваш код для додавання стовпця буде працювати на MySQL, але не на Postgres або Oracle або SQL Server.
- Чи довіряєте ви клієнт насправді додати дані добре ? Звичайно, EAV далеко не ідеальний, але тепер у вас є жахливі незрозумілі назви таблиць, які розробник не додав, з неправильним типом індексу (якщо такий є), без обмежень, що додаються в код, де потрібно бути тощо.
- Ви надали права модифікації схеми користувачеві, який запускає додаток. Таблиці скидання Little Bobby неможливі, якщо ви обмежені в SQL, а не DDL (впевнені, що можете зробити це
delete * from students
замість цього, але ви не можете дійсно зіпсувати базу даних поганими способами). Кількість речей, які можуть зірватися з доступом до схеми або через аварію чи зловмисну активність.
Це дійсно зводиться до "не робіть цього". Якщо ви дійсно цього хочете, перейдіть до відомого шаблону структури таблиці EAV або бази даних, яка повністю присвячена цій структурі. Не дозволяйте людям створювати довільні поля в таблиці. Головні болі просто не варті того.