2014-03-06 4 views
0

멋진 기사 The Cost of GUIDs as Primary Keys 덕분에 COMB GUID가 있습니다. 타임 스탬프타임 스탬프의 경우 8 바이트 또는 SQLServer의 COMB GUID의 타임 스탬프의 경우 6 바이트

  1. 사용 지난 6 바이트 : 사용하여 타임 스탬프 GUIDs as fast primary keys under multiple databases
  2. 사용 지난 8 바이트 창 틱 : 현재 구현을 바탕으로 2 가지가 있습니다 GUID COMB strategy in EF4.1 (CodeFirst)

는 우리 모두에 대한 것을 알고있다 GUID에서 6 바이트 타임 스탬프, GUID의 충돌을 줄이기 위해 임의 바이트에 대해 더 많은 바이트가 있습니다. 그러나 동일한 타임 스탬프가있는 GUID가 더 많이 생성되고 순차적으로 정렬되지 않습니다. 이를 통해 8 바이트 타임 스탬프가 선호됩니다.

그래서 어려운 선택입니다. GUIDs as fast primary keys under multiple databases 위의 문서를 기반으로, 그것은 말한다 :

우리는이 방법에 대한 짧은 각주를 계속하기 전에 : 1 밀리 초 해상도의 타임 스탬프를 사용하는 GUID가이 같은 타임 스탬프 값을 가질 수 서로 매우 가까운 생성 등을 의미 순차적이지 않습니다. 일부 응용 프로그램에서는이 문제가 자주 발생하며 실제로 System.Diagnostics.Stopwatch와 같은 고해상도 타이머를 사용하거나 시퀀스를 보장하는 "카운터"와 타임 스탬프를 결합하는 등의 몇 가지 대체 방법을 실험했습니다 타임 스탬프가 업데이트 될 때까지 계속되었습니다. 그러나 테스트를하는 동안 동일한 1 밀리 초 창 내에서 수십 또는 심지어 수백 개의 GUID가 생성되는 경우에도 식별 할 수있는 차이가 전혀 없음을 발견했습니다. 이것은 지미 닐슨 (Jimmy Nilsson)이 COMBs를 테스트하는 과정에서 겪었던 것과 일치합니다.

내부 데이터베이스를 아는 사람이 위의 관찰에 대해 몇 가지 조명을 공유 할 수 있는지 궁금합니다. 데이터베이스 서버가 메모리에 데이터를 저장하고 특정 임계 값에 도달하면 디스크에 쓰기 만하기 때문입니까? 따라서, 동일한 타임 스탬프를 갖는 비 시퀀스 GUID를 갖는 삽입 된 데이터의 재정렬은 일반적으로 메모리에서 발생하여 성능 페널티를 최소화 할 수있다.

업데이트 : COMB GUID는 임의 GUID와 비교하여 COMB GUID가 인터넷을 통해 청구됨에 따라 테이블 조각화를 줄일 수 없습니다. 지금 SQL Server를 사용하여 순차 GUID를 생성하는 것이 유일한 방법 인 것 같습니다.

+1

나는 나열된 모든 기사가 * 클러스터 된 색인 키 *로 기본 키 *를 혼란스럽게 생각한다고 생각합니다. GUIDS는 특히 다중 마스터 상황에서 주요 키로 작동하지만 클러스터 된 인덱스 키로는 잘 작동하지 않습니다 ("잘 작동하지 않지만"은 테이블에있는 다른 열에 따라 다름). –

+0

예, 당신 말이 맞습니다. 우리의 주된 관심사는 우리 테이블에 클러스터 된 PK 인 GUID의 무작위로 인해 많은 단편화가 발생한다는 것입니다. 동일한 타임 스탬프 내에서 임의 GUID의 성능에 대한 위의 내 질문에 대한 의견? – windfly2006

+0

클러스터 된 인덱스 키로 사용할 다른 열이 없다면'newsequentialid()'(아래 @ErikE에서)로 이동합니다. –

답변

2

참조한 문서가 2002 년이며 매우 오래된 문서입니다. newsequentialid (SQL Server 2005 이상에서 사용 가능) 만 사용하십시오. 이렇게하면 생성하는 각 새 ID가 이전의 ID보다 큼을 보장하여 인덱스 조각화/페이지 분할 문제를 해결할 수 있습니다.

