web-dev-qa-db-ja.com

古いクエリよりも論理的な読み取りが少ない場合でも、新しいクエリは遅くなります

範囲内のすべての日付をリストする必要があるストアドプロシージャにクエリがあります、その日に存在する場合、テーブルからその日付に結合します。

この手順は、私がDBAとして採用される前に作成されたため、少し最適化することを検討しました。しかし、レンガの壁にぶつかったようで、その理由がわかりません。

プロシージャの現在の実装では、2つの通常のテーブル(TableAとTableBと呼ぶことにします)からデータを(FROM句で)派生クエリとしてSELECTし、これをRIGHT JOINとして使用します。

RIGHT JOIN (
     SELECT DATEADD(DAY,number,@DateFrom) AS DATE
     FROM (
         SELECT DISTINCT number
         FROM master.dbo.spt_values
         WHERE name IS NULL
     ) n
     WHERE DATEADD(DAY,number,@DateFrom) <= @DateTo
) AS y ON derived.Date = y.Date -- "derived" is an alias of the derived query

この同じコードが複数の手順で使用されているため、2005-01-01から2039-01-01までの日付でテーブルを作成すると思いました。

CREATE TABLE Dates(
     [Date] DATE NOT NULL PRIMARY KEY
)

テーブルには、日付のディメンションを持つ倉庫からデータが入力されました。

だから、その正しい結合の代わりに、私は書きました:

FROM Dates d
LEFT JOIN derived ON derived.Date = d.[Date] -- the "derived" table was moved to CTE, since that's easier to read
WHERE d.[Date] BETWEEN @DateFrom AND @DateTo

コードに満足して、STATISTICS IOをオンにして、両方のバージョンのプロシージャコードを実行しましたが、結果に完全にショックを受けました。

古いクエリの統計:

テーブル 'TableA'。スキャンカウント0、論理読み取り456516、物理読み取り0、先読み読み取り0、LOB論理読み取り0、LOB物理読み取り0、LOB先読み読み取り0。

テーブル 'TableB'。スキャンカウント367、論理読み取り3949、物理読み取り0、先読み読み取り0、LOB論理読み取り0、LOB物理読み取り0、LOB先読み読み取り0。

テーブル 'spt_values'。スキャンカウント1、論理読み取り14、物理読み取り0、先読み読み取り0、LOB論理読み取り0、LOB物理読み取り0、LOB先読み読み取り0。

新しいクエリの統計:

テーブル「ワークテーブル」。スキャンカウント0、論理読み取り0、物理読み取り0、先読み読み取り0、lob論理読み取り0、lob物理読み取り0、lob先読み読み取り0。

テーブル 'TableB'。スキャンカウント1、論理読み取り1767、物理読み取り0、先読み読み取り0、lob論理読み取り0、lob物理読み取り0、lob先読み読み取り0。

テーブル 'TableA'。スキャンカウント1、論理読み取り6、物理読み取り0、先読み読み取り0、lob論理読み取り0、lob物理読み取り0、lob先読み読み取り0。

テーブル「日付」。スキャンカウント1、論理読み取り3、物理読み取り0、先読み読み取り0、LOB論理読み取り0、LOB物理読み取り0、LOB先読み読み取り0。

しかし、2番目のクエリは遅くなります

実行プランを見ると、最初のクエリは2%のコストしかかかりませんが、2番目のクエリは98%かかります。両方ともTableBで同じインデックスシーク(大きい方)を持っていますが、次の点が異なります。

  • 最初のクエリでは、そのIndex Seekは367回実行され、クエリ全体の5.4%がかかります。
  • 2番目のクエリでは、そのインデックスシークは1回しか実行されませんが、クエリ全体の47.1%のコストがかかります。

どちらの場合も、インデックスシークから返される行数は228258です。

次に、両方の実行計画も示します。 ExecutionPlans

そして、XML形式: 両方のクエリのXMLプラン

私の質問は:

  1. 2番目のクエリが遅いのはなぜですか?
  2. 2番目のクエリを高速化できますか?
6
Vatroslav

実際の実行計画が作成された場合でも、実行計画のパーセンテージコストはオプティマイザの推定値からのものです。実際の実行計画は正確な計画を使用し、推定行と実際の行数の両方を含みます。行数の不一致は、推定がどれほど正確であったかを判断するのに役立ちます。

サブクエリとderivedの列との比較のどこかで、オプティマイザは一致する行数を正しく推定できませんでした。実際に220,000を超える場合、derivedから18行あると推測されました。追加の手がかりは、SELECTノード上の警告メッセージCardnality Estimate: CONVERT(nvarchar(35),[mssqlsystemresource].[sys].[spt_values].[name],0)です。

クエリの実行時間をSTATISTICS TIMEなどの他のもので確認した場合、それらはより近く、おそらく2番目のクエリの実行が速くなると思います。

もう少し 計画分析 があり、状況はやや似ています。 (SQL Server Plan Explorer)(オプティマイザをだます方法について Kendra Little へのヒント付き)

見積もりは93%/ 7%のコスト分割を示していますが、実際のCPU、時間、またはIOを見ると、その差は極端ではありません。 IOは約75%/ 25%で、CPUは約60%/ 40%です(さらに何かを考え出そうとしましたが、できませんでした。)

2