EAV - чи справді це погано у всіх сценаріях?


65

Я думаю про використання моделі сутнісних атрибутів-значень (EAV) для деяких речей в одному з проектів, але всі питання про нього в "Переповнюванні стека" закінчуються відповідями, що називають EAV антидіаграмою.

Але мені цікаво, чи не так це у всіх випадках.

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

Все це припускає, що для відображення списку товарів достатньо інформації в таблиці продуктів (це означає, що EAV не задіяна), а також лише коли показується один продукт / порівнюється до 5 товарів / тощо. використовуються дані, збережені за допомогою EAV.

Я бачив такий підхід у торгівлі Magento, і він досить популярний, тож чи бувають випадки, коли EAV є розумним?



Для прикладу справді добре розробленої схеми EAV, погляньте на базу даних Datomic. Він зберігає все у шаблоні EAVT (T - "часова марка", насправді більше нагадує ідентифікатор транзакції). Їх [документація щодо індексування] (docs.datomic.com/indexes.html), здається, найкраще показує це. Для прикладу того, як EAV страшенно працює, див. Wordpress .
Ден Росс

Відповіді:


80

https://web.archive.org/web/20140831134758/http://www.dbforums.com/database-concepts-design/1619660-otlt-eav-design-why-do-people-hate.html

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

З іншого боку, вона працює дуже погано у випадку неправильно визначеного запиту і може підтримувати інші погані практики.

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


32
Любіть останнє речення.
Зохар Пелед

2
Гниле посилання. Чи є десь кешована версія?
Wildcard

1
Не переходьте за посиланням. Сторінка завантажується повільно і не є корисною. Також такі смердючі форуми у старому стилі. Замість цього використовуйте переповнення стека! Запропонуйте хороші / корисні відповіді та натисніть сміття.
Джесс

29

У двох словах, EAV корисний, коли ваш список атрибутів часто зростає або коли він настільки великий, що більшість рядків заповнюватиметься здебільшого NULL, якщо ви зробили кожен атрибут стовпцем. Він стає антидіаграмою, коли використовується поза цим контекстом.


16
Я б замінив "часто" на "потребує можливості змінити під час виконання".
Док Браун

3
Ми можемо ще більше скоротити цього Дока Брауна, використовуючи досить добре зрозуміле слово "динамічний" - EAV корисний, коли ваш список атрибутів може динамічно змінюватися.
Олександр Міллс

Навіть далі до "коли ваші атрибути можуть змінюватися" - "динамічно" є дещо зайвим у цьому контексті :)
Wranorn

1
Чи обов'язково корисніше, ніж, скажімо, форма для зміни атрибута виконувати а CREATE TABLEдля нового атрибута?
Даміян Єрік

@DamianYerrick цікавий підхід. Ви використовували це у виробництві?
графа

21

Скажімо, товарний предмет магазину, у нього є спільні риси, такі як назва, опис, зображення, ціна тощо, які беруть участь у логіці у багатьох місцях і мають (напів) унікальні особливості, такі як годинник та пляжний м'яч описуються абсолютно іншими аспектами . Тож я думаю, що EAV підходить для зберігання цих (напів) унікальних особливостей?

Використання структури EAV для має кілька наслідків, які є компромісними.

Ви торгуєте "менше місця для рядка, оскільки у вас немає 100 стовпців, null" проти "складніших запитів та моделі".

Наявність EAV зазвичай означає, що значення є рядком, в який можна заповнити будь-які дані. Це може мати наслідки для перевірки дійсності та обмежень. Розглянемо ситуацію, коли ти помістив кількість акумуляторів, що використовуються як щось у таблицю EAV. Ви хочете знайти ліхтарик, який використовує батареї розміром C, але менше 4 з них.

select P.sku
from
  products P
  attrib Ab on (P.sku = Ab.sku and Ab.key = "batteries")
  attrib Ac on (P.sku = Ac.sku and Ac.key = "count")
where
  cast(Ac.value as int) < 4
  and Ab.value = 'C'
  ...

Тут потрібно усвідомити, що не можна розумно використовувати індекс за значенням. Ви також не можете перешкодити комусь вводити щось, що не є цілим числом, або недійсне ціле число (використовує батареї '-1'), оскільки стовпець значення використовується знову і знову для різних цілей.

