development

표준 Guid에 비해 Sequential Guid의 성능 향상은 무엇입니까?

big-blog 2020. 11. 19. 21:42
반응형

표준 Guid에 비해 Sequential Guid의 성능 향상은 무엇입니까?


누군가 데이터베이스 내에서 기본 키로 사용될 때 Sequential Guid와 Standard Guid의 성능을 측정 한 적이 있습니까?


GUID 대 순차 GUID



일반적인 패턴은 Guid를 테이블에 대한 PK로 사용하는 것이지만 다른 논의에서 언급했듯이 ( GUID / UUID 데이터베이스 키의 장단점 참조 ) 몇 가지 성능 문제가 있습니다.

이것은 전형적인 Guid 시퀀스입니다.

f3818d69-2552-40b7-a403-01a6db4552f7
7ce31615-fafb-42c4-b317-40d21a6a3c60
94732fc7-768e-4cf2-9107-f0953f6795a5


이러한 종류의 데이터 문제는 다음과 같습니다. <
-

  • 다양한 가치 분포
  • 거의 무작위로
  • 인덱스 사용은 매우, 매우, 매우 나쁩니다.
  • 많이 움직이는 잎
  • 거의 모든 PK는 최소한 클러스터되지 않은 인덱스에 있어야합니다.
  • Oracle과 SQL Server 모두에서 문제가 발생합니다.



가능한 해결책은 다음과 같이 생성되는 Sequential Guid를 사용하는 것입니다.

cc6466f7-1066-11dd-acb6-005056c00008
cc6466f8-1066-11dd-acb6-005056c00008
cc6466f9-1066-11dd-acb6-005056c00008


C # 코드에서 생성하는 방법 :

[DllImport("rpcrt4.dll", SetLastError = true)]
static extern int UuidCreateSequential(out Guid guid);

public static Guid SequentialGuid()
{
    const int RPC_S_OK = 0;
    Guid g;
    if (UuidCreateSequential(out g) != RPC_S_OK)
        return Guid.NewGuid();
    else
        return g;
}


혜택

  • 더 나은 인덱스 사용
  • 클러스터 된 키 사용 허용 (NLB 시나리오에서 확인)
  • 적은 디스크 사용량
  • 최소 비용으로 20-25 %의 성능 향상



실생활 측정 : 시나리오 :

  • SQL Server에서 UniqueIdentifier 유형으로 저장된 Guid
  • Oracle에서 CHAR (36)로 저장된 Guid
  • 단일 트랜잭션에서 함께 일괄 처리되는 많은 삽입 작업
  • 테이블에 따라 1 ~ 100 개의 인서트
  • 일부 테이블> 천만 행



실험실 테스트 – SQL Server

VS2008 테스트, 동시 사용자 10 명,인지 시간 없음, 리프 테이블에 대해 일괄 적으로 600 개의 삽입이있는 벤치 마크 프로세스
Standard Guid
Avg. 처리 시간 : 10.5
평균 초에 대한 요청 : 54.6
Avg. Resp. 시간 : 0.26

순차 가이드
평균 처리 시간 : 평균 4.6
초에 대한 요청 : 87.1
Avg. Resp. 시간 : 0.12

Oracle에서의 결과 (죄송합니다. 테스트에 다른 도구가 사용됨) 1.327.613 Guid PK

Standard Guid가 있는 테이블에 삽입 , 0.02 초. 각 인서트의 경과 시간, 2.861 초. CPU 시간, 총31.049경과 된

Sequential Guid , 0.00 초. 각 인서트의 경과 시간, 1.142 초. CPU 시간 총 3.667elapsed

DB 파일 순차 읽기 대기 시간이 62.415 초 동안 640 만 개의 대기 이벤트에서 11.063 초 동안 120 만 개의 대기 이벤트로 전달되었습니다 .

모든 순차 GUID를 추측 할 수 있다는 것을 확인하는 것이 중요하므로 보안이 문제가되는 경우 표준 GUID를 사용하는 경우 사용하는 것은 좋지 않습니다.
간단히 말해서 ... Guid를 PK로 사용하면 UI에서 앞뒤로 전달되지 않을 때마다 순차 GUID를 사용하면 작업 속도가 빨라지고 구현 비용이 들지 않습니다.


