我不会使用递归 CTE,而是使用更简单的方法:
DECLARE @oddNum INT = 1;
SELECT number
FROM master..spt_values
WHERE [type] = N'P'
AND number % 2 = 1
AND number BETWEEN @oddNum AND 11;
另一种方式,如果你有一个数字表(这非常有用)。它不必包含 1,000,000 行,这只是为了证明它可以。通过压缩,这需要 11 MB;没有,13 MB。
CREATE TABLE dbo.Numbers(number INT PRIMARY KEY)
WITH (DATA_COMPRESSION = PAGE); -- recommended if your edition supports it
INSERT dbo.Numbers(number) SELECT TOP (1000000)
ROW_NUMBER() OVER (ORDER BY s1.[object_id])
FROM sys.all_objects AS s1
CROSS JOIN sys.all_objects AS s2;
SELECT number FROM dbo.Numbers; -- prime it
(当你使用它时,你可以创建你的函数WITH SCHEMABINDING
,这有额外的好处。)
现在:
DECLARE @oddNum INT = 1;
SELECT number
FROM dbo.Numbers
WHERE number % 2 = 1
AND number BETWEEN @oddNum AND 11;
所以你的功能可能是:
CREATE FUNCTION [dbo].[oddNumFunction2]
(
@oddNum INT
)
RETURNS TABLE
WITH SCHEMABINDING
AS
RETURN
(
SELECT number
FROM dbo.Numbers
WHERE number % 2 = 1
AND number BETWEEN @oddNum AND 11
);
性能比较,运行 10,000 次(并将输出填充到 #temp 表中):
Gidil: 30.31 seconds
Mahmoud: 29.11 seconds
Me (spt_values): 27.91 seconds
Me (numbers): 28.06 seconds
原因是小spt_values
表已经在内存中(我们强制数字表存在),并且所需读取的少量逻辑(稍微!)比递归 CTE 的计算(即使只产生最多 6 行)。
我很惊讶 Mahmoud 的速度比 Gidil 的快,但我运行了多次,结果是一致的。感觉尝试自己测试它们并进行比较。虽然在大多数情况下,这种性能差异可以忽略不计,但我不会把这些东西扔掉,如果我找到了我知道做某事的最有效方法,我宁愿使用它,即使亚军是紧随其后。
如果您真的希望这是一个 CTE,以下将处理给定 0 到 11 之间的任何输入(奇数或偶数)的奇数:
DECLARE @oddnum INT = 1;
;WITH n(n) AS
(
SELECT @oddNum + ((@oddNum-1)%2)
UNION ALL
SELECT n + 2 FROM n WHERE n < 11
)
SELECT n FROM n;