Це потім має наслідки в спробі написати модель для продукту. У вас будуть приємні набрані значення ... але ви також будете Map<String,String>просто сидіти там з усілякими речами в ньому. Це може мати подальші наслідки при серіалізації його до XML або Json та складності спроб зробити перевірку чи запити проти цих структур.

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

Ви також можете мати пов’язані таблиці, що містять атрибути певного класу продукту. У продуктовому відділі може бути ще одна таблиця, яка містить кілька атрибутів, пов’язаних із нею, які будівельні матеріали не потребують (і навпаки).

+----------+    +--------+    +---------+
|Grocery   |    |Product |    |BuildMat |
|id (fk)   +--->|id (pk) |<---+id (fk)  |
|expiration|    |desc    |    |material |
|...       |    |img     |    |...      |
+----------+    |price   |    +---------+
                |...     |               
                +--------+               

Бувають випадки, коли особливо потрібна таблиця EAV.

Розглянемо ситуацію, коли ти не просто пишеш систему інвентаризації для своєї компанії, де ти знаєш кожен товар та кожен атрибут. Ви зараз пишете систему інвентаризації, щоб продати іншим компаніям. Ви не можете знати кожен атрибут кожного продукту - їх потрібно буде визначити.

Однією ідеєю є "ми дозволимо клієнтові змінити таблицю", і це просто погано (ви потрапляєте в метапрограмування для структур таблиць, оскільки ви вже не знаєте, що там, де вони можуть по- царському зіпсувати структуру або пошкодити додаток, вони мають доступ робити неправильні речі, і наслідки цього доступу набувають значного значення). Більше про цей шлях у MVC4: Як створити модель під час виконання?

Натомість ви створюєте адміністративний інтерфейс для таблиці EAV та дозволяєте використовувати його. Якщо замовник хоче створити запис для "polkadots", він переходить до таблиці EAV, і ви вже знаєте, як з цим боротися.

Приклад цього можна побачити в моделі бази даних для Redmine, ви можете побачити таблицю custom_fields, а таблицю custom_values ​​- це частини EAV, що дозволяє розширити систему.


Зауважте, що якщо ви знайдете всю свою структуру таблиці, щоб вона виглядала як EAV, а не реляційна, ви можете подивитися на KV-аромат NoSQL (cassandra, redis, Mongo, ...). Зрозумійте, що вони часто мають інші компроміси в їх дизайні, які можуть бути або не відповідати тому, для чого ви його використовуєте. Однак вони спеціально розроблені з метою створення структури EAV.

Ви можете прочитати SQL vs NoSQL для системи управління запасами

Слідуючи такому підходу з базою даних NoSQL, орієнтованою на документ (couch, mongo), ви можете вважати, що кожен товарний запас є документом на диску ... витягування всього в одному документі відбувається швидко. Крім того, документ структурований так, що ви можете швидко витягнути будь-яку одну річ. З іншого боку, пошук у всіх документах речей, які відповідають певному атрибуту, може мати меншу продуктивність (порівняйте, використовуючи "grep" проти всіх файлів) ... все це є компромісом.

Іншим підходом був би LDAP, де можна було б встановити базу з усіма пов’язаними з нею елементами, але тоді також було б застосовано до неї додаткові класи об’єктів для інших типів елементів. (див. інвентаризацію системи за допомогою LDAP )

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


10

Через 6 років

Тепер, коли JSON у Postgres тут, у нас є ще один варіант, для тих, хто використовує Postgres. Якщо ви хочете лише додати якісь додаткові дані до товару, то ваші потреби досить прості. Приклад:

CREATE TABLE products (sku VARCHAR(30), shipping_weight REAL, detail JSON);
INSERT INTO products ('beachball', 1.0, '{"colors": ["red", "white"], "diameter": "50cm"}');

SELECT * FROM products;
    sku    | weight |               detail               
-----------+--------+------------------------------------
 beachball |      1 | {"colors": ["red", "white"], "diameter": "50cm"}

Ось більш легкий вступ до JSON у Postgres: https://www.compose.com/articles/is-postgresql-your-next-json-database/ .

