PHP Manual

Повернення з UUID в ціле число

02. 05. 2021

При розробці програмного забезпечення програміст досить часто потрапляє в глухий кут, коли стикається з архітектурним рішенням, яке матиме величезний вплив на майбутнє його роботи на десятиліття вперед. Водночас, це рішення, яке не можна повернути назад, і за кожну помилку доводиться платити дорогу ціну. Бази даних є типовим прикладом архітектурного рішення, де злітають голови через кожну дрібну помилку.

Одним з важливих рішень останнього часу стало питання про те, як зберігати первинні ключі в таблицях баз даних. Хоча це здається тривіальною проблемою, за нею стоїть набагато більше, ніж ви можете собі уявити.

Параметри первинного ключа

В основному є чотири основні варіанти:

  • ціле число
  • integer unsigned
  • big int
  • UUID

Integer - це просто ціле число (у випадку unsigned то беззнакове, тому завжди додатне, а у випадку big int то може досягати надзвичайно великих значень). Дуже проста концепція. UUID - це текстовий рядок (наприклад, виду c4a760a8-dbcf-5254-a0d9-6a4474bd1b62), який складається з декількох частин, кожна з яких може мати певні властивості і є корисною для побудови величезних багатосерверних або децентралізованих додатків. навколо UUID існує велика екосистема корисних технологій, які вирішують проблеми, про які ви, можливо, навіть не підозрюєте, що у вас є, або виникнуть в майбутньому.

Використовуйте правильний молоток

Не так давно (взимку 2020 року) мій друг Павло пояснював концепцію застосування відповідного рішення до проблеми заданого розміру. Це чудова і важлива ідея, про яку багато розробників люблять забувати - вони створюють надзвичайно складні рішення тоді, коли це не потрібно. В англійській мові для цього є гарне словосполучення over-engineering.

Розмір та унікальність UUID

Фундаментальна перевага UUID полягає в тому, що якщо додаток стає занадто великим і ми розбиваємо базу даних на багато веб-серверів, де одна таблиця бази даних настільки величезна, що не поміщається на диску однієї машини, ми можемо розбити її на багато фізичних машин, кожна з яких буде знати свій шматок таблиці і запитувати своїх колег про решту. UUID також вирішує фундаментальну проблему вставки нових рядків, коли у випадку дуже великих додатків нам потрібно записувати рядки паралельно в багатьох місцях і ми не хочемо чекати, поки звільниться ємність для запису на основному сервері.

Концепція написання в багатьох місцях одночасно використовується, наприклад, чат-додатками. Коли ви надсилаєте повідомлення через Messenger, воно потрапляє на найближчий сервер бази даних Facebook, який присвоює повідомленню UUID та мітку часу і записує його до своєї локальної бази даних. Ваш друг на іншому кінці світу, в свою чергу, пише повідомлення до свого локального дата-центру, а тим часом вся хмарна інфраструктура забезпечує синхронізацію по всій земній кулі. Звучить круто, правда? :)

Для того, щоб такий паралельний запис працював, потрібно вирішити проблему колізії записів. Якщо окремі локальні бази даних використовують просте ціле число, то дуже скоро два незалежні сервери будуть записувати два різних записи під одним і тим же ідентифікатором. Коли ці записи синхронізуються, відбувається колізія. Рішення зазвичай немає - не можна перенумерувати ідентифікатори, бо до цього можуть призвести інші сесії.

UUID вирішує цю проблему, наприклад, надаючи кожному серверу узгоджений префікс, який він вставляє на початку кожного UUID, потім вставляє мітку часу, потім сам ідентифікатор.

Цікавий факт: При записі такого величезного об'єму даних нас цікавить не стільки коли який запис був записаний, скільки в якому порядку (щоб ми не переплутали порядок повідомлень для користувача, наприклад).

Ви можете запитати, як впоратися з ситуацією, коли сервери не можуть домовитися один з одним про те, який префікс використовувати. Ця проблема виникає, наприклад, у децентралізованих або офлайн додатках. При цьому UUID може бути згенерований навіть випадковим чином.

Тоді питання полягає в тому, яка ймовірність виникнення конфлікту при випадковій генерації UUID. Ну, з вами, напевно, цього не станеться. Існує приблизно 2^122 унікальних UUID (оскільки це 128-бітне число). На практиці ймовірність виникнення конфлікту становить приблизно 0,00000000006 (6 × 10-11). На практиці це означає, що якщо ми будемо генерувати 1 мільярд UUID щосекунди протягом наступних 100 років, то ймовірність виникнення конфлікту становитиме 50%. Так що конфлікту, швидше за все, не виникне, а UUID - це остаточне рішення ваших проблем з базами даних.

Чи є потреба в такому надійному рішенні?

Якщо ви не знаєте, відповідь - ні.

З первинним ключем, встановленим на int з прапором unsigned, існує 4 294 967 295 можливих значень (4 мільярди). Для порівняння цілочисельних розмірів дивіться документацію MySql.

До того часу, коли ви будете зберігати 4 мільярди записів в одній таблиці, у вас, ймовірно, швидше за все, закінчиться місце на диску.

Цілочисельна та об'єднана продуктивність

Цілі числа дійсно дуже швидкі. Для них існують власні оптимізації в MySql. Індекси працюють належним чином (плюс вони набагато менші), займають лише 4 байти, дуже швидко приєднуються, і вони підійдуть для більшості випадків.

Якщо ви маєте справу з проблемою реплікації бази даних, найкращим рішенням може бути розміщення всієї бази даних у хмарі, наприклад, MS Azure, і запит до неї ззовні. Навіть при зберіганні десятків мільйонів записів швидкість доступу за цілим числом до конкретного рядка становить порядку мілісекунд (менше 3 мс на добре налаштованому сервері), а при кластерному індексі час може бути добре стабільним навіть при великій кількості запитів.

Якщо вам дійсно потрібно використовувати UUID, то краще покинути світ MySql і піти шляхом бази даних Postgres, яка на відміну від MySql має власний тип даних для UUUID. Робота з об'єднаннями є величезною проблемою з UUID і MySql, і при об'єднанні всього 3 таблиць (в кожній з яких всього кілька десятків тисяч записів), весь запит може зайняти від декількох сотень мілісекунд до декількох секунд на обробку. І це, на жаль, проблема MySql, яку ви, ймовірно, не зможете вирішити.

Jan Barášek   Více o autorovi

Autor článku pracuje jako seniorní vývojář a software architekt v Praze. Navrhuje a spravuje velké webové aplikace, které znáte a používáte. Od roku 2009 nabral bohaté zkušenosti, které tímto webem předává dál.

Rád vám pomůžu:

Související články

1.
4.
Status:
All systems normal.
2024