aje*_*jeh 11 order-by hints sql-server-2012
表Client
字段上有一个聚集索引LastName
。
当我简单地从表中转储所有记录时,它们会按字母顺序出现,除非(nolock)
在相关查询中使用了提示。该提示会更改记录的顺序。应该是?。我很肯定没有其他会话有更改该表的开放事务(至少sp_who2
没有向我显示任何内容)。
如何解释顺序上的差异?
从评论中提取的其他信息:
没有顺序。非聚集索引是否应该强制执行顺序?
即使使用指定聚集索引的索引提示,查询仍然返回不同的顺序。他们应该吗?我想知道为什么nolock
在没有明显改变计划的情况下更改返回记录的顺序。
我对它们做了一个 WinDiff - 除了 [the] (nolock)
[query hint]之外相同。
Jam*_*olt 47
没有ORDER BY
子句的有序结果集的出现通常是由于按索引顺序检索行的扫描所致。通常在默认READ COMMITTED
隔离级别下选择索引顺序扫描的一个原因是它减少了不需要的并发异常的机会,例如多次遇到同一行或完全跳过某些行。这在几个地方都有详细说明,包括本系列关于隔离级别的文章。
使用NOLOCK
表提示,可以放宽这种行为,并且在更宽容的READ UNCOMMITTED
隔离级别下执行对表的访问,这可能会按分配顺序而不是索引顺序扫描数据。如该链接中所述,决定使用分配顺序扫描还是索引顺序扫描由存储引擎决定。此选择可能会在执行之间更改,而不会更改查询计划。
这听起来可能非常抽象,但可以通过使用针对AdventureWorks2012 数据库的未记录函数的某些查询更容易地演示。
USE AdventureWorks2012;
GO
-- Appears to be ordered by BusinessEntityID
-- File:Page:Slot goes up and down several times
-- Show physical locations with sys.fn_PhysLocFormatter (undocumented)
SELECT
P.BusinessEntityID,
[(File:Page:Slot)] =
sys.fn_PhysLocFormatter(%%physloc%%)
FROM Person.Person AS P;
-- Same query with TABLOCK or NOLOCK
-- Allocation-order (IAM) scan
-- Now appears to be ordered by File:Page:Slot instead of BusinessEntityID
SELECT P.BusinessEntityID,
[(File:Page:Slot)] =
sys.fn_PhysLocFormatter(%%physloc%%)
FROM Person.Person AS P WITH (NOLOCK);
Run Code Online (Sandbox Code Playgroud)
这些查询是从Paul White借来的,稍作修改。
最后,仅仅是明确的,这个答案是对外观的有序结果集。有没有保证的呈现顺序没有顶层ORDER BY
。
分配顺序扫描可能发生在各种其他情况下,例如获取表级锁或数据库处于只读模式时。并行性还可以影响数据返回的顺序。关键是没有ORDER BY
,返回数据的顺序可能会随着时间的推移而变化。
Aar*_*and 12
当我简单地从表中转储所有记录时
...那么你不应该期待任何订单。事实上,多次运行相同的查询可能会在没有警告的情况下以不同的顺序返回。原因是您的两个查询 - 它们是“不同”的查询,很可能是因为不同的查询文本,而不是因为提示 - 具有不同的执行计划(并且差异可能很微妙,例如在两个计划,但ordered: true
只有一个;或者估计行数大不相同,因为一个是在主要数据更改之前编译的)。也可能是正在执行分配顺序扫描,正如詹姆斯在他的回答中正确概述的那样。
在任何情况下,由于您运行的查询没有ORDER BY
,SQL Server 推断您不关心顺序,因此会确定返回行的最有效方式(如果您不关心顺序,则不关心顺序) )。
让我非常清楚地说明这一点:
之前出现过这种情况:
我已经写了一篇关于它的博客:
这是后者的引述,重申了我所说的内容,以解决您关于使用索引提示而不是ORDER BY
子句的评论:
即使在暗示索引的情况下,也会使用索引(如果可能,否则在大多数情况下会出现错误),但仅仅因为使用了索引并不意味着结果将按中的键排序返回那个指数。您仍然需要
ORDER BY
确保按索引键排序。
Conor Cunningham - 一个非常聪明的人,直接负责 SQL Server 在为您处理查询时所做的大部分工作 - 也在这里发表了关于它的博客:
ORDER BY
在抱怨不同的或意外的排序之前,请先阅读一些内容,然后在您的查询中添加一个子句。
小智 11
James 很好地解释了这是如何工作的,但我只想重申一件事:除非您使用排序函数,否则结果集中行的顺序是undefined。如果你需要一个给定的排序,使用一个明确的order by
子句——如果你没有指定它,你基本上是在说“我根本不关心顺序”,而不是“按聚集索引排序”。