В прошлой статье мы разобрались как в Laravel работать с UUID. Но он не решает всех проблем распределенных систем. Один из новых подходов к генерации уникальных идентификаторов это ULID — Universally Unique Lexicographically Sortable Identifier (универсальный уникальный лексографически сортируемый идентификатор).
Сравнение UUID и ULID
Во многих случаях использование UUID неоптимально:
- Это не самый эффективный способ кодирования 128-битной случайности
- UUID v1/v2 непрактичен во многих средах, так как требует доступа к уникальному стабильному MAC-адресу
- UUID v3/v5 требует уникального начального числа и генерирует случайно распределенные идентификаторы, которые могут вызвать фрагментацию во многих структурах данных
- UUID v4 не предоставляет никакой другой информации, кроме случайности, которая может вызвать фрагментацию во многих структурах данных
Вместо этого ULID предлагает:
- 128-битная совместимость с UUID
- 1.21e+24 уникальных ключей в миллисекунду
- Лексикографическая сортировка (т.е. в алфавитном порядке)
- Канонически кодируется как 26-символьная строка, в отличие от 36-символьного UUID
- Использует Crockford Base32 для лучшей эффективности и читаемости (5 бит на символ). Исключены буквы I, L, O, чтобы не путать с цифрами. И буква U, чтобы случайно не сгенерировались непристойность
- Регистронезависимый
- Без специальных символов (безопасный URL)
- Точность метки времени до миллисекунды
- Да просто выглядит эстетичнее, чем UUID :)
Более подробно можно узнать в спецификации ULID
Пример ULID:
ulid(); // 01d85pp1982gf6ktvfhq7w78fb 01d85pp198 2gf6ktvfhq7w78fb Timestamp Randomness 48bits 80bits
Когда нужен ULID в качестве первичного ключа?
В распределенных системах, когда нужна уверенность, что у идентификаторов не будет коллизий. В высоконагруженной системы, когда автоинкрементный ключ не вариант.
Когда нужна репликация без геморроя (в отличии от int). Когда не хотите показывать пользователю, что получаете информацию об идентификаторе (например: example.com/user/3)
Использование ULID в Laravel
Ставим пакет
composer require rorecek/laravel-ulid:^2.0.0
Создаём модель
php artisan make:model Product -mcr
Исправляем в миграции модели строку
$table->increments('id');
на
$table->char('id', 26)->primary();
Если связанная модель использует ULID, то тип колонки должен это отображать
Schema::create('products', function (Blueprint $table) { $table->char('id', 26)->primary(); .... // связанная модель $table->char('category_id', 26); $table->foreign('category_id')->references('id')->on('categories'); .... $table->timestamps(); });
В модели укажите использование трейта HasUlid и выставьте флаг incrementing на false.
use Illuminate\Database\Eloquent\Model; use Rorecek\Ulid\HasUlid; class Product extends Model { use HasUlid; .... /** * Indicates if the IDs are auto-incrementing. * * @var bool */ public $incrementing = false; .... }
Теперь, когда вы создаете новый экземпляр модели, ULID генерируется автоматически.
$item = Product::create(); echo $item->id; // 01d85pp1982gf6ktvfhq7w78fb
Автор: Алексей Широков
Наш Телеграм-канал — следите за новостями о Laravel.