web-dev-qa-db-ja.com

オペレーターのコストは、少なくともそれを構成するI / OやCPUのコストと同じくらい大きくすべきではありませんか?

オプティマイザが推定するコストが0.01の1つのサーバーに対するクエリがあります。実際には、それは非常にひどく実行されることになります。

  • クラスター化インデックススキャンを実行することになります

:nitty-gritty ddl、sql、tablesなどが見つかります ここではStackoverflow 。しかし、その情報は興味深いものですが、ここでは重要ではありません。これは無関係な質問です。そして、この質問はDDLを必要としません。

カバリングインデックスシークの使用を強制する場合、そのインデックスの使用は推定します。サブツリーのコストは0.04。

  • クラスター化インデックススキャン:0.01
  • カバーするインデックススキャン:0.04

したがって、サーバーが次のような計画を使用することを選択することは、驚くに値しません。

  • 実際にクラスター化インデックスの147,000論理読み取り
  • カバリングインデックスの16読み取りがはるかに高速ではなく

サーバーA:

_| Plan                                       | Cost      | I/O Cost    | CPU Cost  |
|--------------------------------------------|-----------|-------------|-----------|
| clustered index scan (optimizer preferred) | 0.0106035 | 116.574     | 5.01949   | Actually run extraordinarily terrible (147k logical reads, 27 seconds)
| covering index seek (force hint)           | 0.048894  |   0.0305324 | 0.0183616 | actually runs very fast (16 logical reads, instant)
_

これは、WITH FULLSCANと同じように最新の統計です。

別のサーバーで試す

別のサーバーで試してみます。本番データベースの最新のコピーと、最新の統計情報(WITH FULLSCAN)を使用して、同じクエリの見積もりを取得します。

  • この他のサーバーもSQL Server 2014です
  • しかし、正しくクラスター化インデックススキャンが悪いことを認識します
  • 当然、カバーするインデックスシークが優先されます(コストが5桁低いためです)。

サーバーB

_| Plan                                      | Cost        | I/O Cost   | CPU Cost  |
|-------------------------------------------|-------------|------------|-----------|
| Clustered index scan (force hint)         | 115.661     |   110.889  | 4.77115   | Runs extraordinarily terrible as server A (147k logical reads, 27 seconds)
| Covering index seek (optimizer preferred) |   0.0032831 |   0.003125 | 0.0001581 | Runs fast (16 logical reads, near instant)
_

私が理解できないのは、これらの2つのサーバーがデータベースのコピーがほとんど同じで、どちらも最新の統計情報があり、どちらもSQL Server 2014である理由です。

  • クエリを正しく実行できます
  • もう一人は倒れた

統計が古くなっている古典的なケースのように思えます。または、キャッシュされた実行プラン、またはパラメータスニッフィング。ただし、これらのテストクエリはどちらもOPTION(RECOMPILE)を使用して発行されます。例:

_SELECT MIN(RowNumber) FROM Transactions
WITH (index=[IX_Transactions_TransactionDate]) WHERE TransactionDate >= '20191002 04:00:00.000' OPTION(RECOMPILE)
_

よく見ると「オペレーター」の見積もりが間違っているようです

クラスター化インデックススキャンは悪いことです。そして、サーバーの1つはそれを知っています。これは非常に負荷の高い操作であり、スキャン操作がそれを教えてくれるはずです。

クラスタ化インデックススキャンをforceし、両方のサーバーからの推定スキャン操作を確認すると、何かが飛び出してきます。

enter image description here

_| Cost                | Server A    | Server B   |
|---------------------|-------------|------------|
| I/O Cost            | 116.573     | 110.889    |
| CPU Cost            |   5.01945   |   4.77155  |
| Total Operator Cost |   0.0106035 | 115.661    |
                        mistakenly  | avoids it
                          uses it   |
_

