В чем разница между кластерным и некластерным индексом в SQL?

Ответ

Кластерный индекс определяет физический порядок хранения строк данных в таблице. Таблица может иметь только один кластерный индекс, так как данные не могут быть физически упорядочены более чем одним способом. В SQL Server и MySQL (InnoDB) первичный ключ по умолчанию создает кластерный индекс.

Некластерный индекс — это отдельная структура, которая хранит отсортированные ключевые значения вместе с указателями на фактические строки данных (row locators). На одну таблицу можно создать множество некластерных индексов.

Ключевые различия:

Аспект Кластерный индекс Некластерный индекс
Количество Один на таблицу Множество на таблицу
Структура Данные таблицы физически отсортированы Отдельная структура (B-дерево) с указателями
Скорость чтения Быстрее для диапазонных запросов и поиска по первичному ключу Быстрее для точечных запросов по индексируемым полям
Скорость вставки Медленнее (требуется переупорядочивание) Быстрее (добавляется только запись в индекс)
Хранение Содержит сами данные Содержит ключи + указатели на данные

Примеры в SQL:

-- Создание таблицы с кластерным индексом (первичный ключ)
CREATE TABLE Orders (
    OrderID INT PRIMARY KEY,  -- Создает кластерный индекс
    CustomerID INT,
    OrderDate DATE,
    Amount DECIMAL(10,2)
);

-- Создание некластерного индекса
CREATE NONCLUSTERED INDEX IX_Orders_CustomerID 
ON Orders(CustomerID);

-- Составной некластерный индекс
CREATE NONCLUSTERED INDEX IX_Orders_Date_Customer
ON Orders(OrderDate DESC, CustomerID);

Практический опыт: В проектах с высокой нагрузкой на запись я тщательно проектирую кластерный индекс, чтобы минимизировать фрагментацию. Для часто запрашиваемых полей, не входящих в кластерный индекс, создаю покрывающие некластерные индексы (covering indexes), которые включают все необходимые для запроса столбцы, чтобы избежать обращений к самой таблице (key lookups).

Ответ 18+ 🔞

А, ну это про индексы, ёпта! Сидишь такой, думаешь — ну что за хуйня, почему одна таблица тормозит, как черепаха в патоках? А потом вспоминаешь, что индексы — это как карта сокровищ для базы данных, без них она слепая и тупая.

Смотри, есть два главных типа: кластерный и некластерный. Разница между ними — как между твоей старой, засаленной кроватью, где всё валяется в одном месте (кластерный), и умным шкафом с кучей полочек для каждой хуйни (некластерный).

Кластерный индекс — это царь и бог таблицы. Он один, как первичный пахан. Он не просто указывает на данные, он и есть сами данные, упорядоченные по выбранному ключу. Создаёшь PRIMARY KEY — и бац, у тебя уже есть кластерный индекс (в SQL Server и InnoDB). Данные на диске лежат именно в этом порядке. Поэтому он быстрый для поиска по этому ключу и для выборки диапазонов. Но, бля, есть подвох: если вставляешь запись не в конец, а куда-то в середину, системе приходится двигать всё остальное, как в переполненном автобусе, — это может быть долго. Один на таблицу, и точка.

Некластерный индекс — это уже отдельная, хитрая структура. Как записная книжка с оглавлением. В ней хранятся отсортированные значения выбранных полей (например, CustomerID или OrderDate) и указатели на то место в куче или кластерном индексе, где лежат полные данные строки. Таких индексов можно наделать овердохуища, под каждую частую операцию поиска. Быстро нашли по индексу, а потом — прыг! — по указателю за остальными данными.

Вот тебе ключевые различия, чтобы не путать:

Что сравниваем Кластерный индекс (Царь) Некластерный индекс (Шкаф с полками)
Сколько можно Один, блядь! Много, хоть всю таблицу ими облепи
Что внутри Сами строки данных, упорядоченные Ключи + адреса-указатели на строки
Читает Охуенно быстро, если по его порядку Быстро находит ключ, но потом может быть прыжок
Вставляет/Обновляет Иногда медленно, если порядок ломается Обычно быстрее, просто добавил запись в свой список
Занимает место Это и есть данные, места не занимает отдельно Занимает, иногда прилично, это же отдельная структура

На практике это выглядит так:

-- Создаём таблицу. PRIMARY KEY сделает кластерный индекс по OrderID.
-- Данные на диске будут лежать в порядке возрастания OrderID.
CREATE TABLE Orders (
    OrderID INT PRIMARY KEY,  -- Вот он, пахан кластерный
    CustomerID INT,
    OrderDate DATE,
    Amount DECIMAL(10,2)
);

-- А это уже некластерный индекс. Отдельная структура для быстрого поиска по CustomerID.
CREATE NONCLUSTERED INDEX IX_Orders_CustomerID
ON Orders(CustomerID);

-- Составной некластерный индекс. Сначала по дате (сортировка обратная), потом по клиенту.
-- Удобно для отчётов "покажи заказы за вчера".
CREATE NONCLUSTERED INDEX IX_Orders_Date_Customer
ON Orders(OrderDate DESC, CustomerID);

А теперь жизненный лайфхак, чувак. Когда нагрузка дикая, и запросы летят каждую секунду, просто накидать индексов — мало. Надо думать.

  1. Кластерный индекс выбирай с умом. Чаще всего это монотонно растущий PK (типа IDENTITY). Чтобы новые записи просто приклеивались в конец, а не вызывали пиздец с фрагментацией.
  2. Некластерные индексы делай "покрывающими" (covering). Это когда в индекс включаешь не только поля для поиска, но и те, которые нужны в SELECT. Тогда запросу вообще не надо лезть в саму таблицу — всё есть в индексе. Это как если бы в оглавлении книги была не только страница, но и сам абзац. Скорость взлетает до небес.

В общем, индексы — это не магия, а инструмент. Используй с умом, а не как мартышлюшка, которая на кнопки тыкает. И тогда твоя база не будет бздеть на каждый запрос.