Какие типы сканирования таблиц существуют
Что проверяют
Умеете ли вы прочитать план запроса и объяснить, почему он медленный. Для data-ml вопрос шире обычной базы: интервьюер часто продолжает про аналитические хранилища, как ClickHouse или Spark не читают лишние данные.
Как отвечать
Начните с классической базы на примере PostgreSQL, где типы видны в EXPLAIN:
- Seq Scan: чтение всей таблицы подряд. Выгоден, когда нужна заметная доля строк или таблица маленькая: последовательное чтение дешевле случайного;
- Index Scan: проход по индексу и чтение строк из таблицы по найденным адресам. Хорош при высокой селективности;
- Index Only Scan: все нужные колонки есть в индексе, в таблицу ходить не нужно. Работает в полную силу, только если карта видимости свежая, то есть таблицу недавно обработал
VACUUM; - Bitmap Index Scan и Bitmap Heap Scan: сначала собирается битовая карта страниц по одному или нескольким индексам, потом страницы читаются по порядку. Вариант для средней селективности и условий через
OR; - Parallel Seq Scan: полное чтение несколькими воркерами.
Выбор делает планировщик по статистике (ANALYZE) и стоимостям вроде random_page_cost. Смотреть надо EXPLAIN (ANALYZE, BUFFERS): оценку строк против фактической и число прочитанных страниц.
В колоночных форматах вместо классических индексов работают:
- column pruning: читаются только нужные колонки;
- partition pruning: пропуск партиций по условию на ключ партиционирования;
- predicate pushdown: фильтр по min/max статистике row group в Parquet. В Spark это видно как
PushedFiltersвexplain(); - разреженный первичный индекс ClickHouse: засечки на гранулы (по умолчанию 8192 строки) позволяют пропускать целые блоки.
Где спотыкаются
Считают Seq Scan всегда ошибкой. Для выборки половины таблицы он быстрее любого индекса.
Оборачивают колонку в функцию или приводят тип в WHERE, и индекс перестаёт работать. В Spark то же самое ломает pushdown: фильтр по to_date(ts) вместо самой колонки.
Надеются на predicate pushdown по колонке, по которой данные не отсортированы. Если значения размазаны по всем row group, min/max ничего не отсекают, и читается весь файл.