Apakah saya menggunakan varchar (36) atau apakah ada cara yang lebih baik untuk melakukannya?
Apakah saya menggunakan varchar (36) atau apakah ada cara yang lebih baik untuk melakukannya?
Jawaban:
DBA saya bertanya ketika saya bertanya tentang cara terbaik untuk menyimpan GUID untuk objek saya mengapa saya perlu menyimpan 16 byte ketika saya bisa melakukan hal yang sama dalam 4 byte dengan Integer. Karena dia memberikan tantangan itu kepada saya, saya pikir sekarang adalah waktu yang tepat untuk menyebutkannya. Yang telah dibilang...
Anda dapat menyimpan panduan sebagai biner CHAR (16) jika Anda ingin memanfaatkan ruang penyimpanan yang paling optimal.
Saya akan menyimpannya sebagai char (36).
-
.
Menambah jawaban oleh ThaBadDawg, gunakan fungsi-fungsi praktis ini (terima kasih kepada kolega saya yang lebih bijak) untuk mendapatkan dari string 36 panjang kembali ke array byte 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)
sebenarnya adalah BINARY(16)
, pilih rasa yang Anda sukai
Untuk mengikuti kode dengan lebih baik, ambil contoh yang diberikan GUID yang dipesan dengan digit di bawah ini. (Karakter ilegal digunakan untuk tujuan ilustrasi - setiap tempat karakter unik.) Fungsi akan mengubah urutan byte untuk mencapai urutan bit untuk pengelompokan indeks superior. Panduan yang diperintahkan ditampilkan di bawah contoh.
12345678-9ABC-DEFG-HIJK-LMNOPQRSTUVW
78563412-BC9A-FGDE-HIJK-LMNOPQRSTUVW
Tanda hubung dihapus:
123456789ABCDEFGHIJKLMNOPQRSTUVW
78563412BC9AFGDEHIJKLMNOPQRSTUVW
GuidToBinary
($ guid char (36)) RETURNS biner (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)));
"Lebih baik" tergantung pada apa yang Anda optimalkan.
Seberapa besar Anda peduli dengan ukuran / kinerja penyimpanan vs kemudahan pengembangan? Lebih penting - apakah Anda menghasilkan cukup GUID, atau cukup sering mengambilnya, sehingga itu penting?
Jika jawabannya "tidak", char(36)
lebih dari cukup baik, dan itu membuat penyimpanan / pengambilan GUID menjadi sangat sederhana. Kalau tidak, binary(16)
masuk akal, tetapi Anda harus bersandar pada MySQL dan / atau bahasa pemrograman pilihan Anda untuk mengkonversi bolak-balik dari representasi string yang biasa.
Binary (16) akan lebih baik, lebih baik daripada penggunaan varchar (32).
Rutin GuidToBinary yang diposting oleh KCD harus disesuaikan untuk memperhitungkan tata letak bit stempel waktu dalam string GUID. Jika string mewakili UUID versi 1, seperti yang dikembalikan oleh rutin uuid () mysql, maka komponen waktu disematkan dalam huruf 1-G, tidak termasuk D.
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
Ketika Anda mengonversi ke biner, urutan terbaik untuk pengindeksan adalah: EFG9ABC12345678D + sisanya.
Anda tidak ingin menukar 12345678 ke 78563412 karena big endian sudah menghasilkan urutan byte indeks biner terbaik. Namun, Anda ingin byte yang paling signifikan dipindahkan di depan byte yang lebih rendah. Oleh karena itu, EFG pergi dulu, diikuti oleh bit tengah dan bit rendah. Hasilkan selusin UUID dengan uuid () selama satu menit dan Anda akan melihat bagaimana pesanan ini menghasilkan peringkat yang benar.
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
Dua UUID pertama dihasilkan paling mendekati waktu. Mereka hanya bervariasi dalam 3 gigitan terakhir dari blok pertama. Ini adalah bit paling tidak signifikan dari cap waktu, yang berarti kita ingin mendorong mereka ke kanan ketika kita mengonversinya ke array byte yang dapat diindeks. Sebagai contoh balasan, ID terakhir adalah yang terbaru, tetapi algoritma swapping KCD akan menempatkannya di depan ID ke-3 (3e sebelum dc, byte terakhir dari blok pertama).
Urutan pengindeksan yang benar adalah:
1e497556eec5eb6...
1e497556eec5f10...
1e497556eec8ddc...
1e497556eee30d0...
1e497556efda038...
1e497556f9641bf...
1e49755758c3e3e...
Lihat artikel ini untuk informasi pendukung: http://mysql.rjweb.org/doc.php/uuid
Perhatikan bahwa saya tidak membagi nibble versi dari 12 bit cap waktu yang tinggi. Ini adalah gigitan D dari contoh Anda. Saya hanya membuangnya di depan. Jadi urutan biner saya akhirnya menjadi DEFG9ABC dan seterusnya. Ini menyiratkan bahwa semua UUID saya yang diindeks mulai dengan gigitan yang sama. Artikel itu melakukan hal yang sama.
Bagi mereka yang hanya tersandung di sini, sekarang ada alternatif yang jauh lebih baik sesuai penelitian oleh Percona.
Ini terdiri dari reorganisasi potongan UUID untuk pengindeksan yang optimal, kemudian dikonversi menjadi biner untuk penyimpanan berkurang.
Baca artikel selengkapnya di sini
Saya akan menyarankan menggunakan fungsi di bawah ini karena yang disebutkan oleh @ bigh_29 mengubah panduan saya menjadi yang baru (karena alasan saya tidak mengerti). Juga, ini sedikit lebih cepat dalam tes yang saya lakukan di meja saya. 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 ;
jika Anda memiliki nilai char / varchar yang diformat sebagai GUID standar, Anda dapat menyimpannya sebagai BINARY (16) menggunakan CAST sederhana (MyString AS BINARY16), tanpa semua urutan CONCAT + SUBSTR yang membingungkan.
BINARY (16) bidang dibandingkan / diurutkan / diindeks jauh lebih cepat daripada string, dan juga mengambil dua kali lebih sedikit ruang dalam database
select CAST("hello world, this is as long as uiid" AS BINARY(16));
menghasilkanhello world, thi