Зауважте, що Postgres насправді зберігає JSONB, а не простий текст JSON, і він підтримує індекси на полях всередині документа / поля JSONB, якщо ви виявите, що ви дійсно хочете запитувати ці дані.

Також зауважте, що поля в полі JSONB не можна змінювати індивідуально за допомогою UPDATE-запиту; вам доведеться замінити весь вміст поля JSONB.

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


3
Я думаю, що це прекрасна ідея розмістити альтернативне рішення. Для того, щоб інших слідкувати, MS SQL підтримував стовпці XML з можливістю їх індексувати деякий час, і починаючи з 2016 року він може робити те ж саме з JSON (хоча JSON не є рідним типом стовпців у MS SQL, ви все одно можете індексувати це ). З іншого боку - з того, що я читав, підтримка Postgres JSON краща, наприклад, схоже, що вона робить індекси підтримки даних у властивостях масиву JSON.
Гедрій

1
"... поля в полі JSONB не можуть бути змінені індивідуально запитом UPDATE; вам доведеться замінити весь вміст поля JSONB." Це застаріло, чи не так? Існує jsonb_set()функція в Postgres 9.5 і пізнішої, яка саме для цього. (Стаття, яку ви посилаєте на посилання, у свою чергу, до нової статті, де обговорюються доповнення до 9.5 .)
Wildcard

7

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

Для загального випадку зберігання різних даних у довгій тонкій таблиці ... Ви не повинні боятися створювати нові таблиці, якщо вам потрібно, і мати лише одну-дві довгі худі таблиці не набагато краще, ніж мати лише одну або дві короткі жирові таблиці.

Незважаючи на це, я відомий тим, що використовую таблиці EAV для ведення журналів. Вони мають добру корисність.


Будь ласка, визначте "худий стіл" та "жировий стіл".
Тулан Кордова

@ TulainsCórdova: "Худенька" таблиця - це одна з кількома рядками та багатьма стовпцями, тоді як жирна таблиця - одна з багатьма стовпцями та кількома рядами. Прикладом може бути побудова таблиці пошуку, де у вас є властивості для, скажімо, книг. Таблиця жирів матиме один запис на книгу, з багатьма стовпцями для конкретних фрагментів даних, тоді як у тонкій таблиці може бути чотири ідентифікатори стовпців, книга, ім'я поля, дані_поля. Перевага першого полягає в тому, що записів менше, але мінусом є те, що деякі поля можуть бути порожніми, а всю справу важче розширити.
Satanicpuppy

@Satanicpuppy Я думаю, що твої худі / товсті визначення змішані - вони однакові. Ви маєте на увазі, що худий стіл має кілька стовпців і багато рядків?
Чарльз Вуд

1

EAV змінює проблему явної структури, на неявне сприйняття. Замість того, щоб сказати, що X - це таблиця зі стовпцями A і B. Ви маєте на увазі, що стовпці A і B утворюють таблицю X. Це в зворотному сенсі зворотне, але не потрібно відображати одноосібне відображення. Ви можете сказати, що A і B обидва відображають таблицю (або введіть) X і Y. Це може бути важливим у більш задіяній області, де важливий контекст.

Я вивчав Datomic для такого типу підходу і думаю, що це дуже корисна і потужна система з обмеженнями в тому, що ви повинні з нею робити (не те, що не могли).

Те, що EAV буде повільним, або "дасть вам достатньо мотузки, щоб повісити себе", - це не твердження, з яким я б погоджувався. Швидше я б поставив більше уваги на сильні сторони EAV, і якщо він відповідає вашому проблемному простору, ви повинні це врахувати.

Мій досвід полягає в тому, що це чудовий майже нестримний підхід до моделювання. Зокрема, у випадку з Datomic вони накладають набір семантики понад усе. Будь-яке рішення моделювання, яке моделювання відносин може вільно переходити від однієї до багатьох, не потребуючи перепроектування стовпців / таблиць. Ви також можете повернутися до тих пір, поки обмеження не порушує інваріант. Це все одно під капотом.

Проблема з EAV в моїй свідомості полягала в тому, що не було такої реалізації, як Datomic. Оскільки це питання щодо EAV, я не хочу бідувати про Datomic, але це одна з тих речей, де я думаю, що у них все в порядку щодо EAV.

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