UNIQUEIDENTIFIER 대신 BINARY (16)를 사용하면 위약금이 있습니까?


19

최근에 Guid를 저장 하는 BINARY(16)대신 사용하는 SQL Server 데이터베이스를 상속했습니다 UNIQUEIDENTIFIER. 기본 키를 포함한 모든 작업에 적용됩니다.

걱정해야합니까?


전체적으로 binary (16)를 일관되게 사용합니까? 변수와 매개 변수를 포함하여? 그렇지 않은 경우 암시 적 캐스트의 영향을 고려해야합니다.
Martin Smith

고맙게도 나는 암시 적 캐스트를 다룰 필요가 없습니다.
Jonathan Allen

답변:


21

걱정해야합니까?

글쎄, 여기에 약간 관련된 몇 가지가 있습니다.

첫째 : a UNIQUEIDENTIFIER(즉, Guid)가 16 바이트 이진 값인 것이 사실이지만 다음과 같은 사항도 적용됩니다.

  1. 모든 데이터는 이진 형식 INT으로 저장 될 수 있습니다 (예 :에 저장 가능 BINARY(4),에 DATETIME저장 가능 BINARY(8)등). # 2 ↴
  2. 편의상 GUID에 대해 별도의 데이터 유형을 갖는 이유가있을 수 있습니다 (예 : sysname에 대한 별명 NVARCHAR(128)).

내가 찾을 수있는 세 가지 행동 차이는 다음과 같습니다.

  • UNIQUEIDENTIFIER더 나은지 나쁜지에 대한 SQL Server의 값 비교 는 실제로 BINARY(16)값 을 비교하는 것과 같은 방식으로 수행되지 않습니다 . SQL Server에서 값을 비교할 때 GUID 및 uniqueidentifier Value 비교 에 대한 MSDN 페이지에 따르면 UNIQUEIDENTIFIER:

    값의 마지막 6 바이트가 가장 중요합니다

  • 이 값은 자주 정렬되지 않지만이 두 유형 간에는 약간의 차이가 있습니다. uniqueidentifier 에 대한 MSDN 페이지에 따르면 :

    순서는 두 값의 비트 패턴을 비교하여 구현되지 않습니다.

  • SQL Server와 .NET 사이에서 GUID 값을 처리하는 방법 (위의 "GUID와 uniqueidentifier 값 비교"페이지에 설명되어 있음)에 차이가 있으므로 SQL Server에서이 데이터를 앱 코드로 가져 오는 것이 제대로 처리되지 않을 수 있습니다. SQL Server 비교 동작을 에뮬레이션해야하는 경우 앱 코드 이 동작은로 변환하여 에뮬레이션 할 수 SqlGuid있지만 개발자가 알고 있어야합니까?

둘째 : 다음 진술에 근거

기본 키를 포함한 모든 작업에 적용됩니다.

대체 키 대신 GUID를 PK로 사용 INT하거나 PK로 사용하여 시스템 성능에 일반적으로 관심이 있습니다 BIGINT. 이러한 GUID PK가 클러스터형 인덱스인지에 대해서는 더욱 우려됩니다.

최신 정보

@Rob의 답변에 대한 OP의 의견은 다음과 같습니다.

그것은 MySQL에서 생각

GUID는 2 가지 이진 형식 으로 저장할 수 있습니다 . 따라서 다음에 따라 우려의 원인 이 있을 수 있습니다.

  1. 바이너리 표현이 생성 된 시스템
  2. 문자열 값이 원래 시스템 외부에서 사용 된 경우 (예 : 앱 코드 또는 가져 오기 파일 등에서 사용하도록 클라이언트에 제공)

