web-dev-qa-db-ja.com

2つのインライン関数を結合すると、2番目の関数でフィルタリングするとかなり遅くなる

私は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の元のフィルターは迅速に再度実行されます。

2
Jweaver

回避策の提案:

関数を変更できる場合は、インライン関数ではなく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つの関数のクラスター化インデックスを適切に位置合わせしている場合、それらの出力テーブルを結合することは迅速な作業になるはずです。

これは、どのようなクエリプランが期待できるかを示したものです(関数の内部の仕組みは除きます)。

Example query plan

2

ほとんどの場合、この状況は「ブール」フィールドの統計から発生します。統計はインデックスから取得され、自動または手動で作成できることに注意してください。このフィールドの統計が更新されていることを確認してください。 2014年未満のSQLでは(Cardinality Estimatorが120未満)、統計からの値は0と推定され、統計が更新されないか、更新のサンプルがクエリでフィルターされた値を持つ行を取得しないため、この値は統計から外れる可能性があります。この列の値に変数を使用してこれを回避し、OPTION(OPTIMIZE FOR(@ariable UNKNOWN))を使用できます。この方法では、統計情報は実行プランのパラメーターではなくなるため、統計情報は考慮されません。

0
Grzegorz Łyp