Model EAV – cudowny sposób na dynamiczne dane?

Model EAV (Entity – Attribute – Value) jest jednym z tych ciekawych schematów, z którymi każdy w końcu się zderza. Niestety jest to bardzo kuszące rozwiązanie będące często zabójcą systemów IT.

Głównym powodem napisania tego postu, jest przestroga dla tych, którzy mają tą przygodę przed sobą. Warto wiedzieć, z czym wiąże się EAV, zanim powstanie kolejny system, który nie powinien być oparty na tym modelu : )

Czym jest EAV?

W skrócie EAV jest typem strukturyzowania danych w bazie. Nazwa i wartość pola są przechowywane w odrębnych kolumnach relacyjnej bazy danych. Pozwala to na definiowanie dowolnej ilości pól bez potrzeby zmiany schematu bazy danych.

Najlepszym sposobem na wyjaśnienie czym jest EAV, jest porównanie go z tradycyjnym modelem relacyjnym.

Tradycyjny model danych

Zamodelujmy produkt w sklepie używając standardowego modelu danych:

CREATE TABLE PRODUCT(
   ID             INT     NOT NULL PRIMARY KEY,
   NAME           TEXT    NOT NULL,
   PRICE          INT     NOT NULL,
   DESCRIPTION    TEXT    NOT NULL
);

INSERT PRODUCT(
   (1, 'product1', 10, 'description1'),
   (2, 'product2', 20, 'description2')
)

Nie ma w tym modelu nic niezwykłego. Każde pole jest wyrażone jako kolumna w tablicy PRODUCT.

Model EAV

Ten sam produkt zamodelowany w EAV.

CREATE TABLE PRODUCT_ATTRIBUTE(
   ID             INT     NOT NULL PRIMARY KEY,
   PRODUCT_ID     INT     NOT NULL,
   NAME           TEXT    NOT NULL,
   VALUE          TEXT    NOT NULL
);

INSERT PRODUCT_ATTRIBUTE(
   (1, 1, 'NAME', 'product1'),
   (2, 1, 'PRICE', '10'),
   (3, 1, 'DESCRIPTION', 'description1'),
   (4, 2, 'NAME', 'product2'),
   (5, 2, 'PRICE', '20'),
   (6, 2, 'DESCRIPTION', 'description2')
)

Jak widzimy ten model deklaruje dynamiczne pola. Każde pole zdefiniowane jest w postaci NAME – VALUE i przypięte do ID produktu.

Pokusa związana z EAV

Na pierwszy rzut oka wygląda to świetnie. Możemy definiować dowolną ilość pól, bez potrzeby migracji schematu. Po co więc ograniczać się przez model bazy danych? Zawsze możemy dodać walidację na poziomie aplikacji, jeśli zależy nam na spójności danych.

Wydaje się, że aplikacja oparta na takim modelu może obsłużyć wszystko. Czyżby doszło do znalezienia świętego Grala modelowania danych?

Dlaczego więc EAV jest taki zły?

Pierwszy problem to rozkład relacji pomiędzy obiektami. Wypadają nam wszystkie mechanizmy spójności relacji po stronie bazy danych. Na poziomie aplikacji tracimy też wszystko, co jest związane z ORM. Implementacja logiki biznesowej w takich warunkach staje się niesamowicie trudna.

Drugi problem z logiką to trudność w obsłudze pól w aplikacji. Czysto zmapowany obiekt tradycyjny jest bardzo przyjemny w manipulowaniu jego stanem. Dynamiczne pola EAV bardzo zaciemniają takie operacje.

Trzeci problem to indeksacja bazy danych. W tradycyjnym modelu każde pole może być zaindeksowane zgodnie z potrzebami aplikacji, ponieważ baza rozpoznaje typy wszystkich kolumn. W standardowym EAV pozostaje przeszukiwanie tekstowe. Prędzej, czy później spowoduje to niemożliwe do obejścia problemy wydajnościowe.

Czwarty problem to sortowanie i wyszukiwanie w danych EAV. W jaki sposób posortujemy np. daty zapisane tekstem? Jest to oczywiście możliwe, ale jest też bardzo niewydajne.

Piąty problem to zapytania wyciągające dane z EAV. Jeśli chcemy pobrać wiele pól z EAV, każde z nich musi być kolejnym JOINem do tabeli. W tym momencie życie osób piszących te zapytania zamienia się w koszmarne copy-pastowanie dziesiątek JOINów. Jeśli oni wytrzymają to zadanie, to w końcu baza danych nie będzie w stanie tego obsłużyć.

Od razu dodam, że są formy EAV, które potrafią obchodzić niektóre wymienione problemy. Możemy kombinować z typami danych w kolumnach i indeksach, czy tworzyć widoki posiadające tradycyjnie relacyjną strukturę. Wszystko to jednak znowu prowadzi do coraz większego skomplikowania, co jest samo w sobie nowym problemem.

Co dalej się stanie z takim systemem?

Problemy z EAV nie są jednoznaczne na początku. Każdy z nich można przeforsować większą ilością godzin programistycznych. Bagno trudności powoli, ale sukcesywnie doprowadza system do stanu kompletnego braku utrzymywalności. Dlatego EAV jest taki groźny, wygląda świetnie na początku, po czym powoduje szybki wzrost niemożliwego do obsłużenia skomplikowania.

Co jeśli potrzebuję “dynamicznych pól” w systemie, czy EAV jest konieczny?

Jest kilka alternatyw do EAV, które posiadają podobną elastyczność pól:

  • dokumentowe bazy danych
  • specjalne pola takie jaki xmltype w Oracle, czy JSON w PosgteSQL

Istnienie tego typu rozwiązań, powoduje że możemy mieć część dynamiczną aplikacji beż zmagania się problemami związanymi z EAV. Co więcej są to rozwiązania stworzone w tym celu, więc zawierają specyficzne optymalizacje zwiększające ich wydajność. Jakby tego było mało… ze startu wspierają strukturę hierarchiczną, co daje dodatkowe możliwości ponad EAV.

Czy EAV kiedykolwiek ma rację bytu?

Moja prywatna opinia brzmi nie, ponieważ są rozwiązania prostsze, wydajniejsze i zawierające w sobie wszystkie potrzebne funkcje i ułatwienia. Jednak nie oznacza to, że nie ma systemu który może z powodzeniem działać na EAV. Szczególnie jest to możliwe jeśli:

  • system zawiera mało logiki biznesowej
  • potrzeba wysoce elastycznych pól jest głównym założeniem systemu
  • obecne są funkcje na poziomie bazy danych i/lub kodzie aplikacji, które ułatwiają zapytania i dostęp do pól

W takim środowisku EAV może się udać, jednak moim zdaniem inwestycja nie jest tego warta.

Leave A Comment