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 会在未询问的情况下对结果进行排序,我该怎么做才能阻止这种情况?
我试图向我的学生证明,除非指定,否则顺序是不确定的,但这对我的情况没有帮助。
我承认我正在处理一小组样本数据。
谢谢
Conor Cunningham(Microsoft 的软件架构师,SQL Server 引擎)的这篇文章应该可以回答您的问题:
部分摘录如下:
这里的难点在于,任何外部用户都无法通过合理的方式知道计划何时会发生变化。所有计划的空间都很大,令人头疼。如果更改了足够多的参数,SQL Server 的优化器将更改计划,即使对于简单查询也是如此。您可能很幸运并且没有更改计划,或者您可以不考虑这个问题并添加
ORDER BY
.[...]
在优化器中计划可以更改的情况很多 - 对于更复杂的查询,可能有数千个或更多的计划选择,并且每个计划都有可能被选中的情况。对于这些计划中的每一个,如果您不指定该计划的排序,则它可能会有所不同。
所以,我今天的建议是:
如果您需要在查询结果中排序,请将
ORDER BY
. 就这么简单。其他任何事情就像乘坐没有安全带的汽车一样。
在什么情况下 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)
然后希望您会看到无序的结果,而不必更改隔离级别。
对于第二个查询,您需要散列聚合而不是流聚合。您可以使用查询提示或不太明显的计划指南强制执行此操作,但是如果与表的大小相比,不同的组相对较少,则更有可能有机地选择。
归档时间: |
|
查看次数: |
445 次 |
最近记录: |