SQL Server的奇怪行为 - 随机选择

时间:2016-09-05 04:43:09

标签: sql sql-server

我一直在调试以下声明几个小时:

SELECT 
(
SELECT  t1.anotherColumn
FROM table1 t1
WHERE t1.aColumn=(1+ABS(Checksum(NewId()))%54)
) res, *
FROM 
(
SELECT TOP 200 * --PLEASE NOTICE HERE
FROM table2
)RESULT

问题是始终res每行包含相同的值。现在,如果我将查询语句中突出显示的200更改为176以下的任何数字,则会显示table1的随机行,这是所需的结果!
请注意54对结果没有影响,只是因为我的表有{54}个不同的值,从1到54 aColumn
我在不同的表上尝试过这个查询,这种奇怪的行为会重复出现!

2 个答案:

答案 0 :(得分:4)

结果的差异可以通过查询计划的差异来解释。

SQL优化器可以选择使用Table Spool / Lazy Spool运算符。在这种情况下,NEWID()被调用一次,GUID存储在临时表中并用于所有其他行。

https://technet.microsoft.com/en-us/library/ms191221(v=sql.105).aspx

... 更新: 可以通过在底部添加以下行来修复查询计划:

option(use plan 
N'
<your XML plan>
')

要捕获“好”的XML计划,请运行

SET SHOWPLAN_XML ON

并执行显示预期结果的查询。将其复制粘贴到OPTION(使用计划......)

此解决方案适用于大量行(数百万)

答案 1 :(得分:2)

这将强制子查询在每一行上重新获得,并避免复杂的随机逻辑。

SELECT top 200
    (SELECT top 1 t1.anotherColumn from table1 t1 with( nolock ) where t2.t2Id is not null order by newid()  ) res, 
    *
FROM table2 t2

它的工作原理是因为newid()已经是一个随机唯一标识符,而table2上的比较强制对table1中的每一行检查table1的每一行。