範囲内のすべての日付をリストする必要があるストアドプロシージャにクエリがあります、その日に存在する場合、テーブルからその日付に結合します。
この手順は、私が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で同じインデックスシーク(大きい方)を持っていますが、次の点が異なります。
どちらの場合も、インデックスシークから返される行数は228258です。
そして、XML形式: 両方のクエリのXMLプラン
私の質問は:
実際の実行計画が作成された場合でも、実行計画のパーセンテージコストはオプティマイザの推定値からのものです。実際の実行計画は正確な計画を使用し、推定行と実際の行数の両方を含みます。行数の不一致は、推定がどれほど正確であったかを判断するのに役立ちます。
サブクエリと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%です(さらに何かを考え出そうとしましたが、できませんでした。)