기본 키 또는 고유 인덱스?


127

직장에서 우리는 기본 키 대신 고유 인덱스가있는 큰 데이터베이스를 가지고 있으며 모두 잘 작동합니다.

새 프로젝트를 위해 새 데이터베이스를 디자인하고 있는데 딜레마가 있습니다.

DB 이론에서 기본 키는 기본 요소이지만 괜찮습니다. 그러나 REAL 프로젝트에서는 두 가지 장점과 단점이 무엇입니까?

프로젝트에서 무엇을 사용하십니까?

편집 : ... 그리고 MS SQL 서버의 기본 키 및 복제는 어떻습니까?


2
여기서 다루는 몇 가지 추가 고려 사항이 있습니다 (커버링 인덱스의 추가 컨텍스트가 있음에도 불구하고) -dba.stackexchange.com/questions/21554/…
StuartLC

참고 : SQLite는 레거시 문제로 인해 일반적인 표준에 비해 기본 키가 null이 될 수 있다는 점에서 다릅니다. sqlite.org/lang_createtable.html
bitinn

답변:


168

고유 인덱스 란 무엇입니까?

열의 고유 인덱스는 해당 열의 인덱스로, 두 열에서 동일한 열에 두 개의 동일한 값을 가질 수 없다는 제약 조건을 적용합니다. 예:

CREATE TABLE table1 (foo int, bar int);
고유 인덱스 생성 ux_table1_foo ON table1 (foo); -foo에 고유 인덱스를 만듭니다.

INSERT INTO table1 (foo, bar) 값 (1, 2); -- 확인
INSERT INTO table1 (foo, bar) 값 (2, 2); -- 확인
INSERT INTO table1 (foo, bar) 값 (3, 1); -- 확인
INSERT INTO table1 (foo, bar) 값 (1, 4); -실패!

'ux_table1_foo'키에 대한 중복 항목 '1'

마지막 삽입 foo은 값 1을이 열에 두 번째로 삽입하려고 할 때 열의 고유 인덱스를 위반하므로 실패합니다 .

MySQL에서 고유 제한 조건은 여러 NULL을 허용합니다.

여러 열에서 고유 한 인덱스를 만들 수 있습니다.

기본 키와 고유 인덱스

같은 것 :

  • 기본 키는 고유 인덱스를 의미합니다.

다른 것들 :

  • 기본 키는 NOT NULL을 의미하지만 고유 인덱스는 널 입력 가능할 수 있습니다.
  • 기본 키는 하나만있을 수 있지만 고유 인덱스는 여러 개있을 수 있습니다.
  • 클러스터 된 인덱스가 정의되지 않은 경우 기본 키는 클러스터 된 인덱스입니다.

4
참고 고유 인덱스는 컬럼에 인덱스가이 하나 개의 고유 인덱스 또는 기본 키가 하나 개 이상의 열을 포함 할 수로 완전히 정확하지 않습니다.
Alex Jasmin

2
@ Alexandre Jasmin : 고마워요. 여러 열에 대한 부분은 나중에 설명합니다.
Mark Byers

null 표준과 관련하여 ansi 표준은 고유 한 제약 조건이있는 데이터 세트에서 여러 null 값을 허용하며 이는 Oracle 및 PostgreSQL의 구현이기도합니다. SQL Server는 하나의 null 값만 허용한다고 생각합니다.
David Aldridge

3
하지만 여전히 기본 키를 사용할 때 또는 고유 인덱스를 사용할 때와 같이 얻지 못했습니다. 또는 같은 상황에서 둘 다있을 수 있습니다.
Amit

33

다음과 같이 볼 수 있습니다.

기본 키는 고유합니다

고유 한 값이 요소의 표현 일 필요는 없습니다

의미?; "개인"이있는 경우 기본 키를 사용하여 요소를 식별하고 개인의 기본 개인 식별 번호 (SSN 등)를 갖고 싶습니다.

다른 한편으로, 그 사람은 고유하지만 그 사람을 식별하지 못하는 전자 메일을 가질 수 있습니다.

관계 테이블 (중간 테이블 / 연결 테이블)에서도 기본 키가 항상 있습니다. 왜? 코딩 할 때 표준을 따르고 싶습니다. "개인"에 식별자가 있고 자동차에 식별자가 있다면 Person-> Car에도 식별자가 있어야합니다!


