Что такое кардинальность (cardinality) индекса в базах данных?

Ответ

Кардинальность индекса — это оценка уникальности значений в индексируемом столбце или комбинации столбцов. Она показывает, насколько эффективно индекс может отфильтровать строки.

Уровни кардинальности:

  1. Высокая: Столбец содержит много уникальных или почти уникальных значений (например, email, primary key). Индекс очень эффективен.
  2. Низкая: Столбец содержит мало уникальных значений (например, gender, status). Индекс может быть неэффективен, и оптимизатор СУБД может его проигнорировать.

Пример в SQL:

-- Высокая кардинальность: индекс очень полезен
CREATE INDEX idx_user_email ON users(email);

-- Низкая кардинальность: индекс, скорее всего, бесполезен для поиска по одному статусу
CREATE INDEX idx_order_status ON orders(status); -- status может быть 'new', 'processed', 'shipped'

-- Комбинированный индекс может иметь хорошую кардинальность
CREATE INDEX idx_status_created ON orders(status, created_at);

Почему это важно для оптимизатора запросов? Оптимизатор использует статистику по кардинальности, чтобы решить:

  • Использовать ли индекс или выполнить полное сканирование таблицы.
  • Какой индекс выбрать, если доступно несколько.
  • Порядок соединения таблиц (JOIN). Индекс с высокой кардинальностью лучше сужает поиск.

Ответ 18+ 🔞

Давай разжую эту тему про кардинальность индексов, чтобы ты понял, как будто я тебе на пальцах объясняю. Представь себе, что ты ищешь друга в толпе.

Кардинальность индекса — это, по сути, ответ на вопрос: «Насколько уникальны данные в этом столбце, чтобы по ним можно было нормально искать?» Это как оценить, насколько хорошо работает фильтр.

Два главных уровня, чувак:

  1. Высокая кардинальность (Овердохуища уникальных значений). Это когда в столбце почти все значения разные. Например, почта (email) или айдишник (primary key). Это идеально, блядь! Представь, ты ищешь одного конкретного Васю по паспорту в толпе из тысячи человек. Паспорт — штука уникальная, ты его нашёл — и сразу понял, кто это. Индекс в таком случае работает на ура, оптимизатор запросов его обожает и сразу использует.

  2. Низкая кардинальность (Хуй с горы уникальности). А вот это полная противоположность. Значений мало, и они постоянно повторяются. Классика — gender (пол: «М»/«Ж») или status заказа («новый», «отправлен», «доставлен»). Смотри: ты заходишь на стадион и кричишь: «Эй, мужик!». На тебя обернётся тысяч пять человек, и толку от такого «поиска» — нихуя. Вот и индекс по такому столбцу часто бесполезен. База посмотрит на статистику, поймёт, что отфильтрует он всего ничего, и проигнорирует его, пойдёт сканировать всю таблицу целиком. Доверия ебать ноль у оптимизатора к такому индексу.

Смотри на примере кода, тут всё чётко:

-- Вот это — огонь. Почта почти всегда уникальна. Индекс будет летать.
CREATE INDEX idx_user_email ON users(email);

-- А вот это — сомнительная затея. Статусов-то всего штук 5-6 на всю таблицу заказов.
-- Создашь индекс, а он, скорее всего, так и будет пылиться.
CREATE INDEX idx_order_status ON orders(status);

-- Но иногда можно схитрить! Комбинированный индекс.
-- Сам по себе `status` — не очень. Но `status` + дата создания — уже уникальнее.
-- Например, «новых» заказов, созданных сегодня в 14:30, будет уже не так дохуя.
CREATE INDEX idx_status_created ON orders(status, created_at);

А нахуя это всё вообще надо? Всё просто: оптимизатор запросов — не дурак, он смотрит на статистику. Кардинальность — главная метрика в этой статистике. Он решает по ней:

  • Использовать индекс или просканировать всю таблицу (full scan)? Если кардинальность низкая — зачем ему по индексу бегать, если всё равно почти всё выбирать придётся?
  • Какой индекс выбрать из нескольких? Он возьмёт тот, который отфильтрует больше всего строк, то есть с самой высокой кардинальностью для твоего конкретного запроса.
  • В каком порядке таблицы соединять (JOIN)? Он будет стараться начинать с той таблицы, где после фильтрации останется меньше всего строк, чтобы дальше работать с этим небольшим набором.

Короче, высокая кардинальность = узкий, точный поиск = довольный оптимизатор = быстрый запрос. Запомни это, и будешь создавать индексы не просто так, а с умом.