Что такое селективность данных в базах данных
Что проверяют
Понимаете ли, почему планировщик иногда игнорирует индекс, и умеете ли читать план запроса. Для сервиса на Go это ежедневная тема: запросы идут из кода без обёртки тяжёлой ORM, и цена ошибки в условии видна сразу по задержке ответа.
Как отвечать
Селективность предиката это доля строк, которые условие оставляет от таблицы. Чем меньше доля, тем избирательнее условие. Рядом стоит кардинальность колонки, то есть число различных значений в ней: при более или менее равномерном распределении предикат равенства оставит примерно одну такую долю строк. Путать эти две величины нельзя, потому что при перекосе данных колонка с тысячей значений всё равно даст условие, под которое подходит почти вся таблица.
Дальше решает стоимость. Чтение по индексу это случайные обращения к страницам плюс поход в таблицу за остальными колонками, последовательное сканирование читает подряд и на большой доле строк выигрывает. Планировщик оценивает долю по статистике, то есть по гистограммам и спискам самых частых значений, и выбирает план по своей оценке стоимости, а не по наличию индекса.
Практика в Go: EXPLAIN (ANALYZE, BUFFERS) и сравнение ожидаемого числа строк с фактическим, потому что расхождение на порядки это почти всегда устаревшая статистика или зависимые колонки. И помнить, что подготовленные запросы в драйвере после нескольких выполнений могут перейти на общий план, не зависящий от конкретного параметра.
Где спотыкаются
Смешивают два определения и говорят, что высокая селективность это много уникальных значений, а следом, что она означает мало возвращаемых строк. На равномерных данных это совпадает, на перекошенных расходится, и именно на перекосе ломаются планы.
Верят оценке планировщика, не сверив её с фактом. После массовой заливки статистика не обновлена, оценка занижена на порядки, план построен под неё, а запрос идёт минутами. Лечится это обновлением статистики, иногда более подробной по конкретной колонке.
Вешают индекс на колонку с двумя значениями и удивляются последовательному сканированию. Если нужен как раз редкий случай, помогает частичный индекс по условию, а не обычный индекс по колонке с низкой кардинальностью.