2013-06-15 1 views
5

다른 제품 유형이 포함 된 데이터베이스가 있습니다. 각 유형에는 서로 크게 다른 필드가 있습니다. 첫 번째 유형의 제품은 세 가지 범주로 분류됩니다. 두 번째 유형의 제품은 세 가지 범주로 분류됩니다. 그러나 세 번째와 네 번째 것은 어떤 것으로 분류되지 않습니다.데이터베이스 디자인 변수 특성이있는 여러 제품 유형

각 제품은 여러 가지 속성을 가질 수 있습니다.

나는 기본적으로 있는 데이터베이스 모델을 사용하고 http://www.damirsystems.com/dp_images/product_model_01.png

가 나는 제품 테이블에 약 500,000 제품을 포함하는 거대한 데이터베이스를 가지고 (링크 참조).

그래서 모든 특성을 가진 데이터베이스에서 제품을 가져 오거나 특성으로 제품 필터링을 검색하려고하면 성능에 좋지 않은 영향을줍니다.

SQL에서 테이블 구조가 될 사람을 도와 주거나이 문제에 대한 인덱싱 또는 가능한 해결책을 더 많이 줄 수 있습니까? 다른 전자 상거래 사이트는 이러한 종류의 데이터베이스를 사용하고 있으며 거대한 종류의 제품으로 잘 작동하기 때문입니다.

답변

22

연결할 모델은 부분 entity–attribute–value (EAV) 모델과 비슷합니다. EAV는 매우 유연하지만 데이터 무결성이 좋지 않으며 성 가시고 일반적으로 비효율적입니다. 그것은 관계형 모델의 정신이 아닙니다. 일부 대형 전자 상거래 사이트에서 작업 한 결과 저는 이것이이 분야에서 표준 또는 좋은 데이터베이스 설계 방법이 아니라고 말할 수 있습니다.

엄청난 수의 제품 유형 (최대 10 개까지는 수백 개가 아님)이없는 경우 두 가지 일반적인 접근 방법 중 하나를 사용하여이를 처리 할 수 ​​있습니다.

첫 번째 방법은 제품의 각기 다른 종류의 필요한 수있는 모든 속성 열이, 제품에 대한 하나의 테이블을 가지고하는 것입니다. 각 종류의 제품에 적합한 열을 사용하고 나머지는 null로 두십시오. 책, 음악 및 비디오를 판매한다고 가정하십시오.

create table Product (
    id integer primary key, 
    name varchar(255) not null, 
    type char(1) not null check (type in ('B', 'M', 'V')), 
    number_of_pages integer, -- book only 
    duration_in_seconds integer, -- music and video only 
    classification varchar(2) check (classification in ('U', 'PG', '12', '15', '18')) -- video only 
); 

이렇게하면 간단하고 조인이 필요하지 않습니다. 그러나, (당신이 예를 들어, 페이지 번호가없는 책을 가질 수) 데이터에 대한 무결성을 적용하는 좋은 일을하지 않고, 당신이 제품의 몇 가지 유형 이상이있는 경우, 테이블은 매우 다루기 힘든 얻을 것이다 .

는이 같은 특정 컬럼 값을 가지고 제품의 각 유형을 필요로 테이블 수준 점검 제한 조건과 무결성 문제를 통해 석고 할 수 있습니다 조 셀코에

check ((case when type = 'B' then (number_of_pages is not null) else true end))) 

(모자 팁 - 나는 고개 어떻게 SQL에서 논리적 의미를 수행하고 그는 매우 유사한 점검 제한 조건을 구성하기 위해이 건축과를 수행하는 예를 발견하기 위해)

는 당신은 말할 수 있습니다!

check ((case when type = 'B' then (number_of_pages is not null) else (number_of_pages is null) end))) 

행에 해당 유형에 적합하지 않은 값이 있는지 확인하십시오. 해당 유형의 제품에 특정 제품 잡고 컬럼의 각 유형에 대한 모든 제품에 공통적으로 하나 개의 기본 테이블을 잡고 열, 하나 개의 보조 테이블 :

두 번째 방법은 여러 테이블을 사용하는 것입니다.따라서 :

create table Product (
    id integer primary key, 
    type char(1) not null check (type in ('B', 'M', 'V')), 
    name varchar(255) not null 
); 

create table Book (
    id integer primary key references Product, 
    number_of_pages integer not null 
); 

create table Music (
    id integer primary key references Product, 
    duration_in_seconds integer not null 
); 

create table Video (
    id integer primary key references Product, 
    duration_in_seconds integer not null, 
    classification varchar(2) not null check (classification in ('U', 'PG', '12', '15', '18')) 
); 

