Joh*_*ner 5 sql-server temporary-tables
当我将一些测试数据集放在一起时,我注意到临时表的一些有趣行为。在处理通过并行执行计划填充的集群临时表中的大量数据时,选择数据时集群键看起来不受欢迎。这个问题似乎也影响了我测试过的所有版本的 SQL Server(包括 vNext)。
这是测试的dbfiddle.uk示例。您可能需要执行几次才能得到我找到的结果,但执行一次或两次才能产生相同的结果。此外,这是我在我的环境中得到的本地执行计划,它表明大数据集和小数据集之间的唯一区别是数据输入表的方式(例如并行与串行计划)。
如果你想在家玩,这是我正在运行的测试:
-- Large Data Set
CREATE TABLE #tmp
(
ID INT PRIMARY KEY CLUSTERED
)
INSERT INTO #tmp
-- Purposely insert in reverse order
SELECT TOP 100 PERCENT RN
FROM
(
SELECT TOP (10000000) ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) RN
FROM master..spt_values t1
CROSS JOIN master..spt_values t2
) x
ORDER BY RN DESC
-- Smaller Data Set
CREATE TABLE #tmp2
(
ID INT PRIMARY KEY CLUSTERED
)
INSERT INTO #tmp2
-- Purposely insert in reverse order
SELECT TOP 100 PERCENT RN
FROM
(
SELECT TOP (10000) ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) RN
FROM master..spt_values t1
CROSS JOIN master..spt_values t2
) x
ORDER BY RN DESC
-- Large Record Set
-- Clustered Key Not Honored*
SELECT TOP 10 *
FROM #tmp
-- Small Record Set
-- Clustered Key Honored
SELECT TOP 10 *
FROM #tmp2
DROP TABLE #tmp
DROP TABLE #tmp2
Run Code Online (Sandbox Code Playgroud)
我没有找到任何表明这是预期行为的参考资料,但在我提交连接项目之前,我首先想联系并确认这不是本地化问题。有人可以指出我的文档来确定这是预期的行为,或者确认这实际上是一个错误吗?
编辑:在回应评论有关不包括的ORDER BY条款,我总是TOP关键字在它被插入的顺序,其返回的数据的假设下,应该在这种情况下,是由聚集键所规定的顺序。对正式表运行相同的语句时,将返回预期的行为:
-- Large Data Set with a Formal Data Table
CREATE TABLE tmp
(
ID INT PRIMARY KEY CLUSTERED
)
INSERT INTO tmp
-- Purposely insert in reverse order
SELECT TOP 100 PERCENT RN
FROM
(
SELECT TOP (10000000) ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) RN
FROM master..spt_values t1
CROSS JOIN master..spt_values t2
) x
ORDER BY RN DESC
-- Large Record Set
-- Clustered Key Not Honored*
SELECT TOP 10 *
FROM tmp
DROP TABLE tmp
(6325225 row(s) affected)
(1 row(s) affected)
ID
-----------
1
2
3
4
5
6
7
8
9
10
(10 row(s) affected)
(1 row(s) affected)
Run Code Online (Sandbox Code Playgroud)
甚至执行计划都是一样的,那么为什么临时表和正式定义的表之间的结果集不同呢?
最后,向Joe Obbish大声喊叫,因为我无缘无故地撕掉了他的 CROSS JOIN 方法来构建大量测试数据,因为它非常有效!
有没有保证ORDER没有ORDER BY。
两者的执行计划都有“Ordered = False”。

这意味着您可能会按关键顺序获得结果,但同样可能不会。
仅当数据不可能更改时(例如,指定 TABLOCK 提示时,或表位于只读数据库中时)或明确声明我们不关心时,才会使用此类扫描(例如,当指定了 NOLOCK 提示或处于 READ UNCOMMITTED 隔离级别时)。作为进一步的转折,分配顺序扫描的设置成本与将要读取的页数之间存在权衡——只有在要读取的页数超过 64 时才会使用分配顺序扫描。
由于其他连接无法访问本地临时表,因此您无需明确获取表锁即可获得此行为,但是关于表大小的注释仍然适用,这就是为什么您会看到两种情况的差异。
如果您需要特定的顺序,请添加一个ORDER BY以按关键顺序进行扫描(使用"Ordered = True")。
当TOP与ORDER BY子句结合使用时,结果集限制为前N个有序行;否则,它以未定义的顺序返回前 N 行。
• 按指定的列列表对查询结果集进行排序,并可选择将返回的行限制在指定范围内。除非指定了 ORDER BY 子句,否则无法保证结果集中返回行的顺序。
因此,无论您对表执行什么主键、索引或其他任何操作,在没有 top N 的情况下获得任何排序的唯一方法是使用 order by 子句。