관계 테이블에서 : 인공 기본 키 (예 : 정수)가있는 새 열을 도입했거나 구성된 기본 키 (person_id, car_id)를 사용합니까?

3
기본 키 (person_id, car_id)가 가장 좋습니다. 그러나 나는 일반적으로 새 열을 작성합니다. 오버 헤드를 제공하지만 그것이 좋을 것이라고 생각했습니다. 나중 시나리오에서 특정 관계와 관련이 있는지는 알 수 없습니다.
Filip Ekberg

1
대리 기본 키가 복합 / 결합 테이블에 대해 수행하는 다른 작업은 수동 작업을 쉽게 유지 관리하는 것입니다.
Robert C. Barth

2
자녀가있는 경우 기본 키만 있으면됩니다. 값이 아무 것도 사용되지 않으면 값이 아무 곳에도 나타나지 않으면 열과 시퀀스를 추가해야하는 이유는 무엇입니까? Access에서 PK를 요청하지 않도록하기위한 작업입니다. 자녀의 기록을 확인해야하는 경우 PK를 작성하십시오. 그렇지 않으면 낭비입니다.

3
그것이 관계와 관련이 없다면 그것은 무엇과 관련이 있습니까? 당신은 필드를 가리키고, 그것이 기본이라고 말합니다. 과? 그러면 어떻게됩니까? 그리고 자연스러운 pk가 없으면 열과 시퀀스 및 트리거를 추가하고 ____ 때문입니까? 일부는 단지 기본이어야합니다. 이유없이 규칙을 피합니다.

10

외래 키는 기본 키뿐만 아니라 고유 제약 조건으로 작동합니다. 온라인 설명서에서 :

FOREIGN KEY 제약 조건은 다른 테이블의 PRIMARY KEY 제약 조건에만 연결될 필요는 없습니다. 다른 테이블에서 UNIQUE 제약 조건의 열을 참조하도록 정의 할 수도 있습니다.

트랜잭션 복제의 경우 기본 키가 필요합니다. 온라인 설명서에서 :

트랜잭션 복제를 위해 게시 된 테이블에는 기본 키가 있어야합니다. 테이블이 트랜잭션 복제 게시에 있으면 기본 키 열과 관련된 인덱스를 비활성화 할 수 없습니다. 이러한 인덱스는 복제에 필요합니다. 인덱스를 비활성화하려면 먼저 게시에서 테이블을 삭제해야합니다.

두 가지 답변 모두 SQL Server 2005에 대한 것입니다.


그것은 나에게 지옥을 두려워합니다 (첫 번째 인용문). 왜? PK 인 임의의 ID를 가진 개인 테이블이 있지만 전화, 전자 메일 및 SSN에 영국을 추가하기로 결정했습니다. 이제 4 개의 다른 테이블이 4 개의 다른 열에있는 사람과 합류합니까? 일관성을 위해 얻을 수있는 유연성을 잊어 버린 것 같습니다.

5

자연 키가 아닌 대리 기본 키를 사용할시기를 선택하는 것은 까다 롭습니다. 항상 또는 결코 같은 답은 거의 유용하지 않습니다. 상황에 따라 다릅니다.

예를 들어 다음 표가 있습니다.

CREATE TABLE toll_booths (
    id            INTEGER       NOT NULL PRIMARY KEY,
    name          VARCHAR(255)  NOT NULL,
    ...
    UNIQUE(name)
)

CREATE TABLE cars (
    vin           VARCHAR(17)   NOT NULL PRIMARY KEY,
    license_plate VARCHAR(10)   NOT NULL,
    ...
    UNIQUE(license_plate)
)

CREATE TABLE drive_through (
    id            INTEGER       NOT NULL PRIMARY KEY,
    toll_booth_id INTEGER       NOT NULL REFERENCES toll_booths(id),
    vin           VARCHAR(17)   NOT NULL REFERENCES cars(vin),
    at            TIMESTAMP     DEFAULT CURRENT_TIMESTAMP NOT NULL,
    amount        NUMERIC(10,4) NOT NULL,
    ...
    UNIQUE(toll_booth_id, vin)
)

