【问题标题】:How does sql server sort your data?sql server 如何对数据进行排序?
【发布时间】:2010-01-11 08:54:02
【问题描述】:

我想知道 sql server 如何对其数据进行排序。 我注意到,如果我有一个不包含列“Id”的表并且您选择没有“ORDER BY”的数据,sql server 不会自动对主列进行排序。

有谁知道 sql server 遵循什么规则对其数据进行排序?

【问题讨论】:

    标签: sql-server-2008 select sql-order-by


    【解决方案1】:

    虽然很想知道如何解释您经常看到相同的顺序,但我想指出,依赖底层数据库引擎的特定实现导致的隐式顺序绝不是一个好主意.换句话说,很高兴知道为什么,但你永远不应该依赖它。对于 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
    ...    ..    .........
    

    如您所见,与我们第一次运行此查询时完全不同。 (看起来行是按二级索引排序的,但我没有解释为什么会这样)。

    无论如何,底线是 - 不要依赖隐含的顺序。您可以想出为什么可以观察到特定顺序的解释,但即便如此,如果不深入了解实现和运行时状态,您也不能总是预测它(就像在后一种情况下一样)。

    【讨论】:

    • 值得补充的是,具有聚集主键的表上的任何二级索引都会在索引的隐藏字段中保存主键的副本。所以确实它可以用来获取 id 和 value(在我们的例子中是 *)。感谢您的回答,我不知道查询优化器可以根据它是否已经在 RAM 缓存中来选择索引。
    【解决方案2】:

    如果您没有明确指定 ORDER BY 子句,则无法保证对结果进行排序。甚至不能保证基于聚集索引。

    您可以在this article 中查看此示例。

    【讨论】:

      【解决方案3】:

      AS SQL 基于集合理论,集合不保证任何顺序,因此如果您不明确指定特定顺序,则无法保证顺序。

      【讨论】:

        【解决方案4】:

        我有类似的体验,SQL Server 返回的结果排序与我预期的不同。我发现如果你在 select 语句中指定一个表提示,给出聚集索引的名称,你会得到你想要的结果:

        select * from test_order WITH (INDEX([ClusteredIndexName]))
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-04-26
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多