14

実行に1秒しかかからない次のSQLクエリがあります。

select a.date, b.rate, c.type, a.value from

a inner join b on a.id = b.aid
c inner join b.id = c.bid
where a.name = 'xxx'

しかし、レートが 0 より大きい結果を取得するには、結果セットが必要です。したがって、クエリを次のように変更すると、実行に 7 分かかります。

select a.date, b.rate, c.type, a.value from

a inner join b on a.id = b.aid
c inner join b.id = c.bid
where a.name = 'xxx' and b.rate>0

これにより、クエリ時間が 1 秒から 7 分に増加するのはなぜですか? b テーブルは巨大なので、CTE を使用しようとしましたが、パフォーマンスも向上しませんでした。CTE を使用すると、フィルタリングする値のセットが小さくなるので、高速になるはずですが、それは役に立ちませんでした。

;with x as
(select a.date, b.rate, c.type, a.value from

a inner join b on a.id = b.aid
c inner join b.id = c.bid
where a.name = 'xxx')
select * from x where rate>0

クエリ以外のデータベースへのアクセス許可がないため、実行計画を含めることはできません。

4

6 に答える 6

16

私の推測では、実行計画が遅いためrate>0に、ループ結合などの内部でのスキャンの一部として、残念な方法でフィルターが実行されていると思われます。

結局のところ、1 つの解決策は、中間結果セットを保存し、それを別のステートメントでフィルター処理することです。

ベンダーのデータベースに変更を加えることができず、基本的に行き詰まっていることを理解した上で、これをお勧めします。これは基本的に、オプティマイザから一部の制御を奪っています (通常はやりたくないことです)。また、一時テーブルの作成により、比較的少量のオーバーヘッドが追加されます。ただし、この場合の速度低下は緩和されるはずです。可能であれば、インデックス作成戦略についてベンダーと引き続き協力したいと思います。

select a.date, b.rate, c.type, a.value 
into #t
from a inner join b on a.id = b.aid
c inner join b.id = c.bid
where a.name = 'xxx' 

select * from #t where rate>0
于 2012-07-12T17:32:50.860 に答える
1

まず最初に、あなたが悪い計画を立てた理由を説明させてください。一つは、今考えられることです。レートがなかったとき。テーブル a が最初で、sarg と index に基づいて、10000 行と見積もられたと言います。これは、マージ結合を使用した可能性があります。今度は、テーブル b と結合します (現時点では、1 対 n のマッピングがあり、平均では a の行ごとに 2 つの行があると想定しています)。次に、結合後の推定行数は 20000 で、テーブル C と結合されています。テーブル C の大きさに基づいて、Merge Join を使用できたとします。実際の行は数十万であるとします。

しかし、SARG レート > 0 を追加すると、オプティマイザは A と B の結合後に 20K 行を推定せず、代わりに 6667 行を推定し (auto_create_statistics がオンになっていない場合、> 0 のデフォルトとして 30%)、選択した可能性があります。マージ結合ではなく、テーブル C との入れ子になったループ結合と言います。しかし、実際の行ははるかに多い可能性があるため、入れ子になったループ結合は数十万回使用された可能性があり、最終的な入れ子になったループ結合にはこれだけの時間がかかる可能性があります。

要約すると、私が言おうとしているのは、余分な sarg のためにオプティマイザーからの不適切な見積もりがあり、したがって悪い計画があったということです。

You do not create index here at all.Index is not the solution for each and every thing there are way too many overhead of having them and in specially your case the less restrictiev query is runing much better so issue is not to do with index but it is more to do with the statistics. Check following

Is auto_create_statistics on or off for your database?Or table b has stats for the column rate? When stats are updated/created for these tables? if not first create statistics for this column and I am sure your plan will be normal. If you can not create statistics then try to force the same plan as you are getting without rate > 0 CTE doesnt improve the code perf as such,there might be excpetion .These are there to make the code much more readable.

于 2012-07-14T12:02:00.973 に答える
0

レート名前の列にインデックスを作成すると、大きな違いが見られます。

編集:

列は 2 つの異なるテーブルに属しているため、2 つの個別のインデックスが必要になります。

編集:

索引付けのガイドライン

于 2012-07-12T17:03:08.343 に答える
0

CTE を使用してクエリを最適化する方法をサーバーに伝えようとしている場合は、冗談だと思います。インデックスを使用すると、より良い結果が得られます。しかし、いずれにせよ、あなたは頭にCTEの部分を持っているようです。サーバーに最初に CTE を実行してから、外部クエリを評価するように依頼します。このように、もしかして…

;with x as (Select a.id, a.date, a.value from a where a.name='xxx')
Select x.date, b.rate, c.type, x.value
From x
  Inner join b on x.id=b.aid
  Inner Join c on b.id=c.bid
where b.rate>0

また

;with x as (
   Select b.id, b.rate, c.type 
   From b 
     Inner Join c on b.id=c.bid
   where b.rate>0)
Select a.date, x.rate, x.type, a.value
From a
  Inner join x on a.id=b.id
Where a.name='xxx'
于 2012-07-12T17:09:49.970 に答える
-2

b>0サーバーはクラスター化インデックスやその他の方法を使用してクエリを最適化できなくなるため、この部分は大幅に変更されます。これを追加するb>0と、このクエリは範囲クエリになり、実際により多くの値をチェックする必要があるため、より多くの時間が必要になります。そのようなクエリの B ツリー編成など、いくつかの最適化が既に行われていると思いますが、それほど改善されることはありません。

于 2012-07-12T16:54:43.123 に答える