2012-05-15 8 views
5

検索値がスワップされたときにパフォーマンスが著しく低下するデュアル自己結合クエリがあります。 "XYZ"検索値の順序によってSQLクエリのパフォーマンスが低下する

-- 500,000 i/o & 500ms execution 
select 
    fooA.ID 
    , fooB.ID 
from 
    foo AS fooA 
    INNER JOIN bar AS barA ON fooA.barID = barA.barID 
    INNER JOIN foo AS fooB ON fooA.fooID = fooB.fooID -- self join 
    INNER JOIN bar AS barB ON fooB.barID = barB.barID 
where 
    barA.value = 'xyz' 
    AND barB.value = '60' 

-- 5,000 i/o & 5ms execution 
select 
    fooA.ID 
    , fooB.ID 
from 
    foo AS fooA 
    INNER JOIN bar AS barA ON fooA.barID = barA.barID 
    INNER JOIN foo AS fooB ON fooA.fooID = fooB.fooID -- self join 
    INNER JOIN bar AS barB ON fooB.barID = barB.barID 
where 
    barA.value = '60' 
    AND barB.value = 'xyz' 
  • 値は "バー" のテーブル15万回表示されます。
  • 値「60」は「バー」テーブルに500回表示されます。
  • 最初にリストされた検索値に応じて、最も内側のループが150,000行または500行を返すという点を除いて、クエリプランは同じです。
  • 検索では、クラスタ化されていないインデックスの検索が実行されます。
  • 両方のテーブルの統計がFULLSCANで更新されました。

なぜSQLクエリオプティマイザは、どちらのインスタンスでも、クエリプランの最も内側の結合が最小の行数である必要があることを正しく認識していませんか?

+0

クエリの行数を常に最も制限する基準を使用します。それは一般的な経験則です。 – JonH

+1

可能な答え:クエリパラメータ化、パラメータスニッフィング&プランの再利用。 –

+0

fooテーブルとbarテーブルのIDを主キーにすることはできますか? –

答えて

3

SQL Serverは、実行されるたびにクエリを再コンパイルしません。これは一度だけ行い、初めて見た正確な値に最適化します。私はあなたが不幸な計画をキャッシュしていると思います。

最後にOPTION (RECOMPILE)を追加してみてください。

+0

これを追加しても変更はありませんでした。最も内側の結合からの推定行数は両方の問合せ計画で2,500ですが、実際は大きく異なります。 –

+0

それは変です。等価マッチングの索引に関するカーディナリティ推定は、通常、非常に正確です。あなたが探しているテーブルには非常に多くの行があり、重複はほとんどありませんか? – usr

+0

私は本当にここでトラブルを引き起こす可能性のあるものは一切見ません。 2つの実際の実行計画のスクリーンショットを投稿できますか? – usr