私が更新している行の数に応じて、まったく異なるプランを使用してT-SQLクエリ

dba.stackexchange https://dba.stackexchange.com/questions/20178

質問

「Top(x)」句を持つSQLアップデートステートメントがあり、値を更新している行には約40億行があります。 「Top(10)」を使用すると、ほぼ瞬時に実行される1つの実行計画が取得されますが、「Top(50)」以下を使用すると、クエリは(少なくとも私が待っている間はそうではありません)終了することはありません。まったく異なる実行計画を使用します。小さいクエリは、一対のインデックスシークとネストされたループ結合を備えた非常に単純なプランを使用します。ここで、まったく同じクエリ(更新ステートメントの上部句に異なる行数があります)は、2つの異なるインデックスシークを含む計画を使用します。 、テーブルスプール、並列性、および他の複雑さの束。

「オプション(プランを使用する...)」を使用して、より小さなクエリによって生成された実行計画を使用するように強制します。これを行うと、数秒で最大100,000行を更新できます。クエリプランは良いことを知っていますが、SQL Serverは少数の行のみが関与している場合にのみ、独自にその計画を選択します。アップデートのかなり大きな行数は、最適な計画になります。

並列性は責任があるかもしれないと思ったので、設定します MAXDOP 1 クエリでは、しかし効果はありませんが、そのステップはなくなりましたが、選択/パフォーマンスが悪いことはありません。私も走った sp_updatestats それが原因ではないことを確認するために今朝。

2つの実行計画を添付しました。短いプランも速いです。さらに、問題のクエリは次のとおりです(私が含めた選択が、小さい列と大規模の両方のカウントの場合、迅速であるように見えることに注意する価値があります):

    update top (10000) FactSubscriberUsage3
               set AccountID = sma.CustomerID
    --select top 50 f.AccountID, sma.CustomerID
      from FactSubscriberUsage3 f
      join dimTime t
        on f.TimeID = t.TimeID
      join #mac sma
        on f.macid = sma.macid
       and t.TimeValue between sma.StartDate and sma.enddate 
     where f.AccountID = 0 --There's a filtered index on the table for this

これがクイックプランです: Quick Execution Plan

そして、これが遅いものです: Slow Execution Plan

クエリを設定する方法や、クエリエンジンが作成している悪い選択に役立つ実行計画で明らかなことはありますか?必要に応じて、関連するテーブル定義とそれらに定義されているインデックスを含めることもできます。

データベースオブジェクトの統計バージョンを要求した人に:私はあなたがそれをすることができることさえ気づいていませんでしたが、それは完全に理にかなっています!他の人が自分で実行計画をテストできるように、統計のみのデータベースのスクリプトを生成しようとしましたが、フィルタリングされたインデックスで生成された統計/ヒストグラムを生成できます(スクリプトの構文エラーなど)幸運から。私はフィルターを削除しようとしましたが、クエリ計画は近づいていましたが、まったく同じではありませんでした。

更新といくつかの完全な実行計画:最初に、 SQL Sentry's Plan Explorer 信じられないほどのツールです。このサイトで他のクエリプランの質問を表示するまで、それが存在することさえ知りませんでした。私のクエリがどのように実行されているかについてはかなりのことを言っていました。問題にどのように取り組むかはわかりませんが、問題が何であるかを明らかにしました。

10、100、および1000行の概要は次のとおりです。1000行のクエリが他の行とは並んでいないことがわかります。Statement Summary

3番目のクエリにはばかげた数の読み取りがあることがわかります。そのため、明らかにまったく違うことをしています。これは、行数を持つ推定実行計画です。1000列の推定実行計画: 1000-row estimated execution plan

そして、これが実行計画の実際の結果です(ちなみに、「決して終了しない」ことで、「1時間で終了」を意味していることがわかりました)。1000列の実際の実行計画 1000-row actual execution plan

私が最初に気づいたのは、予想されるようにDimtimeテーブルから60k行を引っ張るのではなく、実際に引っ張っていることです。 16億、b. 。私の質問を見ると、Dimtimeテーブルから多くの行がどのように引き戻されているのかわかりません。私が使用している間のオペレーターは、Fact TableのTime Recordに基づいて#MACから正しいレコードを引き出すことを保証します。ただし、T.timevalue(またはT.TimeID)を単一の値にフィルタリングする句に行を追加すると、100,000行を1秒で正常に更新できます。その結果、そして私が含めた実行計画で明らかにされたように、それが私の時間テーブルが問題であることは明らかですが、この問題を回避し、精度を維持するために結合基準を変更する方法はわかりません。何かご意見は?

参照のために、ここでは100行の更新の計画(行カウント付き)。あなたはそれが同じインデックスにヒットし、それでもたくさんの行があることがわかりますが、同じ大きさの問題に近いところはありません。行数を使用した100行の実行: enter image description here

正しい解決策はありません

ライセンス: CC-BY-SA帰属
所属していません dba.stackexchange
scroll top