하나를 제외한 모든 열을 기본 키로 표시하는 것이 합리적입니까?


9

영화를 나타내는 테이블이 있습니다. 필드는 다음과 같습니다
id (PK), title, genre, runtime, released_in, tags, origin, downloads..

중복 된 행으로 데이터베이스를 오염시킬 수 없으므로 고유성을 강화하고 싶습니다. 문제는 다른 영화는 같은 제목을 가질 수있다, 또는 같은 필드를 제외하고 있다는 점이다 tags하고 downloads. 독창성을 강화하는 방법?

나는 두 가지 방법을 생각했다.

  • downloads기본 키를 제외한 모든 필드를 작성하십시오 . downloadsJSON이기 때문에 유지 하고 있으며 아마도 성능에 영향을 줄 것입니다.
  • id기본 키로 만 유지 하고 다른 모든 열에 대해 고유 제한 조건을 추가하십시오 (다시, 제외 downloads).

나는 이 질문 을 매우 비슷하게 읽었 지만 어떻게 해야하는지 이해하지 못했습니다. 현재이 테이블은 다른 테이블과 관련이 없지만 앞으로는 가능합니다.

현재 20,000 개 미만의 레코드를 보유하고 있지만 그 수가 증가 할 것으로 예상합니다. 이것이 문제와 관련이 있는지 모르겠습니다.

편집 : 스키마를 수정했으며 다음은 테이블을 만드는 방법입니다.

CREATE TABLE movies (
    id          serial PRIMARY KEY,
    title       text NOT NULL,
    runtime     smallint NOT NULL CHECK (runtime >= 0),
    released_in smallint NOT NULL CHECK (released_in > 0),
    genres      text[] NOT NULL default ARRAY[]::text[],
    tags        text[] NOT NULL default ARRAY[]::text[],
    origin      text[] NOT NULL default ARRAY[]::text[],
    downloads   json NOT NULL,
    inserted_at timestamp NOT NULL default current_timestamp,
    CONSTRAINT must_be_unique UNIQUE(title,runtime,released_in,genres,tags,origin)
);

또한 timestamp열 을 추가 했지만 열지 않아도 문제가되지 않습니다. 따라서 항상 자동적이고 독창적입니다.


SO에 대한 밀접한 관련 질문 (답변이있는) : UNIQUE (복합 4 열)가있는 테이블의 기본 키가 필요합니까? 하나는 NULL 일 수 있습니까? . 열을가 널이 될 수있는 경우, 긴급하게이 사항을 고려하십시오 dba.stackexchange.com/q/9759/3684를 .
Erwin Brandstetter

답변:


4

이제 테이블 정의가 합리적으로 보입니다. 오타와 철자의 약간의 차이를 제외하고 모든 열 NOT NULL에서 UNIQUE제약 조건이 예상대로 작동합니다. 두려운 것이 일반적입니다. @a_horse 님의 의견을 고려하십시오 .

기능적 고유 인덱스를 사용한 대안

다른 옵션은 기능적인 고유 인덱스입니다 ( @Dave의 주석 과 유사 ). 그러나 uuid인덱스 크기와 성능을 최적화하기 위해 데이터 형식을 사용합니다 .

배열에서 텍스트로 캐스트는 IMMUTABLE(일반 구현으로 인해 )되지 않습니다 .

따라서 불변 으로 선언 하려면 작은 도우미 함수가 필요합니다 .

CREATE OR REPLACE FUNCTION f_movie_uuid(_title text
                                      , _runtime int2
                                      , _released_in int2
                                      , _genres text[]
                                      , _tags text[]
                                      , _origin text[])
  RETURNS uuid LANGUAGE sql IMMUTABLE AS  -- faking IMMUTABLE
'SELECT md5(_title || _runtime::text || _released_in::text
         || _genres::text || _tags::text || _origin::text)::uuid';

색인 정의에 사용하십시오.

CREATE UNIQUE INDEX movies_uni_idx
ON movies (f_movie_uuid(title,runtime,released_in,genres,tags,origin));

SQL 바이올린.

자세한 내용은:

생성 된 UUID를 PK로 사용할 수 있지만 여전히 serial4 바이트 의 열을 사용하는데 , 이는 FK 참조 및 기타 목적으로 간단하고 저렴합니다. UUID는 PK 값을 독립적으로 생성해야하는 분산 시스템에 적합한 옵션입니다. 또는 매우 큰 테이블의 경우 태양계에는 영화가 거의 없습니다.

장점과 단점

고유 제한 조건은 침범 된 열에 고유 인덱스로 구현됩니다. 제약 조건 정의에 관련 열을 먼저 넣고 부수적 이익으로 다른 목적으로 유용한 색인을 얻습니다.

다른 특정 이점이 있습니다. 여기에 목록이 있습니다.

기능 고유 인덱스는 실질적으로 빠르게 할 수있는 작은 크기의 (잠재적으로 많은)이다. 열이 너무 크지 않으면 차이가 크지 않습니다. 계산에는 적은 오버 헤드 비용도 있습니다.

