성능과 관련하여 GUID를 기본 키로 사용하는 가장 좋은 방법은 무엇입니까?


336

거의 모든 테이블에서 GUID를 기본 키로 사용하는 응용 프로그램이 있으며 GUID를 기본 키로 사용할 때 성능에 문제가 있음을 읽었습니다. 솔직히, 나는 어떤 문제도 보지 못했지만 새로운 응용 프로그램을 시작하려고하지만 GUID를 기본 키로 사용하고 싶지만 복합 기본 키 (GUID 및 다른 필드)를 사용하려고했습니다. .)

GUID는 "생산", "테스트"및 "dev"데이터베이스와 같은 다른 환경이 있고 데이터베이스 간 마이그레이션 데이터와 같은 다른 환경이있을 때 관리하기 쉽고 편리하기 때문에 GUID를 사용하고 있습니다.

Entity Framework 4.3을 사용하고 데이터베이스에 Guid를 삽입하기 전에 응용 프로그램 코드에서 Guid를 할당하려고합니다. (즉, SQL이 Guid를 생성하게하고 싶지 않습니다).

이 방법과 관련된 예상 성능 저하를 피하기 위해 GUID 기반 기본 키를 작성하는 가장 좋은 방법은 무엇입니까?


20
문제는 아닙니다. PK가 클러스터 된 경우 거의 모든 삽입물에 페이지가 분할 될 가능성이 있습니다. 최신 버전의 SQL Server에서는 NEWSEQUENTIALID ()를 사용하여 "고정"되었지만 미리 계산할 수 있다는 이점이 없습니다. GUID에 대해서는이 글이 너무 광범위해서 몇 시간 동안 계속 될 종교적 전투를 요구할 것이므로 다른 곳에서 GUID를 읽어 보는 것이 좋습니다.
Aaron Bertrand

4
나는 또한 워드 것을 추가 할 것 서버 에 모호 나는에 GUID를 할당 할 서버 측 (말라가 GUID를 생성하는 SQL을하자 싶어) .
Erik Philips

이 질문이 "SQL 서버-GUID-정렬 알고리즘 이유"에 유사성을 가지고 stackoverflow.com/questions/7810602/...
클린턴 워드

답변:


495

GUID는 기본 키의 자연스러운 선택으로 보일 수 있습니다. 실제로 필요한 경우 테이블의 PRIMARY KEY에 사용할 수도 있습니다. 내가 하지 말 것을 강력히 권유 하는 것은 GUID 열을 클러스터링 키로 사용하는 것입니다. 특별히 명시하지 않는 한 SQL Server는 기본적으로 SQL Server에서 수행합니다.

실제로 두 가지 문제를 구분해야합니다.

  1. 기본 키는 논리적 구조입니다 - 고유 안정적으로 테이블의 모든 행을 식별하는 후보 키 중 하나. 이 할 수있는 일, 정말 - INT하는 GUID문자열 - 당신의 시나리오에 가장 적합한 것을 선택합니다.

  2. 클러스터링 키 (열 또는 테이블의 "클러스터 된 인덱스"를 정의 열) -이 인 물리적 작은, 안정, 계속 증가하는 데이터 타입이 최선의 선택이다, 여기에 스토리지 관련 것, 그리고 - INT또는 BIGINT로 기본 옵션.

기본적으로 SQL Server 테이블의 기본 키는 클러스터링 키로도 사용되지만 반드시 그럴 필요는 없습니다! 이전 GUID 기반 기본 / 클러스터 키를 GUID의 기본 (논리) 키와 별도의 INT IDENTITY(1,1)열의 클러스터링 (순서화) 키로 분리 할 때 개인적으로 엄청난 성능 향상을 보았습니다 .

킴벌리 트립 인덱싱의 여왕 - - 그리고 다른 좋은 여러 번 언급 한 - GUID클러스터링 키가 무작위로 인한 때문에, 대규모 페이지와 인덱스 조각에 일반적으로 나쁜 성능으로 이어질 것입니다, 최적 아니므로.

예, 알고 있습니다 newsequentialid(). SQL Server 2005 이상이 있습니다. 그러나 그것은 심지어 완전하고 순차적이지 않으므로 동일한 문제로 인해 GUID덜 두드러지게 나타납니다.

고려해야 할 또 다른 문제가 있습니다. 테이블의 클러스터링 키가 테이블의 각 클러스터되지 않은 인덱스의 각 항목에 추가되므로 가능한 한 작게 만들어야합니다. 일반적으로 INT2 십억 행 이상의 행이 대부분의 테이블에 충분해야합니다 GUID. 클러스터링 키 와 비교하면 디스크와 서버 메모리에 수백 메가 바이트의 스토리지를 절약 할 수 있습니다.

