SQLで大きなパフォーマンスの違い(1時間から1分)が見つかりました。理由を説明できますか?
-
10-07-2019 - |
質問
次のクエリは、100万レコードの標準マシンでそれぞれ70分と1分かかります。考えられる理由は何ですか?
クエリ[01:10:00]
SELECT *
FROM cdc.fn_cdc_get_net_changes_dbo_PartitionTest(
CASE WHEN sys.fn_cdc_increment_lsn(0x00)<sys.fn_cdc_get_min_lsn('dbo_PartitionTest')
THEN sys.fn_cdc_get_min_lsn('dbo_PartitionTest')
ELSE sys.fn_cdc_increment_lsn(0x00) END
, sys.fn_cdc_get_max_lsn()
, 'all with mask')
WHERE __$operation <> 1
クエリの変更[00:01:10]
DECLARE @MinLSN binary(10)
DECLARE @MaxLSN binary(10)
SELECT @MaxLSN= sys.fn_cdc_get_max_lsn()
SELECT @MinLSN=CASE WHEN sys.fn_cdc_increment_lsn(0x00)<sys.fn_cdc_get_min_lsn('dbo_PartitionTest')
THEN sys.fn_cdc_get_min_lsn('dbo_PartitionTest')
ELSE sys.fn_cdc_increment_lsn(0x00) END
SELECT *
FROM cdc.fn_cdc_get_net_changes_dbo_PartitionTest(
@MinLSN, @MaxLSN, 'all with mask') WHERE __$operation <> 1
[変更]
パラメータが各行で評価されるかどうかを確認するために、同様の関数を使用してシナリオを再作成しようとしました。
CREATE FUNCTION Fn_Test(@a decimal)RETURNS TABLE
AS
RETURN
(
SELECT @a Parameter, Getdate() Dt, PartitionTest.*
FROM PartitionTest
);
SELECT * FROM Fn_Test(RAND(DATEPART(s,GETDATE())))
しかし、38秒で100万件のレコードが処理された場合、「パラメータ」列に同じ値が表示されます。
解決
確定的なスカラー関数でも、行ごとに少なくとも1回評価されます。同じ「行」で同じ決定性スカラー関数が複数回発生する場合同じパラメータで、一度だけ評価されると信じています-例えば<コード> CASE WHEN fn_X(a、b、c)&gt;の場合0 THEN fn_X(a、b、c)ELSE 0 END またはそのようなもの。
RANDの問題は、再シードを続けるためだと思います:
RAND()の繰り返し呼び出し 同じシード値は同じを返します 結果。
1つの接続で、RAND()が 指定されたシード値で呼び出され、 RAND()の以降のすべての呼び出しは、 シードされたRAND()に基づく結果 コール。たとえば、次のクエリ 常に同じシーケンスを返します 数字の
私はあなたが示したようにスカラー関数の結果をキャッシュしました-スカラー関数の結果のテーブルを事前計算してそれらに結合するまでです。最終的には、スカラー関数を実行させるために何かをする必要があります。そうではなく、最良のオプションはCLRです-これらは明らかにSQL UDFよりも優れています。残念ながら、現在の環境では使用できません。
他のヒント
最初のクエリでは、 fn_cdc_increment_lsn
および fn_cdc_get_min_lsn
がすべての行に対して実行されます。 2番目の例では、1回だけです。