나는 ROWGUID의 최근의 개념을 연구하고 건너 온 한 이 질문입니다. 이 답변은 통찰력을 주었지만 기본 키 값을 변경한다는 언급으로 다른 토끼 구멍을 내 렸습니다.
필자는 항상 기본 키를 변경할 수 없다는 것을 이해하고 있으며,이 답변을 읽은 후 검색하면 모범 사례와 동일한 답변 만 제공했습니다.
어떤 상황에서 레코드 작성 후 기본 키 값을 변경해야합니까?
나는 ROWGUID의 최근의 개념을 연구하고 건너 온 한 이 질문입니다. 이 답변은 통찰력을 주었지만 기본 키 값을 변경한다는 언급으로 다른 토끼 구멍을 내 렸습니다.
필자는 항상 기본 키를 변경할 수 없다는 것을 이해하고 있으며,이 답변을 읽은 후 검색하면 모범 사례와 동일한 답변 만 제공했습니다.
어떤 상황에서 레코드 작성 후 기본 키 값을 변경해야합니까?
답변:
사람의 이름을 기본 키로 사용하고 이름이 변경된 경우 기본 키를 변경해야합니다. 이것은 무엇을 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
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
기본 키는 동기화가 관련 될 때 변경 될 수 있습니다. 연결이 끊어진 클라이언트가 있고 특정 간격으로 서버와 데이터를 동기화하는 경우가 이에 해당합니다.
몇 년 전에 로컬 컴퓨터의 모든 이벤트 데이터에 -1, -2 등의 음의 행 ID가있는 시스템에서 작업했습니다. 데이터가 서버에 동기화 될 때 서버의 행 Id가 고객. 서버의 다음 행 ID가 58이라고 가정하겠습니다. 그러면 -1은 58, -2 59 등이됩니다. 해당 행 ID 변경은 로컬 컴퓨터의 모든 하위 FK 레코드에 캐스케이드됩니다. 이 메커니즘은 또한 이전에 동기화 된 레코드를 판별하는 데 사용되었습니다.
나는 이것이 좋은 디자인이라고 말하지는 않지만 시간이 지남에 따라 변화하는 기본 키의 예입니다.
PRIMARY KEY
정기적으로 변경을 포함하는 모든 디자인 은 재난을위한 레시피입니다. 이를 변경하는 유일한 이유는 이전에 분리 된 두 개의 데이터베이스가 통합되어 있기 때문입니다.
@MaxVernon에 의해 지적 된 바와 같이 ON UPDATE CASCADE
, 오늘날 대부분의 시스템은 ID를 대리자로 사용하지만 가끔 변경이 발생할 수 있습니다 PRIMARY KEY
.
Joe Celko 와 Fabian Pascal (다음과 같은 사이트) 과 같은 순수 주의자들은 대리 키 사용에 동의하지 않지만이 특정 전투에서 패배했다고 생각합니다.
안정성은 키의 바람직한 특성이지만 절대적인 규칙이 아니라 상대적인 것입니다. 실제로는 키 값을 변경하는 것이 유용합니다. 관계형 용어로 데이터는 (슈퍼) 키로 만 식별 할 수 있습니다. 주어진 테이블에 하나의 키가있는 경우 A) 키 값 변경 또는 B) 테이블의 행 세트를 다른 키 값을 포함하는 유사하거나 다른 행 세트로 바꾸는 것의 차이점은 본질적으로 논리보다는 의미론의 문제.
보다 흥미로운 예는 하나 이상의 해당 키 값이 다른 키 값과 관련하여 변경되어야하는 여러 키가있는 테이블의 경우입니다. LoginName과 Badge Number라는 두 개의 키가있는 Employee 테이블의 예를 보자. 해당 테이블의 샘플 행은 다음과 같습니다.
+---------+--------+
|LoginName|BadgeNum|
+---------+--------+
|ZoeS |47832 |
+---------+--------+
ZoeS가 배지를 잃어버린 경우 새 배지가 할당되고 새 배지 번호가 부여 될 수 있습니다.
+---------+--------+
|LoginName|BadgeNum|
+---------+--------+
|ZoeS |50282 |
+---------+--------+
나중에 그녀는 로그인 이름을 변경하기로 결정할 수 있습니다.
+---------+--------+
|LoginName|BadgeNum|
+---------+--------+
|ZSmith |50282 |
+---------+--------+
두 키 값이 서로 관련하여 변경되었습니다. 반드시 "기본"으로 간주되는 차이를 만들지는 않습니다.
실제로 "불변성", 즉 절대로 값을 절대로 변경하지 않는 것은 달성 할 수 없거나 적어도 검증이 불가능합니다. 변경이 전혀 차이를 만들지 않는 한, 가장 안전한 방법은 모든 키 (또는 속성)를 변경해야 할 수도 있다고 가정하는 것입니다.
흥미롭게도 ROWGUID 종류에 대한 관련 질문은 데이터베이스에서 동기화해야 할 기본 키가 충돌하는 경우 자체 유스 케이스를 제공합니다. 조정해야하는 두 개의 데이터베이스가 있고 기본 키에 시퀀스를 사용하는 경우 키 중 하나를 변경하여 고유하게 유지할 수 있습니다.
이상적인 세상에서는 이런 일이 일어나지 않을 것입니다. 기본 키에 GUID를 사용하여 시작합니다. 그러나 실제로는 디자인을 시작할 때 분산 데이터베이스가 없을 수도 있으며 GUID로 변환하는 작업은 키 업데이트를 구현하는 것보다 더 큰 영향을 미치는 것으로 간주되어 배포하기보다 우선 순위가 낮은 노력 일 수 있습니다. 정수 키에 의존하는 큰 코드 기반이 있고 GUID로 변환하기 위해 큰 수정이 필요한 경우에 발생할 수 있습니다. 드문 드문 GUID (필요에 따라 임의로 생성되는 경우 서로 매우 근접하지 않은 GUID)가 특정 종류의 인덱스에 문제를 일으킬 수 있다는 사실도 있습니다. Byron Jones가 언급 한 기본 키로 사용됩니다 .
누군가가 NIN (National Insurance Number)을 1 차 키로 선택한 경우에 운영자가 NIN이 잘못된 행을 삽입하는 경우와 같은 상황을 상상하십시오. 값을 삽입 한 후 오류를 정정하는 두 가지 방법이 있습니다.