回答:
DBAは、オブジェクトのGUIDを保存する最良の方法について尋ねたとき、整数で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()を使用してダースほどの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
最初の2つの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で言及されたものは私の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 ;
char / varchar値が標準のGUIDとしてフォーマットされている場合は、単純なCAST(MyString AS BINARY16)を使用して、BINCAT(16)として格納するだけで済みます。
BINARY(16)フィールドは、文字列よりもはるかに高速に比較/並べ替え/インデックス付けされ、データベース内のスペースが2分の1になります
select CAST("hello world, this is as long as uiid" AS BINARY(16));
生産hello world, thi