3

テーブル値のインライン UDF があります。その UDF の結果をフィルタリングして、1 つの特定の値を取得したいと考えています。定数パラメーターを使用してフィルターを指定すると、すべてが素晴らしく、パフォーマンスはほぼ瞬時になります。変数パラメーターを使用してフィルターを指定すると、論理読み取りが 500 倍、期間が 20 倍になるという、非常に大きな時間がかかります。

実行計画は、変数パラメーターの場合、プロセスの非常に遅い時間までフィルターが適用されず、定数の場合に実行されるシークではなく、複数のインデックス スキャンが発生することを示しています。

私の質問は次のとおりだと思います:インデックス付きフィールドに対して非常に選択的な単一のフィルターパラメーターを指定しているため、そのパラメーターが変数にあるとパフォーマンスが低下するのはなぜですか? これについて私にできることはありますか?

クエリの分析関数と関係がありますか?

ここに私の質問があります:

CREATE FUNCTION fn_test()
RETURNS TABLE
WITH SCHEMABINDING
AS
    RETURN
    SELECT DISTINCT GCN_SEQNO, Drug_package_version_ID
    FROM
    (
        SELECT COALESCE(ndctbla.GCN_SEQNO, ndctblb.GCN_SEQNO) AS GCN_SEQNO,
            dpv.Drug_package_version_ID, ROW_NUMBER() OVER (PARTITION BY dpv.Drug_package_version_id ORDER BY 
                ndctbla.GCN_SEQNO DESC) AS Predicate
        FROM dbo.Drug_Package_Version dpv
            LEFT JOIN dbo.NDC ndctbla ON ndctbla.NDC = dpv.Sp_package_code
            LEFT JOIN dbo.NDC ndctblb ON ndctblb.SPC_NDC = dpv.Sp_package_code
    ) iq
    WHERE Predicate = 1
GO

GRANT SELECT ON fn_test TO public
GO

-- very fast
SELECT GCN_SEQNO
FROM dbo.fn_test()
WHERE Drug_package_version_id = 10000

GO

-- comparatively slow
DECLARE @dpvid int
SET @dpvid = 10000
SELECT GCN_SEQNO
FROM dbo.fn_test()
WHERE Drug_package_version_id = @dpvid
4

3 に答える 3

1

反応が良くて勉強になりましたが、納得のいく答えにたどり着いたと思います。

ここで問題を引き起こしているのは、PARTITION BY 句の使用だと思います。自己結合イディオムのバリアントを使用して UDF を再定式化しました。

SELECT t1.A, t1.B, t1.C
FROM T t1
    INNER JOIN
    (
        SELECT A, MAX(C) AS C
        FROM T
        GROUP BY A
    ) t2 ON t1.A = t2.A AND t1.C = t2.C

皮肉なことに、これは SQL 2008 固有のクエリを使用するよりもパフォーマンスが高く、オプティマイザは定数ではなく変数を使用してこのバージョンのクエリを結合しても問題ありません。この時点で、オプティマイザは古い SQL 拡張機能だけでなく、最近の SQL 拡張機能も処理していないと結論付けています。おまけとして、アップグレード前の SQL 2000 プラットフォームで UDF を利用できるようになりました。

助けてくれてありがとう、みんな!

于 2009-04-07T15:05:31.160 に答える
1

簡単に言えば、定数は計画で簡単に評価できます。ローカル変数はそうではありません。特にランキング機能とフィルターでPredicate = 1

casparOne を言い換えるとdpv.Drug_package_version_id、iq 派生テーブル内でフィルタリングできるように、フィルターを可能な限り内側にプッシュする必要があります。

PARTITION BYこれを行うと、が 1 つしかないため、 も必要ありませんdpv.Drug_package_version_id。その後、クリーナーを実行できます...TOP 1 ... ORDER BY ndctbla.GCN_SEQNO DESC

于 2009-04-06T20:04:28.517 に答える