为什么SQL Server在"select*"操作中使用非聚集索引而不是聚簇PK?

ger*_*rod 5 sql-server clustered-index sql-execution-plan non-clustered-index

我有一个非常简单的桌子,为人们存储标题("先生","太太"等).这是我正在做的简要版本(在这个例子中使用临时表,但结果是相同的):

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
Run Code Online (Sandbox Code Playgroud)

请注意,表的主键是聚类的(显式,为了示例),并且标题列有一个非聚集唯一性约束.

以下是select操作的结果:

t_id title
---- --------------------
3    Miss
1    Mr
2    Mrs
Run Code Online (Sandbox Code Playgroud)

查看执行计划,SQL在群集主键上使用非聚集索引.我猜这解释了为什么结果按此顺序返回,但我不知道为什么它会这样做.

有任何想法吗?更重要的是,任何阻止这种行为的方法?我希望按照插入的顺序返回行.

谢谢!

mar*_*c_s 6

如果你想要订单,你需要明确指定ORDER BY- 其他任何东西都不会产生订单(它的"订单"是随机的,可能会改变).SQL Server中没有隐含的顺序 - 不是任何东西.如果你需要订单 - 请说明ORDER BY.

SQL Server可能使用非聚集索引(如果它可以 - 如果该索引具有您的查询要求的所有列),因为它更小 - 通常只是索引列和聚类键(再次:一个或多个列).另一方面,聚簇索引是整个数据(在叶级别),因此可能需要读取更多数据,以便得到答案(当然不是在这个过于简化的示例中 - 而是在现实中).


小智 5

(绝对和正确地)保证行顺序的唯一方法是使用ORDER BY- 其他任何东西都是实现细节并且容易爆炸,如图所示.

至于为什么发动机选择了独特的指数:它没关系.

  1. 没有标准支持一个指数而不是另一个指数
  2. 唯一索引涵盖了返回的数据(标题和PK); 这对我来说有些推测,但SQL Server正在做它认为最好的事情.

在一个没有覆盖的附加列的表上尝试它 - 没有赌注,但它可能会使查询计划者改变主意.

快乐的编码.