ここでのキーワード用語はINLINE テーブル値関数 。 T-SQLのテーブル化された値関数には、マルチステートメントとインラインの2種類があります。 T-SQL関数がBEGINステートメントで始まる場合、それはがらくたになります-スカラーまたはそれ以外の場合。一時テーブルをインラインに入れることはできません テーブル値関数なので、スカラーからマルチステートメントのテーブル値関数に移行したと思いますが、これはおそらくもっと悪いでしょう。
インラインテーブル値関数(iTVF)は次のようになります。
CREATE FUNCTION [dbo].[Compute_value]
(
@alpha FLOAT,
@bravo FLOAT,
@charle FLOAT,
@delta FLOAT
)
RETURNS TABLE WITH SCHEMABINDING AS RETURN
SELECT newValue =
CASE WHEN @alpha IS NULL OR @alpha = 0 OR @delta IS NULL OR @delta = 0 THEN 0
WHEN @bravo IS NULL OR @bravo <= 0 THEN 100
ELSE @alpha * POWER((100 / @delta),
(-2 * POWER(@charle * @bravo, DATEDIFF(<unit of measurement>,GETDATE(),'1/1/2000')/365)))
END
GO;
投稿したコードでは、DATEDIFF
ステートメントにdatepart
がありません パラメータ。次のようになります:
@x int = DATEDIFF(DAY, GETDATE(),'1/1/2000')
もう少し進んでください-iTVFがT-SQLスカラー値のユーザー定義関数よりも優れている理由を理解することが重要です。これは、テーブル値関数がスカラー値関数よりも高速であるためではなく、MicrosoftによるT-SQLインライン関数の実装がインラインでないT-SQL関数の実装よりも高速であるためです。同じことを行う次の3つの関数に注意してください。
-- Scalar version
CREATE FUNCTION dbo.Compute_value_scalar
(
@alpha FLOAT,
@bravo FLOAT,
@charle FLOAT,
@delta FLOAT
)
RETURNS FLOAT
AS
BEGIN
IF @alpha IS NULL OR @alpha = 0 OR @delta IS NULL OR @delta = 0
RETURN 0
IF @bravo IS NULL OR @bravo <= 0
RETURN 100
IF (@charle + @delta) / @bravo <= 0
RETURN 100
DECLARE @x int = DATEDIFF(dd, GETDATE(),'1/1/2000')
RETURN @alpha * POWER((100 / @delta), (-2 * POWER(@charle * @bravo, @x/365)))
END
GO
-- multi-statement table valued function
CREATE FUNCTION dbo.Compute_value_mtvf
(
@alpha FLOAT,
@bravo FLOAT,
@charle FLOAT,
@delta FLOAT
)
RETURNS @sometable TABLE (newValue float) AS
BEGIN
INSERT @sometable VALUES
(
CASE WHEN @alpha IS NULL OR @alpha = 0 OR @delta IS NULL OR @delta = 0 THEN 0
WHEN @bravo IS NULL OR @bravo <= 0 THEN 100
ELSE @alpha * POWER((100 / @delta),
(-2 * POWER(@charle * @bravo, DATEDIFF(DAY,GETDATE(),'1/1/2000')/365)))
END
)
RETURN;
END
GO
-- INLINE table valued function
CREATE FUNCTION dbo.Compute_value_itvf
(
@alpha FLOAT,
@bravo FLOAT,
@charle FLOAT,
@delta FLOAT
)
RETURNS TABLE WITH SCHEMABINDING AS RETURN
SELECT newValue =
CASE WHEN @alpha IS NULL OR @alpha = 0 OR @delta IS NULL OR @delta = 0 THEN 0
WHEN @bravo IS NULL OR @bravo <= 0 THEN 100
ELSE @alpha * POWER((100 / @delta),
(-2 * POWER(@charle * @bravo, DATEDIFF(DAY,GETDATE(),'1/1/2000')/365)))
END
GO
次に、いくつかのサンプルデータとパフォーマンステストについて説明します。
SET NOCOUNT ON;
CREATE TABLE #someTable (alpha FLOAT, bravo FLOAT, charle FLOAT, delta FLOAT);
INSERT #someTable
SELECT TOP (100000)
abs(checksum(newid())%10)+1, abs(checksum(newid())%10)+1,
abs(checksum(newid())%10)+1, abs(checksum(newid())%10)+1
FROM sys.all_columns a, sys.all_columns b;
PRINT char(10)+char(13)+'scalar'+char(10)+char(13)+replicate('-',60);
GO
DECLARE @st datetime = getdate(), @z float;
SELECT @z = dbo.Compute_value_scalar(t.alpha, t.bravo, t.charle, t.delta)
FROM #someTable t;
PRINT DATEDIFF(ms, @st, getdate());
GO
PRINT char(10)+char(13)+'mtvf'+char(10)+char(13)+replicate('-',60);
GO
DECLARE @st datetime = getdate(), @z float;
SELECT @z = f.newValue
FROM #someTable t
CROSS APPLY dbo.Compute_value_mtvf(t.alpha, t.bravo, t.charle, t.delta) f;
PRINT DATEDIFF(ms, @st, getdate());
GO
PRINT char(10)+char(13)+'itvf'+char(10)+char(13)+replicate('-',60);
GO
DECLARE @st datetime = getdate(), @z float;
SELECT @z = f.newValue
FROM #someTable t
CROSS APPLY dbo.Compute_value_itvf(t.alpha, t.bravo, t.charle, t.delta) f;
PRINT DATEDIFF(ms, @st, getdate());
GO
結果:
scalar
------------------------------------------------------------
2786
mTVF
------------------------------------------------------------
41536
iTVF
------------------------------------------------------------
153
スカラーudfは2.7秒間、mtvfでは41秒間、iTVFでは0.153秒間実行されました。推定実行計画を見てみましょう理由を理解するには:
実際の実行プランを見るとこれはわかりませんが、スカラーudfとmtvfを使用すると、オプティマイザーは行ごとに実行が不十分なサブルーチンを呼び出します。 iTVFはそうではありません。 PaulWhiteの転職を引用 APPLYに関する記事 ポールはこう書いています:
言い換えると、iTVFを使用すると、オプティマイザーを使用して、他のすべてのコードを実行する必要がある場合には不可能な方法でクエリを最適化できます。 iTVFが優れている理由の他の多くの例の1つは、並列処理を可能にする前述の3つの関数型のうちの1つだけであるということです。各関数をもう一度実行してみましょう。今回は、実際の実行プランをオンにして、traceflag 8649(並列実行プランを強制する)を使用します。
-- don't need so many rows for this test
TRUNCATE TABLE #sometable;
INSERT #someTable
SELECT TOP (10)
abs(checksum(newid())%10)+1, abs(checksum(newid())%10)+1,
abs(checksum(newid())%10)+1, abs(checksum(newid())%10)+1
FROM sys.all_columns a;
DECLARE @x float;
SELECT TOP (10) @x = dbo.Compute_value_scalar(t.alpha, t.bravo, t.charle, t.delta)
FROM #someTable t
ORDER BY dbo.Compute_value_scalar(t.alpha, t.bravo, t.charle, t.delta)
OPTION (QUERYTRACEON 8649);
SELECT TOP (10) @x = f.newValue
FROM #someTable t
CROSS APPLY dbo.Compute_value_mtvf(t.alpha, t.bravo, t.charle, t.delta) f
ORDER BY f.newValue
OPTION (QUERYTRACEON 8649);
SELECT @x = f.newValue
FROM #someTable t
CROSS APPLY dbo.Compute_value_itvf(t.alpha, t.bravo, t.charle, t.delta) f
ORDER BY f.newValue
OPTION (QUERYTRACEON 8649);
実行計画:
iTVFの実行プランに表示される矢印は、並列処理です。つまり、すべてのCPU(またはSQLインスタンスのMAXDOP
と同じ数)です。 設定により)一緒に作業できます。 T-SQLスカラーおよびmtvfUDFはそれを実行できません。マイクロソフトがインラインスカラーUDFを導入するとき、私はあなたがしていることのためにそれらを提案しますが、それまでは:パフォーマンスがあなたが探しているものであるなら、インラインが唯一の道であり、そのために、iTVFは唯一のゲームです市内。
T-SQLを継続的に強調していることに注意してください 関数について話すとき...CLRスカラーとテーブル値の関数は問題ない場合がありますが、それは別のトピックです。