답변:
내 DBA는 객체에 GUID를 저장하는 가장 좋은 방법에 대해 물었을 때 Integer로 4 바이트로 같은 일을 할 수있을 때 16 바이트를 저장 해야하는 이유를 물었습니다. 그가 저에게 그 도전을 줬기 때문에 나는 그것을 언급하기에 좋은 때라고 생각했습니다. 그 말은 ...
스토리지 공간을 최대한 활용하려면 guid를 CHAR (16) 이진으로 저장할 수 있습니다.
나는 그것을 char (36)로 저장할 것이다.
-
s 를 보관해야하는 이유를 알 수 없습니다 .
ThaBadDawg의 대답에 덧붙여,이 편리한 기능을 사용하여 현명한 동료에게 감사하십시오 .36 길이의 문자열에서 16의 바이트 배열로 되돌립니다.
DELIMITER $$
CREATE FUNCTION `GuidToBinary`(
$Data VARCHAR(36)
) RETURNS binary(16)
DETERMINISTIC
NO SQL
BEGIN
DECLARE $Result BINARY(16) DEFAULT NULL;
IF $Data IS NOT NULL THEN
SET $Data = REPLACE($Data,'-','');
SET $Result =
CONCAT( UNHEX(SUBSTRING($Data,7,2)), UNHEX(SUBSTRING($Data,5,2)),
UNHEX(SUBSTRING($Data,3,2)), UNHEX(SUBSTRING($Data,1,2)),
UNHEX(SUBSTRING($Data,11,2)),UNHEX(SUBSTRING($Data,9,2)),
UNHEX(SUBSTRING($Data,15,2)),UNHEX(SUBSTRING($Data,13,2)),
UNHEX(SUBSTRING($Data,17,16)));
END IF;
RETURN $Result;
END
$$
CREATE FUNCTION `ToGuid`(
$Data BINARY(16)
) RETURNS char(36) CHARSET utf8
DETERMINISTIC
NO SQL
BEGIN
DECLARE $Result CHAR(36) DEFAULT NULL;
IF $Data IS NOT NULL THEN
SET $Result =
CONCAT(
HEX(SUBSTRING($Data,4,1)), HEX(SUBSTRING($Data,3,1)),
HEX(SUBSTRING($Data,2,1)), HEX(SUBSTRING($Data,1,1)), '-',
HEX(SUBSTRING($Data,6,1)), HEX(SUBSTRING($Data,5,1)), '-',
HEX(SUBSTRING($Data,8,1)), HEX(SUBSTRING($Data,7,1)), '-',
HEX(SUBSTRING($Data,9,2)), '-', HEX(SUBSTRING($Data,11,6)));
END IF;
RETURN $Result;
END
$$
CHAR(16)
실제로 BINARY(16)
선호하는 맛을 선택하십시오.
코드를 더 잘 따르려면 아래의 숫자로 정렬 된 GUID를 예로 들어 보겠습니다. (잘못된 문자는 설명 목적으로 사용되며 각 위치마다 고유 한 문자가 사용됩니다.)이 함수는 우수한 인덱스 클러스터링을 위해 비트 순서를 달성하도록 바이트 순서를 변환합니다. 재정렬 된 guid가 예제 아래에 표시되어 있습니다.
12345678-9ABC-DEFG-HIJK-LMNOPQRSTUVW
78563412-BC9A-FGDE-HIJK-LMNOPQRSTUVW
대시가 제거되었습니다.
123456789ABCDEFGHIJKLMNOPQRSTUVW
78563412BC9AFGDEHIJKLMNOPQRSTUVW
GuidToBinary
($ guid char (36)) RETURNS binary (16) RETURN CONCAT (UNHEX (SUBSTRING ($ guid, 7, 2)), UNHEX (SUBSTRING ($ guid, 5, 2)), UNHEX (SUBSTRING ($ guid, 3, 2)), UNHEX (SUBSTRING ($ guid, 1, 2)), UNHEX (SUBSTRING ($ guid, 12, 2)), UNHEX (SUBSTRING ($) guid, 10, 2)), UNHEX (SUBSTRING ($ guid, 17, 2)), UNHEX (SUBSTRING ($ guid, 15, 2)), UNHEX (SUBSTRING ($ guid, 20, 4)), UNHEX (SUBSTRING) ($ guid, 25, 12));
"더 나은"은 최적화하는 대상에 따라 다릅니다.
스토리지 크기 / 성능 대 개발 용이성에 대해 얼마나 관심이 있습니까? 더 중요한 것은-충분한 GUID를 생성하거나 자주 가져 오는 것이 중요합니까?
대답이 "아니오"이면 char(36)
충분하고 GUID를 저장 / 가져 오기가 매우 간단합니다. 그렇지 않으면 binary(16)
합리적이지만 일반적인 문자열 표현에서 앞뒤로 변환하려면 MySQL 및 / 또는 프로그래밍 언어를 사용해야합니다.
KCD에 의해 게시 된 GuidToBinary 루틴은 GUID 문자열에서 타임 스탬프의 비트 레이아웃을 설명하도록 조정되어야합니다. 문자열이 uuid () mysql 루틴이 리턴 한 것과 같이 버전 1 UUID를 나타내는 경우 시간 구성 요소는 D를 제외하고 문자 1-G로 임베드됩니다.
12345678-9ABC-DEFG-HIJK-LMNOPQRSTUVW
12345678 = least significant 4 bytes of the timestamp in big endian order
9ABC = middle 2 timestamp bytes in big endian
D = 1 to signify a version 1 UUID
EFG = most significant 12 bits of the timestamp in big endian
이진으로 변환 할 때 인덱싱에 가장 적합한 순서는 EFG9ABC12345678D + 나머지입니다.
빅 엔디안은 이미 최고의 이진 인덱스 바이트 순서를 생성하므로 12345678을 78563412로 바꾸지 않으려 고합니다. 그러나 가장 중요한 바이트를 더 낮은 바이트 앞으로 이동 시키길 원합니다. 따라서 EFG가 먼저 시작한 다음 중간 비트와 하위 비트가 이어집니다. 1 분 동안 uuid ()를 사용하여 12 개 정도의 UUID를 생성하면이 순서가 올바른 순위를 얻는 방법을 확인해야합니다.
select uuid(), 0
union
select uuid(), sleep(.001)
union
select uuid(), sleep(.010)
union
select uuid(), sleep(.100)
union
select uuid(), sleep(1)
union
select uuid(), sleep(10)
union
select uuid(), 0;
/* output */
6eec5eb6-9755-11e4-b981-feb7b39d48d6
6eec5f10-9755-11e4-b981-feb7b39d48d6
6eec8ddc-9755-11e4-b981-feb7b39d48d6
6eee30d0-9755-11e4-b981-feb7b39d48d6
6efda038-9755-11e4-b981-feb7b39d48d6
6f9641bf-9755-11e4-b981-feb7b39d48d6
758c3e3e-9755-11e4-b981-feb7b39d48d6
처음 두 UUID는 가장 가까운 시간에 생성되었습니다. 그것들은 첫 번째 블록의 마지막 3 니블에서만 다릅니다. 이것들은 타임 스탬프에서 가장 중요하지 않은 비트이므로 인덱스 가능한 바이트 배열로 변환 할 때 오른쪽으로 푸시하려고합니다. 반대의 예로서, 마지막 ID가 가장 최신이지만, KCD의 스와핑 알고리즘은이를 3 번째 ID (3e 앞의 3e, 첫 번째 블록의 마지막 바이트) 앞에 둡니다.
올바른 색인 순서는 다음과 같습니다.
1e497556eec5eb6...
1e497556eec5f10...
1e497556eec8ddc...
1e497556eee30d0...
1e497556efda038...
1e497556f9641bf...
1e49755758c3e3e...
지원 정보는이 기사를 참조하십시오 : http://mysql.rjweb.org/doc.php/uuid
*** 버전 니블을 타임 스탬프의 상위 12 비트에서 분리하지 않습니다. 이것은 귀하의 예에서 D 니블입니다. 방금 던졌습니다. 따라서 이진 시퀀스는 DEFG9ABC 등이됩니다. 이것은 색인 된 모든 UUID가 동일한 니블로 시작한다는 것을 의미합니다. 기사도 마찬가지입니다.
이 문제를 극복하는 데있어 Percona의 연구에 따르면 훨씬 더 나은 대안이 있습니다.
최적의 인덱싱을 위해 UUID 청크를 재구성 한 다음 스토리지를 줄이기 위해 이진으로 변환합니다.
@ bigh_29에서 언급 한 기능이 내 guid를 새로운 것으로 변환하기 때문에 아래 함수를 사용하는 것이 좋습니다 (내가 이해하지 못하는 이유로). 또한 이것들은 내가 테이블에서 한 테스트에서 조금 더 빠릅니다. https://gist.github.com/damienb/159151
DELIMITER |
CREATE FUNCTION uuid_from_bin(b BINARY(16))
RETURNS CHAR(36) DETERMINISTIC
BEGIN
DECLARE hex CHAR(32);
SET hex = HEX(b);
RETURN LOWER(CONCAT(LEFT(hex, 8), '-', MID(hex, 9,4), '-', MID(hex, 13,4), '-', MID(hex, 17,4), '-', RIGHT(hex, 12)));
END
|
CREATE FUNCTION uuid_to_bin(s CHAR(36))
RETURNS BINARY(16) DETERMINISTIC
RETURN UNHEX(CONCAT(LEFT(s, 8), MID(s, 10, 4), MID(s, 15, 4), MID(s, 20, 4), RIGHT(s, 12)))
|
DELIMITER ;
표준 GUID로 형식화 된 char / varchar 값이있는 경우 CONCAT + SUBSTR의 복잡한 순서없이 간단한 CAST (MyString AS BINARY16)를 사용하여 간단히 BINARY (16)로 저장할 수 있습니다.
BINARY (16) 필드는 문자열보다 훨씬 빠르게 비교 / 정렬 / 인덱싱되며 데이터베이스의 공간이 2 배 줄어 듭니다.
select CAST("hello world, this is as long as uiid" AS BINARY(16));
생산hello world, thi