web-dev-qa-db-ja.com

クエリオプティマイザ演算子の選択-ネストされたループとハッシュ一致(またはマージ)

私のストアドプロシージャの1つは、実行に時間がかかりすぎていました。クエリ実行プランを見てみると、時間がかかりすぎる操作を見つけることができました。これは、外部テーブル(65991行)と内部テーブル(19223行)を持つネストされたループ物理演算子でした。ネストされたループでは、次のように推定行= 1,268,544,993(65991に19223を掛けたもの)が表示されました。

enter image description here

結合に使用される物理演算子に関するいくつかの記事を読みましたが、ネストされたループとハッシュの一致のどちらがこの場合に適しているかについて少し混乱しました。私が集めることができたものから:

ハッシュ一致-有用なインデックスが利用できない場合、一方のテーブルが他方よりも大幅に小さい場合、テーブルが結合列でソートされていない場合に、オプティマイザーによって使用されます。また、ハッシュ一致は、より効率的な結合方法(ネストされたループまたはマージ結合)を使用できることを示している可能性があります。

質問:このシナリオでは、ハッシュ一致はネストされたループよりも優れていますか?

ありがとう

21

絶対に。ハッシュ一致は大幅な改善になります。小さい19,223行のテーブルでハッシュを作成してから大きい65,991行のテーブルでプローブすることは、1,268,544,993行の比較を必要とするネストされたループよりもはるかに小さい操作です。

サーバーがネストされたループを選択する唯一の理由は、関係する行の数を大幅に過小評価しているためです。テーブルには統計がありますか?ある場合、定期的に更新されていますか?統計は、サーバーが適切な実行プランを選択できるようにするものです。

統計に適切に対処しても問題が解決しない場合は、次のようにHASH結合を使用するように強制できます。

SELECT *
FROM
   TableA A -- The smaller table
   LEFT HASH JOIN TableB B -- the larger table

これを実行すると、結合順序も強制されることに注意してください。これは、結合順序が意味をなすように、すべてのテーブルを正しく配置する必要があることを意味します。通常、サーバーがすでに持っている実行プランを調べて、クエリ内のテーブルの順序を変更して一致させます。これを行う方法に慣れていない場合、基本は各「左」入力が最初に来ることであり、グラフィカル実行プランでは、左入力は 1です。多くのテーブルを含む複雑な結合では、実行プランを最適化するために、結合を括弧内にグループ化するか、RIGHT JOINを使用する必要があります(左右の入力を入れ替えますが、結合の正しいポイントにテーブルを導入します)注文)。

一般に、結合ヒントの使用や結合順序の強制は避けるのが最善です。そのため、最初にできることは何でもしてください。テーブルのインデックス、断片化、列サイズの縮小(Unicodeが不要な場合はvarcharの代わりにnvarcharを使用するなど)、またはクエリを部分に分割する(挿入して最初に一時テーブル、次にそれに結合します)。

26
ErikE

ヒントを一方向または別の方向に強制することによって計画を「修正」しようとすることはお勧めしません。代わりに、インデックス、統計、TSQLコードを調べて、19000から12億行をロードするテーブルスプールがある理由を理解する必要があります。

10
Grant Fritchey