UATでの同じクエリの実行(3秒で実行)とPROD(23秒で実行)でこのような大きな違いがある理由を理解したいと思います。
UATとPRODの両方が正確にデータとインデックスを持っています。
クエリ:
set statistics io on;
set statistics time on;
SELECT CONF_NO,
'DE',
'Duplicate Email Address ''' + RTRIM(EMAIL_ADDRESS) + ''' in Maintenance',
CONF_TARGET_NO
FROM CONF_TARGET ct
WHERE CONF_NO = 161
AND LEFT(INTERNET_USER_ID, 6) != 'ICONF-'
AND ( ( REGISTRATION_TYPE = 'I'
AND (SELECT COUNT(1)
FROM PORTFOLIO
WHERE EMAIL_ADDRESS = ct.EMAIL_ADDRESS
AND DEACTIVATED_YN = 'N') > 1 )
OR ( REGISTRATION_TYPE = 'K'
AND (SELECT COUNT(1)
FROM CAPITAL_MARKET
WHERE EMAIL_ADDRESS = ct.EMAIL_ADDRESS
AND DEACTIVATED_YN = 'N') > 1 ) )
ON UAT:
SQL Server parse and compile time:
CPU time = 0 ms, elapsed time = 0 ms.
SQL Server Execution Times:
CPU time = 0 ms, elapsed time = 0 ms.
SQL Server parse and compile time:
CPU time = 11 ms, elapsed time = 11 ms.
SQL Server Execution Times:
CPU time = 0 ms, elapsed time = 0 ms.
SQL Server Execution Times:
CPU time = 0 ms, elapsed time = 0 ms.
(3 row(s) affected)
Table 'Worktable'. Scan count 256, logical reads 1304616, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'PORTFOLIO'. Scan count 1, logical reads 84761, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'CAPITAL_MARKET'. Scan count 256, logical reads 9472, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'CONF_TARGET'. Scan count 1, logical reads 100, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
(1 row(s) affected)
SQL Server Execution Times:
CPU time = 2418 ms, elapsed time = 2442 ms.
SQL Server parse and compile time:
CPU time = 0 ms, elapsed time = 0 ms.
SQL Server Execution Times:
CPU time = 0 ms, elapsed time = 0 ms.
PROD:
SQL Server parse and compile time:
CPU time = 0 ms, elapsed time = 0 ms.
SQL Server Execution Times:
CPU time = 0 ms, elapsed time = 0 ms.
SQL Server parse and compile time:
CPU time = 0 ms, elapsed time = 0 ms.
SQL Server Execution Times:
CPU time = 0 ms, elapsed time = 0 ms.
SQL Server Execution Times:
CPU time = 0 ms, elapsed time = 0 ms.
(3 row(s) affected)
Table 'PORTFOLIO'. Scan count 256, logical reads 21698816, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'CAPITAL_MARKET'. Scan count 256, logical reads 9472, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'CONF_TARGET'. Scan count 1, logical reads 100, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
(1 row(s) affected)
SQL Server Execution Times:
CPU time = 23937 ms, elapsed time = 23935 ms.
SQL Server parse and compile time:
CPU time = 0 ms, elapsed time = 0 ms.
SQL Server Execution Times:
CPU time = 0 ms, elapsed time = 0 ms.
PRODでは、クエリはインデックスが欠落していることを示唆しており、私がテストしたようにそれは有益ですが、それは議論のポイントではありません。
私はそれを理解したいだけです:ON UAT-なぜSQLサーバーはワーカーテーブルを作成し、PRODでは作成しませんか? PRODではなくUATにテーブルスプールを作成します。また、なぜUATとPRODで実行時間がそれほど異なるのですか?
注意 :
私はsql server 2008 R2を実行していますRTM両方のサーバーで(かなりすぐに最新のSPでパッチを適用する予定です)。
UAT:最大メモリ8GB。 MaxDop、プロセッサアフィニティ、および最大ワーカースレッドは0です。
Logical to Physical Processor Map:
*------- Physical Processor 0
-*------ Physical Processor 1
--*----- Physical Processor 2
---*---- Physical Processor 3
----*--- Physical Processor 4
-----*-- Physical Processor 5
------*- Physical Processor 6
-------* Physical Processor 7
Logical Processor to Socket Map:
****---- Socket 0
----**** Socket 1
Logical Processor to NUMA Node Map:
******** NUMA Node 0
PROD:最大メモリ60GB。 MaxDop、プロセッサアフィニティ、および最大ワーカースレッドは0です。
Logical to Physical Processor Map:
**-------------- Physical Processor 0 (Hyperthreaded)
--**------------ Physical Processor 1 (Hyperthreaded)
----**---------- Physical Processor 2 (Hyperthreaded)
------**-------- Physical Processor 3 (Hyperthreaded)
--------**------ Physical Processor 4 (Hyperthreaded)
----------**---- Physical Processor 5 (Hyperthreaded)
------------**-- Physical Processor 6 (Hyperthreaded)
--------------** Physical Processor 7 (Hyperthreaded)
Logical Processor to Socket Map:
********-------- Socket 0
--------******** Socket 1
Logical Processor to NUMA Node Map:
********-------- NUMA Node 0
--------******** NUMA Node 1
更新:
UAT実行計画XML:
PROD実行プランXML:
UAT実行プランXML-PRODから生成されたプラン:
サーバー構成:
PROD:PowerEdge R720xd-Intel(R)Xeon(R)CPU E5-2637 v2 @ 3.50GHz。
UAT:PowerEdge 2950-Intel(R)Xeon(R)CPU X5460 @ 3.16GHz
answers.sqlperformance.com に投稿しました
提案のために@swasheckに感謝します
PRODの最大メモリを60GBから7680MBに変更すると、同じプランをPRODで生成できます。クエリはUATと同時に完了します。
今、私は理解する必要があります-なぜですか?また、これにより、このモンスターサーバーを正当化して古いサーバーを置き換えることはできなくなります。
バッファープールの潜在的なサイズは、クエリオプティマイザーによるプランの選択にいくつかの方法で影響します。私の知る限り、ハイパースレッディングはプランの選択に影響を与えません(ただし、利用可能なスケジューラーの数は確かに影響します)。
ソートやハッシュなどのメモリを消費するイテレータを含むプランの場合、バッファプールのサイズ(とりわけ)は、実行時にクエリで使用できるメモリ許可の最大量を決定します。
SQL Server 2012(すべてのバージョン)では、この番号はクエリプランのルートノードのOptimizer Hardware Dependencies
セクションに報告され、Estimated Available Memory Grant
と表示されます。 2012年より前のバージョンでは、この数は番組プランでは報告されません。
使用可能なメモリの見積もりは、クエリオプティマイザが使用するコストモデルへの入力です。その結果、大規模なソートまたはハッシュ操作を必要とする代替プランは、設定が低いマシンよりも、バッファープール設定が大きいマシンで選択される可能性が高くなります。 very大量のメモリを備えたインストールの場合、コストモデルはこの種の考え方では行き過ぎになる可能性があります-代替戦略が望ましい場所で非常に大きなソートまたはハッシュを持つ計画を選択する( KB2413549-大量のメモリを使用すると、SQL Serverで計画が非効率になる可能性があります-TF2335 )。
ワークスペースのメモリ付与は、あなたの場合の要因ではありませんが、知っておく価値のあるものです。
バッファープールの潜在的なサイズは、データアクセスのオプティマイザーのコストモデルにも影響します。モデルで行われた前提の1つは、すべてのクエリがコールドキャッシュで始まることです。そのため、ページへの最初のアクセスは、物理I/Oが発生すると想定されます。このモデルは、繰り返しアクセスがキャッシュから発生する可能性を考慮に入れています。これは、とりわけバッファープールの潜在的なサイズに依存する要因です。
質問に示されているクエリプランのクラスター化インデックススキャンは、繰り返しアクセスされる1つの例です。スキャンは、ネストされたループのセミジョインの反復ごとに巻き戻されます(相関パラメーターを変更せずに繰り返されます)。準結合への外部入力は28.7874行を推定し、これらのスキャンのクエリプランプロパティは結果として27.7874での推定巻き戻しを示します。
この場合も、SQL Server 2012のみで、プランのルートイテレータのEstimated Pages Cached
セクションにOptimizer Hardware Dependencies
の数が表示されます。この数は、キャッシュから繰り返しアクセスされるページへのアクセスの可能性を考慮したコストアルゴリズムへの入力の1つを報告しています。
その結果、最大バッファープールサイズが大きく構成されたインストールでは、最大バッファープールサイズが小さいインストールよりも同じページを複数回読み取るスキャン(またはシーク)のコストが削減される傾向があります。
単純な計画では、巻き戻しスキャンのコスト削減は、(estimated number of executions) * (estimated CPU + estimated I/O)
を推定されるオペレーターコストと比較することで確認できます。セミ結合とユニオンの効果により、サンプル計画では計算がより複雑になります。
それにもかかわらず、問題の計画は、スキャンを繰り返すか、一時インデックスを作成するかの選択が非常に細かくバランスされているケースを示しているように見えます。バッファプールが大きいマシンでは、スキャンを繰り返すコストは、インデックスを作成するコストよりもわずかに低くなります。バッファープールが小さいマシンでは、スキャンコストが少し削減されます。つまり、インデックススプールプランは、オプティマイザーにとって少し安く見えます。
オプティマイザのコストモデルは、多くの仮定を行い、多数の詳細な計算を含みます。必要なすべての数値が公開されているわけではなく、アルゴリズムがリリース間で変更される可能性があるため、すべての詳細に従うことが常に(または通常は可能です)可能であるとは限りません。特に、キャッシュされたページに遭遇する可能性を考慮して適用されるスケーリング式はよく知られていません。
この特定のケースの要点として、オプティマイザのプランの選択は、とにかく正しくない数値に基づいています。 Clustered Index Seekからの推定行数は28.7874ですが、実行時に256行が検出されます-ほぼ1桁違います。これらの28.7874行内の予想される値の分布についてオプティマイザが持っている情報を直接見ることはできませんが、恐ろしく間違っている可能性も非常に高いです。
見積もりがこれほど間違っている場合、プランの選択と実行時のパフォーマンスは、基本的に偶然に過ぎません。インデックススプールを使用した計画happensは、スキャンを繰り返すよりもパフォーマンスが向上しますが、バッファプールのサイズを増やすことが異常の原因であると考えるのは間違いです。
オプティマイザが正しい情報を持っている場合、それがまともな実行計画を生成する可能性ははるかに優れています。メモリが多いインスタンスは、通常、メモリが少ない別のインスタンスよりもワークロードのパフォーマンスが向上しますが、特にプランの選択が誤ったデータに基づいている場合は保証されません。
どちらのインスタンスも、独自の方法で欠落しているインデックスを提案しました。 1つは明示的な欠落したインデックスを報告し、もう1つは同じ特性を持つインデックススプールを使用しました。インデックスが優れたパフォーマンスと計画の安定性を提供する場合、それで十分な場合があります。私の傾向はクエリも書き直すことですが、それはおそらく別の話です。
Paul Whiteは、背後にある理由を優れた明快な方法で説明しています-より多くのメモリを搭載したサーバーで実行するときのSQLサーバーの動作。
また、最初に問題を発見してくれた@ swasheckに感謝します。
マイクロソフトでケースをオープンし、以下が提案されたものです。
この問題は、トレースフラグT2335を起動パラメーターとして使用することで解決されます。
KB2413549-大量のメモリを使用すると、SQL Serverの計画が非効率になる可能性があります により詳細に説明されています。
このトレースフラグにより、SQL Serverは、クエリを実行するときのメモリ消費に関してより保守的な計画を生成します。 SQL Serverが使用できるメモリの量は制限されません。 SQL Server用に構成されたメモリは、引き続きデータキャッシュ、クエリ実行、およびその他のコンシューマによって使用されます。 このオプションを運用環境にロールインする前に、十分にテストしてください。
最大メモリ設定とハイパースレッディングは、どちらもプランの選択に影響を与える可能性があります。
また、「設定」オプションは環境ごとに異なります。
UATのStatementSetOptions:
ANSI_NULLS="true"
ANSI_PADDING="true"
ANSI_WARNINGS="true"
ARITHABORT="true"
CONCAT_NULL_YIELDS_NULL="true"
NUMERIC_ROUNDABORT="false"
QUOTED_IDENTIFIER="true"
製品のStatementSetOptions:
ANSI_NULLS="true"
ANSI_PADDING="true"
ANSI_WARNINGS="true"
ARITHABORT="false"
CONCAT_NULL_YIELDS_NULL="true"
NUMERIC_ROUNDABORT="false"
QUOTED_IDENTIFIER="true"
SQLは、SETオプションに基づいて異なるプランを生成できます。これは、異なるSSMSセッションから、またはアプリからの異なる実行からプランをキャプチャする場合に頻繁に発生します。
開発者が一貫した接続文字列を使用していることを確認してください。