Почему SQL Server использует некластеризованный индекс поверх кластеризованного PK в операции «выбор *»? - PullRequest
5 голосов
/ 04 августа 2011

У меня есть очень простая таблица, в которой хранятся заголовки для людей («Мистер», «Миссис» и т. Д.). Вот краткая версия того, что я делаю (используя временную таблицу в этом примере, но результаты совпадают):

create table #titles (
    t_id    tinyint     not null    identity(1, 1),
    title   varchar(20) not null,

    constraint pk_titles primary key clustered (t_id),
    constraint ux_titles unique nonclustered (title)
)
go

insert #titles values ('Mr')
insert #titles values ('Mrs')
insert #titles values ('Miss')

select * from #titles

drop table #titles

Обратите внимание, что первичный ключ таблицы кластеризован (явно для примера), и в столбце заголовка есть некластеризованное ограничение уникальности.

Вот результаты операции выбора:

t_id title
---- --------------------
3    Miss
1    Mr
2    Mrs

Глядя на план выполнения, SQL использует некластеризованный индекс поверх кластерного первичного ключа . Я предполагаю, что это объясняет, почему результаты возвращаются в таком порядке, но я не знаю, почему это происходит.

Есть идеи? И что более важно, есть ли способ остановить это поведение? Я хочу, чтобы строки возвращались в том порядке, в котором они были вставлены.

Спасибо!

Ответы [ 4 ]

6 голосов
/ 04 августа 2011

Если вы хотите заказать, вам нужно указать явный ORDER BY - все остальное, что не создает заказ (это «заказ» является случайным и может измениться). Там нет никакого подразумеваемого порядка в SQL Server - ни в чем. Если вам нужен заказ - так и скажите ORDER BY.

SQL Server, вероятно, использует некластеризованный индекс (если он может - если в этом индексе есть все столбцы, которые запрашивает ваш запрос), поскольку он меньше - обычно это только столбцы индекса и ключ кластеризации (опять же: один или несколько столбцов). С другой стороны, кластеризованный индекс - это целые данные (на уровне листа), поэтому для его получения может потребоваться намного больше данных, чтобы получить ответ (конечно, не в этом упрощенном примере, а в реальный мир).

5 голосов
/ 04 августа 2011

Единственный способ (абсолютно и правильно) гарантировать порядок строк - использовать ORDER BY - все остальное - это деталь реализации и возможность взорваться, как показано.

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

  1. Не было критериев, предпочитающих один индекс над другим
  2. Уникальный индекс покрыто возвращены данные (название и PK);с моей стороны это несколько умозрительно, но SQL Server делает то, что считает лучше.

Попробуйте это на столе с дополнительным столбцом, который не покрыт - никаких ставок, но это может сделатьпланировщик запросов передумает.

Удачного кодирования.

4 голосов
/ 04 августа 2011

SQLServer вероятно выбрал некластеризованный индекс, поскольку все запрошенные вами данные (идентификатор и заголовок) могут быть получены из этого индекса.

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

Как кто-то прокомментировал выше, если вы хотите, чтобы ваши данные были в определенном порядке, вы должны специально запросить это, используя предложение «ORDER BY», в противном случае вы получите довольно случайный ответ.

3 голосов
/ 04 августа 2011

Некластеризованные индексы обычно меньше кластеризованных, поэтому обычно быстрее сканировать некластеризованный индекс, чем кластеризованный.Это, вероятно, объясняет предпочтение SQL Server для некластеризованного индекса, даже если в вашем случае индексы имеют одинаковый размер.

Единственный способ гарантировать порядок возвращаемых строк - указать ORDER BY.Если вы не укажете ORDER BY, вы неявно сообщаете оптимизатору, что он может выбирать, в каком порядке возвращать строки.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...