빠른 계산 INT-vs. GUID를 기본 및 클러스터링 키로 사용 :

  • 1'000'000 개의 행이있는 기본 테이블 (3.8MB vs. 15.26MB)
  • 비 클러스터형 인덱스 6 개 (22.89MB vs. 91.55MB)

총계 : 25MB 대 106MB- 단일 테이블에 있습니다.

킴벌리 트립 (Kimberly Tripp)의 훌륭한 재료-생각을위한 음식이 더 있습니다. 읽고, 다시 읽고, 소화하십시오! 실제로 SQL Server 인덱싱 복음입니다.

추신 : 물론, 수백 또는 수천 행을 다루는 경우 이러한 인수의 대부분은 실제로 당신에게 큰 영향을 미치지 않습니다. 그러나 : 당신이 수십 또는 수백 행의 수천에 들어가, 또는 수백만에서 계산을 시작하는 경우 - 다음 그 점은 매우 중요하고 이해하기 매우 중요하게된다.

업데이트 : 당신은 당신이 원하는 경우 PKGUID기본 키로 열 (그러나 클러스터링 키) 및 다른 열 MYINT( INT IDENTITY클러스터링 키 등이) - 이것을 사용 :

CREATE TABLE dbo.MyTable
(PKGUID UNIQUEIDENTIFIER NOT NULL,
 MyINT INT IDENTITY(1,1) NOT NULL,
 .... add more columns as needed ...... )

ALTER TABLE dbo.MyTable
ADD CONSTRAINT PK_MyTable
PRIMARY KEY NONCLUSTERED (PKGUID)

CREATE UNIQUE CLUSTERED INDEX CIX_MyTable ON dbo.MyTable(MyINT)

기본적으로 제약 조건 을 명시 적으로 명시 해야합니다 (그렇지 않으면 기본적으로 클러스터형 인덱스로 생성됩니다). 그런 다음 정의 된 두 번째 인덱스를 만듭니다.PRIMARY KEYNONCLUSTEREDCLUSTERED

이것은 작동하며 성능을 위해 "재 설계"되어야하는 기존 시스템이있는 경우 유효한 옵션입니다. 새로운 시스템의 경우 처음부터 시작하고 복제 시나리오가 아닌 경우 항상 ID INT IDENTITY(1,1)다른 어떤 것보다 훨씬 효율적인 클러스터 된 기본 키로 선택 합니다!


2
이것은 훌륭한 답변입니다. 언급 한 가지는 삽입하기 전에 키를 생성 할 수 있다는 것이 종종 유용하다는 것입니다. "newsequentialid ()"를 사용하면 클러스터링에 도움이 될 수 있지만 SQL에 대한 추가 왕복이 필요합니다. 따라서 "서로 게이트 키"접근 방식의 또 다른 이점은 인덱스 조각화 문제를 줄이면서 클라이언트 측에서 새 ID를 생성 할 수 있다는 것입니다.
Andrew Theken

2
내가 이것을 읽는 방식은 클러스터되지 않은 uniqueidentifier 열과 int identity 열을 모두 가지고 있다는 것입니다 .FK도 uniqueidentifier이어야합니까? 그렇게하면 실제로 언제 ID 열을 직접 사용하겠습니까, 그렇지 않습니까?
pinkfloydx33

2
작은 질문, 이제 GUID를 조인 또는 int ID에 사용해야합니까? 내 본능은 GUID를 사용해야한다고 말해 주지만 int id를 사용하여 기술적 문제를 보지 못합니다 ...
Nicolas Belley

3
@marc_s이지만 복제 시나리오에서 int 열이 ID 인 경우 int 열이 여러 장치에서 반복 될 수 있으므로 GUID를 사용해서는 안됩니까?
Nicolas Belley

6
@Kipei : 주요 문제는 자연 가치가 있다면 IF입니다. 그렇다면 기본 키로 사용할 수 있습니다. 그러나DATETIME를 들어 같은 값 은 3.33ms의 정확도만을 가지므로 복제 키가 존재할 수 있기 때문에 클러스터링 키에는 유용 하지 않습니다. 따라서 이런 경우에는 여전히INT IDENTITY 대신 필요합니다. 따라서 20 년 이상 경험 한 frmo이기 때문에 실제로 사용할 수있는 자연 키가 거의 존재하지 않기 때문에 일반적으로 기본적으로 사용 합니다. ...
marc_s

