EAV-모든 시나리오에서 정말 나쁩니 까?


65

나는 사용할 생각하고 엔티티 - 속성 - 값 (EAV) 모델을 프로젝트 중 하나에있는 물건의 일부 있지만, 모든 스택 오버플로에 대한 질문은 EAV에게 안티 패턴을 호출 답변을 끝낸다.

그러나 모든 경우에 그것이 잘못되었는지 궁금합니다.

상점 제품 실체는 이름, 설명, 이미지 및 가격과 같은 많은 기능을 논리에 참여하고 시계 및 비치 볼과 같은 (반) 고유 한 기능을 완전히 다른 측면으로 설명하는 공통 기능을 가지고 있다고 가정 해 봅시다. 따라서 EAV는 이러한 (반) 고유 한 기능을 저장하는 데 적합하다고 생각합니다.

이 모든 것은 제품 목록을 표시하기 위해 제품 테이블에 충분한 정보 (EAV가 포함되어 있지 않음)와 하나의 제품을 표시 할 때 / 최대 5 개의 제품 등을 비교할 때 충분하다고 가정합니다. EAV를 사용하여 저장된 데이터가 사용됩니다.

마 젠토 커머스 (Magento commerce)에서 이러한 접근 방식을 보았고 매우 인기가 많으므로 EAV가 합리적 일 경우가 있습니까?


2
@busy_wait "Entity-Attibute-Value"테이블-Wikipedia의 엔티티 속성 값 모델을 참조하십시오 .
로스 패터슨

실제로 잘 작동하는 EAV 패턴의 예를 보려면 Datomic 데이터베이스를 살펴보십시오. 모든 것을 EAVT 패턴으로 저장합니다 (T는 "타임 스탬프"이며 실제로 트랜잭션 ID와 비슷합니다). 그들의 [인덱싱 문서] (docs.datomic.com/indexes.html)가 가장 잘 보입니다. EAV가 끔찍하게 작동하는 예는 Wordpress를 참조하십시오 .
Dan Ross

답변:


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
마지막 문장을 사랑하십시오.
Zohar Peled

2
썩은 링크. 캐시 된 버전이 있습니까?
와일드 카드

1
링크를 따르지 마십시오. 페이지가 느리게로드되고 도움이되지 않습니다. 또한 오래된 스타일의 포럼은 악취가납니다. 대신 스택 오버플로를 사용하십시오! 좋은 / 유용한 답변을 찬성하고 쓰레기를 내립니다.
Jess

29

간단히 말해서 EAV는 속성 목록이 자주 늘어나거나 모든 속성을 열로 만들면 대부분의 행이 대부분 NULL로 채워질 정도로 큰 경우에 유용합니다. 해당 컨텍스트 외부에서 사용하면 안티 패턴이됩니다.


16
"빈번하게"가능성을 "런타임으로 변경해야 할 필요성"으로 바꿉니다.
Doc Brown

3
이해하기 쉬운 단어 "dynamic"을 사용하여 Doc Brown을 더욱 단축 할 수 있습니다. EAV는 속성 목록이 동적으로 변경 될 때 유용합니다.
Alexander Mills

더 나아가 "속성이 변할 때"- "동적으로"는이 맥락에서 약간 중복됩니다 :)
Wranorn

1
속성 변경 양식 CREATE TABLE이 새 속성에 대해 수행하는 것보다 반드시 더 유용 합니까?
Damian Yerrick

@DamianYerrick 재미있는 접근법. 프로덕션에서 이것을 사용 했습니까?
digout

21

상점 제품 엔티티, 이름, 설명, 이미지, 가격 등과 같은 많은 기능을 논리에 참여시키는 공통 기능을 가지고 있으며 시계 및 비치 볼과 같은 (반) 고유 한 기능은 완전히 다른 측면으로 설명됩니다. . 그래서 EAV가 (세미) 고유 한 기능을 저장하는 데 적합하다고 생각합니까?

EAV 구조를 사용하면 몇 가지 의미가 있습니다.

null'보다 복잡한 쿼리 및 모델'에 대해 100 개의 열이 없기 때문에 '행을위한 공간이 부족합니다 .

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으로 직렬화 할 때 그리고 해당 구조 에 대해 유효성 검증 또는 조회를 수행하는 복잡성에 영향을 미칩니다 .

