Сколько кластерных индексов может быть у таблицы в реляционной СУБД?

«Сколько кластерных индексов может быть у таблицы в реляционной СУБД?» — вопрос из категории Базы данных, который задают на 25% собеседований C# Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Только один кластерный индекс на таблицу. Это фундаментальное ограничение в большинстве реляционных СУБД (SQL Server, MySQL/InnoDB, PostgreSQL).

Почему только один? Кластерный индекс определяет физический порядок хранения данных на диске. Данные в таблице сами являются «листьями» (leaf level) кластерного индекса. Поскольку строки не могут быть физически упорядочены одновременно двумя разными способами, кластерный индекс может быть только один.

Альтернатива: некластеризованные индексы. Для ускорения других запросов можно создавать множество некластеризованных индексов. Они представляют собой отдельные структуры (например, B-деревья), которые хранят ключи индекса и указатели на соответствующие строки данных (в виде ключа кластерного индекса).

Пример в T-SQL (SQL Server):

-- Создание таблицы с кластерным индексом по полю Id (чаще всего PRIMARY KEY).
CREATE TABLE dbo.Orders (
    Id INT IDENTITY(1,1) NOT NULL PRIMARY KEY CLUSTERED, -- Единственный кластерный индекс
    OrderDate DATETIME NOT NULL,
    CustomerId INT NOT NULL,
    TotalAmount DECIMAL(10,2) NOT NULL
);

-- Создание некластеризованных индексов для ускорения поиска по другим полям.
-- Их может быть много (в пределах технических ограничений СУБД).
CREATE NONCLUSTERED INDEX IX_Orders_CustomerId ON dbo.Orders(CustomerId);
CREATE NONCLUSTERED INDEX IX_Orders_OrderDate ON dbo.Orders(OrderDate DESC);

Практические рекомендации по выбору поля для кластерного индекса:

  • PRIMARY KEY — частый и хороший кандидат, особенно если это монотонно возрастающий ключ (IDENTITY, последовательность), что минимизирует фрагментацию.
  • Выбирайте столбец (или столбцы), по которым часто происходят запросы диапазонов (range scans) (например, WHERE Date BETWEEN ...).
  • Избегайте выбора широких (много столбцов) или часто изменяемых (volatile) столбцов, так как это влияет на производительность всех некластеризованных индексов и может вызывать фрагментацию.