여기에 뭔가 빠졌을 수도 있지만 (그렇다면 자유롭게 수정 해주십시오), 기본 키에 순차 GUID / UUID를 사용하는 데 따른 이점은 거의 없습니다.

자동 증가 정수 대신 GUID 또는 UUID를 사용 하는 요점 은 다음과 같습니다.

  • 데이터베이스에 접속 하지 않고 어디서나 생성 가능
  • 애플리케이션 내에서 완전히 고유 한 식별자입니다 (UUID의 경우 보편적으로 고유함).
  • 하나의 식별자를 감안할 때, 다음 또는 이전 (또는 추측 할 방법이 없으면 어떤 짐승이-강제의 다른 유효한 식별자) 외부의 키 스페이스를.

불행히도 귀하의 제안을 사용하면 모든 것을 잃게됩니다 .

네. GUID를 개선했습니다. 그러나 그 과정에서 애초에 그것들을 사용해야하는 거의 모든 이유를 버렸습니다.

당신이 경우 정말 성능을 향상시키고 자하는, 기본 키 정수 표준 autoincrementing를 사용합니다. 그것은 거의 모든면에서 '순차적 가이드'보다 더 나은 동시에 설명 한 모든 이점을 제공합니다.

이것은 귀하의 질문에 구체적으로 답변하지 않기 때문에 망각에 빠질 가능성이 높지만 (자신이 직접 답변 할 수 있도록 신중하게 제작 된 것임), 제기하는 것이 훨씬 더 중요한 포인트라고 생각합니다.


massimogentilini가 이미 말했듯이 UuidCreateSequential을 사용할 때 (코드에서 guid를 생성 할 때) 성능이 향상 될 수 있습니다. 그러나 사실이 누락 된 것 같습니다. SQL Server (적어도 Microsoft SQL 2005/2008)는 동일한 기능을 사용하지만 Guid의 비교 / 순서는 .NET과 SQL Server에서 다르므로 여전히 더 많은 IO가 발생합니다. GUID가 올바르게 주문되지 않기 때문입니다. SQL Server에 대해 올바르게 정렬 된 GUID를 생성하려면 (순서 지정) 다음을 수행해야합니다 ( 비교 세부 정보 참조).

[System.Runtime.InteropServices.DllImport("rpcrt4.dll", SetLastError = true)]
static extern int UuidCreateSequential(byte[] buffer);

static Guid NewSequentialGuid() {

    byte[] raw = new byte[16];
    if (UuidCreateSequential(raw) != 0)
        throw new System.ComponentModel.Win32Exception(System.Runtime.InteropServices.Marshal.GetLastWin32Error());

    byte[] fix = new byte[16];

    // reverse 0..3
    fix[0x0] = raw[0x3];
    fix[0x1] = raw[0x2];
    fix[0x2] = raw[0x1];
    fix[0x3] = raw[0x0];

    // reverse 4 & 5
    fix[0x4] = raw[0x5];
    fix[0x5] = raw[0x4];

    // reverse 6 & 7
    fix[0x6] = raw[0x7];
    fix[0x7] = raw[0x6];

    // all other are unchanged
    fix[0x8] = raw[0x8];
    fix[0x9] = raw[0x9];
    fix[0xA] = raw[0xA];
    fix[0xB] = raw[0xB];
    fix[0xC] = raw[0xC];
    fix[0xD] = raw[0xD];
    fix[0xE] = raw[0xE];
    fix[0xF] = raw[0xF];

    return new Guid(fix);
}

또는 이 링크 또는 이 링크 .


이 경우 필요 순차적 GUID를 사용하여, SQL 서버 2005와 함께 당신을 위해 그 (것)들을 생성 할 수있는 NEWSEQUENTIALID()기능.

However since the basic usage of GUIds is to generate keys (or alternate keys) that cannot be guessed (for example to avoid people passing guessed keys on GETs), I don't see how applicable they are because they are so easily guessed.