보조 테이블에는 주 테이블과 동일한 기본 키가 있습니다. 기본 키 열은 주 테이블에 대한 외래 키이기도합니다.

이 방법은 여전히 ​​매우 간단하며 무결성을 강화하는 데 더 효과적입니다. 쿼리는 일반적으로 포함하지만, 조인됩니다

select 
    p.id, 
    p.name 
from 
    Product p 
    join Book b on p.id = b.id 
where 
    b.number_of_pages > 300; 

무결성은 아직 완벽하지 않습니다, 기본 테이블에서 잘못된 유형의 행에 대응하는 보조 테이블에서 행을 만들 수 있습니다, 또는 행을 만들 수 있기 때문에 주 테이블의 단일 행에 해당하는 여러 보조 테이블. 모델을 더 정제하여 문제를 해결할 수 있습니다. 기본 키를 유형 열을 포함하는 복합 키로 만들면 제품의 유형이 기본 키에 임베드됩니다 (책은 ('B', 1001)과 같은 기본 키를 갖습니다). 보조 테이블에 유형 컬럼을 도입하여 외래 키가 기본 테이블을 가리킬 수 있도록하고, 유형이 올 Y 르 기가 필요한 각 보조 테이블에 점검 제한 조건을 추가 할 수 있도록해야합니다. 이처럼 :이 또한 쉽게에만 기본 키 가지게되는 권한 테이블을 조회 할 수

create table Product (
    type char(1) not null check (type in ('B', 'M', 'V')), 
    id integer not null, 
    name varchar(255) not null, 
    primary key (type, id) 
); 

create table Book (
    type char(1) not null check (type = 'B'), 
    id integer not null, 
    number_of_pages integer not null, 
    primary key (type, id), 
    foreign key (type, id) references Product 
); 

- 당신은 즉시 먼저 기본 테이블을 쿼리하지 않고도를 말합니다 제품의 종류를 알 수 있습니다.

그러나 보조 테이블에서 해당 행이 없어도 메인 테이블에 행을 만들 수 있습니다. 나는 그 문제를 해결하는 방법을 모릅니다.

기간 열이 두 테이블에 복제되는 위의 스키마에서와 같이 잠재적 인 열 중복 문제가 있습니다. 공유 열에 대한 중간 보조 테이블을 도입하여이를 해결할 수 있습니다.

create table Media (
    type char(1) not null check (type in ('M', 'V')), 
    id integer not null, 
    duration_in_seconds integer not null, 
    primary key (type, id), 
    foreign key (type, id) references Product 
); 

create table Music (
    type char(1) not null check (type = 'M'), 
    id integer not null, 
    primary key (type, id), 
    foreign key (type, id) references Product 
); 

create table Video (
    type char(1) not null check (type = 'V'), 
    id integer not null, 
    classification varchar(2) not null check (classification in ('U', 'PG', '12', '15', '18')), 
    primary key (type, id), 
    foreign key (type, id) references Product 
); 

추가 작업이 필요하다고 생각하지 않을 수 있습니다. 그러나이 같은 상황에 대처하기 위해 두 가지 접근 방식 (단일 테이블과 보조 테이블) 혼합되어 일을하고, 제품의 일부 유사한 종류의 공유 ​​테이블을 가진 고려해 볼 수 있습니다 무엇 :

create table Media (
    type char(1) not null check (type in ('M', 'V')), 
    id integer not null, 
    duration_in_seconds integer not null, 
    classification varchar(2) check (classification in ('U', 'PG', '12', '15', '18')), 
    primary key (type, id), 
    foreign key (type, id) references Product, 
    check ((case when type = 'V' then (classification is not null) else (classification is null) end))) 
); 

특히 유용 할 것 응용 프로그램에서 함께 뭉친 유사한 종류의 제품이있는 경우 이 예에서 상점가가 오디오 및 비디오를 함께 제공하지만 책과 별도로 제공하는 경우이 구조는 각 유형의 미디어에 대해 별도의 보조 테이블을 갖는 것보다 훨씬 효율적인 검색을 지원할 수 있습니다.

+0

감사합니다. 도움을 받으십시오. 그러나 이것이 내가별로 도움이되지 않을 것이라고 생각합니다. – user2455135

+1

아, 그게 부끄러운 일입니다. 행운을 빌어 해결책을 찾는 것! –

+0

@TomAnderson 이것은 매혹적이고 완전한 대답입니다. 엔티티 속성 값 디자인의 팬이 아닌 이유에 대한 정보를 더 제공 할 수 있습니까? 감사합니다. – mils

관련 문제