문제

데이터베이스 내부의 기본 키로 사용될 때 누군가가 순차 안내 대 표준 Guid의 성능을 측정 한 적이 있습니까?

도움이 되었습니까?

해결책

GUID vs. Secondent Guid



일반적인 패턴은 테이블의 PK로 안내를 사용하는 것이지만 다른 토론에서 언급 된대로 Guid / UUID 데이터베이스 키의 장점 및 단점) 몇 가지 성능 문제가 있습니다.

이것은 전형적인 안내 시퀀스입니다

F3818D69-2552-40B7-A403-01A6DB4552F7
7CE31615-FAFB-42C4-B317-40D21A6A3C60
94732FC7-768E-4CF2-9107-F0953F6795A5


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

  • 넓은 값 분포
  • 거의 무작위로
  • 인덱스 사용량은 매우, 매우 나쁘다
  • 많은 잎이 움직입니다
  • 거의 모든 PK는 적어도 클러스터되지 않은 인덱스에 있어야합니다.
  • Oracle과 SQL Server에서 문제가 발생합니다



가능한 솔루션은 다음과 같이 생성되는 순차적 인 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에 고유 한 식별기 유형으로 저장된 안내서
  • 오라클에 문자 (36)로 저장된 안내서
  • 단일 트랜잭션에서 함께 배치 된 많은 삽입 작업
  • 테이블에 따라 1 내지 100의 인서트
  • 일부 테이블> 10 백만 행



실험실 테스트 - SQL Server

vs2008 테스트, 10 명의 동시 사용자, 생각 시간 없음, 잎 테이블 배치에 600 인서트가있는 벤치 마크 프로세스
표준지도
avg. 프로세스 지속 시간 : 10.5 비서
avg. 두 번째 요청 : 54.6
avg. resp. 시간: 0.26

순차 안내
avg. 프로세스 지속 시간 : 4.6 비서
avg. 두 번째 요청 : 87.1
avg. resp. 시간: 0.12

Oracle에 대한 결과 (죄송합니다, 테스트에 사용 된 다른 도구) 1.327.613 Guid PK가있는 테이블에 삽입

표준지도, 0.02 비서. 각 삽입에 대한 경과 시간, 2.861 비서. CPU 시간, 총 31.049 비서. 경과

순차 안내, 0.00 비서. 각 삽입에 대한 경과 시간, 1.142 비서. CPU 시간, 총 3.667 비서. 경과

DB 파일 순차 읽기 대기 시간이 전달되었습니다 6.4 수백만 명이 이벤트를 기다립니다 62.4151.2 백만 개의 대기 행사 11.063 초.

모든 순차 안내를 추측 할 수 있다는 것을 알 수 있으므로 보안이 여전히 표준 안내서를 사용하는 경우 보안을 사용하는 것이 좋지 않습니다.
짧게 만들기 위해 ... PK로 Guid를 사용하면 UI에서 뒤로 전달되지 않을 때마다 순차 안내서를 사용하면 작동 속도를 높이고 구현 비용이 들지 않습니다.

다른 팁

나는 여기서 무언가를 놓치고 있을지도 모르지만 (내가 있다면 나를 바로 잡으십시오), 기본 키에 순차적 인 Guid/UUID를 사용하는 데 거의 도움이되지 않습니다.

그만큼 가리키다 자동화 된 정수에 대한 안내 또는 UUID를 사용하는 것.

  • 그들은 어디서나 만들 수 있습니다 없이 데이터베이스 연락
  • 응용 프로그램 내에서 완전히 고유 한 식별자 (및 UUID의 경우 보편적으로 고유 한 식별자입니다).
  • 하나의 식별자가 주어지면 다음 또는 이전을 추측 할 방법이 없습니다 (또는 심지어 어느 Brute-Forcing 이외의 다른 유효한 식별자) a 거대한 키 공간.

불행히도, 당신의 제안을 사용하여 당신은 잃습니다 모두 그것들.

그래서 그렇습니다. 당신은 더 나은지도를 만들었습니다. 그러나 그 과정에서, 당신은 처음에 그것들을 사용해야하는 거의 모든 이유를 버렸습니다.

만약 너라면 진짜 성능을 향상시키고 표준 자동화 정수 기본 키를 사용하려고합니다. 그것은 거의 모든면에서 '순차적 인 Guid'보다 낫지 만, 설명한 모든 이점을 제공합니다.

이것은 당신의 질문에 구체적으로 대답하지 않기 때문에 망각에 빠질 가능성이 높습니다 (즉시 조심스럽게 제작되어 즉시 스스로 대답 할 수 있습니다).

Massimogentilini가 이미 말했듯이 Uuidcreatesequential을 사용할 때 (코드에서 Guids를 생성 할 때) 성능을 향상시킬 수 있습니다. 그러나 사실은 누락 된 것 같습니다. SQL Server (적어도 Microsoft SQL 2005 / 2008)는 동일한 기능을 사용하지만 : Guid의 비교 / 순서는 .NET와 SQL Server에서 다릅니다. 안내서는 올바르게 주문되지 않기 때문입니다. SQL Server (주문)에 대해 올바르게 주문한 안내서를 생성하려면 다음을 수행해야합니다 ( 비교 세부):