From MSDN:

Important:
If privacy is a concern, do not use this function. It is possible to guess the value of the next generated GUID and, therefore, access data associated with that GUID.


See This article: (http://www.shirmanov.com/2010/05/generating-newsequentialid-compatible.html)

Even though MSSql uses this same function to generate NewSequencialIds ( UuidCreateSequential(out Guid guid) ), MSSQL reverses the 3rd and 4th byte patterns which does not give you the same result that you would get when using this function in your code. Shirmanov shows how to get the exact same results that MSSQL would create.


Check out COMBs by Jimmy Nilsson: a type of GUID where a number of bits have been replaced with a timestamp-like value. This means that the COMBs can be ordered, and when used as a primary key result in less index page splits when inserting new values.

Is it OK to use a uniqueidentifier (GUID) as a Primary Key?


OK, I finally got to this point in design and production myself.

I generate a COMB_GUID where the upper 32 bits are based on the bits 33 through 1 of Unix time in milliseconds. So, there are 93 bits of randomness every 2 milliseconds and the rollover on the upper bits happens every 106 years. The actual physical representation of the COMB_GUID (or type 4 UUID) is a base64 encoded version of the 128 bits, which is a 22 char string.

When inserting in postgres the ratio of speed between a fully random UUID and a COMB _GUID holds as beneficial for the COMB_GUID. The COMB_GUID is 2X faster on my hardware over multiple tests, for a one million record test. The records contain the id(22 chars), a string field (110 chars), a double precision, and an INT.

In ElasticSearch, there is NO discernible difference between the two for indexing. I'm still going to use COMB_GUIDS in case content goes to BTREE indexes anywhere in the chain as the content is fed time related, or can be presorted on the id field so that it IS time related and partially sequential, it will speed up.

Pretty interesting. The Java code to make a COMB_GUID is below.

import java.util.Arrays;
import java.util.UUID;
import java.util.Base64; //Only avail in Java 8+
import java.util.Date;

import java.nio.ByteBuffer; 

    private ByteBuffer babuffer = ByteBuffer.allocate( (Long.SIZE/8)*2 );
private Base64.Encoder encoder = Base64.getUrlEncoder();
public  String createId() {
    UUID uuid = java.util.UUID.randomUUID();
        return uuid2base64( uuid );
}

    public String uuid2base64(UUID uuid){ 

        Date date= new Date();
        int intFor32bits;
        synchronized(this){
        babuffer.putLong(0,uuid.getLeastSignificantBits() );
        babuffer.putLong(8,uuid.getMostSignificantBits() );

                long time=date.getTime();
        time=time >> 1; // makes it every 2 milliseconds
                intFor32bits = (int) time; // rolls over every 106 yers + 1 month from epoch
                babuffer.putInt( 0, intFor32bits);

    }
        //does this cause a memory leak?
        return encoder.encodeToString( babuffer.array() );
    }

}


I messured difference between Guid (clustered and non clustered), Sequential Guid and int (Identity/autoincrement) using Entity Framework. The Sequential Guid was surprisingly fast compared to the int with identity. Results and code of the Sequential Guid here.


I do not see the need for unique keys to be guessable or not, passing them from a web UI or in some other part seems a bad practice by itself and I do not see, if you have security concerns, how using a guid can improve things (if this is the matter use a real random number generator using the proper crypto functions of the framework).
The other items are covered by my approach, a sequential guid can be generated from code without need for DB access (also if only for Windows) and it's unique in time and space.
And yes, question was posed with the intent of answering it, to give people that have choosen Guids for their PK a way to improve database usage (in my case has allowed the customers to sustain a much higher workload without having to change servers).

It seems that security concerns are a lot, in this case do not use Sequential Guid or, better still, use standard Guid for PK that are passed back and forward from your UI and sequential guid for everything else. As always there is no absolute truth, I've edited also main answer to reflect this.

참고URL : https://stackoverflow.com/questions/170346/what-are-the-performance-improvement-of-sequential-guid-over-standard-guid

반응형