51

2005 년부터 GUID를 PK로 사용해 왔습니다.이 분산 데이터베이스 세계에서는 분산 데이터를 병합하는 것이 가장 좋은 방법입니다. 결합 된 테이블에서 int가 일치하지 않아도 병합 테이블을 실행하고 잊을 수 있습니다. GUID 조인은 걱정없이 복사 할 수 있습니다.

이것은 GUID 사용을위한 설정입니다.

  1. PK = GUID. GUID는 문자열과 비슷하게 인덱싱되므로 높은 행 테이블 (5 천만 개가 넘는 레코드)에는 테이블 파티셔닝 또는 기타 성능 기술이 필요할 수 있습니다. SQL Server의 효율성이 높아 지므로 성능 문제가 점점 줄어들고 있습니다.

  2. PK Guid는 비 클러스터형 인덱스입니다. GUID가 NewSequentialID가 아닌 한 클러스터 인덱싱하지 마십시오. 그러나 서버를 다시 부팅하면 주문이 크게 중단됩니다.

  3. 모든 테이블에 ClusterID Int를 추가하십시오. 이것은 당신의 CLUSTERED Index입니다 ... 당신의 테이블을 주문합니다.

  4. ClusterID (int)에 대한 조인이보다 효율적이지만 2 천만에서 3 천만 건의 레코드 테이블로 작업하므로 GUID에 조인해도 성능에 눈에 띄게 영향을 미치지 않습니다. 최대 성능을 원한다면 ClusterID 개념을 기본 키로 사용하고 ClusterID에서 조인하십시오.

여기 내 이메일 테이블이 있습니다 ...

CREATE TABLE [Core].[Email] (
    [EmailID]      UNIQUEIDENTIFIER CONSTRAINT [DF_Email_EmailID] DEFAULT (newsequentialid()) NOT NULL,        
    [EmailAddress] NVARCHAR (50)    CONSTRAINT [DF_Email_EmailAddress] DEFAULT ('') NOT NULL,        
    [CreatedDate]  DATETIME         CONSTRAINT [DF_Email_CreatedDate] DEFAULT (getutcdate()) NOT NULL,      
    [ClusterID] INT NOT NULL IDENTITY,
    CONSTRAINT [PK_Email] PRIMARY KEY NonCLUSTERED ([EmailID] ASC)
);
GO

CREATE UNIQUE CLUSTERED INDEX [IX_Email_ClusterID] ON [Core].[Email] ([ClusterID])
GO

CREATE UNIQUE NONCLUSTERED INDEX [IX_Email_EmailAddress] ON [Core].[Email] ([EmailAddress] Asc)

PK_Email 제약 조건을 설명해 주시겠습니까? 왜 ... Nonclustered (ClusterID ASC) 대신 ... NonClustered (EmailID ASC)가 있습니까?
Phil

2
물론이지. 인덱스와 관련된 두 가지 주요 사항 : 1. ClusterID에 클러스터링-테이블을 디스크에 정렬합니다 (0 % 조각화). 2. EmailID에서 비 클러스터-EmailID 필드를 인덱싱하여 GUID ID 조회 속도를 높입니다. GUID 필드 조회는 문자열처럼 동작하므로 색인이 없으면 EmailID 조회가 느려집니다.
Robert J. Good

@ RobertJ.Good 클러스터에 대리 int 키를 추가하기 전에이 방법을 논의했습니다. 그러나 힙을 사용하여 대리 키 클러스터 인덱스를 사용하여 성능 향상을 보여주는 곳은 어디에서도 찾을 수 없습니다. 벤치 마크 데이터에 대한 링크가 있습니까?
Dale K

1
안녕하세요 @DaleBurrell, 클러스터 인덱스는 테이블 조각화를 방지하는 것입니다. 디스크에서 조각화가 적은 테이블이 자연스럽게 증가함에 따라 성능이 향상됩니다.
Robert J. Good

@ RobertJ.Good 웹 애플리케이션입니까? urls / hrefs에서 무엇을 사용하고 있습니까? guid 또는 int?
dariol '12

10

현재 EF Core로 웹 응용 프로그램을 개발 중이며 다음과 같은 패턴을 사용합니다.

