> Что такое селективность данных в базах данных (Go)

Уровень: junior · Роль: backend · Категория: Технические вопросы

Компании: VK

Стек: Go

> Пример ответа

Короткий ответ

Селективность данных - это метрика, показывающая, какая доля строк таблицы будет отобрана по условию запроса. Она вычисляется как отношение количества строк, удовлетворяющих условию, к общему количеству строк. Высокая селективность означает, что условие отбирает мало строк, низкая - много. Селективность напрямую влияет на выбор плана выполнения запроса: при высокой селективности оптимизатор, скорее всего, использует индекс, при низкой - full scan.

Подробное объяснение

Селективность - ключевое понятие для понимания работы оптимизатора запросов. Она определяется для каждого предиката в WHERE, JOIN или HAVING.

Формально: селективность = количество уникальных значений столбца / общее количество строк. Например, для столбца id с 1 000 000 уникальных значений на 1 000 000 строк селективность = 1.0 (максимальная). Для столбца is_deleted с двумя значениями (true/false) селективность = 0.000002 - крайне низкая.

Оптимизатор использует статистику по распределению данных (гистограммы, количество NULL, density) для оценки селективности каждого предиката. На основе этих оценок он выбирает стратегию:

  • Высокая селективность (близка к 1.0): условие отбирает мало строк - выгодно использовать индекс, чтобы не сканировать всю таблицу.
  • Низкая селективность (близка к 0): условие отбирает много строк (например, 50% таблицы) - full scan часто быстрее, чем чтение индекса и последующие random access к таблице.

Важно: селективность зависит не только от столбца, но и от конкретного значения в условии. Для столбца с неравномерным распределением (например, 90% строк имеют значение status = 'active') селективность по status = 'active' будет низкой, а по status = 'archived' - высокой.

В PostgreSQL, MySQL, Oracle оптимизатор хранит статистику по каждому столбцу и обновляет её через ANALYZE / auto-analyze. Устаревшая статистика - частая причина деградации производительности.

На практике

Для backend-разработчика на Go понимание селективности важно при:

  1. Проектировании индексов - индекс имеет смысл только для столбцов с высокой селективностью. Индекс по is_deleted почти бесполезен.
  2. Написании запросов - если условие по низкоселективному столбцу комбинируется с высокоселективным, порядок условий в WHERE не влияет на план (оптимизатор сам решает), но составной индекс нужно строить от высокоселективного к низкоселективному.
  3. Диагностике медленных запросов - если запрос с WHERE status = 'active' выполняется долго, причина может быть в том, что оптимизатор выбрал index scan вместо seq scan из-за неверной оценки селективности (устаревшая статистика).

На практике часто используют EXPLAIN ANALYZE для проверки реальной селективности против ожидаемой. Расхождение в оценках (estimated rows vs actual rows) - сигнал к обновлению статистики или пересмотру индекса.

Пример кода

Пример на Go с использованием database/sql и PostgreSQL - проверка селективности через EXPLAIN:

GO
package main
import (
"database/sql"
"fmt"
"log"
_ "github.com/lib/pq"
)
func checkSelectivity(db *sql.DB, query string) {
explainQuery := "EXPLAIN (FORMAT JSON) " + query
var result []byte
err := db.QueryRow(explainQuery).Scan(&result)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Plan for %s:\n%s\n", query, result)
}
func main() {
db, err := sql.Open("postgres", "postgres://user:pass@localhost/db?sslmode=disable")
if err != nil {
log.Fatal(err)
}
defer db.Close()
// Низкая селективность - full scan
checkSelectivity(db, "SELECT * FROM users WHERE is_active = true")
// Высокая селективность - index scan
checkSelectivity(db, "SELECT * FROM users WHERE email = 'test@example.com'")
}

В выводе EXPLAIN можно увидеть "Actual Rows" и "Plan Rows" - их отношение и есть фактическая селективность.

Как отвечать на собеседовании

Начни с определения и формулы. Затем объясни влияние на выбор плана запроса. Приведи конкретный пример из практики: столбец с низкой селективностью (булевый флаг) и высокой (email). Упомяни, что оптимизатор опирается на статистику, и что устаревшая статистика - частая проблема. Если спросят про индексы - свяжи селективность с выбором типа индекса и порядком колонок в составном индексе.

Держи ответ структурированным: определение → влияние на оптимизатор → практические выводы. Не углубляйся в детали реализации конкретных СУБД, если не просят.

Что проверяет интервьюер

Интервьюер оценивает:

  • Понимание базового определения и формулы.
  • Умение связать селективность с планом выполнения запроса.
  • Понимание разницы между высокой и низкой селективностью на практике.
  • Знание того, что оптимизатор использует статистику, и что она может быть устаревшей.
  • Способность применить понятие к проектированию индексов.

Для junior-уровня достаточно уверенного ответа на первые три пункта. Упоминание статистики и её обновления - плюс.

Типичные ошибки

  • Путаница с кардинальностью - кардинальность это количество уникальных значений, а селективность это отношение. Не смешивай.
  • Утверждение, что индекс всегда ускоряет - при низкой селективности index scan может быть медленнее full scan из-за random I/O.
  • Игнорирование распределения данных - селективность зависит от конкретного значения, а не только от столбца.
  • Забывание про NULL - NULL не участвует в индексах (в большинстве СУБД), что влияет на оценку селективности.
  • Незнание, как посмотреть фактическую селективность - без EXPLAIN ANALYZE сложно диагностировать проблемы.

> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?

Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью