据我所知,从关系数据库理论来看,select
没有order by
子句的语句应该被认为没有特定的顺序。但实际上在 SQL Server 和 Oracle 中(我已经在这两个平台上进行了测试),如果我order by
多次从没有子句的表中查询,我总是以相同的顺序得到结果。这种行为可以依赖吗?任何人都可以帮忙解释一下吗?
4 回答
不,不能依赖这种行为。顺序由查询计划器决定构建结果集的方式确定。像这样的简单查询select * from foo_table
可能会按照它们存储在磁盘上的顺序返回,这可能是主键顺序或它们被创建的顺序,或者其他一些随机顺序。更复杂的查询,例如select * from foo where bar < 10
可能会根据索引读取或表顺序以不同列的顺序返回,以进行表扫描。where
具有多个条件、group by
子句s 的更复杂的查询union
将按照规划器决定最有效生成的任何顺序进行。
仅仅因为这些查询之间的数据发生了变化,两个相同查询之间的顺序甚至可能发生变化。“where”子句可能会满足一个查询中的索引扫描,但后来的插入可能会使该条件的选择性降低,并且计划程序可以决定使用表扫描执行后续查询。
把它放在一个更好的点。RDBMS 系统的任务是尽可能高效地准确地为您提供所需的内容。这种效率可以采取多种形式,包括最小化 IO(到磁盘以及通过网络向您发送数据)、最小化 CPU 并保持其工作集的大小较小(使用需要最少临时存储的方法)。
如果没有ORDER BY
子句,您将不会确切地询问特定的顺序,因此 RDBMS 将根据 RDBMS 期望生成的任何算法,以某种顺序(可能)与查询的某些巧合方面对应的顺序为您提供那些行数据最快。
如果您关心效率而不是顺序,请跳过该ORDER BY
子句。如果您关心顺序而不关心效率,请使用该ORDER BY
子句。
由于您实际上关心两者的使用ORDER BY
,然后仔细调整您的查询和数据库,使其高效。
不,您不能依赖每次都以相同的顺序返回结果。我在处理带有分页网格的网页时发现了这一点。当我转到下一页,然后再回到上一页时,上一页包含不同的记录!我完全被迷惑了。
那么,为了获得可预测的结果,您应该包括一个ORDER BY
. 即使那样,如果那里的指定列中有相同的值,您可以获得不同的结果。您可能需要ORDER BY
填写您认为并不真正需要的字段,只是为了获得可预测的结果。
正确答案
这是为纠正旧答案而添加的新答案。我从 Tom Kyte 那里得到了答案,我把它贴在这里:
如果要对行进行排序,则必须使用订单。不,如果,并且,或但是关于它。时期。http://tkyte.blogspot.ru/2005/08/order-in-court.html您需要通过该物联网订购。行在叶块中排序,但叶块未排序存储。快速全扫描=未排序的行。
https://twitter.com/oracleasktom/status/625318150590980097
https://twitter.com/oracleasktom/status/625316875338149888
错误的答案
(注意!问题的原始答案放在下面只是为了历史。这是错误的答案。正确的答案放在上面)
正如汤姆凯特在之前提到的文章中所写:
您应该将堆组织表视为一大无序的行集合。这些行将以看似随机的顺序出现,并且根据使用的其他选项(并行查询、不同的优化器模式等),它们可能会以不同的顺序出现在相同的查询中。除非您的查询中有 ORDER BY 语句,否则永远不要指望查询中的行顺序!
但请注意,他只谈论堆组织表。但也有索引组织表。在这种情况下,您可以依赖选择的顺序,而不是ORDER BY
因为主键隐式定义的顺序。对于甲骨文来说确实如此。
对于默认创建的 SQL Server 聚集索引(索引组织表)。PostgreSQL 存储信息也可以按索引对齐。更多信息可以在这里找到
更新: 我明白了,我的回答被否决了。所以我会试着稍微解释一下我的观点。在索引组织表概述部分中有一个短语:
在索引组织的表中,行存储在表的主键上定义的索引中......当相关的数据必须存储在一起或数据必须以特定的顺序物理存储时,索引组织的表很有用。
http://docs.oracle.com/cd/E25054_01/server.1111/e25789/indexiot.htm#CBBJEBIH
由于索引,所有数据都按特定顺序存储,我相信 Pg 也是如此。 http://www.postgresql.org/docs/9.2/static/sql-cluster.html
如果您不同意我的观点,请给我一个文档链接。我很高兴知道有一些东西要学。