我写了这个函数,然后去测试它。结果有点让我吃惊。知道为什么会这样吗?
CREATE FUNCTION dbo.chunk(@input VARCHAR(MAX), @chunkSize INT = 36)
RETURNS TABLE AS
RETURN (
WITH CTE AS (
SELECT SUBSTRING(@input,1,@chunkSize) AS [chunk], 1 AS [row]
UNION ALL
SELECT SUBSTRING(@input,1+([row]*@chunkSize),@chunkSize)
, [row] + 1
FROM cte
WHERE LEN(@input) > ([row]*@chunkSize)
)
SELECT [chunk]
FROM cte
)
GO
/* This does what I would expect this to do. */
DECLARE @input varchar(MAX) = REPLICATE(NEWID(),2);
SELECT * FROM dbo.chunk(@input,36)
/* But this, this is odd. If I call replicate here it calls newid() twice... */
SELECT * FROM dbo.chunk(REPLICATE(NEWID(),2),36);
| 大块|
| - ------|
| E1810B3D-三个数据分配器4 - 4F55-B650-ED2DB28BCF70|
| E1810B3D-三个数据分配器4 - 4F55-B650-ED2DB28BCF70|
| 大块|
| - ------|
| 89A26C8B-D5C7 - 47A8-三位一体式|
| 型号:F9636F76 - 1ED6 - 4D19-A309-BA35EAC9F782|
1条答案
按热度按时间atmip9wb1#
这是意料之中的。
您使用的函数是内联表值函数,因此调用内联到常规执行计划中。
该函数具有
VARCHAR(MAX)
类型的@input
参数,并且您将REPLICATE(NEWID(),2)
传递给它,因此概念上@input
的所有示例替换为CONVERT(VARCHAR(MAX),REPLICATE(NEWID(),2))
。@chunkSize
的所有示例替换为36。一旦你这样做了,你就得到了下面的结果,它给出了一个相同的执行计划和行为。
NEWID()
在计划中被引用了三次。一次在递归CTE的锚分支中,两次在递归分支中。在您的情况下,您得到了定位点的一次调用和递归分支的一次调用,因此它被计算了三次。对于涉及LEN
的表达式,重新计算不会'因为即使实际GUID已经改变,长度也将相同,所以不会对结果产生任何差别。一些非确定性函数被当作runtime constants处理,但是
NEWID()
不是其中之一,这在这个递归CTE的情况下并没有真正的帮助。如果您尝试以下操作...
结果和
锚分支和递归分支中的调用被视为两个不同的调用,并被赋予不同的运行时常量标签,因此得到one value in the first row and a different value in the subsequent rows。