모든 열을 연결하는 오탐 (false positive)을 (도입 할 수 'foo ' || 'bar' = 'foob ' || 'ar'있지만 보인다 매우 이 경우에 대한 가능성. 오타가 훨씬 더 가능성이 안전하게 여기를 무시할 수 있습니다.

독창성과 배열

배열은 연산자에 의존하는 고유 한 배열로 이해하기 위해 일관성있게 정렬 되어야 합니다. 나는에 대한 룩업 테이블을 제안 , 그리고 와 배열 요소에 대한 퍼지 검색을 허용 PK와 고유 한 항목을. 그때:='{1,2}' <> '{2,1}'genretagoriginserial

어쨌든 배열을 직접 사용하거나 정규화 된 스키마 및 구체화 된 뷰를 사용하여 검색하면 올바른 인덱스와 연산자를 사용하여 매우 효율적으로 검색 할 수 있습니다.

곁에

당신이 포스트 그레스를 사용하는 경우 9.4 이상 고려 jsonb대신json .


6

친구 그룹과 대화를 나누고 대화가 영화로 바뀐다 고 상상해보십시오. 누군가가 묻습니다. " '삼총사에 대해 어떻게 생각하니?" "어느 쪽?"

동일한 영화를 생각하고 있다는 것을 확실히 확신하려면 어떤 추가 정보가 필요합니까? 감독의 이름은? 프로덕션 스튜디오? 출시 년도? 별 이름 중 하나? 둘 이상의 조합?

내 질문에 대한 답변과 귀하의 답변은 같습니다.

그러나 장르 가 좋은 후보 라고 생각하지는 않습니다 . 한 가지 이유는 장르가 너무 주관적인 기준입니다. '삼총사'행동입니까? 드라마? 모험? 코메디? 액션 어드벤처? 로맨틱 코미디? 나는 종종 같은 영화가 다른 장르로 나옵니다. 여러 장르를 허용하더라도 사용자는 찾고있는 실제 영화에 나열되지 않은 완전히 다른 장르를 선택할 수 있습니다.

심지어 극장과 VCR / DVD / b-ray 버전 간에는 런타임이 다를 수 있습니다.

따라서 한 매체 릴리스에서 다른 매체 릴리스로 변경되지 않는 단단하고 객관적인 속성이 필요합니다. 불행히도, 특히 속편이 출시 된 후 영화의 이름이 바뀌어 영화 이름이 제외 될 수 있습니다.

출시일은 어떻습니까? 1993 년의 연극 공개? 1999 년 VCR 릴리스? 2004 년 DVD 출시? 당신은 아이디어를 얻습니다.

Alan Smithee가 감독 한 모든 영화는 무엇입니까? 실제 감독은 사실 이후 프로젝트에 그의 이름을 넣기 위해 앞으로 나아 갔습니까? 모르겠어요

흠, 여전히 몇 가지 기준이 남아있는 동안 멈추는 것이 좋습니다.

몇 가지 추가 사항 :

  • 예, 대리 키를 유지하고 자연 키 필드에 고유 한 인덱스를 만듭니다 (마지막으로 필드를 축소 할 수있는 경우). 대리 키는 외래 키 참조에 가장 적합합니다. 영화에 대한 참조가 포함 된 모든 테이블에서 모든 자연 키 필드를 복제하지는 않습니다.
  • 배열 필드 (장르, 태그, 원점)를 삭제하십시오. 계속해서 해당 속성을 올바르게 정규화하십시오. 나는 당신이 그것들을 검색 할 수 있기를 원한다면 ( "... 장르 = '공포'..."), 그 가치보다 더 큰 문제가 아닌 배열 필드를 본 적이 없다. 것이주의 하지 - 자동 ( "공상 과학"대 "과학 소설")의 경우 차이 및 맞춤법 문제를 제거 제대로 룩업 테이블을 유지하지 않는 한 . 그러나 큰 테이블의 모든 행에있는 모든 배열 셀보다 작은 테이블의 한 필드에서 이러한 차이를 확인하는 것이 훨씬 쉽습니다.

4

ID 열은 적용하려는 고유성에있어 전혀 이점이 없습니다. 의미없는 ID를 추가하여 속성 조합이 유일무이하지는 않습니다. "이점"은 외래 키가 필요한 새 테이블이 필요한 시점에 도달했을 때만 표시됩니다. 이 경우 ID를 포함시킨 경우 새 테이블에서 해당 ID를 FK로 사용할 수 있습니다. (그러나 그것이 무료 점심이 될 것이라고 생각하지 마십시오. 그러한 접근법의 단점은 당신이 만든 새로운 테이블의 일부가 될 수있는 정보를 가져 오기위한 단순한 목적으로 더 많은 조인을 작성한다는 것을 알게 될 것입니다. )


1
비즈니스 규칙에서 속성 FOO 및 BAR의 값 조합이 고유해야한다고 말하면 ID를 추가해도 그렇게되지 않습니다. ID를 추가하면 표를 참조 할 때 FOO와 BAR을 포함시키지 않아도됩니다. FOO 및 BAR 속성 (BUSINESS 식별자를 포함하는)이있을 수있는 위치가 아니고 (적어도 비즈니스 관점에서 볼 수있는 위치) 있기 때문에 더 많은 조인이 필요합니다.
Erwin Smout

1
고유해야하는 것은 "행"이 아니며, 비즈니스가 말해야 할 식별자입니다. 이것이 FOO와 BAR 속성의 조합 인 경우 FOO와 BAR 속성의 조합입니다.
Erwin Smout

2
ID가 있거나없는 것은 테이블에서 "비즈니스"열의 고유성 시행 문제를 해결하지 않습니다. 고유성을 강화하려면 적절한 키를 선언하여 수행해야합니다 ( "KEY"대신 구문 단어 "CONSTRAINT"를 사용했다는 것이 키가 아님을 의미하지는 않습니다).
Erwin Smout
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.