Каков примерный размер индекса в базе данных для таблицы размером в терабайт
Что проверяют
Умеете ли вы оценить порядок величины, а не угадывать. Интервьюер ждёт, что вы переспросите про число строк и ширину ключа, потому что размер индекса от терабайта таблицы напрямую не зависит. Следом обычно спрашивают, как создать такой индекс на живой таблице и не остановить запись.
Как отвечать
Сначала уточните вводные: сколько строк, какой ключ, какая СУБД. Дальше считайте на примере PostgreSQL и B-tree:
- запись индекса: заголовок в 8 байт (в нём ссылка на строку таблицы), сам ключ с выравниванием до 8 байт и 4 байта указателя на странице. Для
bigintвыходит около 20 байт на строку, дляuuidоколо 28; - заполнение страниц: у B-tree по умолчанию
fillfactor90, а после вставок в середину и расщеплений страниц реальная заполненность ниже, закладывайте запас; - число строк: терабайт при средней строке в 200 байт это около 5 млрд строк, при строке в 1 КБ около миллиарда.
Отсюда оценка: индекс по bigint на 5 млрд строк займёт порядка 100 ГБ и больше, на миллиарде строк пару десятков гигабайт. Составной индекс или индекс по text будет в разы тяжелее. В MySQL InnoDB учтите, что каждый вторичный индекс хранит ещё и первичный ключ.
Проверяется это запросом, а не формулой: pg_relation_size('idx_name'), pg_indexes_size('table_name'), раздутость покажет расширение pgstattuple.
Для Java-стека добавьте практику: на такой таблице индекс не создают простым CREATE INDEX в миграции Flyway или Liquibase и тем более не отдают это hibernate.ddl-auto. Обычный CREATE INDEX блокирует запись на всё время построения. Нужен CREATE INDEX CONCURRENTLY, и такую миграцию нельзя выполнять внутри транзакции.
Где спотыкаются
Считают только ширину ключа, как будто индекс это массив чисел. Служебные поля и ссылка на строку часто весят больше самого ключа.
Берут долю от объёма таблицы: «индекс это около 10% таблицы». Широкая строка с узким ключом даст индекс в десятки раз меньше, а узкая строка с составным ключом может дать сопоставимый размер.
Забывают про разбухание: после массовых UPDATE и DELETE индекс занимает заметно больше расчётного и сам не сожмётся, нужен REINDEX CONCURRENTLY (PostgreSQL 12 и новее).