Какой индекс лучше использовать для таблицы коротких ссылок и почему
Что проверяют
Умеете ли вы выбирать индекс от запросов, а не от списка типов. Таблица коротких ссылок это классическая нагрузка с редкой записью и массовым чтением по ключу. Следом спрашивают, как генерировать короткий код и что делать при коллизии.
Как отвечать
Начните с запросов. Главный: SELECT long_url FROM links WHERE code = $1 на каждый переход, тысячи раз в секунду. Второстепенные: вставка новой ссылки, список ссылок пользователя, иногда поиск уже существующей длинной ссылки.
Отсюда индексы:
- уникальный B-tree на
code: код делают первичным ключом или вешают на негоUNIQUE. Поиск по равенству за несколько чтений страниц, и заодно база гарантирует, что одинаковых кодов не будет; - хэш-индекс не нужен: он тоже быстр на равенстве, но в PostgreSQL не бывает уникальным, так что B-tree всё равно придётся строить ради ограничения;
(user_id, created_at DESC): если есть личный кабинет со списком ссылок, этот составной индекс отдаёт страницу без сортировки;- дедупликация длинных ссылок: URL бывает длиннее 2704 байт, это лимит записи B-tree, поэтому индекс строят по
md5(long_url)или хэш-индексом, а не по самой колонке.
Индекс на expires_at добавляйте, только если по нему реально фильтруете, например фоновой очисткой просроченных ссылок.
Про генерацию кода: случайные 7 символов base62 дают около 3,5 трлн вариантов. Вставку делают с ON CONFLICT (code) DO NOTHING или ловят ошибку 23505 через pgconn.PgError в pgx и повторяют с новым кодом. При большом трафике популярные ссылки кешируют в Redis, чтобы переход вообще не доходил до базы.
Где спотыкаются
Выбирают хэш-индекс «потому что только равенство» и забывают, что уникальность он не обеспечивает.
Индексируют всё подряд: длинный URL, дату, счётчик переходов. Счётчик, который обновляется на каждый клик, лучше вынести в отдельную таблицу или копить пачками, иначе строка ссылки постоянно переписывается.
Генерируют код без проверки на коллизию. При миллионах ссылок совпадение это вопрос времени.