각 제품에 많은 매개 변수가있는 여러 종류의 제품에 대한 제품 테이블을 디자인하는 방법


140

나는 테이블 디자인에 많은 경험이 없습니다. 내 목표는 아래 요구 사항을 충족하는 하나 이상의 제품 테이블을 만드는 것입니다.

  • 많은 종류의 제품 (TV, 전화, PC 등)을 지원합니다. 각 제품 종류는 다음과 같은 다른 매개 변수 세트를 갖습니다.

    • 전화는 색상, 크기, 무게, OS가 있습니다 ...

    • PC에는 CPU, HDD, RAM이 있습니다 ...

  • 매개 변수 세트는 동적이어야합니다. 원하는 매개 변수를 추가하거나 편집 할 수 있습니다.

각 제품 종류에 대한 별도의 표없이 이러한 요구 사항을 어떻게 충족시킬 수 있습니까?

답변:


233

설명하는 유형 계층 구조를 모델링하기위한 최소한 다음 5 가지 옵션이 있습니다.

  • 단일 테이블 상속 : 모든 제품 유형에 대해 하나의 테이블이며 모든 유형의 모든 속성을 저장하기에 충분한 열이 있습니다. 이것은 많은 열을 의미 하며 대부분의 주어진 행에서 NULL입니다.

  • 클래스 테이블 상속 : 모든 제품 유형에 공통적 인 속성을 저장하는 제품에 대한 하나의 테이블. 그런 다음 제품 유형마다 하나의 테이블이 있으며 해당 제품 유형에 특정한 속성이 저장됩니다.

  • 콘크리트 테이블 상속 : 일반적인 제품 속성에 대한 테이블이 없습니다. 대신 제품 유형 당 하나의 테이블로 공통 제품 속성과 제품 별 속성이 모두 저장됩니다.

  • 직렬화 된 LOB : 모든 제품 유형에 공통적 인 속성을 저장하는 제품에 대한 하나의 테이블. 하나의 추가 열은 반 구조적 데이터의 BLOB를 XML, YAML, JSON 또는 기타 형식으로 저장합니다. 이 BLOB를 사용하면 각 제품 유형에 특정한 속성을 저장할 수 있습니다. Facade 및 Memento와 같은 멋진 디자인 패턴을 사용하여이를 설명 할 수 있습니다. 그러나 SQL 내에서 쉽게 쿼리 할 수없는 다양한 속성이 있습니다. 전체 blob을 다시 응용 프로그램으로 가져 와서 정렬해야합니다.

  • Entity-Attribute-Value : Products에 대한 하나의 테이블과 속성을 열 대신 행으로 피벗하는 테이블. EAV는 관계형 패러다임과 관련하여 유효한 디자인은 아니지만 많은 사람들이이를 사용합니다. 이것은 다른 답변에서 언급 한 "속성 패턴"입니다. 일부 함정에 대해서는 StackOverflow 에서 eav 태그로 다른 질문을 참조하십시오 .

Extensible Data Modeling 프레젠테이션에서 이에 대해 더 많이 썼습니다 .


EAV에 대한 추가 생각 : 많은 사람들이 EAV를 선호하는 것처럼 보이지만, 저는 그렇지 않습니다. 가장 유연한 솔루션처럼 보이므로 최고입니다. 그러나 adage TANSTAAFL 을 명심하십시오 . EAV의 단점은 다음과 같습니다.

  • 열을 필수로 만들 수있는 방법은 없습니다 (에 해당 NOT NULL).
  • SQL 데이터 유형을 사용하여 항목의 유효성을 검사 할 방법이 없습니다.
  • 속성 이름의 철자를 일관되게 보장 할 방법이 없습니다.
  • 주어진 속성의 값에 외래 키를 넣을 방법이 없습니다 (예 : 조회 테이블).
  • 기존 테이블 형식 레이아웃에서 결과를 가져 오는 것은 복잡하고 비용이 많이 듭니다. 여러 행에서 속성을 가져 오려면 JOIN각 속성에 대해 수행해야하기 때문 입니다.

EAV의 유연성 정도는 다른 영역에서 희생을 요구하며, 아마도 기존의 방식으로 원래 문제를 해결하는 것보다 코드를 복잡하거나 악화시킬 수 있습니다.

대부분의 경우 유연성을 가질 필요는 없습니다. 제품 유형에 대한 OP의 질문에서 제품 별 속성에 대해 제품 유형별로 테이블을 작성하는 것이 훨씬 간단하므로 최소한 동일한 제품 유형의 항목에 대해 일관된 구조가 적용됩니다.

모든 행 에 고유 한 속성 집합을 가질 수 있어야하는 경우에만 EAV를 사용 합니다. 유한 제품 유형 세트를 사용하는 경우 EAV가 과잉 상태입니다. 클래스 테이블 상속이 나의 첫 번째 선택이 될 것입니다.


