web-dev-qa-db-ja.com

同じSQLステートメントで実行プランが異なる

この質問の背景として、詳細は this link にあります。

簡単に言うと、RIGHTテーブルを除いてほとんど同じ2つのSQLステートメントがあります。 LEFT JOINは同じであり、テーブルが異なるため、返される列は異なります。データベースは2008年からSQL Server 2012インスタンスに移動されました。2012インスタンスでは、1つのクエリが3秒未満で実行され、他のクエリは実行に約2時間かかります。実行計画は異なり、リンクに掲載されています。

ただし、両方のクエリを取得してSQL Server 2008サーバーで実行することができ、どちらも3秒以内に完了します。 2008サーバーの両方の実行プランは、2012サーバーの「良好」な実行プランと同じです。

機能する新しいステートメントがありますが、それが使用されているアプリケーションは、インラインSQLを使用するC#Windowsアプリケーションです。この1つのステートメントでそのパターンを壊さないようにしたいと思います。誰でもこの問題に光を当てることができますか?

4
Tim

クエリオプティマイザーには、このクエリの実行プランを作成するときにいくつかの選択肢があります。利用可能な多くの戦略の中から、ハッシュ結合とネストされたループ結合のどちらかを選択できます。どちらを使用するかは、利用可能な統計情報や、SQL Serverが使用するように構成されているメモリの量などの他の要因に依存します。

たまたま、オプティマイザがネストされたループ戦略を選択し、他のケースではハッシュ結合を選択することがあります。ハッシュ結合の使用を強制する場合(たとえば、ネストされたループ結合が現在使用されている場合にクエリヒントOPTION (HASH JOIN)を使用)、estimatedネストされたループプランのコストは、オプティマイザにとって安価なオプションのようです。

これはバグではありません。これは、(とりわけ)利用可能な統計情報に敏感である計画選択のかなり日常的な例です。ネストされたループ結合が実際にはパフォーマンスが非常に低いという事実は、クエリとデータベースの設計がオプティマイザにあまり適していないためです。処理する情報の質が非常に低いため、オプティマイザの計画の選択は、推測よりもかろうじて優れています。

とにかく、ソースコードを変更せずにパフォーマンスの低い計画の形を回避する必要がある場合(ところで、インラインSQLよりもストアドプロシージャを優先する理由)、次の2つの主なオプションがあります。

1つ目は、 プランガイド を使用して、ターゲットクエリの「適切な」プラン形状を強制することです。これまでプランガイドを使用したことがない場合、これはかなり高度な作業です。例で指定されたリテラル値が異なる可能性がある場合は、追加の手順が必要になります。

2番目のオプションは、オプティマイザに使用するより有用なインデックスを提示することです。この場合、これには計算列の追加(高速なメタデータのみの操作)と、新しい列のインデックス作成が含まれます。

_-- Metadata-only operation
ALTER TABLE dbo.InHouse_CSV_Backup
ADD MERSNUMBER_CC AS 
    REPLACE(LTRIM(RTRIM([MERSNUMBER])),'-', '');

-- Index on computed column
CREATE NONCLUSTERED INDEX
    IX_dbo_InHouse_CSV_Backup__MERSNUMBER_CC
ON dbo.InHouse_CSV_Backup (MERSNUMBER_CC)
INCLUDE (MERSNUMBER);
_

クエリはインデックスを使用する可能性が非常に高いため、プランの安定性が向上し、パフォーマンスも向上する可能性が高くなります。これは決して完璧なソリューションではありませんが、入手可能な情報を考慮すれば、比較的シンプルで目立たないソリューションです。

将来の改善のための潜在的な領域:

13
Paul White 9