私は2つのテーブルを持っています(それらを変更することはできません)
Parent (id, date, amount)
Child (parent_id, key, value)
索引
Parent.pk (id)
Parent.idx1 (id, date) include (amount)
Child.pk (parent_id, key)
Child.idx1 (parent_id, key, value)
とクエリ
select sum(amount)
from Parent as p
left outer join Child as c1 on c1.parent_id = p.id and c1.key = 'X'
left outer join Child as c2 on c2.parent_id = p.id and c2.key = 'Y'
where p.date between '20120101' and '20120131'
and c1.value = 'x1'
and c2.value = 'y1'
問題はパフォーマンスです。
親には ~1,500,000 レコード、子には ~6,000,000 レコードがあります
テイク 1
このクエリには ~3 秒かかりますが、これは私のシナリオでは長すぎます。数ミリ秒未満である必要があります。
実行計画は、SQL Server がインデックス スキャンを実行しており、クラスター化されたインデックス シークをParent.idx1
使用してマージ結合を 実行していることを示しています。Child.idx1
テイク 2
私がに変更Parent.idx1
するとき
Parent.idx1 (date, id) include (amount)
Sqlサーバーは、クラスター化されたインデックススキャンを選択しParent.pk
、再び結合を結合しChild.idx1
ます。実行時間は約 6 秒です。
テイク 3
強制的に使用Parent.idx1 (date, id) include (amount)
すると、マージ結合の前に結果がソートされ、実行時間はさらに悪化します。
テイク 4
インデックス付きビューを作成しようとしましたが、LEFT OUTER JOIN のために使用できません。
そのようなクエリを作成する方法はありますか - 両方のフィルターを使用した親子結合 - より高速ですか?
非正規化なし。
更新 2013-07-04:
回答者には INNER JOIN を使用してください - はい、はるかに高速ですが、使用できません。
ここで示したのは、私が本当に必要としているものの単純化されたバージョンです。
MS Dynamics NAV の "G/L Entry" (親) テーブルと "Ledger Entry Dimension" (子) テーブルの SQL ビューを作成して、そのアプリケーションから読み取ることができるようにする必要があります。現在、完全なビューは次のようになっています。
create view analysis
as
select
v.id as view_id
, p.date
, p.Amount
, c1.value as value1
, c2.value as value2
, c3.value as value3
, c4.value as value4
from Parent as p
cross join analysis_view as v
left outer join Child as c1 on c1.parent_id = p.id and c1.key = v.key1
left outer join Child as c2 on c2.parent_id = p.id and c2.key = v.key2
left outer join Child as c3 on c3.parent_id = p.id and c3.key = v.key3
left outer join Child as c4 on c4.parent_id = p.id and c4.key = v.key4
ここで、analysis_view には現在 8 つのレコードが含まれており、次のようanalysis_view (id, key1, key2, key3, key4)
になっています。
select sum(amount)
from analysis
where view_id = 1 and date between '20120101' and '20120131'
and value1 = 'x1'
and value2 = 'x2'
また
select sum(amount)
from analysis
where view_id = 1 and date between '20120101' and '20120131'
and value1 = 'x1'
and value3 = 'z1'
MS Dynamics NAV には既に正規化されていないテーブルがあり、そこからのクエリは高速ですが、私たちの場合は非常に大きく (~10GB)、誰かが新しい分析ビューを作成すると、システム全体が約 1 時間ロックされます。また、NAV は結合を生成する方法を認識していないため、SQL Server 側で定義する必要があります。