Сегодня хочу поговорить о плюсах минусах разных вариантов идентификаторов в базе данных.
Sequential ID
Думаю, все сталкивались с этим вариантом, когда id новых сущностей генерирует база при вставке, и они получают монотонно возрастающие номера:
id = 1, id = 2, id = 3…
В PostgreSQL это обычно делают через sequence.
Плюсы:
➕ удобно читать и воспринимать человеку
Например, это удобно, когда разбираем какие-то баги, смотрим логи.
➕ просто сделать
➕ можно видеть порядок добавления записей без поля createDate
Не очень частный кейс, но может быть актуально, например, для справочников.
➕ благодаря монотонному возрастанию можно использовать для keyset пагинации без offset.
Keyset — это способ реализации пагинации, при котором для получения данных отдельной страницы вместо добавления в запрос сдвига:
select name
from users
order by id
limit 10
offset 50
используем условие:
select name
from users
where id > x
order by id
limit 10
где
x — это последнее значение с прошлой страницы.➕ использует всего 64 бита (для bigint)
➕ при добавлении новых записей в БД индекс обновляется быстро благодаря последовательности ключей
➕ запросы выполняются быстрее, поскольку благодаря равномерному индексу активно используется кэш базы данных, в котором лежат стабильные части «горячих» данных — последний день, месяц
Минусы:
➖ основной минус проявляется при шардинге: если у нас много шардов базы, то при стандартном подходе сложно сохранить уникальность числовых идентификаторов.
Если каждый шард базы генерирует свои идентификаторы, то они будут пересекаться с другими шардами.
Решением может стать отдельный сервис для централизованной генерации айдишников, но у него тоже есть свои минусы (единая точка отказа, снижение скорости ответа в случае географически распределенных серверов).
➖ если числовой айдишник показывается на фронте, то из этой информации кто-то может сделать выводы, вредные для репутации или безопасности продукта.
Например, мы сделали свой новый продукт, написали на главной странице «Нам доверяют более 1000 пользователей!». Новый пользователь регистрируется на сайте, фронт отправляет запрос:
POST /users{
“name”: “Alex”,
“age”: 25
}и получает ответ:
{
“id”: 8,
“name”: “Alex”,
“age”: 25
}😅
В некоторых источниках можно встретить упоминание, что последовательно возрастающие числовые идентификаторы небезопасны, так как злоумышленник может угадать/перебрать идентификаторы и получить доступ к чужим данным.
Однако здесь дело не только в типе айдишника. Злоумышленник может подсмотреть или получить от пользователя данные в любом случае.
Независимо от типа идентификатора, на бэке всегда нужно проверять права пользователя. Может ли этот пользователь взаимодействовать с этой сущностью, может ли он ее читать, редактировать, удалять.
История из личного опыта. После сдачи дома застройщик не торопился присылать данные обмеров квартир, и люди в домовом чате забеспокоились. Один из участников чата нашел на сайте застройщика нужный PDF с id в адресе файла и рассказал в чате. Путём подбора id в URL все смогли скачать себе PDF своих (и чужих) квартир. Не то чтобы обмеры квартир — это секретная информация, но вот так мы добыли их до официальной рассылки застройщика.
Продолжение ⬇️
#бд