두 개의 엔티티 테이블 ( toll_boothscars)과 트랜잭션 테이블 ( drive_through)이 있습니다. toll_booth는 변경이 보장되지는 자연적인 속성이 없기 때문에 테이블이 대리 키를 사용 (이름을 쉽게 변경할 수 있습니다). cars이 아닌 변경 고유 식별자를 가지고 있기 때문에 테이블 천연 차 키를 사용한다 ( vin). drive_through트랜잭션 테이블은 쉽게 식별 할 수 있도록 서로 게이트 키를 사용뿐만 아니라 레코드가 삽입 될 때 고유성을 보장받을 수 있습니다 속성에 고유 제한 조건이 있습니다.

http://database-programmer.blogspot.com 에는이 특정 주제에 대한 훌륭한 기사가 있습니다.


4

기본 키의 단점은 없습니다.

@MrWiggles 및 @Peter Parker 답변에 정보를 추가하기 위해 테이블에 기본 키가없는 경우 일부 응용 프로그램에서 데이터를 편집 할 수 없습니다 (예 : 기본 키). Postgresql은 여러 NULL 값을 UNIQUE 열에 허용하고 PRIMARY KEY는 NULL을 허용하지 않습니다. 또한 코드를 생성하는 일부 ORM은 기본 키가없는 테이블에 일부 문제가있을 수 있습니다.

최신 정보:

내가 아는 한 적어도 문제 (없이, MSSQL에서 기본 키없이 테이블을 복제 할 수 없습니다 세부 사항 ).


새 행이 삽입되거나 해당 열이 업데이트되면 오버 헤드가 발생합니다.

3

어떤 것이 기본 키인 경우 DB 엔진에 따라 전체 테이블이 기본 키로 정렬됩니다. 이는 다른 종류의 인덱스와 관련하여 참조 해제를 수행 할 필요가 없기 때문에 기본 키에서 조회 속도가 훨씬 빠르다는 것을 의미합니다. 게다가, 그것은 단지 이론 일뿐입니다.


3
테이블은 기본 키가 아닌 클러스터형 인덱스로 정렬됩니다.
Ray Booysen

1
대부분의 사람들이 기본 키를 클러스터형 인덱스로 설정합니다.
Ray Booysen 2012 년

어떤 우리가 알고는, 종종 정말 나쁜 생각하지 않는 한 우리는 물론 핫 스팟과 우리 테이블의 불균형 인덱스 나무, ... 등
마이크 우드 하우스

1
항상 나쁜 생각은 아닙니다. 데이터, RDBMS, 선택의 의미를 알고 있습니다. 선택이 항상 좋거나 나쁘지는 않습니다. 항상 하나 인 경우 데이터베이스가이를 지시하거나 허용하지 않습니다. 그들은 '의존에 따라'선택권을줍니다.

2

다른 답변에서 말한 것 외에도 일부 데이터베이스 및 시스템 에는 기본 데이터베이스가 있어야 할 수도 있습니다. 한 가지 상황이 떠 오릅니다. Informix와 함께 엔터프라이즈 복제를 사용할 때 테이블이 복제에 참여하려면 PK가 있어야합니다.


2

값에 NULL을 허용하지 않는 한 값은 동일하게 처리해야하지만 데이터베이스에서 NULL 값은 다르게 처리됩니다 (AFAIK MS-SQL은 둘 이상의 NULL 값을 허용하지 않음, mySQL 및 Oracle에서 허용) , 열이 UNIQUE 인 경우) 이 열을 정의 해야합니다. NOT NULL UNIQUE INDEX


1
MS-SQL은 모든 RDBMS와 마찬가지로 고유 인덱스가있는 열에 여러 개의 NULL 값을 허용합니다. NULL은 값이 아니므로 두 번째 NULL을 삽입하면 기존 NULL과 절대 일치하지 않습니다. 표현식 (NULL == NULL)은 true 또는 false로 평가되지 않으며 NULL로 평가됩니다.
gregmac

MS가 이것을 따른다면 고맙습니다 gregmac, 나는 확실하지 않았다. 몇 년 전 (2000 년 이전)에 MS Quirks를 기억했으며 오래된 Access-DB 기침
Peter Parker

2

관계형 데이터 이론에는 기본 키와 같은 것이 없으므로 실제 수준에서 질문에 대답해야합니다.

고유 인덱스는 SQL 표준의 일부가 아닙니다. DBMS의 특정 구현은 고유 인덱스를 선언 한 결과가 무엇인지 결정합니다.

