키 값의이 데이터베이스 스키마 이름이 있습니까?


68

우리는 데이터베이스를 리팩터링 한 클라이언트로부터 친숙한 것으로 보이는 (엔터티 당 한 행, 속성 당 한 열) 나에게 익숙하지 않은 것으로 (속성 당 엔터티 당 한 행) 일상적인 데이터 피드를 처리합니다.

이전 : 속성 당 하나의 열

ID   Ht_cm   wt_kg   Age_yr  ... 
1      190      82     43    ...
2      170      60     22    ...
3      205      90     51    ...

이후 : 모든 속성에 대한 하나의 열

ID    Metric   Value
 1     Ht_cm     190
 1     Wt_kg     82
 1     Age_yr    43
 1      ...
 2     Ht_cm     170
 2     Wt_kg     60
 2     Age_yr    22
 2     ...
 3     Ht_cm     205
 3     Wt_kg     90
 3     Age_yr    51
 3     ...

이 데이터베이스 구조의 이름이 있습니까? 상대적인 장점은 무엇입니까? 이전 방식은 특정 속성 (널 (NULL)이 아니거나 음이 아닌 등)에 대한 유효성 제약 조건을 쉽게 정의하고 평균을 계산하기가 더 쉬워 보입니다. 그러나 데이터베이스를 리팩토링하지 않고 새로운 속성을 추가하는 것이 더 쉬운 방법을 알 수 있습니다. 이것이 데이터를 구성하는 표준 / 선호적인 방법입니까?

답변:


91

Entity-Attribute-Value (때때로 '이름-값 쌍')라고도하며 사람들이 관계형 데이터베이스에서 EAV 패턴을 사용할 때 "사각 구멍의 둥근 못"의 전형적인 사례입니다.

