2億5000万件のレコードを持つテーブルにアクセスしているクエリからさらにパフォーマンスを引き出そうとしています。実際の(推定ではない)実行プランを読んだところ、最初のボトルネックは次のようなクエリです。
select
b.stuff,
a.added,
a.value
from
dbo.hugetable a
inner join
#smalltable b on a.fk = b.pk
where
a.added between @start and @end;
関連するテーブルとインデックスの定義については、下を参照してください。
実行計画は、ネストされたループが#smalltableで使用されていること、およびhugetableに対するインデックススキャンが480回(#smalltableの各行に対して)実行されていることを示しています。これは私には逆に思えるので、代わりにマージ結合を使用するように強制しようとしました:
select
b.stuff,
a.added,
a.value
from
dbo.hugetable a with(index = ix_hugetable)
inner merge join
#smalltable b with(index(1)) on a.fk = b.pk
where
a.added between @start and @end;
問題のインデックス(完全な定義については以下を参照)は、列fk(結合述語)をカバーし、追加(where句で使用)およびid(役に立たない)を昇順で含み、valueを含みます。
ただし、これを実行すると、クエリが2分半から9分以上に吹き飛ばされます。ヒントによって、各テーブルで1回のパスしか実行しないより効率的な結合が強制されることを期待していましたが、明らかにそうではありませんでした。
どんなガイダンスも大歓迎です。必要に応じて追加情報が提供されます。
アップデート(2011/06/02)
テーブルのインデックスを再編成したことで、大幅なパフォーマンスの向上が見られましたが、巨大なテーブルのデータを要約することに関して、新たな障害に直面しました。結果は月ごとの要約で、現在は次のようになります。
select
b.stuff,
datediff(month, 0, a.added),
count(a.value),
sum(case when a.value > 0 else 1 end) -- this triples the running time!
from
dbo.hugetable a
inner join
#smalltable b on a.fk = b.pk
group by
b.stuff,
datediff(month, 0, a.added);
現在、hugetableにはクラスター化インデックスpk_hugetable (added, fk)
(主キー)があり、非クラスター化インデックスはその逆ix_hugetable (fk, added)
です。
上記の4列目がない場合、オプティマイザーは以前と同様にネストされたループ結合を使用し、#smalltableを外部入力として使用し、非クラスター化インデックスシークを内部ループとして使用します(再度480回実行)。気になるのは、推定された行(12,958.4)と実際の行(74,668,468)の違いです。これらのシークの相対コストは45%です。ただし、実行時間は1分未満です。
4列目では、実行時間は4分に急上昇します。今回(2実行)は同じ相対コスト(45%)でクラスター化インデックスを検索し、ハッシュ一致(30%)を介して集計し、#smalltable(0%)でハッシュ結合を実行します。
私の次の行動方針がわかりません。私の懸念は、日付範囲検索も結合述部も保証されていないこと、または結果セットを大幅に削減する可能性が高いことです。ほとんどの場合、日付範囲はレコードのおそらく10〜15%しかトリムせず、fkの内部結合はおそらく20〜30%を除外する可能性があります。
ウィルAの要求に応じて、次の結果sp_spaceused
:
name | rows | reserved | data | index_size | unused
hugetable | 261774373 | 93552920 KB | 18373816 KB | 75167432 KB | 11672 KB
#smalltableは次のように定義されます:
create table #endpoints (
pk uniqueidentifier primary key clustered,
stuff varchar(6) null
);
一方、dbo.hugetableは次のように定義されています。
create table dbo.hugetable (
id uniqueidentifier not null,
fk uniqueidentifier not null,
added datetime not null,
value decimal(13, 3) not null,
constraint pk_hugetable primary key clustered (
fk asc,
added asc,
id asc
)
with (
pad_index = off, statistics_norecompute = off,
ignore_dup_key = off, allow_row_locks = on,
allow_page_locks = on
)
on [primary]
)
on [primary];
次のインデックスが定義されています:
create nonclustered index ix_hugetable on dbo.hugetable (
fk asc, added asc, id asc
) include(value) with (
pad_index = off, statistics_norecompute = off,
sort_in_tempdb = off, ignore_dup_key = off,
drop_existing = off, online = off,
allow_row_locks = on, allow_page_locks = on
)
on [primary];
IDのフィールドは、と主張した前回のDBAからアーチファクト冗長であるすべてのテーブルがどこにでもGUID、例外なくを持つ必要があります。