私のシステムはかなり重い処理を行っており、より短い時間でより多くのテストを実行できるようにするために、パフォーマンスを攻撃してきました。
たとえば、500 万行で UDF を呼び出さなければならないケースがかなりあります (そして、それを回避する方法はほとんどないと思っていました)。
結局のところ、これを回避する方法があり、行の合計セットよりもやや小さい個別のパラメーターのセットで UDF が呼び出されると、パフォーマンスが大幅に向上します。
一連の入力を受け取り、複雑なロジックに基づいて結果を返す UDF を考えてみましょう。ただし、500 万行を超える一連の入力の場合、たとえば 100,000 の個別の入力しかないため、100,000 の個別の結果タプルしか生成されません (私の特定のケースは金利から複雑なコード割り当てまでさまざまですが、それらはすべて離散的です。この手法の基本的なポイントは、を実行することでトリックが機能するかどうかを簡単に判断できることですSELECT DISTINCT
)。
私はこのようなことをすることでそれを見つけました:
INSERT INTO PreCalcs
SELECT param1
,param2
,dbo.udf_result(param1, param2) AS result
FROM (
SELECT DISTINCT param1, param2 FROM big_table
)
PreCalcs が適切にインデックス化されている場合、それと次の組み合わせ:
SELECT big_table.param1
,big_table.param2
,PreCalcs.result
FROM big_table
INNER JOIN PreCalcs
ON PreCalcs.param1 = big_table.param1
AND PreCalcs.param2 = big_table.param2
パフォーマンスが大幅に向上します。どうやら、何かが決定論的だからといって、SQL Server が過去の呼び出しをキャッシュして再利用しているとは限りません。
注意しなければならない唯一のことは、NULL が許可されている場所です。その後、結合を慎重に修正する必要があります。
SELECT big_table.param1
,big_table.param2
,PreCalcs.result
FROM big_table
INNER JOIN PreCalcs
ON (
PreCalcs.param1 = big_table.param1
OR COALESCE(PreCalcs.param1, big_table.param1) IS NULL
)
AND (
PreCalcs.param2 = big_table.param2
OR COALESCE(PreCalcs.param2, big_table.param2) IS NULL
)
これが役に立てば幸いです。UDF を使用した同様のトリックや、パフォーマンスのためのクエリのリファクタリングは大歓迎です。
問題は、なぜこのような手動キャッシュが必要なのかということだと思います-関数が決定論的であることをサーバーが知っているのはそれではないでしょうか? そして、それが非常に大きな違いを生み、UDF が非常に高価である場合、なぜオプティマイザーは実行計画でそれを行わないのでしょうか?