Jak przechowywać GUID w tabelach MySQL?
Czy używam varchar (36) czy są na to jakieś lepsze sposoby?
10 answers
Mój DBA zapytał mnie, kiedy pytałem o najlepszy sposób przechowywania GUID dla moich obiektów, dlaczego muszę przechowywać 16 bajtów, kiedy mogę zrobić to samo w 4 bajtach z liczbą całkowitą. Skoro postawił mi to wyzwanie, pomyślałem, że to dobry moment, żeby o tym wspomnieć. Skoro tak mówisz...
Możesz zapisać guid jako znak binarny CHAR(16), jeśli chcesz optymalnie wykorzystać przestrzeń dyskową.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-01-05 05:44:13
Zapisałbym jako char (36).
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-01-05 05:41:27
Dodając do odpowiedzi Thabaddawga, użyj tych przydatnych funkcji (dzięki mądrzejszemu koledze), aby uzyskać od 36 długości łańcucha z powrotem do tablicy bajtów 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)
jest rzeczywiście BINARY(16)
, Wybierz preferowany smak
Aby lepiej podążać za kodem, weźmy przykład podany poniżej, uporządkowany cyfrowo identyfikator GUID. (Niedozwolone znaki są używane w celach ilustracyjnych - każde miejsce ma unikalny charakter.) Funkcje przekształcą kolejność bajtów w celu uzyskania kolejności bitowej dla lepsze grupowanie indeksów. Zmiana kolejności guid jest pokazana poniżej przykładu.
12345678-9ABC-DEFG-HIJK-LMNOPQRSTUVW
78563412-BC9A-FGDE-HIJK-LMNOPQRSTUVW
Usunięte myślniki:
123456789ABCDEFGHIJKLMNOPQRSTUVW
78563412BC9AFGDEHIJKLMNOPQRSTUVW
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-02-22 21:30:40
Char (36) byłby dobrym wyborem. Można również użyć funkcji uuid() MySQL, która zwraca 36-znakowy format tekstu (hex z myślnikami), który może być używany do pobierania takich identyfikatorów z db.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-01-05 05:47:58
"lepsze" zależy od tego, do czego optymalizujesz.
Jak bardzo zależy ci na wielkości/wydajności pamięci a łatwości rozwoju? Co ważniejsze-czy generujesz wystarczająco dużo GUID, czy pobierasz je na tyle często, że ma to znaczenie?
Jeśli odpowiedź brzmi "Nie", char(36)
jest wystarczająco dobra i sprawia, że przechowywanie/pobieranie plików GUID jest martwe-proste. W przeciwnym razie binary(16)
jest rozsądne, ale będziesz musiał oprzeć się na MySQL i / lub wybranym języku programowania, aby konwertować tam iz powrotem od zwykłej reprezentacji łańcuchów.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-02-28 16:26:30
Binary(16) byłoby w porządku, lepsze niż użycie varchar(32).
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-05-31 12:00:16
Procedura guidtobinary opublikowana przez KCD powinna zostać zmodyfikowana, aby uwzględnić układ bitowy znacznika czasu w łańcuchu GUID. Jeśli łańcuch znaków reprezentuje UUID w wersji 1, jak te zwracane przez uuid() mysql, to składniki czasu są osadzone w literach 1-G, z wyłączeniem 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
Po konwersji na binarny, najlepszym porządkiem indeksowania będzie: EFG9ABC12345678D + reszta.
Nie chcesz zamienić 12345678 na 78563412 bo big endian już daje najlepsza kolejność bajtów indeksu binarnego. Chcesz jednak, aby najistotniejsze bajty zostały przesunięte przed niższymi bajtami. Stąd EFG idzie pierwszy, a następnie środkowe bity i dolne bity. Wygeneruj kilkanaście uuid za pomocą uuid () w ciągu minuty i powinieneś zobaczyć, jak ta kolejność daje poprawną rangę.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
Pierwsze dwa uuid zostały wygenerowane najbliżej czasu. Różnią się one tylko w ostatnich 3 nibbles pierwszego bloku. Są to najmniej znaczące bity znacznika czasu, które oznacza to, że chcemy je przesunąć w prawo, gdy przekonwertujemy to na indeksowalną tablicę bajtów. Jako przykład licznika, ostatni identyfikator jest najbardziej aktualny, ale algorytm zamiany KCD umieściłby go przed trzecim identyfikatorem (3E przed dc, Ostatnie bajty z pierwszego bloku).
Prawidłowa kolejność indeksowania to:
1e497556eec5eb6...
1e497556eec5f10...
1e497556eec8ddc...
1e497556eee30d0...
1e497556efda038...
1e497556f9641bf...
1e49755758c3e3e...
Zobacz ten artykuł, aby uzyskać dodatkowe informacje: http://mysql.rjweb.org/doc.php/uuid
*** zauważ, że nie dzielę wersji z high 12 fragmenty znacznika czasu. To jest D skubanie z twojego przykładu. Rzucam ją z przodu. Więc moja Sekwencja binarna kończy się DEFG9ABC i tak dalej. Oznacza to, że wszystkie moje indeksowane uuid zaczynają się od tego samego skubania. Artykuł robi to samo.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-01-08 17:19:00
Dla tych, którzy po prostu natykają się na to, istnieje teraz znacznie lepsza alternatywa według badań Percona.
Polega na reorganizacji fragmentów UUID w celu optymalnego indeksowania, a następnie konwersji na binarne w celu zmniejszenia pamięci masowej.
Przeczytaj cały artykuł tutaj
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-06-26 14:24:21
Sugerowałbym użycie poniższych funkcji, ponieważ te wymienione przez @bigh_29 przekształca moje GUID na nowe (z powodów, których nie rozumiem). Ponadto są one nieco szybsze w testach, które zrobiłem na moich stołach. 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 ;
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-12-17 15:22:12
Jeśli masz wartość char/varchar sformatowaną jako standardowy GUID, możesz po prostu zapisać ją jako binarną(16) używając prostego CAST(MyString jako BINARY16), bez tych wszystkich zadziwiających sekwencji CONCAT + SUBSTR.
Pola binarne(16) są porównywane/sortowane / indeksowane znacznie szybciej niż łańcuchy, a także zajmują dwa razy mniej miejsca w bazie danych
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-11-04 21:13:14