2019 년 업데이트 : "많은 사용자 정의 속성"문제에 대한 솔루션으로 JSON을 사용하는 사람들이 많을수록 그 솔루션을 좋아하지 않습니다. 특수 JSON 함수 를 사용하여 지원하는 경우에도 쿼리를 너무 복잡하게 만듭니다 . 일반 행과 열에 저장하는 것보다 JSON 문서를 저장하는 데 더 많은 저장 공간이 필요합니다.

기본적으로 이러한 솔루션 중 어느 것도 관계형 데이터베이스에서 쉽고 효율적이지 않습니다. "가변 속성"을 갖는 전체 아이디어는 기본적으로 관계 이론과 상충됩니다.

그것은 무엇에 내려 오는 것은 당신이 가장 나쁜 기반으로하는 솔루션 중 하나를 선택해야한다는 것입니다 귀하의 응용 프로그램을. 따라서 데이터베이스 디자인을 선택하기 전에 데이터를 쿼리하는 방법을 알아야합니다. 솔루션 중 하나가 특정 응용 프로그램에 가장 적합 할 수 있으므로 "최고의"솔루션을 선택할 수있는 방법이 없습니다.


11
@HimalayaGarg 옵션 "4.5"는 실제로 Bill 게시물의 요점과 반대입니다.
user3308043

2
MySQL과 달리 SQL Server는 XML, XPath 및 XQuery를 광범위하게 지원합니다. 따라서 SQL Server 사용자의 경우 가장 좋은 옵션은 추가 속성을 XML 유형의 열에 저장하는 것입니다 (옵션 4). 이렇게하면 "전체 블롭을 다시 응용 프로그램으로 가져 와서 정렬 할 필요가 없습니다". SQL Server의 XML 열에 인덱스를 만들 수도 있습니다.
Delphi.Boy


2
내 경우에는 Serialized LOB을 선호합니다. 그러나 ORM에 적합합니까? 나는 EF를 사용합니다.
Mahmood Jenami

물론 @ user2741577이지만 LOB에서 구조화되지 않은 데이터 필드의 압축을 풀고 ORM 오브젝트의 각 엔티티 필드에 적용하려면 사용자 정의 코드를 작성해야합니다. EF를 모르지만이 작업을 수행하는 기본 ORM 클래스를 만들 수 있다고 가정합니다. 데이터베이스 행의 콘크리트 필드에서 온 필드와 LOB 필드에서 온 필드를 추적해야 오브젝트를 저장할 때 LOB를 재구성 할 수 있습니다.
Bill Karwin

12

@돌 심장

나는 EAV와 MVC와 함께 여기에 갈 것입니다.

@Bill Karvin

EAV의 단점은 다음과 같습니다.

  • 열을 필수로 만들 수있는 방법은 없습니다 (NOT NULL과 동일).
  • SQL 데이터 유형을 사용하여 항목의 유효성을 검사 할 방법이 없습니다.
  • 속성 이름의 철자를 일관되게 보장 할 방법이 없습니다.
  • 주어진 속성의 값에 외래 키를 넣을 방법이 없습니다 (예 : 조회 테이블).

여기에 언급 한 모든 것 :

  • 데이터 유효성 검사
  • 속성 이름 철자 유효성 검사
  • 필수 열 / 필드
  • 종속 속성 파괴 처리

내 의견으로는 응용 프로그램의 프로그래밍 언어와 같이 적절한 수준에서 이러한 상호 작용 및 요구 사항을 처리 할 수있는 데이터베이스가 없기 때문에 데이터베이스에 전혀 속하지 않습니다.

내 생각에 이런 식으로 데이터베이스를 사용하는 것은 손톱을 망치로 바위를 사용하는 것과 같습니다. 바위로 할 수는 있지만 이런 종류의 활동을 위해 더 정확하고 구체적으로 설계된 망치를 사용하지 않습니까?

여러 행에서 속성을 가져 오려면 각 속성에 대해 JOIN을 수행해야하므로 기존 테이블 형식 레이아웃에서 결과를 가져 오는 것은 복잡하고 비용이 많이 듭니다.

이 문제는 부분 데이터에 대한 쿼리를 거의하지 않고 응용 프로그램에서 테이블 형식 레이아웃으로 처리하여 해결할 수 있습니다. 600GB의 제품 데이터가 있더라도이 표의 모든 단일 행의 데이터가 필요한 경우 일괄 처리 할 수 ​​있습니다.

계속 진행 쿼리 성능을 향상 시키려면보고 또는 글로벌 텍스트 검색과 같은 특정 작업을 선택하고 필요한 데이터를 저장하고 주기적으로 재생성되는 인덱스 테이블을 준비하여 30 분마다 알려주십시오.

추가 데이터 스토리지 비용은 매일 저렴하고 저렴 해 지므로 걱정할 필요가 없습니다.

애플리케이션에서 수행하는 작업의 성능에 여전히 관심이있는 경우, 항상 Erlang, C ++, Go Language를 사용하여 데이터를 사전 처리하고 나중에 기본 앱에서 최적화 된 데이터를 추가로 처리 할 수 ​​있습니다.


