В PostgreSQL необходим официальный бенчмарк для функции uuidv7()

4adef1c213dfbf4b5e07bfd309391c95.jpg

Преимущества функции uuidv7()

В 18 версии PostgreSQL появится функция uuidv7(). Она разработана для замены последовательных автоинкрементных идентификаторов SERIAL, BIGSERIAL и IDENTITY, которые могут привести к катастрофическому дублированию ключей при слиянии данных, и для замены более медленных UUIDv4.

Функция uuidv7() в PostgreSQL имеет следующие преимущества:

  • Безопасное слияние данных из нескольких источников без необходимости перегенерации ключей

  • Генерация ключей одновременно в нескольких процессах без ущерба для уникальности и порядка ключей

  • Возможность искажения даты и времени создания записи для конфиденциальной информации (в отличие от почти всех других аналогичных функций)

Функция uuidv7() также полезна для приложений, требующих хронологического извлечения данных, таких как системы логирования и базы данных временных рядов.

Таким образом, использование функции uuidv7() позволит упростить архитектуру информационных систем, упростить SQL-запросы, избежать некоторых ошибок, облегчить внесение изменений и благодаря этому повысить надежность и снизить стоимость разработки и сопровождения информационных систем.

Необходимость официального бенчмарка

Иногда встречаются бездоказательные утверждения, что использование идентификаторов UUIDv7 вместо автоинкремента якобы замедляет вставку записей в таблицы баз данных. Чтобы такого рода утверждения не влияли на выбор типа идентификатора, нужен официальный бенчмарк.

Кроме того, такой бенчмарк должен облегчить выбор типа идентификатора с учетом оборудования, задач и условий конкретного клиента.

Еще одна причина для разработки официального бенчмарка — это абсурдно низкое качество самодельных бенчмарков.

Например, часто функции генерации идентификаторов сравниваются и оцениваются по темпу генерации. Но это лишено всякого смысла, так как в любом случае идентификаторы генерируются гораздо быстрее, чем в них возникает потребность — из-за относительно низкого темпа создания записей в таблицах баз данных.

Другие самодельные бенчмарки доказывают и без того очевидный факт, что UUIDv7 гораздо быстрее, чем UUIDv4.

Некоторые без бенчмарков сравнивают только длину UUIDv7 и целочисленных идентификаторов, не обращая внимания на остальные обстоятельства. Но «скупой платит дважды» (см. выше пункт «Преимущества uuidv7()»).

На самом деле критически важен темп однопоточной и многопоточной вставки записей (в том числе, с учетом партиционирования) с ключами, сгенерированными функцией uuidv7() — по сравнению с автоинкрементом. Но для некоторых клиентов могут оказаться важными и другие параметры, в частности, скорость работы SQL-запросов различных типов.

Кроме того, наличие официального бенчмарка вообще избавило бы клиентов от необходимости разработки самодельных бенчмарков. Ведь в абсолютном большинстве случаев клиенты нуждаются в одних и тех же сценариях работы бенчмарков, а различия в потребностях могут быть учтены изменением значений входных параметров (количество строк в таблице, объем строки).

Хорошо было бы включить бенчмарк в 18 версию PostgreSQL, отдельно от патча для собственно функции uuidv7(). Время для этого еще есть, так как заморозка фич произойдет в апреле 2025 года.

Входные параметры бенчмарка

Бенчмарк должен запускаться как функция с одним обязательным параметром «тип идентификатора» (по умолчанию «uuidv7() без намеренного сдвига таймстемпа») и двумя опциональными параметрами:

  • Количество записей в тестовой таблице, по умолчанию 1 миллион

  • Объем данных в поле типа BYTEA, по умолчанию 2048 байтов

Шаги бенчмарка

До запуска шагов бенчмарка создается тестовая таблица mock_table:

CREATE TABLE mock_table (id UUID PRIMARY KEY DEFAULT uuidv7(), payload BYTEA);

На каждом своем шаге бенчмарк должен выполнять SQL-запросы различных типов, поскольку именно это в конечном итоге требуется клиентам, выбирающим тип идентификатора. Однако в бенчмарке не нужно, чтобы запросы выводили какие-то осмысленные результаты, а важно лишь время исполнения запросов.

  1. INSERT INTO mock_table (id, payload) VALUES (uuidv7(), (decode (repeat ('FF', payload_size_b), 'hex'))); --здесь вместо uuidv7() может быть подставлена другая функция, генерирующая идентификаторы

  2. Параллельная (многопоточная) вставка записей. Это не выразить на SQL

  3. SELECT COUNT (*) FROM mock_table a LEFT JOIN mock_table b ON b.id = a.id WHERE b.id IS NULL;

  4. SELECT COUNT (*) FROM mock_table a INNER JOIN mock_table b ON b.id = a.id WHERE b.id IS NULL;

  5. SELECT id, COUNT (*) FROM mock_table GROUP BY id HAVING COUNT (*) > 1;

  6. DELETE FROM mock_table a USING mock_table b WHERE b.id = a.id;

Таблица результатов бенчмарка

Таблица результатов запущенного бенчмарка должна содержать одну строку значений для каждого шага бенчмарка, в том числе:

  • Дата и время (в формате по умолчанию) запуска бенчмарка

  • Значения каждого входного параметра (в том числе, взятые по умолчанию)

  • Имя шага бенчмарка (1_insert, 2_parallel_insert, 3_left_join, 4_inner_join, 5_group_by, 6_delete)

  • Темп обработки записей, штук в миллисекунду

  • Использование CPU, %

  • Использование памяти, МБ

  • Использование диска, МБ/с

Сравниваемые типы идентификаторов

Помимо UUIDv7 и BIGSERIAL имеет смысл запускать бенчмарк по меньшей мере с такими типами идентификаторов по выбору пользователя: UUIDv4, ULID, Snowflake ID.

Habrahabr.ru прочитано 872 раза