Як зберігати uuid як номер?


77

На основі відповіді на запитання, продуктивності UUID в MySQL , особа, яка відповідає, пропонує зберігати UUID як число, а не як рядок. Я не настільки впевнений, як це можна зробити. Хто-небудь міг би мені щось запропонувати? Як мій рубіновий код справляється з цим?


5
Проблеми з продуктивністю виникають лише тоді, коли ви використовуєте UUID первинний ключ, оскільки UUID не дуже ефективні первинні ключі. Навіщо потрібні UUID? Чи можете ви зберегти UUID і просто використовувати автоінкремент як первинний ключ?
Том Сміт

4
@ThomSmith Re "UUID - це не дуже ефективні первинні ключі" .. дбати про цитування джерела, яке пояснює, чому?
Pacerier

2
Це більший шматок даних, і для порівняння зазвичай потрібно більше інструкцій. Це не послідовно, тому накладні витрати на індексацію трохи вищі. І, звичайно, якщо ви зберігаєте його як рядок замість 128-розрядного числа, як це, здається, робить OP, ситуація погіршується. Це не страшний ключ, але я б не використовував його, якщо б для цього не існувала якась зовнішня причина.
Том Сміт

Автоінкремент може спричинити проблеми з кількома серверами спільних баз даних - часто спричиняючи зіткнення ключів. UUID призначені для вирішення подібних питань. Якщо ви зберігаєте свій UUID не як текст, а як смітник (16), тоді у вас, звичайно, є числовий UUID. Швидше порівнювати двійковий файл, ніж текст. Ось сайт, що це обговорює - mysql.rjweb.org/doc.php/uuid
Джефф Клейтон

Відповіді:


109

Якщо я правильно розумію, ви використовуєте UUID у своєму основному стовпці? Люди скажуть, що звичайний (цілочисельний) первинний ключ буде швидшим, але існує інший спосіб використання темної сторони MySQL. Насправді MySQL швидше використовує двійковий файл, ніж будь-що інше, коли потрібні індекси.

Оскільки UUID становить 128 біт і записаний як шістнадцятковий, дуже легко пришвидшити та зберегти UUID.

По-перше, у вашій мові програмування видаліть тире

Від 110E8400-E29B-11D4-A716-446655440000до 110E8400E29B11D4A716446655440000.

Зараз це 32 символи (як хеш MD5, з яким це також працює).

Оскільки сингл BINARYу MySQL має розмір 8 біт, BINARY(16)це розмір UUID (8 * 16 = 128).

Ви можете вставити, використовуючи:

INSERT INTO Table (FieldBin) VALUES (UNHEX("110E8400E29B11D4A716446655440000"))

і запит за допомогою:

SELECT HEX(FieldBin) AS FieldBin FROM Table

Тепер у вашій мові програмування знову вставте тире в позиції 9, 14, 19 та 24, щоб відповідати вашому вихідному UUID. Якщо позиції завжди різні, ви можете зберегти цю інформацію у другому полі.

Повний приклад:

CREATE TABLE  `test_table` (
    `field_binary` BINARY( 16 ) NULL ,
    PRIMARY KEY (  `field_binary` )
) ENGINE = INNODB ;

INSERT INTO  `test_table` (
    `field_binary`
)
VALUES (
    UNHEX(  '110E8400E29B11D4A716446655440000' )
);

SELECT HEX(field_binary) AS field_binary FROM `test_table`

Якщо ви хочете використовувати цю техніку з будь-яким шістнадцятковим рядком, завжди робіть це length / 2для довжини поля. Отже, для sha512 поле буде таким, BINARY (64)оскільки кодування sha512 має 128 символів.


3
@Chamnap Припустимо, у вашій базі даних 10 000 рядків, і вони були додані за допомогою функції UNHEX, і ви хочете шукати UUID 110E8400-E29B-11D4-A716-446655440000. Просто зробіть щось на кшталт:SELECT * FROM test_table WHERE field_binary LIKE CONCAT("%", UNHEX('110E8400E29B11D4A716446655440000'), "%")
Девід Беланже

5
Ви можете прочитати це, якщо є час. Зосередьтеся на пункті 3: xaprb.com/blog/2009/02/12/…
Девід Беланже,

4
@Chamnap Так, ти можеш, ти повинен. Я просто хотів продемонструвати, чи хочете ви використовувати символ% з функцією UNHEX всередині LIKE. Ви могли б це зробити WHERE Field = UNHEX('110E8400E29B11D4A716446655440000'). Замість того, щоб робити WHERE Field = 3щось інше, ви обгортаєте поле UNHEX, коли використовуєте шістнадцятковий рядок (для пошуку, вставлення, де, оновлення, видалення тощо), і обгортаєте поле HEX, коли хочете читати з MySQL (виберіть).
Девід Белангер,

2
@ DavidBélanger Ви сказали, що MySQL швидше індексує двійкові файли порівняно з ints. Будь-які джерела?
Pacerier

4
Формулювання заплутане щодо типу BINARY. Один "BINARY" у mysql має розмір 8 біт , саме тому BINARY (16) працює (8 * 16 = 128, розмір UUID). Він НЕ "зберігає в 1 біті те, що робить шістнадцяткове число в 4 бітах". Це неможливо. "Два шістнадцяткові значення можуть зберігатися в кожному розмірі одиниці типу BINARY, який сам має розмір 8 біт, тому нам потрібні 16 розмірів одиниць BINARY, отже, ми будемо використовувати BINARY (16)."
lilbyrdie


0

Я не думаю, що це хороша ідея використовувати двійковий файл.

Скажімо, ви хочете запитати якесь значення:

SELECT HEX(field_binary) AS field_binary FROM `test_table`

Якщо ми повертаємо кілька значень, тоді ми кілька разів викликаємо функцію HEX.

Однак основною проблемою є наступна:

SELECT * FROM `test_table`
    where field_binary=UNHEX('110E8400E29B11D4A716446655440000')

А використання функції всередині де, просто ігнорує індекс.

Також

SELECT * FROM `test_table`
    where field_binary=x'skdsdfk5rtirfdcv@#*#(&#@$9' 

Може призвести до багатьох проблем.


1
Ви перевіряли ефективність своїх проблем? Ви припускаєте, що продуктивність HEX та UNHEX гірша, ніж проблеми з продуктивністю використання 36-значного поля як індексу. Мені навіть не потрібно тестувати, щоб знати, що це неправда. (Але оскільки ви вважаєте інакше, протестуйте) По-друге, код, який ви показуєте, не є таким, як з цим найкраще поводитися. Весь ваш код БД повинен просто включати 16-байтове поле. Не Hex і Unhex. Просто передайте його до і з вашої БД як ці 16 байтів. Робіть усі запити безпосередньо з цими 16-байтовими значеннями. Тільки при відображенні користувачеві вам потрібно перетворити його на зручну для користувача версію.
ToolmakerSteve
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.