고려할 패턴에 대한 일부 대안 또는 수정은 올바른 키가있는 다른 테이블을 갖는 자유 형식 키 대신에 있습니다. 데이터베이스에서 문자열 비교를 수행하는 대신 외래 키 ID가 같은지 확인하는 것입니다. 키 자체 변경은 한 번에 수행됩니다. 알려진 키 세트가 있습니다. 즉, 키로 열거로 수행 할 수 있습니다.

특정 제품 클래스의 속성을 포함하는 관련 테이블이있을 수도 있습니다. 식료품 부서에는 건축 자재에 필요하지 않은 (그리고 그 반대의) 여러 속성이있는 다른 테이블이있을 수 있습니다.

+----------+    +--------+    +---------+
|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처럼 보이는 경우 NoSQL (cassandra, redis, Mongo 등) 의 KV 특징 을보고 싶을 수 있습니다 . 이것들은 종종 당신이 그것을 사용하는 것에 적합하거나 적합하지 않을 수있는 디자인의 다른 트레이드 오프 와 함께 제공됩니다 . 그러나 이들은 EAV 구조의 의도로 특별히 설계되었습니다.

재고 관리 시스템에 대해 SQL vs NoSQL 을 읽을 수 있습니다

문서 지향 NoSQL 데이터베이스 (couch, mongo)를 사용하여이 접근 방식을 수행하면 각 인벤토리 항목을 디스크의 문서로 간주 할 수 있습니다. 단일 문서에서 모든 항목을 빠르게 가져올 수 있습니다. 또한, 문서는 하나의 것을 빠르게 뽑을 수 있도록 구성되어 있습니다. 반면에 특정 속성과 일치하는 것을 찾기 위해 모든 문서를 검색하면 성능이 떨어질 수 있습니다 (모든 파일에 대해 'grep'를 사용하는 것과 비교).

또 다른 방법은 모든 관련 항목이있는 기본을 갖는 LDAP이지만 다른 유형의 항목에 추가 객체 클래스가 적용되는 LDAP입니다. ( LDAP를 사용한 시스템 인벤토리 참조 )

이 길을 따라 가면 찾고있는 것과 정확히 일치하는 것을 찾을 수 있습니다 .


10

6 년 후

이제 포스트 그레스에서 JSON이 여기에, 우리는 포스트 그레스를 사용하는 사람들을위한 또 다른 옵션을 가지고있다. 제품에 일부 추가 데이터 만 첨부하려는 경우 요구 사항이 매우 간단합니다. 예:

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"}

https://www.compose.com/articles/is-postgresql-your-next-json-database/ 에서 JSON을보다 부드럽게 소개합니다 .

Postgres는 실제로 일반 텍스트 JSON이 아닌 JSONB를 저장하며 실제로 해당 데이터에 대해 쿼리하려는 경우 JSONB 문서 / 필드 내부 필드의 인덱스를 지원합니다.

또한 JSONB 필드 내의 필드는 UPDATE 쿼리를 사용하여 개별적으로 수정할 수 없습니다. JSONB 필드의 전체 내용을 바꿔야합니다.

이 답변은 질문을 직접 해결하지는 못하지만, 원래 질문을 숙고하는 사람이 고려해야 할 EAV 패턴의 대안을 제공합니다.


3
대체 솔루션을 게시하는 것이 좋습니다. 다른 사람들을 추적하기 위해 MS SQL은 XML 열을 잠시 동안 인덱싱 할 수있는 기능을 지원했으며 2016 년부터 JSON과 동일한 작업을 수행 할 수 있습니다 (JSON은 MS SQL의 기본 열 유형이 아니지만 여전히 인덱싱 할 수 있음) ). 반면에 내가 읽은 것으로부터 Postgres JSON 지원이 더 좋습니다. 예를 들어 JSON 배열 속성의 데이터 인덱스를 지원하는 것처럼 보입니다.
Giedrius

