문제

Varchar (36)를 사용합니까? 아니면 더 좋은 방법이 있습니까?

도움이 되었습니까?

해결책

내 DBA는 내 객체에 대한 지침을 저장하는 가장 좋은 방법에 대해 물었을 때 저에게 정수로 4 바이트로 같은 일을 할 수있을 때 16 바이트를 저장 해야하는 이유에 대해 물었습니다. 그가 그 도전을 저에게 내놓았 기 때문에 나는 지금 그것을 언급하기에 좋은시기라고 생각했습니다. 그 말 ...

저장 공간을 가장 최적으로 사용하려면 char (16) 이진으로 안내를 저장할 수 있습니다.

다른 팁

나는 그것을 숯으로 보관할 것이다 (36).

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) 실제로 a BINARY(16), 선호하는 맛을 선택하십시오

코드를 더 잘 따르려면 아래의 숫자 주문 안내서가 주어지면 예를 들어보십시오. (불법 문자는 예시적인 목적으로 사용됩니다 - 각 장소는 고유 한 문자입니다.) 함수는 바이트 순서를 변환하여 우수한 인덱스 클러스터링을 위해 약간의 순서를 달성합니다. 재정렬 된 안내서는 아래에 표시됩니다.

12345678-9ABC-DEFG-HIJK-LMNOPQRSTUVW
78563412-BC9A-FGDE-HIJK-LMNOPQRSTUVW

제거 된 대시 :

123456789ABCDEFGHIJKLMNOPQRSTUVW
78563412BC9AFGDEHIJKLMNOPQRSTUVW

Char (36)는 좋은 선택이 될 것입니다. 또한 MySQL의 uuid () 함수는 DB에서 이러한 ID를 검색하는 데 사용할 수있는 36-character 텍스트 형식 (하이픈이있는 16 진수)을 반환 할 수 있습니다.

"더 나은"은 최적화하는 것에 달려 있습니다.

스토리지 크기/성능 대 개발의 용이성에 대해 얼마나 관심이 있습니까? 더 중요한 것은 - 충분한 안내를 생성하거나 자주 가져 오는 것이 중요합니까?

대답이 "아니오"인 경우 char(36) 충분히 좋은 것 이상이며, 저장/가져 오기 가이드를 단순하게 만듭니다. 그렇지 않으면, binary(16) 합리적이지만 일반적인 문자열 표현에서 앞뒤로 변환하기 위해 MySQL 및/또는 선택한 프로그래밍 언어에 의지해야합니다.

바이너리 (16)는 Varchar (32)를 사용하는 것보다 좋습니다.

KCD가 게시 한 Guidtobinary 루틴은 Guid String에서 타임 스탬프의 비트 레이아웃을 설명하기 위해 조정해야합니다. 문자열이 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 + 나머지.

Big Endian이 이미 최고의 바이너리 인덱스 바이트 순서를 산출하기 때문에 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 (DC 이전 3E, 첫 번째 블록의 마지막 바이트) 앞에 놓을 것입니다.

인덱싱의 올바른 순서는 다음과 같습니다.

1e497556eec5eb6... 
1e497556eec5f10... 
1e497556eec8ddc... 
1e497556eee30d0... 
1e497556efda038... 
1e497556f9641bf... 
1e49755758c3e3e... 

지원 정보는이 기사를 참조하십시오. http://mysql.rjweb.org/doc.php/uuid

*** 버전 니블을 타임 스탬프의 높은 12 비트에서 나누지 않습니다. 이것은 당신의 예에서 D 니블입니다. 나는 단지 그것을 앞에 던져 버린다. 따라서 내 이진 시퀀스는 결국 defg9abc 등입니다. 이것은 내 인덱스 된 모든 UUID가 동일한 니블로 시작한다는 것을 의미합니다. 이 기사는 같은 일을합니다.

이 문제를 해결하는 사람들에게는 이제 Percona의 연구에 따라 훨씬 더 나은 대안이 있습니다.

최적의 인덱싱을 위해 UUID 청크를 재구성 한 다음 저장 감소를 위해 이진으로 변환하는 것으로 구성됩니다.

전체 기사를 읽으십시오 여기

@bigh_29에서 언급 한 기능은 내지도를 새로운 안내로 변환하기 때문에 아래의 기능을 사용하는 것이 좋습니다 (이해하지 못하는 이유로). 또한 테이블에서 수행 한 테스트에서는 조금 더 빠릅니다. 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 ;

표준 안내서로 형식화 된 char/varchar 값이있는 경우, 간단한 캐스트 (Mystring as binary16)를 사용하여 이진 (16)으로 간단히 저장할 수 있으며, 모든 마음을 사로 잡는 일련의 Concat + Substr.

바이너리 (16) 필드는 문자열보다 훨씬 빠르게 비교/분류/인덱싱되며 데이터베이스에서 공간이 2 배 더 적습니다.

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