필자가 언급 한 또 다른 측면은, 글을 쓰는 작가는 4면을 필요로 할 때 16 바이트를 사용하는 것이 좋지 않다는 점이다. 예를 들어, 클러스터 된 열을 포함하지 않고 평균 150,000 바이트의 행을 가진 테이블이 있고 테이블에 4 바이트, 25 바이트 및 50 개의 평균 행이 차례로있는 3 개의 비 클러스터형 인덱스 (각 행에 클러스터형 열을 반복 함)가 있다고합시다. 바이트는 클러스터 된 열을 계산하지 않습니다. 완벽한 100 % 채우기 비율에서

스토리지 요구 사항이 다음이다 (제외 메가 바이트의 모든 숫자 곳 %) : 4 바이트의 한 int 열을 갖는 클러스터되지 않은 인덱스에서

Item Clust 50  25  4  Total 
---- ----- ----- ----- ----- ------ 
GUID 79.1 31.5 19.6 9.5 139.7 
int 73.4 25.7 13.8 3.8 116.7 
%imp 7.2% 18.4% 29.6% 60.0% 16.5% 

(일반적인 시나리오) 클러스터 된 인덱스를 int으로 전환하면 60 % 작아집니다!이는 테이블 스캔의 경우 60 % 성능 향상으로 직접 변환됩니다. 작은 행의 경우 페이지 분할이 덜 자주 발생하고 조각화가 더 오래 유지되기 때문에 보수적입니다.

클러스터 된 인덱스 자체에서도 여전히 7.2 %의 성능 향상이 있습니다.

전체 데이터베이스에서 int으로 전환하면 이와 비슷한 프로필을 가진 테이블이 있었고 데이터베이스 크기가 1.397 테라 바이트였습니다. 전체 데이터베이스는 230Gb 더 클 것입니다 (전체 열, 139.7 - 116.7 참조). 현실 세계에서 고 가용성 스토리지를위한 실질적인 돈이됩니다. 회사의 수익에 유해한 디스크 구매 일정을 일찌감치 옮깁니다.

필요 이상으로 큰 데이터 유형을 사용하지 마십시오. 그것은 이유없이 당신의 차에 무게를 더하는 것과 같습니다 : 은 그것을 지불합니다 (속도가 빠르면 연비가 떨어집니다).

UPDATE 지금은 당신이 당신의 클라이언트 측 코드에서 GUID를 만드는 알고

, 좀 더 명확하게 문제의 본질을 볼 수 있습니다. 이 행 삽입 시간까지 GUID 생성을 연기 할 수있는 인 경우이를 수행하는 한 가지 방법이 있습니다.

:

ALTER TABLE dbo.Customer ADD CONSTRAINT DF_Customer_CustomerID 
    DEFAULT (newsequentialid()) FOR Customer; 

지금 당신이 어떤 INSERTCustomerID을 위해 삽입하고, 쿼리는 다음과 같이 볼 수 있었다 어떤 값을 지정할 필요가 없습니다 :

먼저, CustomerID 컬럼에 대한 기본 설정

DECLARE @Name varchar(100) = 'Acme Spy Devices'; 
INSERT dbo.Customer (Name) 
OUTPUT inserted.CustomerID -- a GUID 
VALUES (@Name); 

이 간단한 예제에서는 Customer 테이블에 새 행을 삽입하고 방금 작성한 값을 포함하는 행 집합을 클라이언트에 모두 한 쿼리로 반환했습니다.

명시 적으로 작동시킬 VALUES (newsequentialid(), @Name)을 삽입하고 싶다면.

+0

대단히 감사합니다. 우리는 Entity Framework를 사용하고 있으며이 코드를 사용하여 PK 용 GUID를 생성하므로 코드에서 순차 GUID를 생성하기위한 최소한의 코드 변경을 찾고 있습니다. 이 시점에서 우리는 너무 많은 코드 변경으로 인해 PK로 INT로 돌아갈 수 없습니다. newsequentialid를 사용하는 경우 해당 GUID를 생성하기위한 추가 데이터베이스 왕복이 생깁니다. 맞습니까? – windfly2006

+0

올바른,'newsequentialid()'데이터베이스에서 호출해야합니다. 경우에 따라 ID를 가져 오는 대신 전체 레코드를 삽입 한 후 ID *를 얻기 위해 코드를 다시 작성할 수 있습니다. 그렇다면 데이터베이스에 대한 추가 출장이 필요하지 않습니다. – ErikE

+0

다시 한번 감사드립니다. 데이터베이스로의 추가 출장이 필요하지 않은 경우 사례에 대한 링크 또는 코드 샘플을 공유 할 수 있을지 궁금합니다. – windfly2006