[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);
}

또는 이 링크 또는 이 링크.

만약 너라면 필요 순차 안내서를 사용하려면 SQL Server 2005는 NEWSEQUENTIALID() 기능.

하지만 Guids의 기본 사용법은 추측 할 수없는 키 (또는 대체 키)를 생성하는 것이기 때문에 (예를 들어, 추측 된 열쇠를 지나가는 사람들을 피하기 위해), 나는 그들이 쉽게 추측 할 수 있기 때문에 얼마나 적용 할 수 있는지 알 수 없습니다.

에서 MSDN:

중요한:
프라이버시가 우려되는 경우이 기능을 사용하지 마십시오. 다음 생성 된 GUID의 가치를 추측 할 수 있으므로 해당 GUID와 관련된 데이터에 액세스 할 수 있습니다.

이 기사를 참조하십시오 : (http://www.shirmanov.com/2010/05/generating-new evidentialid-compatible.html)

MSSQL은이 동일한 기능을 사용하여 NewSedEncialIDS (UUIDCreateseQuential (Out Guid Guid))을 생성하지만 MSSQL은 3 및 4 번째 바이트 패턴을 역전시켜 코드 에서이 기능을 사용할 때 얻을 수있는 것과 동일한 결과를 제공하지 않습니다. Shirmanov는 MSSQL과 동일한 결과를 얻는 방법을 보여줍니다.

체크 아웃 Jimmy Nilsson : 여러 비트가 타임 스탬프와 같은 값으로 대체 된 유형의 유형. 즉, 콤을 주문할 수 있으며 기본 키로 사용하면 새 값을 삽입 할 때 인덱스 페이지가 줄어 듭니다.

고유 한 식별기 (Guid)를 기본 키로 사용해도 괜찮습니까?

좋아, 나는 마침내 디자인과 제작 에서이 시점에 도달했다.

상단 32 비트가 밀리 초의 유닉스 시간의 비트 33에서 1 비트를 기준으로하는 COMB_GUID를 생성합니다. 따라서 2 밀리 초마다 93 비트의 무작위성이 있으며 상단 비트의 롤오버는 106 년마다 발생합니다. COMB_GUID (또는 Type 4 UUID)의 실제 물리적 표현은 128 비트의 Base64 인코딩 된 버전이며, 이는 22 문자열입니다.

Postgres를 삽입 할 때 완전 무작위 UUID와 COMB _GUID 사이의 속도 비율은 COMB_GUID에 유리합니다. COMB_GUID는입니다 2x 백만 레코드 테스트를 위해 여러 테스트보다 하드웨어가 빠릅니다. 레코드에는 ID (22 숯), 문자열 필드 (110 숯), 이중 정밀도 및 int가 포함됩니다.

Elasticsearch에서는 인덱싱을위한 두 가지 사이에 눈에 띄는 차이가 없습니다. 콘텐츠가 컨텐츠가 공급되거나 ID 필드에 선별 될 수 있으므로 체인의 어느 곳에서나 BTREE 인덱스로 이동하는 경우 COMB_GUIDS를 여전히 사용하겠습니다. 이다 시간 관련 및 부분적으로 순차적으로 속도가 빨라집니다.

꽤 흥미 롭습니다. COMB_GUID를 만들기위한 Java 코드는 다음과 같습니다.

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() );
    }

}

엔티티 프레임 워크를 사용하여 Guid (클러스터 및 비 클러스터), 순차적 인 Guid 및 INT (Identity/AutoinCrement) 간의 차이를 전했습니다. 순차 안내는 동일성을 가진 INT에 비해 놀랍게도 빠릅니다. 순차 안내서의 결과 및 코드.

나는 고유 한 키가 추측 할 수 있거나 없어야 할 필요가 없으며, 웹 UI에서 그들을 전달하거나 다른 부분에서 전달하는 것은 그 자체로는 나쁜 관행 인 것처럼 보이며 보안 문제가 있다면 Guid를 사용하는 방법이 개선 될 수 있습니다. 사물 (이것이 문제라면 프레임 워크의 적절한 암호화 함수를 사용하여 실제 임의 숫자 생성기를 사용합니다).
다른 항목은 내 접근 방식으로 다루고, DB 액세스가 필요하지 않고 (Windows의 경우에만) 코드에서 순차 안내서를 생성 할 수 있으며 시간과 공간이 고유합니다.
그렇습니다. 질문에 대답하려는 의도로 PK를 선택한 사람들에게 데이터베이스 사용량을 개선하는 방법을 제공하기 위해 질문이 제기되었습니다 (제 경우에는 고객이 서버를 변경하지 않고 훨씬 더 높은 워크로드를 유지할 수있었습니다).

보안 문제는 많이있는 것 같습니다.이 경우 순차적 인 Guid를 사용하지 않거나 UI에서 뒤로 전달되는 PK에 대한 표준 안내서와 다른 모든 것에 대한 순차 안내서를 사용합니다. 항상 절대적인 진실은없고, 나는 이것을 반영하기 위해 주요 답변을 편집했습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top