再帰的な 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;