1
CREATE function [dbo].[fn_GetDateOnly](@dateWithTime datetime)
    returns datetime WITH SCHEMABINDING
as
begin
    return DATEADD(DAY, DATEDIFF(DAY, 0, @dateWithTime), 0)
end


SELECT stuff, count(ff.id)
FROM dbo.foo AS ff 
where
--DATEADD(DAY, DATEDIFF(DAY, 0, ff.startDate), 0) <= @curdate --6700ms
--dbo.fn_GetDateOnly(ff.startDate) <= @curdate --9300ms
group by stuff
order by stuff desc

Why is calling fn_getdateonly so much slower than inlining it? Doesn't SQL inline the function call?

4

1 に答える 1

3

列の式

まず、使用する関数に関係なく、WHERE句またはテーブルの列のJOIN条件に配置するのは最適ではありません。定数で計算を行い、比較します。WHERE句は次のようになります。

ff.startDate < DateAdd(day, 1, @curdate) -- if @curdate has time portion removed
ff.startDate < DateAdd(day, 1, dbo.fn_GetDateOnly(@curdate)) -- if @curdate has time

特定の日付のアイテムを一般的に検索するには、次のパターンを使用します。

WHERE
   DateCol >= '20120901'
   AND DateCol < '20120902'

等号の列とは反対側に関数を配置します。これは単独で行う必要があります。式をSARGableにする方法を調べるのに役立つ場合があります。列を両側に配置する必要がある場合は、実行プランの「左側」の入力である側にすべての式を配置します(データが最初に来る、LOOP JOINの外側のループ、またはHASH JOIN)。たとえば、これを実行しようとしている場合:

WHERE dbo.fn_getDateOnly(A.DateCol) = dbo.fn_getDateOnly(B.DateCol)

次に、A.DateColが実行プランの最初に来ると仮定して、次のように切り替えます。

WHERE
   B.DateCol >= DateAdd(day, DateDiff(day, 0, A.DateCol), 0)
   AND B.DateCol < DateAdd(day, DateDiff(day, 0, A.DateCol), 0)

(または、以下の関数のインラインバージョンを使用しますが、同じように扱いにくいので、間接的であることに余分な価値はありません)。

この種のクエリが関連するテーブルで頻繁に実行される場合は、おそらく、時間部分が削除された(おそらくインデックスが付けられた)永続化された計算列を追加して、日時を別の日付に分割するために、何らかの再設計が必要です。および時間フィールド、または最初の日付として保存します(本当に日時が必要ない場合)。

注:もちろん、dbo.fn_getDateOnlyへの参照は単純に。に置き換えることができますDateAdd(day, DateDiff(day, 0, DateCol), 0)。さらに、値にデータ型がある場合は、使用するのではなくdatetime、実行することができます(ただし、SQL 2008以降のデータ型では機能しないため、注意してください)。DateCol + 1DateAdddate

UDFのインライン機能

SELECT句での関数のパフォーマンスに関しては、SQL Serverは「インライン関数」のみをインライン化し、スカラー関数はインライン化しません。単一行のレコードセットを返すように関数を変更し、次のCREATE FUNCTION ... RETURNS TABLE AS RETURN (SELECT ...)ように使用します。

SELECT
   (SELECT DateValue FROM dbo.fn_GetDateOnly(Col)),
   ...

これは、実際にはパラメーター化されたビューと同じです。

このインラインバージョンをWHERE句で使用すると、扱いにくくなります。DateDiffを実行する方がほとんど簡単です。SQL 2008では、もちろん、計算式を配置する場所(列の等号の反対側)に関する規則を使用しますが、それに従いConvert(date, DateCol)ます。

MicrosoftConnectでインラインスカラーUDFに投票してください。この機能がひどく欠けていると思っているのはあなただけではありません。

于 2012-07-23T15:37:59.540 に答える