기본 키 값이 변경되는 이유는 무엇입니까?


18

나는 ROWGUID의 최근의 개념을 연구하고 건너 온 한 질문입니다. 답변은 통찰력을 주었지만 기본 키 값을 변경한다는 언급으로 다른 토끼 구멍을 내 렸습니다.

필자는 항상 기본 키를 변경할 수 없다는 것을 이해하고 있으며,이 답변을 읽은 후 검색하면 모범 사례와 동일한 답변 만 제공했습니다.

어떤 상황에서 레코드 작성 후 기본 키 값을 변경해야합니까?


7
변경할 수없는 기본 키를 선택할 때?
ypercubeᵀᴹ

2
지금까지 아래의 모든 답변에 약간의 도움이되었습니다. 기본 키가 클러스터형 인덱스가 아닌 한 기본 키의 값을 변경하는 것은 그리 중요하지 않습니다. 클러스터형 인덱스의 값이 변경되는 경우에만 중요합니다.
케네스 피셔

6
@KennethFisher 또는 다른 테이블이나 같은 테이블에있는 하나 이상의 FK가 참조한 경우 변경은 여러 행 (수백만 또는 수십억 행)으로 캐스케이드되어야합니다.
ypercubeᵀᴹ

9
Skype에 문의하십시오. 몇 년 전에 가입했을 때 사용자 이름을 잘못 입력했습니다 (성에서 문자를 남김). 여러 번 수정하려고했지만 기본 키에 사용되어 변경을 지원하지 않았기 때문에 변경할 수 없었습니다. 고객이 기본 키를 변경하기를 원하지만 Skype는이를 지원하지 않았습니다. 그들은 그들이 (또는 더 나은 디자인을 만들 수있다)하기를 원한다면 그 변화를 지원하지만 그것을 허용하는 장소에 아무것도 현재 존재하지 않는다. 따라서 내 사용자 이름이 여전히 올바르지 않습니다.
Aaron Bertrand

3
모든 실제 값이 변경 될 수 있습니다 (다양한 원인으로). 이것은 대리 / 합성 키의 원래 동기 중 하나였습니다. 결코 변하지 않을 것으로 의존 할 수있는 인공적인 값을 생성 할 수 있습니다.
RBarryYoung

답변:


24

사람의 이름을 기본 키로 사용하고 이름이 변경된 경우 기본 키를 변경해야합니다. 이것은 무엇을 ON UPDATE CASCADE본질적 이후에 사용되는 캐스케이드 기본 키 외래 키 관계를 맺고 관련된 모든 테이블에 대한 변경 다운.

예를 들면 다음과 같습니다.

USE tempdb;
GO

CREATE TABLE dbo.People
(
    PersonKey VARCHAR(200) NOT NULL
        CONSTRAINT PK_People
        PRIMARY KEY CLUSTERED
    , BirthDate DATE NULL
) ON [PRIMARY];

CREATE TABLE dbo.PeopleAKA
(
    PersonAKAKey VARCHAR(200) NOT NULL
        CONSTRAINT PK_PeopleAKA
        PRIMARY KEY CLUSTERED
    , PersonKey VARCHAR(200) NOT NULL
        CONSTRAINT FK_PeopleAKA_People
        FOREIGN KEY REFERENCES dbo.People(PersonKey)
        ON UPDATE CASCADE
) ON [PRIMARY];

INSERT INTO dbo.People(PersonKey, BirthDate)
VALUES ('Joe Black', '1776-01-01');

INSERT INTO dbo.PeopleAKA(PersonAKAKey, PersonKey)
VALUES ('Death', 'Joe Black');

SELECT두 테이블에 대한 A :

SELECT *
FROM dbo.People p
    INNER JOIN dbo.PeopleAKA pa ON p.PersonKey = pa.PersonKey;

보고:

여기에 이미지 설명을 입력하십시오

PersonKey열 을 업데이트 하고 다음을 다시 실행하십시오 SELECT.

UPDATE dbo.People
SET PersonKey = 'Mr Joe Black'
WHERE PersonKey = 'Joe Black';

SELECT *
FROM dbo.People p
    INNER JOIN dbo.PeopleAKA pa ON p.PersonKey = pa.PersonKey;

우리는보다:

여기에 이미지 설명을 입력하십시오

UPDATE명령문 의 계획을 살펴보면 다음과 같이 정의 된 외래 키로 인해 두 테이블이 단일 업데이트 명령문으로 업데이트됩니다 ON UPDATE CASCADE.

