我一直在准备面试,只是来这些事情。
我已执行以下声明:
create table trial
(
Id int not null,
Name varchar(10)
)
alter table trial add constraint unq unique clustered (Name)
alter table trial add constraint pk primary key nonclustered(Id)
insert into trial values (1,'a'),(3,'d'),(5,'b'),(2,'c')
select * from trial
结果如下所示:
我的问题是:为什么结果不按名称列排序,因为名称列具有聚集索引?
结果是:
1 a
2 c
3 d
5 b
如何使用索引对表进行物理排序?
答案 0 :(得分:4)
重复:SQL表代表无序集。除非查询包含order by
子句,否则SQL结果集无序。
因此,如果您想按顺序获取数据,请使用order by
:
select t.*
from trial t
order by t.name;
如果您想要按特定顺序排列结果,请使用order by
。 SQL Server有一个很好的优化器。如果它可以使用查询的索引 - 以避免实际排序 - 那么它通常会使用索引。
答案 1 :(得分:2)
在这种情况下,我确信优化器决定进行全表扫描或非聚簇索引扫描,因为它非常小。您可以包含实际执行计划并查看:
您可以强制使用聚集索引:
SELECT * FROM TRIAL WITH (INDEX(UNQ))
你可能会得到:
和结果集:
Id Name
1 a
5 b
2 c
3 d
但你不应该这样做,因为订购仍然没有保证。如果您希望按某些列对结果进行排序,请明确执行此操作!
我会从书中Exam 70-461: Querying Microsoft SQL Server 2012
复制一个片段,你可以在那里得到一些好的解释:
似乎输出按empid排序,但事实并非如此 保证。更令人困惑的是,如果你运行查询 反复地,似乎结果一直在返回 订购;但同样,这不能保证。当数据库引擎时(SQL 在这种情况下服务器)处理此查询,它知道它可以返回 任何顺序的数据,因为没有明确的指令 按特定顺序返回数据。可能是因为 优化和其他原因,SQL Server数据库引擎选择 这次以特定方式处理数据。甚至还有一些 如果是物理的话,这种选择会重复的可能性 情况保持不变。但是两者之间存在很大差异 由于优化和其他原因而可能发生的事情 什么是实际保证。
数据库引擎可能 - 有时也可能 更改选项可能会影响行的顺序 知道可以自由地回来了。这种变化的例子 在选择中包括数据分布的变化,可用性 物理结构,如索引和资源的可用性 像CPU和内存。此外,随着发动机的变化 升级到更新版本的产品,甚至是申请后 一个服务包,优化方面可能会改变。反过来,这样 除其他外,更改可能会影响行中的行的顺序 结果。
简而言之,这不足以强调:一个不的查询 有明确指示以特定顺序返回行 不保证结果中行的顺序。当你需要的时候 这样的保证,提供它的唯一方法是添加ORDER BY 查询的子句,这是下一节的重点。
根据评论编辑:
问题是,即使您使用聚簇索引,它也可能返回无序集。假设您具有像(1, 2, 3, 4, 5)
这样的聚类键的物理顺序。大多数情况下,您会得到(1, 2, 3, 4, 5)
,但可能会出现优化程序决定执行并行读取并说它有2个并行读取且读取(1, 2, 3)
和{{1 }}。现在可能会首先返回(4, 5)
,然后可以返回(4, 5)
。如果您没有(1, 2, 3)
子句,则引擎将不会花费其资源来订购该集合并将为您提供order by
。这就解释了为什么在订购时应始终确保有(4, 5, 1, 2, 3)
子句。