이진 표현이 생성되는 문제는 4 개의 "필드"중 첫 3 개의 바이트 순서와 관련이 있습니다. 위의 Wikipedia 기사 링크를 따라 가면 RFC 4122가 4 개 필드 모두에 대해 "Big Endian"인코딩을 사용하도록 지정하지만 Microsoft GUID는 "Native"엔디안을 사용하여 지정한다는 것을 알 수 있습니다. 인텔 아키텍처는 Little Endian이므로 처음 3 개의 필드에 대한 바이트 순서는 RFC를 따르는 시스템과 Big Endian 시스템에서 생성 된 Microsoft 스타일 GUID와 반대로 바뀝니다. 첫 번째 필드 인 "Data 1"은 4 바이트입니다. 한 엔디안에서는 (가설 적으로) 표현됩니다 0x01020304. 그러나 다른 엔디안에서는 그럴 것입니다 0x04030201. 현재 데이터베이스가BINARY(16)이진 표현은 RFC를 따르는 시스템에서 생성 된 다음 현재 BINARY(16)필드에있는 데이터를로 변환하면 UNIQUEIDENTIFIER원래 작성된 것과 다른 GUID가됩니다. 이건 정말 문제를 제기하지 않는 경우 값이 데이터베이스를 떠난 적이 결코 값이 오직 주문 어떤지를하지 비교된다.

순서에 대한 문제는로 변환 한 후 순서가 동일하지 않다는 것입니다 UNIQUEIDENTIFIER. 다행히도 원래 시스템이 실제로 MySQL이라면 MySQL에는 UUID 문자열 표현 만 있기 때문에 이진 표현에 대한 주문은 처음부터 이루어지지 않았습니다 .

이진 표현이 Windows / SQL Server 외부에서 생성 된 경우 데이터베이스 외부에서 사용되는 문자열 값에 대한 우려가 더 심각합니다. 바이트 순서가 잠재적으로 다르기 때문에 문자열 형식의 동일한 GUID는 변환이 발생한 위치에 따라 2 개의 다른 2 진 표현을 생성합니다. 응용 프로그램 코드 또는 고객이 같은 문자열 형태의 GUID를 주어진 경우 ABC의 바이너리 형식에서 오는 123 은 RFC에 따라 시스템에서 생성 된 이진 표현, 다음 같은 이진 표현 (즉 것을 123)의 스트링 형태로 변환 할 DEF로 변환 할 때 UNIQUEIDENTIFIER. 마찬가지로의 원래 문자열 형식은 ABC의 이진 형식으로 456변환됩니다 UNIQUEIDENTIFIER.

따라서 GUID가 데이터베이스를 떠나지 않은 경우 주문 외부에 대해 걱정할 필요가 없습니다. 또는 문자열 형식을 변환하여 MySQL에서 가져 오기를 수행 한 경우 (예 : FCCEC3D8-22A0-4C8A-BF35-EC18227C9F40괜찮음) 그렇지 않으면 해당 GUID가 고객 또는 앱 코드에 제공된 경우 하나를 가져 와서 변환 SELECT CONVERT(UNIQUEIDENTIFIER, 'value found outside of the database');하여 예상되는 레코드를 찾는 지 여부를 테스트 할 수 있습니다 . 레코드를 일치시킬 수없는 경우 필드를로 유지해야합니다 BINARY(16).

모든 경우에 문제는 없지만 올바른 조건에서 문제가 발생할 수 있기 때문에 이것을 언급하고 있습니다.

어쨌든 새로운 GUID는 어떻게 삽입됩니까? 앱 코드에서 생성 되었습니까?

업데이트 2

다른 시스템에서 생성 된 GUID의 이진 표현 가져 오기와 관련된 잠재적 문제에 대한 이전의 설명이 약간 혼란 스러우면 다음 사항이 좀 더 명확 해지기를 바랍니다.

DECLARE @GUID UNIQUEIDENTIFIER = NEWID();
SELECT @GUID AS [String], CONVERT(BINARY(16), @GUID) AS [Binary];
-- String = 5FED23BE-E52C-40EE-8F45-49664C9472FD
-- Binary = 0xBE23ED5F2CE5EE408F4549664C9472FD
--          BE23ED5F-2CE5-EE40-8F45-49664C9472FD

