5

我有一个非常简单的表格,用于存储人们的标题(“先生”、“夫人”等)。这是我正在做的事情的简要版本(在这个例子中使用了一个临时表,但结果是一样的):

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

4 回答 4

6

如果你想要订单,你需要指定一个明确的ORDER BY- 其他任何东西都不会产生订单(它的“订单”是随机的并且可能会改变)。SQL Server 中没有隐含的顺序 - 不是任何东西。如果您需要订购 - 请使用ORDER BY.

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

于 2011-08-04T06:20:24.940 回答
5

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

至于引擎为什么选择唯一索引:这无关紧要。

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

在具有未涵盖的附加列的表上尝试它 - 没有赌注,但它可能会使查询计划者改变主意。

快乐编码。

于 2011-08-04T06:18:04.470 回答
4

SQLServer可能选择了非聚集索引,因为您请求的所有数据(id 和标题)都可以从该索引中检索。

对于这样一个微不足道的表,选择哪个访问路径并不重要,因为更糟糕的路径仍然只有两个 IO。

正如上面有人评论的那样,如果您希望您的数据按特定顺序排列,您必须使用“ORDER BY”子句特别请求这个,否则您得到的结果是非常随机的。

于 2011-08-04T06:23:10.123 回答
3

非聚集索引通常比聚集索引小,因此扫描非聚集索引通常比扫描聚集索引更快。这可能解释了 SQL Server 对非聚集索引的偏好,即使在您的情况下索引的大小相同。

保证返回行顺序的唯一方法是指定 ORDER BY。如果您没有指定 ORDER BY,那么您就隐含地告诉优化器它可以选择返回行的顺序。

于 2011-08-04T06:31:23.733 回答