Почему случайные UUID в роли первичного ключа убивают вставки в SQLite
Разбор с бенчмарками и профилированием о том, как выбор типа первичного ключа меняет скорость записи в разы. Суть проблемы: первичный ключ задаёт физический порядок хранения строк в B-дереве. Случайный UUID4 означает вставки в случайные места дерева, а это бесконечные сплиты страниц и ребалансировки.
Автор вставляет 10 миллионов строк пакетами по миллиону и сравнивает:
🔘обычный INTEGER-ключ: стабильные ~715 мс на миллион, эталон;
🔘UUID4 с WITHOUT ROWID: первый миллион 2649 мс, десятый уже 12586 мс — деградация нелинейная, чем больше таблица, тем хуже, итог до 18 раз медленнее эталона;
🔘UUID7 с WITHOUT ROWID: стабильные ~1250 мс на миллион без всякой деградации.
Весь фокус в том, что UUID7 содержит таймстемп в старших битах, поэтому новые ключи монотонно растут и ложатся в конец дерева, как автоинкремент. UUID4 при этом остаётся медленнее целого числа примерно на 70%: ключ занимает 16 байт против 8, строк на страницу помещается меньше.
Отдельный урок про WITHOUT ROWID: эта опция полезна, когда по первичному ключу часто ищут, но в паре со случайным UUID получается худшее из двух миров — данные лежат и в листьях, и в промежуточных узлах дерева, и ребалансировка дорожает максимально.
Выводы переносятся на любую БД с кластерным индексом, от MySQL InnoDB до SQL Server. Сохранять всем, кто сейчас выбирает схему ключей для нового сервиса.
Полная статья: https://andersmurphy.com/2026/06/05/the-perils-of-uuid-primary-keys-in-sqlite.html
@prog_stuff
Post #2851
620