2010-12-15 22 views
8

OKこれで、テーブル値関数とクロス適用を提案する記事を一通り読んだところ、スカラーudfよりも優れたパフォーマンスが得られました。私は両方の方法で機能を書いて、どれが良いのかをテストしたいと思っていましたが、どちらを使うべきかを理解することができません。ScalarのパフォーマンスとSQL Serverのテーブル値関数の比較

私はSQL Server 2005を使用しています。データベースエンジンチューニングアドバイザーの推定実行計画、実際の実行計画、および分析クエリを実行しようとしましたが、何を教えているのかわかりません。

showplan_allをオン/オフにすると、テーブルベースの関数がより多くのCPU 1.157e-06 vs 8.3e-05を使用するように見えますが、テーブル関数の総サブツリーコストは0.000830157対0.01983356です。

テーブル値関数のクエリコストも、スカラー値よりもコストが高いようです。私はそれがより良い選択肢であると考えられていましたが。

私はそれが自分自身であることを証明したいと思いますが、私はこれらのツールで何を探すべきかわからないので、どんな提案も感謝します!

暦日に基づいて学年値(データベースに設定された日付範囲に基づいて)を取得する必要があります。そのため、関数の内容が以下のようになります。今年は他のクエリにも役立ちます..

CREATE FUNCTION fn_AcademicYear 
(
    -- Add the parameters for the function here 
    @StartDate DateTime 
) 
RETURNS 
@AcademicYear TABLE 
(
    AcademicYear int 
) 
AS 
BEGIN 

DECLARE @YearOffset int, @AcademicStartDate DateTime 

    -- Lookup Academic Year Starting Date 
    SELECT @AcademicStartDate = CONVERT(DateTime,[Value]) 
    FROM dbo.SystemSetting 
    WHERE [Key] = 'AcademicYear.StartDate' 

    SET @YearOffset = DATEPART(YYYY,@StartDate) - DATEPART(YYYY,@AcademicStartDate); 
    -- try setting academic looking start date to year of the date passed in 
    SET @AcademicStartDate = DATEADD(YYYY, @YearOffset, @AcademicStartDate); 

    IF @StartDate < @AcademicStartDate 
    BEGIN 
     SET @AcademicStartDate = DATEADD(YYYY, @YearOffset-1, @AcademicStartDate); 
    END 

     INSERT @AcademicYear 
     SELECT YEAR(@AcademicStartDate) 

    RETURN 

ありがとう!!

+2

好奇心がそそら - 「YYYY」は、「Year」よりも読みやすくなっていますか? –

+0

私は本当にそれについて考えていないし、他の人の関数からその構文を取った:)しかし、イエス年は読みやすくなります。 – Jen

答えて

16

テーブル値関数がインラインではなく多機能であるため、期待したパフォーマンスが得られないことがあります。マルチファンクションTVFはスカラーUDFと同じ方法で実行する必要があります(行ごとに1回)ので、ほとんど利益がありません。 this article by Itzik Ben-Ganの例に続き

(インラインTVFSの利点について説明している)、次のテストを設定します

SET NOCOUNT ON; 
IF OBJECT_ID('dbo.T1') IS NOT NULL DROP TABLE T1; 
GO 

WITH 
    L0 AS (SELECT 0 AS c UNION ALL SELECT 0), 
    L1 AS (SELECT 0 AS c FROM L0 AS A CROSS JOIN L0 AS B), 
    L2 AS (SELECT 0 AS c FROM L1 AS A CROSS JOIN L1 AS B), 
    L3 AS (SELECT 0 AS c FROM L2 AS A CROSS JOIN L2 AS B), 
    L4 AS (SELECT 0 AS c FROM L3 AS A CROSS JOIN L3 AS B), 
    L5 AS (SELECT 0 AS c FROM L4 AS A CROSS JOIN L4 AS B), 
    Nums AS (SELECT ROW_NUMBER() OVER(ORDER BY (SELECT 0)) AS n FROM L5) 
SELECT n INTO dbo.T1 FROM Nums WHERE n <= 1000000; 

ラン百万:

を100万行の数値テーブルを作成します。次のコードを使用して、TVFの実行:私のシステムで

set statistics time on 
SELECT n,DATEADD(HOUR,n,'1900-01-01'),AY.AcademicYear 
FROM T1 
CROSS APPLY dbo.fn_AcademicYear(DATEADD(HOUR,n,'1900-01-01')) AS AY 
set statistics time off 

を、これはrunn、3つの実行のための時間を経過した83秒の平均を示しました。各実行の間にDBCC dropcleanbuffersを入力します。

スカラー値関数についても同様のテストを行う場合は、比較パフォーマンスをより明確にする必要があります。

このテストでは、機能にバグがあるようにも見えました。 AcademicYear.StartDateが '2010-09-01'に設定されている場合、 '1900-01-01'の入力に対して返されるAcademic Yearは1789であり、1899年が予想されるようです。

最高のパフォーマンスを得るために、あなたは、インラインであることをTVFを変換する必要があるだろう - 私は、バグを修正すると信じている、以下を思い付いた:

CREATE FUNCTION fn_AcademicYear2 
(
    @StartDate DATETIME 
) 
RETURNS TABLE 
AS 
RETURN 
(
    -- Lookup Academic Year Starting Date 
    WITH dtCTE 
    AS 
    (
     SELECT CONVERT(DATETIME,[Value]) AS dt 
     FROM dbo.SystemSetting 
     WHERE [KEY] = 'AcademicYear.StartDate' 
    ) 
    SELECT CASE WHEN @StartDate >= DATEADD(YEAR,DATEDIFF(YEAR,dt,@StartDate),dt) 
       THEN YEAR(@StartDate) 
       ELSE YEAR(DATEADD(YEAR,DATEDIFF(YEAR,dt,@StartDate) - 1,dt)) 
      END AS AcademicYear 
    FROM dtCTE 
) 
GO 

これは平均を経過していました3回の実行で8.9秒の時間 - ほぼ10倍の速さ。

もう1つ考慮すべきことは、このテストのように、複数の行に適用しない限り、TVFを使用することによるパフォーマンス上のメリットはごくわずかです。一度に1つの値でそれを使用している場合、関数のインスタンスが何千も並行して実行されている場合を除いて、多くのベンチフィットは表示されません。

+0

本当に詳細な回答と私の機能を改善してくれてありがとう!! :) – Jen

関連する問題