Operatorサーバーのコスト[〜#〜] a [〜#〜]は低すぎます。

  • I/Oコストは妥当です
  • [〜#〜] cpu [〜#〜]のコストは妥当です
  • まとめると、全体的なOperatorコストは4桁低すぎます。

それが、悪い実行計画を誤って選択している理由です。単にoperatorコストがかかるだけです。サーバーBはそれを正しく把握し、クラスター化インデックススキャンを回避します。

演算子= cpu + ioではありませんか?

ほぼすべての実行プランノードにカーソルを合わせると、dba、stackoverflow、およびすべてのブログの実行プランのすべてのスクリーンショットに、必ず表示されます。

_operatorCost >= max(cpuCost, ioCost)
_

そして実際には通常です:

_operatorCost = cpuCost + ioCost
_

ここで何が起こっているのでしょうか?

115 + 5のコストはほとんどゼロであるとサーバーが判断し、代わりにそのコストの1/10000の何かを決定するサーバーの説明は何ですか?

SQL Serverには、CPUおよびI/O操作に適用される内部の重みを調整するオプションがあることを知っています。

_DBCC    TRACEON (3604);     -- Show DBCC output
DBCC    SETCPUWEIGHT(1E0);  -- Default CPU weight
DBCC    SETIOWEIGHT(0.6E0); -- I/O multiplier = 0.6
DBCC    SHOWWEIGHTS;        -- Show the settings
_

また、operatorコストがCPU + I/Oコストを下回ることがあります。

enter image description here

しかし、誰もそれらで遊んでいません。 SQL Serverが環境に基づいて、またはディスクサブシステムとの何らかの通信に基づいて、自動ウェイト調整を行うことは可能ですか?

サーバーが仮想SCSIディスクを使用し、ファイバーリンクでストレージエリアネットワーク(SAN)に接続された仮想マシンである場合、CPUとI/Oのコストを無視できると判断する可能性がありますか?

ただし、このサーバーで永続的な環境になることはありません。私が見つけたすべてのotherクエリは適切に動作するためです。

enter image description here

_ I/O:       0.0112613
 CPU:      +0.0001
           =0.0113613 (theoretical)
 Operator:  0.0113613 (actual)
_

サーバーが使用していないことを説明できるもの:

_I/O Cost + Cpu Cost = Operator Cost
_

この1つのインスタンスで正しく?

SQL Server 2014 SP2。

11
Ian Boyd

オペレーターのコストは、少なくともそれを構成するI/OまたはCPUのコストと同じ大きさであるべきではありませんか

場合によります。

私が同様のアイデアを思いついたので他の人が彼らの投稿を削除したのは残念です。

行の目標

これはスクリーンショットに基づいて経験していることではありませんが、これはオペレーターコストの計算の要素です。 I/OとCPUのコストはスケーリングされません。行の目標が有効でない場合は、実行ごとのコストが表示されます。オペレーターのコストは、行の目標を示すためにスケーリングされます。これは、I/OとCPUが正確にオペレーターコストを構成していない場合の1つの例であり、推定実行回数は考慮に入れるべきものです。これらの統計をどのように表示するかは、内部入力と外部入力のどちらを見ているかによって異なります。

ソースオプティマイザ内:ポールホワイトによる行の目標の詳細-2010年8月18日アーカイブ

バッファプールの使用法

これはあなたに影響を与えている要因である可能性があります。

オペレーションの全コストは、実行数にCPUコストを掛けたものに、さらにIOが必要な数の数式が必要になります。IO =は、IOがすでに多くのページにアクセスされた後、すでにメモリ内にある確率を表します。大きなテーブルの場合、以前にアクセスされたページがすでに削除されている可能性をモデル化します。サブツリーコストは、現在の操作と現在の操作にフィードされるすべての操作のコストを表します。

出典ジョーチャンによる実行計画のコストモデル-2009年7月アーカイブ

あなたの問題に

スクリーンショットを見ると、サーバー上で非常に興味深いサブツリーコストが発生していることがわかります。興味深いのは、使用するメモリが多く、CPUが少ないことです。

上記の情報は、サブツリーコストに問題があり、オペレーターコストが症状であることを示しています。

...推定サブツリーコストは、個々のオペレーターの累積(NodeID順で合計された)コストです。

出典Frantcheyによる実際の実行計画のコスト-2018年8月20日アーカイブ

答えはこれらの文にあると思います:

IOの数式は、IOが、すでに多くのページにアクセスした後に、メモリ内に存在する可能性を表しています。大きなテーブルの場合、以前にアクセスされたページが再び必要になったときに、すでに削除されている可能性があります。

あなたに起こっていると私が思うこと:

  1. ハードウェアのセットアップが異なります。 RAM/CPU /ディスク、それは同じではなく、推定に影響を与えています。
  2. 物理データファイル。どのようにコピーを作成しましたか?これを真に複製する唯一の方法は、データファイルを使用してバックアップ/復元を行うことです。
  3. キャッシュをクリアしてから強制的に再コンパイルしましたか?これはどうなるのだろう。

それ以外の場合は、どのように見えるかを深く掘り下げるための推定および実際のクエリプランを確認してください。

重要、これは傷つきます(解雇される可能性があります)何が起こるかを理解せずに、これを計画せずに本稼働でこれを実行した場合。これは、再コンパイルで再度テストするためにキャッシュをクリアする方法です


Bhavesh PatelによるSQL Serverキャッシュのフラッシュまたはクリアの異なる方法-2017年3月31日archive

  • DBCC FREESYSTEMCACHE
  • DBCC FREESESSIONCACHE
  • DBCC FREEPROCCACHE
2
Shaulinator

行の目標

クエリで行の目標が設定されると、行の見積もりとコストに影響する可能性があります。

これが問題の原因であるかどうかを確認するには、トレースフラグ4138を有効にしてクエリを実行します(これにより、行の目標の影響が削除されます)。

バッファープールサイズ

使用可能なバッファープールが大きい場合、一部のI/O操作の推定コストを削減できます(コストが削減されたサーバーのRAMは14 GBですが、他のマシンでは6 GB)。

プランXMLで「EstimatedPagesCached」を探すことにより、この動作の影響を確認できます。このプロパティの値が大きいほど、同じデータにアクセスする可能性のある実行プランの部分のI/Oコストを削減できます。

利用可能なスケジューラ

並列クエリの場合、オペレーターのCPUコストは「スケジューラーの数/ 2」も削減できます。プランXMLで「EstimatedAvailableDegreeOfParallelism」を探すことで、これがどのような値であるかを確認できます。

「遅いクエリ」は4コアのサーバーで実行され、1コアのサーバーでは高速のクエリが実行されることに気付いたので、これについて言及します。

コストは奇妙で壊れている

フォレストは、彼のブログでコストが意味をなさなくなる可能性があるさまざまな方法について語っています: Percentage Non Grata

4
Josh Darnell

サーバーが完全に同一であると想定できますか?

  • cPU数
  • sQLサービスパックレベル
  • db互換性レベル

Sql2012サーバーのdb互換性レベルを修正した後、SP実行プランに対して返されたクエリステップコストの小さな変更に気づきました。(アイドルDB、最初のプランxmlを取得、適用オプションの変更、再コンパイルされたsp 、2番目のプランxmlを取得しました)プラン自体は同じように見えます。オプティマイザ内で使用できるオプションが増え、計算が少し異なる可能性があります。2xサーバー間で異なるパッチ/互換性がある場合、実際のプランが根本的に異なる可能性があります(間違っています) ..)

1
simon coleman

私にとって、サーバーAがクラスター化インデックススキャンを選択するのは、まったく正常なことのようです。これは、オプティマイザが持っている知識を考慮すれば最良の決定です。奇妙なことに、サーバーBは同じものを選択しません。その答えがあると思いますが、まずオプティマイザがクラスタ化インデックススキャンを選択する必要がある理由を説明します。

基本的な理由は、RowNumberとTransactionDateの値が独立していると考えていることに関係しています。それが言うように ここ

独立性:相関情報が利用可能でない限り、異なる列のデータ分布は独立しています。

そしてクエリは

SELECT MIN(RowNumber)   FROM Transactions WHERE TransactionDate >= '20191002 04:00:00.000'

オプションは次のとおりです。1)RowNumberでソートされたクラスター化インデックスのスキャンを開始し、トランザクションの実際の回答となるTransactionDate> = '20191002 04:00:00.000'の最初のタプルが検出されるとすぐに停止します。 2)値 '20191002 04:00:00.000'のTransactionDateの非クラスター化インデックスを検索し、その値以降の残りのインデックスをスキャンし、検出される最小のRowNumberを維持します。