여기에 이미지 설명을 입력하십시오 더 명확하게 보려면 위의 이미지를 클릭하십시오

마지막으로 임시 테이블을 정리합니다.

DROP TABLE dbo.PeopleAKA;
DROP TABLE dbo.People;

선호 방법은이 대리 키를 사용하는 것이해야 할 일 :

USE tempdb;
GO

CREATE TABLE dbo.People
(
    PersonID INT NOT NULL IDENTITY(1,1)
        CONSTRAINT PK_People
        PRIMARY KEY CLUSTERED
    , PersonName VARCHAR(200) NOT NULL
    , BirthDate DATE NULL
) ON [PRIMARY];

CREATE TABLE dbo.PeopleAKA
(
    PersonAKAID INT NOT NULL IDENTITY(1,1)
        CONSTRAINT PK_PeopleAKA
        PRIMARY KEY CLUSTERED
    , PersonAKAName VARCHAR(200) NOT NULL
    , PersonID INT NOT NULL
        CONSTRAINT FK_PeopleAKA_People
        FOREIGN KEY REFERENCES dbo.People(PersonID)
        ON UPDATE CASCADE
) ON [PRIMARY];

INSERT INTO dbo.People(PersonName, BirthDate)
VALUES ('Joe Black', '1776-01-01');

INSERT INTO dbo.PeopleAKA(PersonID, PersonAKAName)
VALUES (1, 'Death');

SELECT *
FROM dbo.People p
    INNER JOIN dbo.PeopleAKA pa ON p.PersonID = pa.PersonID;

UPDATE dbo.People
SET PersonName = 'Mr Joe Black'
WHERE PersonID = 1;

완성도를 높이기 위해 update 문 계획은 매우 간단하며 키를 대리 할 때의 이점 중 하나를 보여줍니다. 즉 , 자연 키 시나리오에서 포함하는 모든 행 과 달리 단일 행만 업데이트하면 됩니다 .

여기에 이미지 설명을 입력하십시오

SELECT *
FROM dbo.People p
    INNER JOIN dbo.PeopleAKA pa ON p.PersonID = pa.PersonID;

DROP TABLE dbo.PeopleAKA;
DROP TABLE dbo.People;

SELECT위 두 문장 의 결과 는 다음과 같습니다.

여기에 이미지 설명을 입력하십시오

본질적으로 결과는 거의 같습니다. 주요 차이점 중 하나는 외래 키가 발생하는 모든 테이블에서 넓은 자연 키가 반복되지 않는다는 것입니다. 내 예에서, 나는 VARCHAR(200)사람의 이름을 유지하기 위해 열을 사용하고 있으며 , 그것은 VARCHAR(200) everywhere를 사용해야 합니다. 외래 키를 포함하는 많은 행과 테이블이 있으면 많은 메모리 낭비가 발생합니다. 대부분의 사람들은 디스크 공간이 본질적으로 여유 공간이 너무 저렴하기 때문에 낭비되는 디스크 공간에 대해서는 이야기하지 않습니다. 그러나 메모리는 비싸고 소중히 여겨야합니다. 키에 4 바이트 정수를 사용하면 평균 이름 길이가 약 15자인 경우 많은 양의 메모리가 절약됩니다.

접선 에 대한 질문에 대한 방법이유를 성능이 설계 목표, 특히 키가 변경할 수있는 재미 있고 어쩌면 더 중요한 질문 인, 대리 키 자연 키를 선택하는 이유에 대한 질문입니다. 그것에 대한 내 질문을 여기에서 보십시오.


1- http : //weblogs.sqlteam.com/mladenp/archive/2009/10/06/Why-I-prefer-surrogate-keys-instead-of-natural-keys-in.aspx


3
CASCADE (특정 시나리오에서 문제가 있음)를 피하기 위해 FK 열을 널 입력 가능하게 만들 수도 있습니다. 따라서 PK를 변경해야하는 경우 관련 행을 NULL로 업데이트 할 수 있습니다 (청크 단위가 많거나 테이블별로) , 테이블이 많거나 둘 다인 경우), PK 값을 변경 한 다음 FK를 다시 변경하십시오.
Aaron Bertrand

8