you can always use Erlang, C++, Go Language to pre-process the data무슨 소리 야? DB 대신 Go lang? 좀 더 자세히 설명해 주시겠습니까?
녹색

1
전적으로 동의합니다. EAV는 갈 수있는 방법입니다. 특히 db 스키마 변경없이 새로운 종류의 제품과 매개 변수를 추가 할 수있는 융통성 수준이 필요한 경우 응용 프로그램을 통해 프로덕션 환경에서 실시간으로 작업 할 수 있습니다. 거기에 있었어요. 나를 위해 일했다. 느린 쿼리에 대해 ... 여기 누군가 캐시에 대해 들어 본 적이 있습니까? ;)
pawel.kalisz

@Green 마지막 단락을 좀 더 명확하게하기 위해 편집했습니다. 그러나 원시 EAV 데이터를 데이터 변환, 트리 구조의 조회 또는 기본 맵 감소 작업을 정말 빠르게 처리하고 처리 할 수있는 언어로 프로세스에 전달하는 것에 관한 것입니다. 메모리 효율적인 방식으로. 구체적인 내용은 여기를 최적화 할 필요가 무엇인지에 따라 달라집니다
파블 Barcik에게

6

Class Table Inheritance의미를 사용하면 :

모든 제품 유형에 공통적 인 속성을 저장하는 제품에 대한 하나의 테이블. 그런 다음 제품 유형마다 하나의 테이블이 있으며 해당 제품 유형에 특정한 속성이 저장됩니다. 빌 카윈

Bill Karwin의 제안 중 가장 좋은 점은 무엇입니까 .. 문제점을 방지하는 방법을 설명하려고하는 한 가지 단점을 예견 할 수 있습니다.

1 유형에만 공통 인 속성이 2, 3 등에 공통적 인 속성이있을 때 어떤 비상 계획을 세워야합니까?

예를 들면 다음과 같습니다 (실제 문제가 아니라 예일 뿐임)

가구를 판매하는 경우 의자, 램프, 소파, TV 등을 판매 할 수 있습니다. TV 유형은 전력 소비량이있는 유일한 유형일 수 있습니다. 그래서에 power_consumption속성을 넣을 것 tv_type_table입니다. 그러나 우리는 power_consumption재산 이있는 홈 시어터 시스템을 가지고 다니기 시작 합니다. 다른 하나의 제품만으로도이 필드를 추가 할 것 stereo_type_table입니다. 아마도이 시점에서 가장 쉬운 방법 일 것입니다. 그러나 시간이 지남에 따라 점점 더 많은 전자 장치를 휴대하기 시작하면서 전자 장치가 전자 장치에 power_consumption포함될만큼 충분히 넓습니다 main_product_table. 지금 어떻게해야합니까?

에 필드를 추가하십시오 main_product_table. 전자 장치를 반복하고 올바른 값을 각각 type_table에 입력하는 스크립트를 작성 하십시오 main_product_table. 그런 다음 각 열에서 해당 열을 삭제하십시오 type_table.

이제 항상 같은 GetProductData클래스를 사용하여 데이터베이스와 상호 작용하여 제품 정보를 가져옵니다. 코드 변경에 리팩토링이 필요한 경우 해당 클래스에만 적용됩니다.


3

제품 테이블과 제품 ID, 추가 정보 이름, 추가 정보 값의 3 개 열이있는 별도의 ProductAdditionInfo 테이블이있을 수 있습니다. 모든 종류의 제품이 아닌 많은 제품에서 색상을 사용하는 경우 제품 테이블에서 Null을 허용하거나 열을 ProductAdditionalInfo에 넣을 수 있습니다.

이 방법은 관계형 데이터베이스에 대한 전통적인 기술은 아니지만 실제로 많이 사용하는 것을 보았습니다. 유연하고 성능이 우수 할 수 있습니다.

Steve Yegge는 이것을 Properties 패턴 이라고 부르고이를 사용하는 것에 대한 긴 글을 썼습니다.


4
속성 패턴은 다른 이름으로 Entity-Attribute-Value입니다. 널리 사용되지만 관계형 데이터베이스에 저장하면 정규화 규칙이 위반됩니다.
Bill Karwin

2
솔직히 말해서, @Bills 답변에서 EAV에 대한 설명을 읽을 때 나는 그가 설명하는 것을 이해하지 못했습니다. 그러나 당신이 말했을 때 3 columns: product ID, additional info name, additional info value나는 그 개념을 이해했습니다. 그리고 나는 실제로 이것을 전에 해왔고 문제가 발생했습니다. 그러나 나는 그 문제가 무엇인지 지금은 기억하지 못합니다.
JD Isaacks

1
@JDIsaacks이 패턴에서 일반적인 문제는 모든 속성을 페치하는 데 필요한 JOIN 수를 모르는 것입니다.
Omid
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.