sql - SELECT 查询中的默认行顺序 - SQL Server 2008 与 SQL 2012

标签 sql sql-server sql-server-2008 sql-server-2012 database-migration

我们的团队最近将数据库从 SQL Server 2008 升级到 SQL Server 2012。我们注意到的一项重大更改是 SELECT 语句返回的行的默认顺序,即未指定显式 ORDER BY 子句时。

根据 MSDN,SQL Server 2012除非指定 ORDER BY 子句,否则不保证返回行的顺序。

我们在 5 个数据库中有 2500 多个存储过程,这些存储过程具有不带 ORDER BY 子句的 SELECT 语句,手动添加 ORDER BY 子句以匹配 SQL Server 2008 中的行为将需要付出相当大的努力。是否有设置或更快这样做的方法?

另一个尚未探索的选项是降级到 SQL Server 2008。这有多困难?

最佳答案

您需要返回并在代码中添加 ORDER BY 子句,因为没有它们,顺序永远无法保证。过去你很“幸运”,因为你总是得到相同的订单,但这并不是因为 SQL Server 2008 无论如何都保证了这一点。它很可能与您的索引或数据在磁盘上的存储方式有关。

如果您在升级时移动到新主机,则仅硬件配置的差异就可能会改变查询的执行方式。更不用说新服务器将重新计算表的统计信息,并且 SQL Server 2012 查询优化器的工作方式可能与 SQL Server 2008 中的有所不同。

您可以依赖 SQL 中结果集的顺序而不明确说明您想要的顺序,这是一个谬论。SQL 结果永远有一个您可以依赖的顺序,而无需使用ORDER BY 子句。 SQL 是围绕集合论构建的。查询结果基本上是集合(或多集合)。

Itzik Ben-Gan 在他的书 Microsoft SQL Server 2012 T-SQL Fundamentals 中很好地描述了与 SQL 相关的集合论。

Set theory, which originated with the mathematician Georg Cantor, is one of the mathematical branches on which the relational model is based. Cantor's definition of a set follows:

By a "set" we mean any collection M into a whole of definite, distinct objects m (which are called the "elements" of M) of our perception or of our thought. - Joseph W. Dauben and Georg Cantor (Princeton University Press, 1990)

在对定义中的术语进行彻底解释后,Itzik 继续说道:

What Cantor's definition of a set leaves out is probably as important as what it includes. Notice that the definition doesn't mention any order among the set elements. The order in which set elements are listed is not imporant. The formal notation for listing set elements uses curly brackets: {a, b, c}. Because order has no relevance you can express the same set as {b, a, c} or {b, c, a}. Jumping ahead to the set of attributes (called columns in SQL) that make up the header of a relation (called a table in SQL), an element is supposed to be identified by name - not ordinal position. Similarly, consider the set of tuples (called rows by SQL) that make up the body of the relation; an element is identified by its key values - not by position. Many programmers have a hard time adapting to the idea that, with respect to querying tables, there is no order among the rows. In other words, a query against a table can return rows in any order unless you explicitly request that the data be sorted in a specific way, perhaps for presentation purposes.

但无论集合的学术定义如何,即使是 SQL Server 中的实现也无法保证结果的任何顺序。这个MSDN blog post from 2005 by a member of the query optimizer team指出您根本不应该依赖中间操作的顺序。

The reordering rules can and will violate this assumption (and do so when it is inconvenient to you, the developer ;). Please understand that when we reorder operations to find a more efficient plan, we can cause the ordering behavior to change for intermediate nodes in the tree. If you’ve put an operation in the tree that assumes a particular intermediate ordering, it can break.

Conor Cunningham(SQL Server 核心引擎架构师)的这篇博客文章“No Seatbelt - Expecting Order without ORDER BY”是关于 SQL Server 2008 的。他有一个包含 20k 行的表,其中有一个索引,该索引似乎总是以相同的索引返回行命令。向查询添加 ORDER BY 甚至不会更改执行计划,因此,如果优化器意识到不需要它,则添加 ORDER BY 不会使查询变得更加昂贵。但是,当他向表中添加另外 20k 行时,查询计划突然发生变化,现在它使用并行性,并且结果不再排序!

The hard part here is that there is no reasonable way for any external user to know when a plan will change . The space of all plans is huge and hurts your head to ponder. SQL Server's optimizer will change plans, even for simple queries, if enough of the parameters change. You may get lucky and not have a plan change, or you can just not think about this problem and add an ORDER BY.

如果您需要更有说服力,请阅读这些帖子:

关于sql - SELECT 查询中的默认行顺序 - SQL Server 2008 与 SQL 2012,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26236352/

相关文章:

sql - OLE DB 或 ODBC 错误 : Login failed for user 'NT AUTHORITY\NETWORK SERVICE

sql - 在一列中搜索不同的值

mysql - 获取每个月的交易余额

mysql - 将 2 列合并为一列,并添加一列以在 SQL 中使用 if 或 case 进行注释

c# - 使用 SQL Server 数据库构建 HTTP REST Web 服务器

sql-server - Sql Server 代理作业的运行时间超过执行间隔

asp.net-mvc - 在生产 MVC/SQL 应用程序中记录大量操作

mysql - 如何修改查询以排除两个特定列?

sql-server - 为什么这个 CTE 比使用临时表慢这么多?

sql-server - SQL Server Profiler : Get stored procedure name