web-dev-qa-db-ja.com

SQL Server 2012内部結合の推定行数の問題

以下のような単純な結合があります:

select * 
from fact_sales f
join dim_company d on f.company_SK = d.company_SK

ファクトテーブルには5億を少し超えるレコード(NC列ストアを含む)が含まれていますが、クエリはそれらすべてを返しますが、結合後の推定行数は3億だけです。ハッシュ結合までは、推定行数は正しいですが、結合後は3億に低下します。クエリの推定計画は次のとおりです。

enter image description here

ファクトテーブル(フルスキャンあり)とディメンションテーブルの両方の結合で使用されるSK列の統計を更新しました。それぞれのヒストグラムは次のとおりです。

enter image description here

この問題は、データベース内のいくつかのディメンションテーブルでのみ発生するようです。他のディメンションテーブルを結合しても、同じタイプのカーディナリティ推定の問題は発生しません。これを修正またはさらに調査する方法に関する提案はありますか?

Where句をクエリに追加すると、結合の前後の行数が正しく推定されます。

select * 
from fact_sales f
join dim_company d on f.company_SK = d.company_SK where company_SK = 1

結合から出てくる467,583,000行を推定します。これは、ヒストグラムの内容と一致します。

この問題は、クエリにフィルターがない場合にのみ発生するようです。より大きなクエリで問題が発生しています(ソート流出)。この特定の結合に絞り込みました。

FK制約はありますが、オフになっています(WITH NOCHECK)ファクトテーブルで(ETLをより高速に実行できるようにオフにするように指示されました)。残念ながら、FKをオンに戻すオプションはありません:(

更新:トレースフラグ2301を有効にすると問題が解決しました:p

5
user107507

レガシーCEおよびTF 4199を有効にしたSQL Server 2014で問題を再現できました。列ストアの経験がほとんどないため、行ストアのファクトテーブルを使用しました。

フィルター付きのクエリの場合、クエリオプティマイザーはクエリを次のように書き換えます。

select * 
from fact_sales f
join dim_company d on f.company_SK = d.company_SK 
where f.company_SK = 1 and d.company_SK = 1

そのクエリの場合、オプティマイザは両方のテーブルに1を含むヒストグラムステップを直接使用でき、推定行数として467,583,000 X 1を取得します。

フィルターなしのクエリ 線形補間を使用します

単一の等式または不等式の述語を使用した結合の場合、レガシーCEは線形補間を使用して2つのヒストグラムを段階的に位置合わせすることにより、結合列のヒストグラムを結合します。

ディメンションテーブルの統計には、RANGE_HI_KEY値が1のヒストグラムステップがないことに注意してください。これは、ほぼすべてのデータがファクトテーブルにある場所です。その値の線形補間ステップで問題が発生しています。 0の値なしでディメンションテーブルを作成すると、ヒストグラムはRANGE_HI_KEY値が1のステップを取得します。これにより、推定が修正されます。要するに、あなたはあなたのヒストグラムで不運になりました。クエリにフィルターを追加したいと思わない限り、ディメンションテーブルのヒストグラムに1のステップを含めるようにサポートする方法はないと思います。

データの正確なルールはわかりませんが、2つの回避策を提供できます。最初の回避策は、クエリのトレースフラグ2301を有効にすることです。これにより、クエリのこの部分の推定値は修正されますが、残りのクエリに他の悪影響が及ぶ可能性があります。このトレースフラグは 文書化 MSですが、使用する前にDBAに相談してください。

2番目の回避策は、クエリオプティマイザが結合にカーディナリティを推定する別の方法を使用するように促すことです。次のクエリは、私に適切な見積もりを与え、ファクトテーブルに対して1回のスキャンのみを実行します。

select * 
from FACT_SALES f
join (SELECT COMPANY_SK FROM DIM_COMPANY UNION SELECT 1) d
on f.company_SK = d.company_SK;
3
Joe Obbish