私は2つのインライン関数を使用して、単独で十分に高速に実行されます。
私が去ったとき、このように彼らに加わりました:
_select *
from
Function1(-1) F1
left join
Function2(-1) F2 on F1.key = F2.key
_
...約14秒で結果セットを取得します。それが何をしているかについては完全に問題ありません。
しかし、where条件を追加した場合:
_Where
F2.Boolean = 0
_
...完了までに8分以上かかります。
F2レコードがない結果がいくつかあるため、それらはnullです。
私はisnull(f2.boolean,0) = 0
でテストを行い、それは10秒で実行されました。また、場所aまたはF2.booleanがnullの場合、すばやく実行されます。
SQL Server 2008 R2を使用しており、SP2およびSP3でテストしました。誰かが何を見るべきかについてのアイデアや提案がありますか?
関数は、複数のテーブルを結合する単純な選択ステートメントです。それらには特別なものはありません。個々の関数は、テーブル全体の結果を10秒未満で返します。
「F2の日付フィールドの1つが2つの日付の間にある場所」を追加すると、高速に実行されます。また、where句のvarchar(2)フィールドでテストしたところ、非常に遅くなっています(ただし、datetimeフィールドではありません)。さて、なぜbitフィールドまたはvarcharの2番目の関数のフィルターがdatetimeの間でこのような速度低下を引き起こすのでしょうか?もう1つの観察された動作:F1にフィルターを追加すると、実際にF2レコードが最初にあるフィルターのみを指定すると、F2の元のフィルターは迅速に再度実行されます。
回避策の提案:
関数を変更できる場合は、インライン関数ではなくmulti-statementテーブル値関数にしてみてください。その場合、RETURNS
部分に出力テーブルを定義します。出力テーブルのDDLで、適切なクラスター化された主キーを宣言します。
例:
CREATE FUNCTION dbo.fn_test1(@i int)
RETURNS @out TABLE (
a char(5) NOT NULL,
b date NOT NULL,
c int NOT NULL,
PRIMARY KEY CLUSTERED (a, b)
)
AS
BEGIN;
INSERT INTO @out (a, b, c)
SELECT x, y, z
FROM dbo.someTable
WHERE someCriteria>@i;
RETURN;
END;
インライン関数をマルチステートメント関数に交換すると、独自の 利点と欠点 のセットが付属しますが、この場合の重要な違いは、出力がクラスター化インデックス付きの一時テーブルに格納されることです。結合が発生する前に。 2つの関数のクラスター化インデックスを適切に位置合わせしている場合、それらの出力テーブルを結合することは迅速な作業になるはずです。
これは、どのようなクエリプランが期待できるかを示したものです(関数の内部の仕組みは除きます)。
ほとんどの場合、この状況は「ブール」フィールドの統計から発生します。統計はインデックスから取得され、自動または手動で作成できることに注意してください。このフィールドの統計が更新されていることを確認してください。 2014年未満のSQLでは(Cardinality Estimatorが120未満)、統計からの値は0と推定され、統計が更新されないか、更新のサンプルがクエリでフィルターされた値を持つ行を取得しないため、この値は統計から外れる可能性があります。この列の値に変数を使用してこれを回避し、OPTION(OPTIMIZE FOR(@ariable UNKNOWN))を使用できます。この方法では、統計情報は実行プランのパラメーターではなくなるため、統計情報は考慮されません。