ここでは、値「20191002 04:00:00.000」が列TransactionDateの最大値であると想定しています。実際には、値の95%より大きいと仮定しましょう。オプション1の独立性の仮定では、スキャンされた各タプルは最終的な回答になる確率が5%であるため、単一のディスクフェッチで回答が見つかると想定するのが妥当です。オプション2では、特定の日付のインデックスを検索すると、すでにディスクページのフェッチが多くなっているため、インデックスの5%もスキャンする必要があります。ただし、実際には、2つの列の値は直接相関しているため、オプティマイザが最良のオプションと見なすものは、クラスター化インデックスの95%をスキャンすることになります。

では、なぜサーバーBはクラスター化インデックスのスキャンを選択しないのでしょうか。明らかに、サーバーBでは、元の質問に投稿された計画からわかるように、クラスター化インデックスはRowNumberでソートされていません。 In server A result of scan is sorted, whereas in Server B it is not

それで、なぜCPU_cost + I/O_cost >>コストなのか。クラスタ化インデックススキャン用のSQLサーバーは、部分的なスキャンのみであり、レポートのみであっても、テーブル全体のCPUとI/Oのコストを報告するようですようです総コストとして期待値を見つける速度に基づく実際の見積もり。投稿されたプランでまったく同じ動作を見ることができます ここ

そして、何ができるかについては、RowNumberとTransactionDateが常に増加している場合、クエリは次のように書き直すことができます。

SELECT RowNumber FROM Transactions WHERE TransactionDate> = '20191002 04:00:00.000' odrer by TransactionDate LIMIT 1

1
dbilid