当我将一些测试数据集放在一起时,我注意到临时表有一些有趣的行为。在通过并行执行计划填充的集群临时表中处理大量数据时,集群键在选择数据时看起来并不重要。这个问题似乎也会影响我测试过的所有 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
我没有找到任何表明这是预期行为的参考资料,但在我提交连接项目之前,我首先想联系并确认这不是本地化问题。有人可以指点我识别这是预期行为的文档,或者确认这实际上是一个错误吗?
编辑:为了回应关于不包含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)
即使执行计划相同,为什么临时表和正式定义表之间的结果集不同?
最后,向Joe Obbish 大声疾呼,因为我无偿地借鉴了他的 CROSS JOIN 方法来构建大量测试数据,因为它非常高效!
不能保证
ORDER
没有ORDER BY
。两者的执行计划都有“Ordered = False”。
这意味着您可能会按关键顺序获得结果,但同样可能不会。
具体看什么时候可以使用分配顺序扫描?
由于其他连接无法访问本地临时表,因此您无需显式获取表锁即可获得此行为,但是关于表大小的注释仍然适用,这就是为什么您会看到两种情况的不同之处。
如果您需要特定顺序,请添加一个
ORDER BY
以按键顺序(使用"Ordered = True"
)进行扫描。来自 Microsoft - 关于 Top
为了获得任何排序,您需要使用order by子句。
因此,无论您对表执行什么主键、索引或任何其他操作,获得任何排序的唯一方法是使用 order by 子句。