Коли розмір бази даних перевищує мільйони рядків, доцільно почати масштабування додатку і розбити базу даних на кілька фізичних серверів.
Найбільшою проблемою поділу бази даних на декілька частин є її подальша синхронізація у разі запиту користувачем конкретних даних.
Припустимо, у вас є таблиця "статей", але через те, що у вас величезний сайт, вище розташовані десятки мільйонів статей, і вам доводиться фізично розподіляти їх між декількома машинами.
Якби ми використовували звичайне ціле число в якості "id" (первинного ключа) з налаштуванням автоінкременту, то дуже швидко виявили б, що при створенні записів на різних машинах децентралізовано, а потім їх синхронізації, виникають колізії ідентифікаторів і доводиться складним чином перенумеровувати записи. Крім того, якщо ми вирішуємо багато сесій за іншими столами, це може бути дуже складною накладною роботою, в якій легко припуститися помилок.
Тому замість числового ідентифікатора ми можемо генерувати UUID, який являє собою текстовий рядок, що генерується за складним алгоритмом, який гарантує, що він буде унікальним, навіть якщо буде згенерований незалежно на декількох машинах.
Переваги:
19010018, то неважко здогадатися, що існує також користувач 19010017 та інші. Aтака називається векторною.UUID можна отримати або простим SQL запитом SELECT UUID();, але при цьому збільшується кількість запитів до бази даних і ми втрачаємо можливість підготувати дані спочатку масово в логіці програми, а потім записати їх відразу.
Тому мені подобається користуватися пакетом ramsey/uuid, отриманим за допомогою Composer, як хорошим рішенням. Сам UUID має кілька версій, і пакет може грайливо генерувати всі види за потреби.
Це робить його простим у використанні:
require 'vendor/autoload.php';use Ramsey\Uuid\Uuid;// Створює об'єкт UUID версії 1 (на основі часу)$uuid1 = Uuid::uuid1();echo $uuid1->toString() . "\n"; // e4eaaaf2-d142-11e1-b3e4-080027620cdd// Генерує об'єкт UUID версії 3 (на основі імені та хешований як MD5)$uuid3 = Uuid::uuid3(Uuid::NAMESPACE_DNS, 'php.net');echo $uuid3->toString() . "\n"; // 11a38b9a-b3da-360f-9353-a5a725514269// Формує об'єкт UUID версії 4 (випадковий)$uuid4 = Uuid::uuid4();echo $uuid4->toString() . "\n"; // 25769c6c-d34d-4bfe-ba98-e0ee856f3e7a// Генерує об'єкт UUID версії 5 (на основі імені та хешований як SHA1)$uuid5 = Uuid::uuid5(Uuid::NAMESPACE_DNS, 'php.net');echo $uuid5->toString() . "\n"; // c4a760a8-dbcf-5254-a0d9-6a4474bd1b62
Якщо ви використовуєте Doctrine, існує розширення ramsey/uuid-doctrine, яке генерує ідентифікатор безпосередньо як тип даних.
У своїх перших спробах я використовував varchar(36) як первинний ключ (ID), але це зовсім не найкраща ідея.
Пояснення внутрішньої логіки:**.
Бази даних MySql (і багато інших) не можуть ефективно використовувати
varchar,charабо інші типи даних, що виражають рядок як первинний ключ.
У деяких базах даних існує тип данихGUID, який призначений для безпосереднього зберігання UUID. Якщо ви не можете використовувати цей тип, є відповідний замінник у виглядіbinary(16).
При фізичному дослідженні бази даних ідентифікатор після цього представляється в HEX форматі (оскільки двійковий формат не відображається), замість красивого ідентифікатора 726c67c4-e5eb-4a4c-8fcc-031da5d6f3c6 ви побачите просто 726C67C4E5EB4A4C8FCC031DA5D6F3C6, який в запиті INSERT виглядає як '?kYߟKg2c;'.
varchar(36) в `binary(16)Я припускаю, що ви представляєте (або плануєте представляти) новий встановлений ідентифікатор в базі даних як:
`id` binary(16) NOT NULL
Oднак, просто змінити тип даних не вийде, тому щось на кшталт:
SET FOREIGN_KEY_CHECKS=0;ALTER TABLE article CHANGE id id BINARY(16) NOT NULLSET FOREIGN_KEY_CHECKS=1;
Причин, в основному, дві:
Тому єдине правильне рішення - зробити резервну копію даних (але це все одно потрібно робити перед кожною міграцією), підготувати порожню базу даних з функціональними зв'язками і знову перенести туди дані за допомогою міграції.
Якщо ви раніше генерували UUID дивним чином, краще вибрати якийсь послідовний метод отримання UUID і перенумерувати всі записи. Причина полягає в тому, що послідовне розміщення дозволяє краще впорядкувати значення і створити btree, що робить продуктивність практично ідентичною bigint.
Якщо ви знаєте кращий спосіб конвертації існуючої бази даних з UUID, що зберігається у вигляді varchar, у двійковий формат без необхідності розробки складних міграцій та зі збереженням зовнішніх ключів, буду дуже вдячний за зворотній зв'язок.
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:
Články a novinky nejen ze světa PHP a programování. Nenechte si ujít jediný článek.
Články píše Jan Barášek © 2009-2025 | Kontakt | Mapa webu
Status | Aktualizováno: ... | uk