1
"... JSONB 필드 내의 필드는 UPDATE 쿼리로 개별적으로 수정할 수 없으므로 JSONB 필드의 전체 내용을 바꿔야합니다." 이것은 구식이지 않습니까? 거기에 있습니다 jsonb_set()포스트 그레스 9.5의 기능은 나중에 정확히 이것에 대한 인. (링크에 링크 한 기사는 9.5 기능 추가에 대해 설명 하는 최신 기사 로 연결됩니다 .)
Wildcard

7

일반적으로 조회 테이블에 사용하는 경우 또는 하나 또는 두 개의 저장된 값에 대한 테이블을 작성하지 않아도되는 다른 상황에서 사람들은 다른 방식으로 보입니다. 설명하는 상황, 기본적으로 항목 속성을 저장하는 위치는 완벽하게 정상적이며 정상적입니다. 가변 개수의 항목 속성을 저장하기 위해 테이블을 확장하는 것은 좋지 않습니다.

이종 데이터를 길고 얇은 테이블에 저장하는 일반적인 경우 ... 필요한 경우 새 테이블을 만드는 것을 두려워 해서는 안되며 , 하나 또는 두 개의 긴 스키니 테이블 만있는 것이 하나 또는 두 개의 테이블 만있는 것보다 낫지 않습니다. 두 개의 짧은 지방 테이블.

즉, 로깅에 EAV 테이블을 사용하는 것으로 악명이 높습니다. 그들은 좋은 유용성을 가지고 있습니다.


"스키니 테이블"및 "팻 테이블"을 정의하십시오.
Tulains Córdova

@ TulainsCórdova : "스키니"테이블은 행이 적고 열이 많은 테이블이고, 팻 테이블은 열이 많고 행이 적은 테이블입니다. 예를 들어 책에 대한 속성이있는 조회 테이블을 작성하는 것이 있습니다. 팻 테이블은 책 당 하나의 레코드를 가지며 특정 데이터 조각에 대한 많은 열을 갖는 반면, 얇은 테이블은 id, book, field_name, field_data 인 4 개의 열을 가질 수 있습니다. 첫 번째의 장점은 레코드 수가 적다는 것입니다. 그러나 부정적인 점은 일부 필드가 비어 있고 전체가 확장하기 어렵다는 것입니다.
Satanicpuppy

@Satanicpuppy 나는 당신의 마른 / 지방 정의가 섞여 있다고 생각합니다. 스키니 테이블에 열이 적고 행이 많음을 의미합니까?
Charles Wood

1

EAV는 명시 적 구조의 문제를 암시 적 인식으로 변경합니다. X는 열 A와 B가있는 테이블이라고 말하는 것이 아니라 열 A와 B가 테이블 X를 형성한다는 것을 암시합니다. 이는 한 가지 의미의 반대이지만 반드시 일대일 매핑은 아닙니다. A와 B가 모두 테이블 (또는 유형) X와 Y에 매핑된다고 말할 수 있습니다. 이는 상황이 중요한보다 관련성이 높은 도메인에서 중요 할 수 있습니다.

나는 이러한 유형의 접근 방식에 대해 Datomic을 연구 해 왔으며 그것이해야 할 일에 제한이있는 매우 유용하고 강력한 시스템이라고 생각합니다.

EAV가 느리거나 "자신을 걸기에 충분한 밧줄을 준다"는 말은 제가 동의 할만한 말이 아닙니다. 오히려, EAV의 강점을 더 강조하고 싶습니다. 문제의 공간에 적합하다면 고려해야합니다.

내 경험은 모델링에 대한 거의 무제한의 접근 방식 이라는 것 입니다. 특히 Datomic의 경우 모든 것 위에 의미를 설정합니다. 관계를 모델링하는 모델링 결정은 열 / 테이블을 다시 디자인하지 않고도 하나에서 많은 것으로 갈 수 있습니다. 구속 조건이 불변 값을 위반하지 않는 한 되돌아 갈 수도 있습니다. 후드 아래에서 모두 동일합니다.

EAV의 문제는 Datomic과 같은 구현이 부족하다는 생각이었습니다. 이것은 EAV에 대한 질문이기 때문에 Datomic에 대해 열망하고 싶지 않지만 EAV와 관련하여 모든 것이 올바른 것으로 생각되는 것 중 하나입니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.