위에 표시된 출력에서 ​​"String"및 "Binary"값은 동일한 GUID에서 가져옵니다. "Binary"행 아래의 값은 "Binary"행과 동일한 값이지만 "String"행과 같은 스타일로 형식이 지정됩니다 (예 : "0x"를 제거하고 네 개의 대시를 추가). 첫 번째와 세 번째 값을 비교하면 정확히 같지는 않지만 매우 가깝습니다. 가장 오른쪽 두 섹션은 동일하지만 가장 왼쪽 세 섹션은 다릅니다. 그러나 자세히 살펴보면 세 섹션의 각 바이트가 다른 순서로 동일한 바이트임을 알 수 있습니다. 처음 세 섹션 만 표시하는지 확인하고 바이트 수를 지정하면 두 표현간에 순서가 어떻게 다른지 쉽게 알 수 있습니다.

문자열 = 1 5F 2 ED 3 23 4 BE 5 E5 6 2C 7 40 8 EE
이진 = 4 BE 3 23 2 ED 1 5F 6 2C 5 E5 8 EE 7 40 (Windows / SQL Server)

따라서 각 그룹 내에서 바이트 순서는 반대로 바뀌지 만 Windows 및 SQL Server 내에서만 바뀝니다. 그러나 RFC를 준수하는 시스템에서 바이트 순서의 반전이 없기 때문에 이진 표현은 찌르기 표현을 반영합니다.

데이터는 MySQL에서 SQL Server로 어떻게 가져 왔습니까? 다음은 몇 가지 선택 사항입니다.

SELECT CONVERT(BINARY(16), '5FED23BE-E52C-40EE-8F45-49664C9472FD'),
       CONVERT(BINARY(16), 0x5FED23BEE52C40EE8F4549664C9472FD),
    CONVERT(BINARY(16), CONVERT(UNIQUEIDENTIFIER, '5FED23BE-E52C-40EE-8F45-49664C9472FD'));

보고:

0x35464544323342452D453532432D3430  
0x5FED23BEE52C40EE8F4549664C9472FD  
0xBE23ED5F2CE5EE408F4549664C9472FD

이진을 이진에서 이진으로 가정하면 (예 : 위의 변환 # 2) 실제 GUID로 변환되는 경우 결과 GUID는 다음과 UNIQUEIDENTIFIER같습니다.

SELECT CONVERT(UNIQUEIDENTIFIER, 0x5FED23BEE52C40EE8F4549664C9472FD);

보고:

BE23ED5F-2CE5-EE40-8F45-49664C9472FD

어느 것이 잘못 되었습니까? 그리고 그것은 우리에게 세 가지 질문을 남깁니다.

  1. SQL Server로 데이터를 어떻게 가져 왔습니까?
  2. 앱 코드는 어떤 언어로 작성됩니까?
  3. 앱 코드는 어떤 플랫폼에서 실행됩니까?

GUID가 데이터베이스에서 보이지 않기 때문에 응용 프로그램에서 GUID가 생성되었다고 가정합니다.
Jonathan Allen

바이트 순서에 대한 설명을 완전히 따르면 말할 수는 없지만 인덱싱에 대해 생각하게합니다. uniqueidentifier가 이진보다 인덱스 조각화가 발생할 가능성이 어느 정도입니까?
Jonathan Allen

2
@JonathanAllen 더 나은 설명을 위해 또 다른 업데이트 섹션을 추가했습니다. 그리고 아닙니다. 색인 생성은 서로 다르지 않아야합니다.
Solomon Rutzky

"고맙게도"SQL Server는 변형 1과 변형 2 사이의 순서를 변경하지 않습니다. '디스크에 다르게 저장 될 수 있더라도 일관되게 혼동되는 순서입니다.
user2864740

5

당신은 항상 걱정할 수 있습니다. ;)

시스템이 고유 식별자를 지원하지 않는 다른 시스템에서 마이그레이션되었을 수 있습니다. 모르는 다른 타협이 있습니까?

디자이너가 고유 식별자 유형에 대해 알지 못했을 수 있습니다. 그들이 모르는 다른 것들은 무엇입니까?

하지만 기술적으로는 큰 문제가되지 않습니다.


예, MySQL에서 마이그레이션되었습니다. 그리고 그렇습니다. 볼만한 흥미로운 것들이 많이 있습니다.
Jonathan Allen
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.