web-dev-qa-db-ja.com

UUIDをbinary(16)として挿入および選択

理由がわかりません

SELECT UUID();

次のようなものを返します。

3f06af63-a93c-11e4-9797-00505690773f

しかし、たとえばBEFORE INSERTトリガーを使用してbinary(16)フィールド(UUID()関数)に挿入し、selectを実行すると、次のような結果が返されます。

0782ef48-a439-11

これら2つのUUIDは同じデータではないことに注意してください。

バイナリとUUID文字列は同一に見えませんが、選択されたデータは少なくとも同じ長さであってはいけません。それ以外の場合、どのように等しく一意である可能性がありますか?

Char(36)として保存する方が良いですか?重複する挿入を防ぐために、一意である必要があります。結合に選択または使用されることはありません。

編集:

beforeトリガーは次のようになります。

BEGIN

if NEW.UUID IS NULL THEN

NEW.UUID = UUID();

END IF

END
22
nickdnk

だから、コメントへの応答として。 36文字のUUIDをbinary(16)として保存する正しい方法は、次のような方法で挿入を実行することです。

_INSERT INTO sometable (UUID) VALUES
       (UNHEX(REPLACE("3f06af63-a93c-11e4-9797-00505690773f", "-","")))
_

UNHEX。これは、UUIDがすでに16進数値であるためです。ステートメント内のダッシュをトリミング(REPLACE)して、長さを32 ASCII文字(16バイトはHEXとして表されます)にします。これは、保存する前のどの時点でも、明らかに、データベースで処理する必要はありません。

次のようにUUIDを取得できます。

_SELECT HEX(UUID) FROM sometable;
_

誰かがこのスレッドに出くわし、これがどのように機能するかわからない場合に備えて。

そして覚えておいてください:UUIDを使用して行を選択している場合、条件でUNHEX()を使用

_SELECT * FROM sometable WHERE UUID = UNHEX('3f06af63a93c11e4979700505690773f');
_

列のHEX()ではない:

_SELECT * FROM sometable WHERE HEX(UUID) = '3f06af63a93c11e4979700505690773f';
_

2番目の解決策は機能しますが、一致する行を判断する前に、MySQL HEXesがすべてのUUIDを必要とします。非常に非効率的です。

編集:MySQL 8を使用している場合は、SlyDaveの回答に記載されているUUID関数をご覧ください。この答えは今でも正しいですが、これらの関数を使用してネイティブに実行できるUUIDインデックスを最適化しません。

60
nickdnk

MySQL 8では、2つの新しい ID関数 を使用できます。

  • BIN_TO_UUID

    SELECT BIN_TO_UUID(uuid, true) AS uuid FROM foo;
    -- 3f06af63-a93c-11e4-9797-00505690773f
    
  • UUID_TO_BIN

    INSERT INTO foo (uuid) VALUES (UUID_TO_BIN('3f06af63-a93c-11e4-9797-00505690773f', true));
    

また、このメソッドは、UUIDの時間コンポーネントの再配置をサポートし、インデックスのパフォーマンスを向上させます(時系列に並べることにより)。2番目の引数をtrueに設定するだけです-これはUUID1でのみ機能します。

インデックスのパフォーマンスにUUID_TO_BINフラグにtrueフラグを使用している場合(推奨)、BIN_TO_UUIDにも設定する必要があります。そうしないと、正しく変換されません。

詳細については、ドキュメントを参照してください。

21
SlyDave

他の答えは正しいです。 UUID()関数は36文字の文字列を返し、表示されている関数(UNHEX()、または新しいプラットフォームではUUID_TO_BIN())を使用して変換する必要があります。

ただし、独自のソフトウェアを使用してUUIDを作成する場合は、代わりに 16進数リテラル表記 を使用できます。

したがって、MySQL UUID()関数で以下を使用します。

INSERT INTO sometable (id) VALUES (UNHEX(REPLACE(UUID(), '-', '')));  -- all versions
INSERT INTO sometable (id) VALUES (UUID_TO_BIN(UUID());               -- since v8.0

ただし、独自のUUIDを生成する場合はこれを使用します。

INSERT INTO sometable (id) VALUES 0x3f06af63a93c11e4979700505690773f;

同様に、WHERE句で16進数リテラルを使用できます。

SELECT * FROM sometable WHERE id = 0x3f06af63a93c11e4979700505690773f;

データを毎回UUID文字列に変換する必要がない場合、これは高速になります。

注:'x' in '0xaBcは大文字と小文字が区別されます。ただし、16進数はそうではありません。

6
Alexis Wilke

MariaDBを使用しているので、BIN_TO_UUID関数ファミリは存在しません。とにかく対応する値を取得することができました。

bin -> hex

ここで、uuidはuuidのbinary(16)値です。以下の値を使用して、読み取り可能なバージョンを選択します。

LOWER(CONCAT(
    SUBSTR(HEX(uuid), 1, 8), '-',
    SUBSTR(HEX(uuid), 9, 4), '-',
    SUBSTR(HEX(uuid), 13, 4), '-',
    SUBSTR(HEX(uuid), 17, 4), '-',
    SUBSTR(HEX(uuid), 21)
))

hex -> bin

ここに、 cc6e6d97-5501-11e7-b2cb-ceedca613421はUUIDの読み取り可能なバージョンであり、WHERE句で以下の値を使用して検索します。

UNHEX(REPLACE('cc6e6d97-5501-11e7-b2cb-ceedca613421', '-', ''))

乾杯

5
Alain Tiemblo