【发布时间】:2010-01-11 08:54:02
【问题描述】:
我想知道 sql server 如何对其数据进行排序。 我注意到,如果我有一个不包含列“Id”的表并且您选择没有“ORDER BY”的数据,sql server 不会自动对主列进行排序。
有谁知道 sql server 遵循什么规则对其数据进行排序?
【问题讨论】:
标签: sql-server-2008 select sql-order-by
我想知道 sql server 如何对其数据进行排序。 我注意到,如果我有一个不包含列“Id”的表并且您选择没有“ORDER BY”的数据,sql server 不会自动对主列进行排序。
有谁知道 sql server 遵循什么规则对其数据进行排序?
【问题讨论】:
标签: sql-server-2008 select sql-order-by
虽然很想知道如何解释您经常看到相同的顺序,但我想指出,依赖底层数据库引擎的特定实现导致的隐式顺序绝不是一个好主意.换句话说,很高兴知道为什么,但你永远不应该依赖它。对于 MS SQL,唯一能以特定顺序可靠地传递行的是显式的ORDER BY 子句。
不仅不同的 RDMBS 表现不同,一个特定的实例也可能由于更新(补丁)而表现不同。不仅如此,即使是 RDBMS 软件的状态也可能会产生影响:“暖”数据库的行为与“冷”数据库的行为不同,小表与大表的行为不同。
即使你有关于实现的背景信息(例如:“有一个聚集索引,因此很可能会按照聚集索引的顺序返回数据”),总有可能存在另一种机制您不知道这会导致行以不同的顺序返回(例如:“如果另一个会话刚刚使用显式 ORDER BY 进行了全表扫描,则结果集可能已被缓存;随后的全扫描将尝试从缓存中返回行"; ex2: "a GROUP BY 可以通过对数据进行排序来实现,从而影响行返回的顺序"; ex3: "如果选择的列都在已经缓存的二级索引中在内存中,引擎可能会扫描二级索引而不是表,很可能会按二级索引的顺序返回行”)。
这是一个非常简单的测试,说明了我的一些观点。
首先,启动 SQL Server(我使用的是 2008)。创建此表:
create table test_order (
id int not null identity(1,1) primary key
, name varchar(10) not null
)
检查表并见证创建了一个聚集索引来支持id 列上的primary key。例如,在 sql server management studio 中,您可以使用树视图并导航到表下方的索引文件夹。在那里您应该看到一个索引,其名称类似于:PK__test_ord__3213E83F03317E3D (Clustered)
使用此语句插入第一行:
insert into test_order(name)
select RAND()
通过重复此语句 16 次插入更多行:
insert into test_order(name)
select RAND()
from test_order
您现在应该有 65536 行:
select COUNT(*)
from test_order
现在,不使用顺序选择所有行:
select *
from test_order
最有可能的是,结果将按主键的顺序返回(尽管不能保证)。这是我得到的结果(确实是按主键的顺序):
# id name
1 1 0.605831
2 2 0.517251
3 3 0.52326
. . .......
65536 65536 0.902214
(# 不是列,而是结果中行的序号位置)
现在,在name 列上创建二级索引:
create index idx_name on test_order(name)
选择所有行,但只检索name 列:
select name
from test_order
很可能会按二级索引 idx_name 的顺序返回结果,因为查询可以通过仅扫描索引来解决(即idx_name 是一个覆盖索引)。这是我得到的结果,确实是按name 的顺序排列的。
# name
1 0.0185732
2 0.0185732
. .........
65536 0.981894
现在,再次选择所有列和所有行:
select *
from test_order
这是我得到的结果:
# id name
1 17 0.0185732
2 18 0.0185732
3 19 0.0185732
... .. .........
如您所见,与我们第一次运行此查询时完全不同。 (看起来行是按二级索引排序的,但我没有解释为什么会这样)。
无论如何,底线是 - 不要依赖隐含的顺序。您可以想出为什么可以观察到特定顺序的解释,但即便如此,如果不深入了解实现和运行时状态,您也不能总是预测它(就像在后一种情况下一样)。
【讨论】:
如果您没有明确指定 ORDER BY 子句,则无法保证对结果进行排序。甚至不能保证基于聚集索引。
您可以在this article 中查看此示例。
【讨论】:
AS SQL 基于集合理论,集合不保证任何顺序,因此如果您不明确指定特定顺序,则无法保证顺序。
【讨论】:
我有类似的体验,SQL Server 返回的结果排序与我预期的不同。我发现如果你在 select 语句中指定一个表提示,给出聚集索引的名称,你会得到你想要的结果:
select * from test_order WITH (INDEX([ClusteredIndexName]))
【讨论】: