5

状況は次のとおりです:
datetime パラメーターを持つテーブル値関数があります。たとえば、 tdf(p_date) とは言えません。これは、列の日付が p_date より小さい列を選択して約 200 万行をフィルター処理し、他の列の集計値を計算します。
それはうまく機能しますが、p_dateがカスタムスカラー値関数(私の場合は一日の終わりを返す)である場合、実行計画が変更され、クエリの実行時間が1秒から1分になります。

概念実証テーブル - 1,000 製品、2,000,000 行:

CREATE TABLE [dbo].[POC](
    [Date] [datetime] NOT NULL,
    [idProduct] [int] NOT NULL,
    [Quantity] [int] NOT NULL
) ON [PRIMARY]

インライン テーブル値関数:

CREATE FUNCTION tdf (@p_date datetime)
RETURNS TABLE 
AS
RETURN 
(
    SELECT idProduct, SUM(Quantity) AS TotalQuantity,
         max(Date) as LastDate
    FROM POC
    WHERE (Date < @p_date)
    GROUP BY idProduct
)

スカラー値関数:

CREATE FUNCTION [dbo].[EndOfDay] (@date datetime)
RETURNS datetime
AS
BEGIN
    DECLARE @res datetime
    SET @res=dateadd(second, -1,
         dateadd(day, 1, 
             dateadd(ms, -datepart(ms, @date),
                 dateadd(ss, -datepart(ss, @date),
                    dateadd(mi,- datepart(mi,@date),
                         dateadd(hh, -datepart(hh, @date), @date))))))
    RETURN @res
END

クエリ 1 - うまくいっている

SELECT * FROM [dbo].[tdf] (getdate())

実行計画の終了: ストリーム集約コスト 13% <--- クラスタ化インデックス スキャン コスト 86%

クエリ 2 - あまり良くない

SELECT * FROM [dbo].[tdf] (dbo.EndOfDay(getdate()))

実行計画の終了: ストリーム集約コスト 4% <--- フィルター コスト 12% <--- クラスター化インデックス スキャン コスト 86%

4

2 に答える 2

6

オーバーヘッドはスカラー関数です。

ここの TVF はインライン マクロのように展開されるので、

SELECT * FROM [dbo].[tdf] (getdate())

になる

SELECT     idProduct, SUM(Quantity) AS TotalQuantity, max(Date) as LastDate
    FROM         POC
    WHERE     Date < getdate()
    GROUP BY idProduct

終業スカラー関数を使用する場合、SQL は EOD(GETDATE()) を定数として評価できません。SQL がこのようなものをどのように評価するかについての私の記事をすぐに見つけることができません。申し訳ありません。

あなたが望むように前もってではなく、行ごとに評価されていると思います。

EOD ステートメントを個別に計算します。

DECLARE @eod datetime;
SET @eod = dbo.EndOfDay(getdate());
SELECT * FROM [dbo].[tdf] (@eod)

これを EOD 関数にも使用します。

DATEADD(second, -1, DATEADD(day, 1, (DATEDIFF(day, 0, @date))))

編集:私が答えた他の質問

于 2009-01-16T14:03:45.430 に答える