Oracle에서는 기본 키를 선언하면 사용자를 대신하여 고유 인덱스가 생성되므로 문제는 거의 없습니다. 다른 DBMS 제품에 대해서는 말할 수 없습니다.

기본 키를 선언하는 것이 좋습니다. 이는 키 열에서 NULL을 금지하고 중복을 금지하는 효과가 있습니다. 또한 엔터티 무결성을 강화하기 위해 REFERENCES 제약 조건을 선언하는 것이 좋습니다. 대부분의 경우 외래 키 열에 대한 인덱스를 선언하면 조인 속도가 빨라집니다. 이런 종류의 색인은 일반적으로 고유하지 않아야합니다.


MS SQL Server의 기본 키는 항상 UNIQUE와 NOT NULL입니다. 예를 들어 실제로는 고유 인덱스이지만 NULL이 될 수 없다는 제한이 추가되었습니다.
marc_s

Oracle은 고유하지 않은 인덱스로 고유 제한 조건을 시행 할 수 있습니다. MSSS가 할 수 없다면 놀랐습니다. "실제로 고유 한 인덱스 일뿐"이라고 말하는 것은 장애입니다.

"많은 경우에 외래 키 열에 대한 인덱스를 선언하면 조인 속도가 빨라집니다." 가능한 경우 해시 조인을 선호하는 데이터웨어 하우징 세계에서는 거의 항상 사실이 아닙니다.
JAC2703

OP는 창고를 언급하지 않았습니다. 해시 허리가 SQL Server에서 어떻게 작동하는지 잘 모르겠습니다. 웨어 하우스 업데이트시 수행 할 수있는 작업량
Walter Mitty

2

CLUSTERED INDEXES와 UNIQUE INDEXES의 단점이 있습니다.

이미 언급했듯이 CLUSTERED INDEX는 실제로 테이블의 데이터를 주문합니다.

즉, 클러스터 된 인덱스가 포함 된 테이블에서 삽입 또는 삭제가 많으면 데이터를 변경할 때마다 데이터를 변경할 때마다 물리적 테이블을 정렬 상태로 업데이트해야합니다.

상대적으로 작은 테이블에서는 문제가 없지만 GB에 해당하는 데이터가 있고 삽입 / 삭제가 정렬에 영향을 미치는 테이블에 도달하면 문제가 발생할 수 있습니다.


그렇다면 장점은 무엇입니까? 정렬 된 쿼리가 더 빠릅니까? 대부분의 데이터를 한 번 (또는 드물게) 작성하고 항상 쿼리 할 때 유스 케이스에 더 좋습니까?
버팔로

1

숫자 기본 키가없는 테이블은 거의 만들지 않습니다. 고유해야하는 자연 키가 있으면 고유 인덱스도 추가합니다. 조인은 여러 열의 자연 키보다 정수에서 빠릅니다. 데이터는 한 곳에서만 변경하면됩니다 (자연 키는 기본 키-외래 키 관계에있을 때 좋지 않은 업데이트가 필요한 경향이 있음). 복제가 필요한 경우 정수 대신 GUID를 사용하지만 대부분 John Smith와 John Smith를 구별하기 위해 사용자가 읽을 수있는 키를 선호합니다.

대리 키를 만들지 않는 경우는 다 대다 관계에 관련된 조인 테이블이있을 때입니다. 이 경우 두 필드를 기본 키로 선언합니다.


“숫자 기본 키가없는 테이블은 거의 만들지 않습니다.”왜 항상 숫자입니까? 기본 키는 숫자 일 필요는 없습니다 (단, AUTO_INCREMENT 일 필요는 없습니다).
Hibou57

@ Hinou57은 자연 키가 거의 고유하지 않으며 거의 ​​항상 변경 가능하다는 것을 알았습니다. interger의 추가 조인은 일반적으로 varcahrr 자연 키의 조인 또는 더 복잡한 복합 키의 조인보다 훨씬 빠릅니다. 나는 그들을 거의 사용하지 않을 것입니다. 이것은 데이터베이스에 저장하는 정보 유형에 따라 다를 수 있지만 개인 경험상 자연 키는 시간이 지남에 따라 매우 신뢰할 수 없다는 것을 알았습니다.
HLGEM