PK로 자연 스럽거나 변경 가능한 키를 사용할 수 있지만 내 경험상 문제가 발생하며 다음 조건을 충족하는 PK를 사용하면 종종 예방할 수 있습니다.

 Guaranteed Unique, Always Exists, Immutable, and Concise.

예를 들어 미국의 많은 회사는 사회 보장 번호를 시스템의 개인 ID 번호 (및 PK)로 사용하려고합니다. 그런 다음 복구해야하는 여러 레코드, SSN이없는 사람, 정부에 의해 SSN이 변경된 사람, SSN이 중복 된 사람 등의 데이터 입력 오류가 발생합니다.

이러한 시나리오 중 하나를 모두 보았습니다. 또한 고객이 "숫자"가되기를 원하지 않는 회사를 보았 기 때문에 PK가 '첫 번째 + 중간 + 마지막 + DOB + zip'또는 이와 유사한 말이되지 않게되었습니다. 고유성을 거의 보장 할 수있는 충분한 필드를 추가했지만 쿼리는 끔찍했으며 이러한 필드 중 하나를 업데이트하면 데이터 일관성 문제가 발생했습니다.

내 경험에 따르면 데이터베이스 자체에서 생성 된 PK는 거의 항상 더 나은 솔루션입니다.

추가 포인터에 대해서는이 기사를 권장합니다. http://www.agiledata.org/essays/keys.html


6
귀하의 답변에 언급 된 Scott Ambler 기사의 유용한 조언 중 하나는 "일부 사람들은 항상 자연 키를 사용해야한다고 말하고 다른 사람들은 항상 대리 키를 사용해야한다고 말할 것입니다. 그들은 "데이터 종교"의 편견을 당신과 공유하는 것 이상의 일을하고 있습니다. 실제로 자연스럽고 대리적인 키는 각각 장단점이 있으며 모든 상황에 완벽한 전략은 없습니다. "
nvogel

7

기본 키는 동기화가 관련 될 때 변경 될 수 있습니다. 연결이 끊어진 클라이언트가 있고 특정 간격으로 서버와 데이터를 동기화하는 경우가 이에 해당합니다.

몇 년 전에 로컬 컴퓨터의 모든 이벤트 데이터에 -1, -2 등의 음의 행 ID가있는 시스템에서 작업했습니다. 데이터가 서버에 동기화 될 때 서버의 행 Id가 고객. 서버의 다음 행 ID가 58이라고 가정하겠습니다. 그러면 -1은 58, -2 59 등이됩니다. 해당 행 ID 변경은 로컬 컴퓨터의 모든 하위 FK 레코드에 캐스케이드됩니다. 이 메커니즘은 또한 이전에 동기화 된 레코드를 판별하는 데 사용되었습니다.

나는 이것이 좋은 디자인이라고 말하지는 않지만 시간이 지남에 따라 변화하는 기본 키의 예입니다.


5

PRIMARY KEY정기적으로 변경을 포함하는 모든 디자인 은 재난을위한 레시피입니다. 이를 변경하는 유일한 이유는 이전에 분리 된 두 개의 데이터베이스가 통합되어 있기 때문입니다.

@MaxVernon에 의해 지적 된 바와 같이 ON UPDATE CASCADE, 오늘날 대부분의 시스템은 ID를 대리자로 사용하지만 가끔 변경이 발생할 수 있습니다 PRIMARY KEY.

Joe CelkoFabian Pascal (다음과 같은 사이트) 과 같은 순수 주의자들은 대리 키 사용에 동의하지 않지만이 특정 전투에서 패배했다고 생각합니다.


3

안정성은 키의 바람직한 특성이지만 절대적인 규칙이 아니라 상대적인 것입니다. 실제로는 키 값을 변경하는 것이 유용합니다. 관계형 용어로 데이터는 (슈퍼) 키로 만 식별 할 수 있습니다. 주어진 테이블에 하나의 키가있는 경우 A) 키 값 변경 또는 B) 테이블의 행 세트를 다른 키 값을 포함하는 유사하거나 다른 행 세트로 바꾸는 것의 차이점은 본질적으로 논리보다는 의미론의 문제.

보다 흥미로운 예는 하나 이상의 해당 키 값이 다른 키 값과 관련하여 변경되어야하는 여러 키가있는 테이블의 경우입니다. LoginName과 Badge Number라는 두 개의 키가있는 Employee 테이블의 예를 보자. 해당 테이블의 샘플 행은 다음과 같습니다.

