我有一个非常简单的桌子,为人们存储标题(“先生”,“太太”等)。这是我正在做的简短版本(在这个例子中使用临时表,但结果是相同的):
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使用群集主键上的非聚集索引。我猜这解释了为什么结果按此顺序返回,但我不知道为什么会这样做。
有什么想法吗?更重要的是,任何阻止这种行为的方法?我希望按照插入的顺序返回行。
谢谢!
答案 0 :(得分:6)
如果您需要订单,则需要指定明确的ORDER BY
- 不生成订单的任何其他内容(它的“订单”是随机的并且可能会更改)。 SQL Server中没有隐含的顺序 - 不是任何东西。如果您需要订单 - 请ORDER BY
说明。
SQL Server可能使用非聚集索引(如果它可以 - 如果该索引具有您的查询要求的所有列),因为它更小 - 通常只是索引列和聚类键(再次:一列或多列)。另一方面,聚簇索引是整个数据(在叶级别),因此可能需要读取更多数据,以便得到答案(当然不是在这个过于简化的示例中 - 而是在现实世界)。
答案 1 :(得分:5)
唯一的方式(绝对和正确)保证行顺序是使用ORDER BY
- 其他任何东西都是一个实现细节,容易爆炸,如图所示。
至于为什么引擎选择了唯一索引:它没关系。
在一个没有覆盖的附加列的表上尝试它 - 没有赌注,但它可能会使查询计划者改变主意。
快乐的编码。
答案 2 :(得分:4)
SQLServer 可能选择了非聚集索引,因为您所请求的所有数据(id和title)都可以从该索引中检索。
对于这样一个简单的表,选择哪个访问路径并不重要,因为更糟糕的路径仍然只有两个IO。
如上所述,如果您希望按特定顺序使用数据,则必须使用“ORDER BY”子句特定地请求此项,否则您将获得相应的随机性。
答案 3 :(得分:3)
非聚簇索引通常小于聚簇索引,因此扫描非聚簇索引而不是聚簇索引通常会更快。这可能解释了SQL Server对非聚簇索引的偏好,即使在您的情况下索引的大小相同。
保证返回行顺序的唯一方法是指定ORDER BY。如果您没有指定ORDER BY,那么您隐式告诉优化器它可以选择返回行的顺序。