회신 HLGEM에 감사드립니다. 신뢰할 수없는 것은 무엇을 의미합니까? 공연? (데이터 무결성의 관점에서 이것이 신뢰성의 문제가 아니기를 바랍니다). 정수 키 또는 짧은 VARCHAR과 같은 더 자연스러운 키를 사용하더라도 가장 간단한 DB 엔진으로도 해싱이 사용되기 때문에 약간의 차이가있을 수 있습니다.
Hibou57

그들은 비록 그들이 예상 되더라도 믿을 수없이 독특하지 않기 때문에 많은 경우에 신뢰할 수 없다. 그들은 변화하기 때문에 신뢰할 수 없으며, 이는 uopdate의 수백만 레코드에 영향을 줄 수 있습니다. 이것은 많은 다른 유형의 정보에 대한 데이터를 저장하는 수백 개의 데이터베이스에서 데이터를 가져오고 관리하거나 쿼리 한 경험입니다.
HLGEM

1

내 이해는 null이 아닌 제약 조건이있는 기본 키와 고유 인덱스가 동일하다는 것입니다 (*). 그리고 나는 스펙이 명시 적으로 진술하거나 암시하는 것에 따라 (표현하고 명시 적으로 시행하려는 것이 무엇인지에 따라) 하나를 선택한다고 가정합니다. 고유성이 필요하고 널이 아닌 경우 기본 키로 만드십시오. 그것이 필요한 경우 고유 색인의 모든 부분이 필요하지 않은 경우 고유 색인으로 만드십시오.

남은 유일한 차이점은 여러 개의 null이 아닌 고유 인덱스가있을 수 있지만 기본 키는 여러 개일 수 없다는 것입니다.

(*) 실제 차이를 제외하고 : 외래 키 정의와 같은 일부 작업의 기본 키는 기본 키가 될 수 있습니다. 전의. 테이블을 참조하는 외래 키를 정의하고 열 이름을 제공하지 않으면 참조 된 테이블에 기본 키가 있으면 기본 키가 참조 된 열이됩니다. 그렇지 않으면 참조 된 열의 이름을 명시 적으로 지정해야합니다.

여기에있는 다른 사람들은 DB 복제에 대해 언급했지만 알지 못합니다.


0

고유 색인은 하나의 NULL 값을 가질 수 있습니다. 비 클러스터형 인덱스를 만듭니다. 기본 키는 NULL 값을 포함 할 수 없습니다. CLUSTERED INDEX를 만듭니다.


0

MSSQL에서 클러스터 된 인덱스에서 최상의 성능을 얻으려면 기본 키가 단조 증가해야합니다. 따라서 ID 삽입을 갖는 정수는 단조롭게 증가하지 않는 자연 키보다 낫습니다.


-1

그것이 나에게 달려 있다면 ...

데이터베이스 및 응용 프로그램의 요구 사항을 만족시켜야합니다.

기본 키 역할을 할 모든 테이블에 자동 증분 정수 또는 긴 ID 열을 추가하면 데이터베이스 요구 사항이 처리됩니다.

그런 다음 응용 프로그램에서 사용하기 위해 하나 이상의 다른 고유 색인을 테이블에 추가합니다. 이것은 employee_id, account_id 또는 customer_id 등의 인덱스입니다. 가능하면이 인덱스는 복합 인덱스가 아니어야합니다.

나는 복합 지수보다 개별적으로 여러 분야의 지수를 선호합니다. 데이터베이스는 where 절에 해당 필드가 포함될 때마다 단일 필드 인덱스를 사용하지만 필드를 정확하게 올바른 순서로 제공 할 때만 복합을 사용합니다. 즉, 제공하지 않으면 복합 인덱스에서 두 번째 필드를 사용할 수 없습니다 where 절의 첫 번째와 두 번째.

나는 계산 또는 함수 유형 인덱스를 모두 사용하기 위해-복합 인덱스보다 사용하는 것이 좋습니다. where 절에서 동일한 함수를 사용하면 함수 인덱스를 매우 쉽게 사용할 수 있습니다.

응용 프로그램 요구 사항을 처리합니다.

기본이 아닌 다른 인덱스는 실제로 해당 인덱스 키 값을 rowid ()가 아닌 기본 키 값에 매핑 할 가능성이 높습니다. 이를 통해 이러한 인덱스를 다시 만들지 않고도 물리적 정렬 작업과 삭제가 가능합니다.

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