EAV를 사용 하지 않아야 하는 이유는 다음과 같습니다 .

  • 데이터 유형을 사용할 수 없습니다. 값이 날짜, 숫자 또는 돈 (십진수)인지는 중요하지 않습니다. 항상 varchar로 강제 변환됩니다. 이것은 사소한 성능 문제에서 대규모 직감에 이르기까지 다양 할 수 있습니다 (매월 롤업 보고서에서 1 %의 변동을 쫓아 야 했습니까?).
  • 구속 조건을 (쉽게) 시행 할 수 없습니다. 각각의 제약 조건이 1-2 줄과 달리 "모든 사람이 0에서 3 미터 사이의 높이를 가져야합니다"또는 "나이는 null이 아니고> = 0이 아니어야합니다"를 시행하기 위해 엄청나게 많은 코드가 필요합니다. 올바르게 모델링 된 시스템에서
  • 위와 관련하여 각 클라이언트에 필요한 정보를 얻도록 쉽게 보장 할 수는 없습니다 (나이가 누락되고 다음에 키가 누락 될 수 있음). 당신 그것을 할 수 있지만, 그것보다 훨씬 어려운 지옥입니다 SELECT height, weight, age FROM Client where height is null or weight is null.
  • 다시 말하면, 중복 데이터는 감지하기가 훨씬 어렵습니다 (한 클라이언트에 대해 두 연령대를 제공하면 어떻게됩니까? 두 속성에 대해 두 개의 개별 항목이 있으면 아래 쿼리에서 4 개의 행을 얻게 됩니다.
  • 속성 이름의 일관성을 보장 할 수도 없습니다. "Age_yr"은 "AGE_IN_YEARS"또는 "age"가 될 수 있습니다. (이것은 사람들이 데이터를 삽입 할 때와 비교할 때 추출을받을 때 문제가되지 않지만 여전히 문제가되지 않습니다.)
  • 사소한 종류의 쿼리는 완전한 재앙입니다. 합리적 방식으로 쿼리 할 수 ​​있도록 3- 속성 EAV 시스템을 관계 화하려면 EAV 테이블의 세 조인이 필요합니다.

비교:

SELECT cID.ID AS [ID], cH.Value AS [Height], cW.Value AS [Weight], cA.Value AS [Age]
FROM (SELECT DISTINCT ID FROM Client) cID 
      LEFT OUTER JOIN 
    Client cW ON cID.ID = cW.ID AND cW.Metric = "Wt_kg" 
      LEFT OUTER JOIN 
    Client cH ON cID.ID = cH.ID AND cW.Metric = "Ht_cm" 
      LEFT OUTER JOIN 
    Client cA ON cID.ID = cA.ID AND cW.Metric = "Age_yr"

에:

SELECT c.ID, c.Ht_cm, c.Wt_kg, c.Age_yr
FROM Client c

다음은 EAV를 사용해야하는시기에 대한 목록입니다.

  • 그 주위에 절대적 으로 방법이 없으며 데이터베이스에서 스키마가없는 데이터를 지원 해야하는 경우.
  • "물건"만 저장하고 더 구조화 된 형태로 필요하지 않을 때. 그러나 괴물은 "변화하는 요구 사항"이라고 불렀다.

나는 EAV 대부분의 경우 끔찍한 생각이 왜 난 그냥 디테일이 전체 게시물을 보냈다 알 -하지만 거기에 있다 가 / 불가피한 필요한 몇 가지 경우가. 그러나 대부분의 경우 (위의 예를 포함하여) 가치보다 훨씬 번거로울 것입니다. EAV 유형 데이터 입력을 광범위하게 지원해야하는 경우 Hadoop / HBase, CouchDB, MongoDB, Cassandra, BerkeleyDB와 같은 키-값 시스템에 저장해야합니다.


7
약간의 통지로 +1 : 다른 유형의 값을 다른 테이블에 넣으면 데이터 유형을 사용할 수 있습니다 (클래식 EAV는 아니지만 개선 된 유형). (그러나 다음과 같은 추가 질문이 있습니다. 새로운 속성의 유형을 어떻게 알 수 있습니까?)
dezso

4
동의하지만, 시스템과 의미 적으로 관련이없는 것 (스키마가 아니라)의 목록을 유지할 때 EAV를 사용하는 것도 좋은 방법이라고 덧붙입니다. 예를 들어 제품 기능을 저장하고 나열해야하는 온라인 제품 카탈로그입니다. 역류 할 키 / 값 쌍의 목록이 있지만 시스템은 실제로 해당 키 또는 값에 대해 알거나 신경 쓰지 않습니다. 이 상황에서 EAV의 위험은 무관합니다.
Joel Brown

10
@JoelBrown 지금은 신경 쓰지 않아도되지만 VP가 카탈로그에 갈색 버튼과 버튼 다운 칼라가있는 셔츠가 몇 개인 지 묻는다면 작성해야 할 일이 많습니다. EAV 자체는 일반적으로 계획이나 예측이 부족함을 나타냅니다.
JNK

2
@JoelBrown 나는 (매우 작음) 사용에 동의하지 않습니다. 그러나 정보가 구조화 된 방식으로 쿼리 될 가능성이 높으면 아마도 EAV에 있지 않아야합니다.
JNK

4
@JoelBrown 비즈니스 요구 사항 또는 저장하는 데이터가 변경되면 데이터 모델도 변경 됩니다. 데이터 모델을 석재로 조각해서는 안됩니다. 또한 관계형 데이터베이스의 경우 사람들이 EAV를 사용하는 시간의 99 %는 "내가 알고있는 모든 데이터베이스 패턴과 모델을 고려하는 것보다는"내 데이터를 저장하는 방법에 대해 생각하는 데 시간을 소비하고 싶지 않습니다 "로 귀결됩니다. EAV는이 데이터 세트에 가장 적합합니다. " 반복합니다 -이 있습니다 EAV 유용 (그리고 어쩌면 '정답') 인 경우는, 그러나 그들은 멀리 사이에 몇입니다.
Simon Righarts

18

엔티티 속성 값 (EAV)

저를 포함한 많은 사람들에게 반 패턴으로 여겨집니다.

대안은 다음과 같습니다.

  1. 데이터베이스 테이블 상속 사용

  2. XML 데이터 및 SQLXML 함수 사용

  3. HBase와 같은 nosql 데이터베이스를 사용하십시오.


3
대부분의 사용 사례에 대한 반 패턴. 데이터 세트가 매우 작고 성능이 중요하지 않은 경우에는 효과가있을 수 있습니다.
JNK

16

PostgreSQL에서 EAV 구조를 처리하는 가장 좋은 방법 hstore은 버전 8.4 이상에서 사용 가능한 추가 모듈 입니다. 나는 매뉴얼을 인용한다.

이 모듈 hstore은 단일 PostgreSQL 값 내에 키 / 값 쌍 세트를 저장하기위한 데이터 유형을 구현합니다 . 이것은 거의 조사되지 않는 많은 속성을 가진 행 또는 반 구조화 된 데이터와 같은 다양한 시나리오에서 유용 할 수 있습니다. 키와 값은 단순히 텍스트 문자열입니다.

Postgres 9.2부터는 그 json유형과 기능이 다양합니다 ( 대부분 9.3 추가됨 ).

Postgres 9.4는 (대부분 우수!) "이진 JSON"데이터 유형 jsonb을 옵션 목록에 추가합니다. 고급 색인 옵션이 있습니다.


10

EAV 구조를 사용하는 데이터베이스가있는 경우 다양한 방법으로 데이터를 쿼리 할 수 ​​있습니다.

@Simon의 답변은 이미 여러 조인을 사용하여 쿼리를 수행하는 방법을 보여줍니다.

사용 된 샘플 데이터 :

CREATE TABLE yourtable ([ID] int, [Metric] varchar(6), [Value] int);

INSERT INTO yourtable ([ID], [Metric], [Value])
VALUES (1, 'Ht_cm', 190),
    (1, 'Wt_kg', 82),
    (1, 'Age_yr', 43),
    (2, 'Ht_cm', 170),
    (2, 'Wt_kg', 60),
    (2, 'Age_yr', 22),
    (3, 'Ht_cm', 205),
    (3, 'Wt_kg', 90),
    (3, 'Age_yr', 51);

PIVOT기능 이있는 RDBMS를 사용하는 경우 ( SQL Server 2005+ / Oracle 11g + ) 다음과 같은 방식으로 데이터를 쿼리 할 수 ​​있습니다.

select id, Ht_cm, Wt_kg, Age_yr
from
(
  select id, metric, value
  from yourtable
) src
pivot
(
  max(value)
  for metric in (Ht_cm, Wt_kg, Age_yr)
) piv;

데모가 포함 된 SQL Fiddle 참조

PIVOT함수에 액세스 할 수 없으면 CASE명령문 과 함께 집계 함수를 사용 하여 데이터를 리턴 할 수 있습니다.

select id,
  max(case when metric ='Ht_cm' then value else null end) Ht_cm,
  max(case when metric ='Wt_kg' then value else null end) Wt_kg,
  max(case when metric ='Age_yr' then value else null end) Age_yr
from yourtable
group by id

데모가 포함 된 SQL Fiddle 참조

이 두 쿼리 모두 결과에 데이터를 반환합니다.

| ID | HT_CM | WT_KG | AGE_YR |
-------------------------------
|  1 |   190 |    82 |     43 |
|  2 |   170 |    60 |     22 |
|  3 |   205 |    90 |     51 |

10

EAV db 모델이 어떻게 비판을 받는지, 심지어 어떤 사람들은 "반 패턴 (anti-pattern)"으로 간주하는 것도 재미있다.

내가 아는 한 주요 단점 은 다음과 같습니다.

  • 얼마 전에 이미 EAV를 사용하기 시작한 프로젝트를 시작하면 학습 곡선이 더 가파 릅니다 . 실제로 조인 (및 테이블) 수를 크게 늘리면 쿼리가 어렵 기 때문에 이해하는 데 더 많은 시간이 필요합니다. Magento 프로젝트를 살펴보고 프로젝트 외부 개발자가 DB 작업에 어려움을 겪고 있지만 문서가 잘 유지되고 있는지 확인하십시오.
  • 이름이 "M"으로 시작한 사람의 수를 확보해야하는 경우 보고에 적합하지 않습니다 .

그러나이 솔루션을 폐기해서는 안되며 다음과 같은 이유가 있습니다.

  • 사이먼 은 "변화하는 요구 사항"이라는 괴물에 대해 이야기했습니다 . 나는이 표현을 좋아한다 :). 그리고 IMHO는 이것이 EAV가 좋은 후보가 될 수있는 이유입니다. 이는 원하는만큼 많은 속성을 추가 할 수 있기 때문에 "change"에 적합하기 때문 입니다. 물론 변경되는 요구 사항에 따라 다릅니다. 완전히 새로운 비즈니스에 대해 이야기하고 있다면 물론 dataModel을 검토해야하지만 EAV는 많은 유연성을 제공합니다. 그것이 더 엄격한 것을 요구한다고해서 이것이 덜 흥미 롭다는 것을 의미하지는 않습니다.
  • 또한 "데이터 유형을 사용할 수 없습니다"라고 말했습니다. : 이것이 잘못되었습니다 . 각 dataType마다 하나씩 여러 값 테이블이있을 수 있습니다 . 그런 다음 속성 테이블에 어떤 종류의 dataType이 속성인지 지정해야합니다. 사실, 고전적인 관계형 / EAV와 클래스 관계의 혼합은 데이터베이스 디자인에서 많은 흥미로운 잠재력을 제공합니다.

2
학습 곡선은 첫 번째 EAV 설계에서 가장 가파르게 나타납니다. 그 후에는 모두 똑같이 보입니다.
ypercubeᵀᴹ

1
임시 의견 : 왜 "보고에 적합하지 않은"주장을 이해하지 못합니다. EAV는보고하기에 좋습니다. propertyId = name 및 'm %'와 같은 값인 eav.values에서 ObjectId를 선택하십시오. 가상 스키마에 대한 변경 (예 : 속성 추가)은 다시 컴파일하지 않고도 모든 동적보고 인터페이스 (드롭 다운과 같은)에 포함될 수 있습니다.
crokusek
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.