모든 수업 (테이블)과 int PK 및 FK. 클러스터되지 않은 인덱스가있는 Guid 유형 (c # 생성자에 의해 생성 됨)이있는 추가 열이 있습니다.

EF 내 테이블의 모든 조인은 int 키를 통해 관리되는 반면 외부 (컨트롤러)의 모든 액세스는 Guid로 수행됩니다.

이 솔루션을 사용하면 URL에 int 키를 표시하지 않고 모델을 깔끔하고 빠르게 유지할 수 있습니다.


데이터 주석과 같이 정수 pK를 클러스터형으로 구성하기 위해해야합니까, 아니면 자동으로 구성되어 있습니까?
Allen Wang

Guid one에는 어떤 부동산의 이름을 사용하십니까?
Trong Phan

3

GUID를 기본 키로 사용하고 클러스터형 인덱스를 만드는 경우 기본값 인 NEWSEQUENTIALID () 값을 사용하는 것이 좋습니다.


왜 그렇게 하시겠습니까?
genuinefafa

3

이 링크는 내가 할 수있는 것보다 나아지고 의사 결정에 도움이되었습니다. 특정 필요가없는 한 일반적으로 int를 기본 키로 선택하고 특별한 이유가없는 한 SQL 서버 가이 필드를 자동 생성 / 유지하도록 허용합니다. 실제로 성능 문제는 특정 앱을 기반으로 결정해야합니다. 여기에는 예상되는 db 크기, 적절한 인덱싱, 효율적인 쿼리 등을 포함하여 여러 가지 요인이 있습니다. 사람들이 동의하지 않을 수도 있지만, 많은 시나리오에서 두 가지 옵션의 차이점을 발견하지 못할 것이며 앱에 더 적합한 것을 선택하고 더 쉽고 빠르며 효과적으로 개발할 수있는 방법을 선택해야합니다 (앱을 완성하지 않은 경우) 나머지는 어떤 차이가 있습니까 :).

https://web.archive.org/web/20120812080710/http://databases.aspfaq.com/database/what-should-i-choose-for-my-primary-key.html

추신 : 나는 왜 당신이 Composite PK를 사용할 것인지 또는 그것이 당신에게 어떤 이익을 줄 것이라고 확신하지 못합니다.


전적으로 동의합니다!! 그러나 그것은 내가 PK로 GUID를 가지고 있거나 GUID를 가진 Composite PK와 다른 필드가 동일한 권리가 될 것임을 의미합니까?
VAAA

1
PK (인덱스)는 두 개의 열로 구성되지만 업무상 특정 이유가 없다면 필요하지 않은 것 같습니다.
Matt

1
BTW이 질문은 가장 양극화되고 토론 된 질문 중 하나이므로 100 % 편안하게 느낄 수있는 답변을 얻는 것이 매우 어렵습니다. 두 가지 방법 모두 장단점이 있으므로 행운을 빕니다 :)
Matt


0

순차적 ID가 있으면 해커 나 데이터 마이너가 사이트와 데이터를 손상시키기가 훨씬 쉽습니다. 웹 사이트를위한 PK를 선택할 때 명심하십시오.


이 주장을 뒷받침하는 논리 나 증거를 제공 할 수 있습니까? 순차적 ID가 보안을 손상시키는 방법을 확인하려고 애 쓰고 있습니다.
jonaglon

물론, ID 번호가 정수라는 것을 알고 있으면 DB에 순차적으로 기록되는 것을 추측 할 수 있습니다. 따라서 단일 항목을 쿼리하면 다음 항목이 pk + 1이라고 말할 수 있습니다. 임의의 GUIDS가 있으면 패턴을 따르지 않습니다. 이전에 쿼리 한 레코드 이외의 다른 레코드를 쿼리하는 것은 거의 불가능합니다 (PK도 알고 있음).
DaBlue

1
해커가 이미 손상된 데이터베이스를 쿼리 할 수 ​​있다면 순차적 ID가 상황을 악화시키는 방법을 알 수 없습니다.
jonaglon

1
사용자가 1012를 다른 번호로 전환하여 데이터를 볼 수 없다면 매우 심각한 보안 문제가 발생하는 것입니다.이 문제는 기본 키 선택으로 인한 것이 아니라 악화됩니다. 나는 당신의 요점을 이해, 철자 주셔서 감사합니다.
jonaglon

2
GUID를 사용하여 웹 페이지에서 테이블의 PK가 아닌 레코드를 찾을 수 있습니다. 웹 사이트에서 쿼리 매개 변수를 사용하여 DB 스키마를 구성하는 방법을 정의해서는 안됩니다. PK는 UI 또는 백엔드 시스템의 입력 및 매개 변수와 관련이 없습니다.
Panos Roditakis
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.