SQL Server:行顺序

Man*_*ngo 5 sql-server order-by select group-by

我们都知道一个简单的语句例如:

SELECT * FROM stuff;
Run Code Online (Sandbox Code Playgroud)

应该不会产生有序的结果。然而,当我试图证明这一点时,它总是以主键顺序出现。

此外还有一个声明,例如:

SELECT thing,whatever FROM stuff
GROUP BY thing,whatever;
Run Code Online (Sandbox Code Playgroud)

似乎总是按GROUP BY子句中的最后一个字段对事物进行排序,这根本没有帮助。

问题是,在什么情况下 SQL SERVER 会在未询问的情况下对结果进行排序,我该怎么做才能阻止这种情况?

我试图向我的学生证明,除非指定,否则顺序是不确定的,但这对我的情况没有帮助。

我承认我正在处理一小组样本数据。

谢谢

Sco*_*red 8

Conor Cunningham(Microsoft 的软件架构师,SQL Server 引擎)的这篇文章应该可以回答您的问题:

部分摘录如下:

这里的难点在于,任何外部用户都无法通过合理的方式知道计划何时会发生变化。所有计划的空间都很大,令人头疼。如果更改了足够多的参数,SQL Server 的优化器将更改计划,即使对于简单查询也是如此。您可能很幸运并且没有更改计划,或者您可以不考虑这个问题并添加ORDER BY.

[...]

在优化器中计划可以更改的情况很多 - 对于更复杂的查询,可能有数千个或更多的计划选择,并且每个计划都有可能被选中的情况。对于这些计划中的每一个,如果您不指定该计划的排序,则它可能会有所不同。

所以,我今天的建议是:

如果您需要在查询结果中排序,请将ORDER BY. 就这么简单。其他任何事情就像乘坐没有安全带的汽车一样。


Mar*_*ith 8

在什么情况下 SQL SERVER 会在未询问的情况下对结果进行排序?

如果检索数据的访问路径恰好生成已排序的数据,例如按键顺序进行索引扫描,则可能会发生这种情况。或者,如果计划包含显式排序以便为需要此操作的运算符(例如合并连接或流聚合)提供数据。如果没有明确的order by顺序,就不能保证顺序,但 SQL Server 也不会特意阻止结果按顺序输出。

我该怎么做才能阻止这种情况?

对于第一个查询,如果 SQL Server 使用分配顺序扫描,您可以看到不同的排序。

因此,请确保表的大小至少为 64 页,并且分配顺序与键顺序不同,然后在读取未提交隔离级别运行查询。

CREATE TABLE T
(
X INT IDENTITY PRIMARY KEY,
Y CHAR(4000)
);

INSERT INTO T
SELECT TOP 100 'A'
FROM master..spt_values;

/* Cause page splits so key order and allocation order differ
   and leaves one row per page so table is now > 64 pages*/
ALTER TABLE T ALTER COLUMN Y CHAR(4001);

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;

SELECT *
FROM T;
Run Code Online (Sandbox Code Playgroud)

在采用表锁定的情况下,上述情况不需要未提交的读,有一个提示,但不太明显的方法是将上面的表定义更改为

CREATE TABLE T
(
X INT IDENTITY PRIMARY KEY WITH(allow_row_locks = off, allow_page_locks = off),
Y CHAR(4000)
);
Run Code Online (Sandbox Code Playgroud)

然后希望您会看到无序的结果,而不必更改隔离级别。

对于第二个查询,您需要散列聚合而不是流聚合。您可以使用查询提示或不太明显的计划指南强制执行此操作,但是如果与表的大小相比,不同的组相对较少,则更有可能有机地选择。

  • 对于第二个查询,他们也可以先在 `(thing,whatever)` 上添加索引后尝试,然后删除索引并在 `(whatever,thing)` 上添加另一个索引。很可能会使用索引并且结果将按不同的顺序排列。然后删除这些索引并尝试获取哈希聚合计划。 (2认同)