+---------+--------+
|LoginName|BadgeNum|
+---------+--------+
|ZoeS     |47832   |
+---------+--------+

ZoeS가 배지를 잃어버린 경우 새 배지가 할당되고 새 배지 번호가 부여 될 수 있습니다.

+---------+--------+
|LoginName|BadgeNum|
+---------+--------+
|ZoeS     |50282   |
+---------+--------+

나중에 그녀는 로그인 이름을 변경하기로 결정할 수 있습니다.

+---------+--------+
|LoginName|BadgeNum|
+---------+--------+
|ZSmith   |50282   |
+---------+--------+

두 키 값이 서로 관련하여 변경되었습니다. 반드시 "기본"으로 간주되는 차이를 만들지는 않습니다.

실제로 "불변성", 즉 절대로 값을 절대로 변경하지 않는 것은 달성 할 수 없거나 적어도 검증이 불가능합니다. 변경이 전혀 차이를 만들지 않는 한, 가장 안전한 방법은 모든 키 (또는 속성)를 변경해야 할 수도 있다고 가정하는 것입니다.


"실제로"불변성 ", 즉 절대로 값을 변경하지 않는 것은 달성 할 수 없거나 적어도 검증이 불가능합니다." 불변성은 가능하며 대리 키를 사용해야하는 가장 중요한 이유 중 하나입니다.
바이런 존스

3
다음 주나 10 년 안에 누군가가 주요 가치를 바꾸지 않을 것임을 어떻게 알 수 있습니까? 당신은 그들이하지 않을 것이라고 가정 할 수는 있지만 현실적으로 그 일이 발생하는 것을 막을 수는 없습니다 (단독 책임을지는 경우 다른 모든 사람들을 내가 영속적으로 유지하도록 장벽을 세울 수는 있지만 가장자리 케이스처럼 보입니다). 실제로 중요한 것은 변경이 발생하지 않는 것이 아니라 변경이 매우 드물다는 것입니다.
nvogel 2016 년

3

흥미롭게도 ROWGUID 종류에 대한 관련 질문은 데이터베이스에서 동기화해야 할 기본 키가 충돌하는 경우 자체 유스 케이스를 제공합니다. 조정해야하는 두 개의 데이터베이스가 있고 기본 키에 시퀀스를 사용하는 경우 키 중 하나를 변경하여 고유하게 유지할 수 있습니다.

이상적인 세상에서는 이런 일이 일어나지 않을 것입니다. 기본 키에 GUID를 사용하여 시작합니다. 그러나 실제로는 디자인을 시작할 때 분산 데이터베이스가 없을 수도 있으며 GUID로 변환하는 작업은 키 업데이트를 구현하는 것보다 더 큰 영향을 미치는 것으로 간주되어 배포하기보다 우선 순위가 낮은 노력 일 수 있습니다. 정수 키에 의존하는 큰 코드 기반이 있고 GUID로 변환하기 위해 큰 수정이 필요한 경우에 발생할 수 있습니다. 드문 드문 GUID (필요에 따라 임의로 생성되는 경우 서로 매우 근접하지 않은 GUID)가 특정 종류의 인덱스에 문제를 일으킬 수 있다는 사실도 있습니다. Byron Jones가 언급 한 기본 키로 사용됩니다 .


0

한 가지 가능한 시나리오는 고유 한 ID를 가진 계열사가 있고 고유 한 시작 문자를 가지므로 계열사간에 중복되지 않는다는 것을 알고 있습니다. 계열사는 데이터를 마스터 테이블에로드합니다. 레코드가 처리 된 후 마스터 ID가 지정됩니다. 사용자는 아직 처리되지 않은 경우라도로드 되 자마자 레코드에 액세스해야합니다. 마스터 ID가 처리 된 주문을 기반으로하기를 원하며 레코드가로드 된 순서대로 항상 처리하지는 않습니다. 나는 조금 날조 된 것을 안다.


-1

누군가가 NIN (National Insurance Number)을 1 차 키로 선택한 경우에 운영자가 NIN이 잘못된 행을 삽입하는 경우와 같은 상황을 상상하십시오. 값을 삽입 한 후 오류를 정정하는 두 가지 방법이 있습니다.

  1. 잘못된 레코드를 삭제하고 새 레코드를 삽입하십시오
  2. 값을 올바른 값으로 업데이트하고 해당 열에 참조 무결성 제약 조건이있는 경우 캐스케이드 업데이트시 사용
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.