「TOP(X)」句を含むSQL UPDATEステートメントがあり、値を更新する行には約40億行あります。「TOP(10)」を使用すると、ほぼ瞬時に実行される1つの実行プランが得られますが、「TOP(50)」以上を使用すると、クエリは(少なくとも、待機中ではなく)終了しません。まったく異なる実行計画を使用します。小さいクエリは、インデックスシークとネストされたループ結合のペアを持つ非常に単純なプランを使用します。まったく同じクエリ(UPDATEステートメントのTOP句の行数が異なる)は、2つの異なるインデックスシークを含むプランを使用します、テーブルスプール、並列処理、その他多数の複雑さ。
「OPTION(USE PLAN ...)」を使用して、より小さいクエリによって生成された実行プランを強制的に使用しました。これを行うと、数秒で100,000行も更新できます。クエリプランが良好であることはわかっていますが、SQL Serverは少数の行のみが関係している場合にのみそのプランを選択します。更新でかなり多くの行数があると、最適ではないプランになります。
並列処理のせいかもしれないと思ったのでMAXDOP 1
、クエリを設定しましたが、効果はありません-そのステップはなくなりましたが、選択/パフォーマンスの低下はありません。sp_updatestats
それが原因ではないことを確認するために、今朝も走りました。
2つの実行計画を添付しました-短いものは速いものです。さらに、問題のクエリは次のとおりです(含まれているSELECTが小さい行カウントと大きい行カウントの両方の場合に高速であるように見えることに注意する価値があります)。
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
クイックプランは次のとおりです。
そして、これは遅いものです:
クエリを設定している方法または実行計画に明らかな何かがありますか?それは、クエリエンジンが行っている悪い選択に役立つでしょうか?必要に応じて、関連するテーブル定義とそれらに定義されているインデックスも含めることができます。
データベースオブジェクトの統計のみのバージョンを要求した人たちへ: あなたがそれができるとは思いませんでしたが、それは完全に理にかなっています!他の人が自分で実行プランをテストできるように、統計のみのデータベース用のスクリプトを生成しようとしましたが、フィルター処理されたインデックスで統計/ヒストグラムを生成できます(スクリプトの構文エラーのようです)、私は運が悪い。フィルターを削除しようとしましたが、クエリプランは近くなりましたが、まったく同じではなく、グースチェイスで誰も送信したくありません。
更新といくつかのより完全な実行計画: まず、SQL SentryのPlan Explorerは信じられないほどのツールです。このサイトにある他のクエリプランの質問を見るまで、それが存在することすら知りませんでした。私のクエリがどのように実行されていたかについては、かなりの発言がありました。問題に取り組む方法がわかりませんが、彼らは問題が何であるかを明らかにしました。
10行、100行、および1000行の概要を以下に示します。1000行のクエリは、他のクエリとは一線を画しています。
3番目のクエリの読み取り数はとんでもない数であることがわかります。したがって、明らかに完全に異なる処理を行っています。行数を含む推定実行計画を以下に示します。 1000行の推定実行計画:
そして、ここに実行計画の実際の結果があります(ちなみに、「決して終了しない」ということは、「1時間で終了する」という意味です)。 1000行の実際の実行計画
最初に気づいたのは、dimTimeテーブルから予想どおりに60K行をプルする代わりに、実際にはBで16億行をプルすることです。私のクエリを見ると、dimTimeテーブルからどれだけ多くの行が引き戻されているのかわかりません。私が使用しているBETWEEN演算子は、ファクトテーブルの時間レコードに基づいて#macから正しいレコードをプルすることを保証するだけです。ただし、t.TimeValue(またはt.TimeID)を単一の値にフィルター処理するWHERE句に行を追加すると、数秒で100,000行を正常に更新できます。その結果、そして私が含めた実行計画で明らかにされたように、それは私のタイムテーブルが問題であることは明らかですが、この問題を回避し、精度を維持するために結合基準をどのように変更するかわかりません。何かご意見は?
参考までに、ここでは、100行更新の計画(行カウント付き)を示します。同じインデックスにヒットし、まだ大量の行があるが、同じ規模の問題には至っていないことがわかります。 行カウントを使用した100行の実行:
from #mac sma join f on f.macid = sma.macid join dimTime t on f.TimeID = t.TimeID and t.TimeValue between sma.StartDate and sma.enddate
対from #mac join t on t.TimeValue between sma.StartDate and sma.enddate join f on f.TimeID = t.TimeID and f.macid = sma.macid
TOP 50
はまだ迅速に実行されるはずです。XMLプランをアップロードできますか?行数を調べる必要があります。TOP 50
maxdop 1で、更新としてではなく、選択として実行し、計画を投稿できますか?(検索スペースを単純化/二分しようとしています)。
t.TimeValue between sma.StartDate and sma.enddate
、さらに多くの無駄な行が生成され、後でFactSubscriberに対する結合で除外され、最終結果にならない場合があります。
sp_updatestatistics
テーブルで走ったことがありますか?