12

わかりましたので、テーブル値関数とクロス適用を提案する記事をたくさん読んだので、スカラー udf よりも優れたパフォーマンスが得られます。私は両方の方法で関数を作成し、どちらが優れているかをテストしたかったのですが、どちらがより良いオプションであるかを理解するために何を使用/探すべきかを理解できません。

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

/off で showplan_all を使用すると、テーブル ベースの関数は 8.3e-05 よりも多くの CPU 1.157e-06 を使用するように見えますが、テーブル関数の合計サブツリー コストは 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 

ありがとう!!

4

1 に答える 1

19

テーブル値関数がインラインではなく多機能であるため、期待するパフォーマンスの向上が見られない場合があります。多機能 TVF は、スカラー UDF と同じように (行ごとに 1 回) 実行する必要があるため、メリットはほとんどありません。

Itzik Ben-Gan によるこの記事の例(インライン TVF の利点について説明しています) に従って、次のテストを設定します。

100 万行の数値テーブルを作成します。

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;

次のコードを使用して、TVF を 100 万回実行します。

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

私のシステムでは、これは 3 回の実行で平均 83 秒の経過時間を示し、DBCC dropcleanbuffers各実行の間に実行されました。

スカラー値関数に対して同様のテストを実行すると、パフォーマンスの比較がより明確になるはずです。

このテストでは、関数のバグと思われるものも明らかになりました。が '2010-09-01' に設定されている場合、AcademicYear.StartDate'1900-01-01' の入力に対して返される学年は 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 つの値に対して使用している場合、関数のインスタンスが何千も並列に実行されていない限り、多くの利点は見られません。

于 2010-12-15T12:13:02.417 に答える