大規模なデータセットに対する CUBE 操作は非常にコストがかかるため、内部クエリでそのすべてのデータが本当に必要かどうかを確認する必要があります。内部で COUNT を実行してから、外部クエリでカウントの合計を取得していることがわかります。つまり、A1-A8 (-A7) のすべての組み合わせについて、A7 の行数を教えてください。次に、WHERE 句でフィルタリングされた選択された組み合わせの SUM のみを取得します。特定の列自体で CUBE を制限することでこれを確実に最適化できますが、これまでに気づいた非常に明白なことは次のとおりです。
以下のクエリを使用し、適切なインデックス o Table1 と Table_reject がある場合、両方のクエリがインデックスを利用して、結合してさらに処理する必要があるデータ セットを減らすことができます。100% 確信はありませんが、部分的な CUBE 処理が可能であり、それを確認する必要があります。
クラスタ化インデックス --> A8 で Table1 が必要で、Table_Reject では NAME でクラスタ化インデックスが必要です。
非クラスター化インデックス --> A3、A9 で Table1 が必要、B3、B2 で Table_reject が必要
SELECT qry1.
(
SELECT A1, A2,A3,A4,A5,A6,A7,A8
FROM table1
WHERE A8 >= NEXT_DAY ( trunc(to_date('17/09/2013 12:00:00','dd/mm/yyyy hh24:mi:ss')) ,'SUN' )
)qry1
LEFT JOIN
(
select B3,B2,ID
from table_reject
where name = 'smith'
)qry2
ON qry1.A3 = qry2.B3 and qry1.A9=qry2.B2
WHERE qry2.ID IS NULL
EDIT1:
すべての列で実行する場合、または結果セットで必要な列のみで実行する場合、CUBE 演算子の結果の違いを見つけようとしました。私が見つけたのは、CUBE関数が機能する方法であり、すべての列でCUBEを実行する必要はありません. 最後に、A1 と A8 が NOT NULL である CUBE によって生成された組み合わせを気にするだけだからです。このリンクを試して、出力を確認してください。
ここにリンクの説明を入力
クエリ 1 とクエリ 2 は、CUBE の結果セットを比較するための最も内側のクエリです。
Query3 と Query4 は、試しているのと同じクエリであり、結果はどちらの場合も同じであることがわかります。
DECLARE @NEXT_DAY DATE = NEXT_DAY ( trunc(to_date('17/09/2013 12:00:00','dd/mm/yyyy hh24:mi:ss')) ,'SUN' )
SELECT distinct A1 ,sum(total) as sum_total FROM
(
SELECT A1,COUNT(A7) AS total,A8
FROM (
select a.a1,a.a7,a.a8
from table1 a
left join (select * from table_reject where name = 'smith') b
on A.A3 = B.B3 and A.A9 =B.B2
where B.ID is null
) t1
WHERE A8 >= @NEXT_DAY
GROUP BY
CUBE(A1,A8)
)INN
WHERE INN.A1 IS NOT NULL AND
INN.A8 IS NOT NULL
GROUP BY A1
ORDER BY sum_total DESC ;
EDIT3
コメントで述べたように、これは Round3 の更新です。コメントは変更できませんが、Round3 ではなく Edit3 を意味していました。
クエリの新しい変更により、WHERE A8 >= @NEXT_DAY
一番左の結合選択にも条件が追加where A8 >= @NEXT_DAY AND B.ID is null
されます。それは選択を非常に改善しました。
最後のコメントで、クエリに 30 ~ 35 秒かかり、A8 の値を変更すると増加し続けると述べました。実行時間については、結果セットに含まれるデータの量について言及していませんでした。なぜそれが重要なのですか? 私のクエリが最終的な結果セットとして 5M 行を返す場合、そのデータを UI にドロップするか、使用している出力ファイルに 90% の時間を費やすことになるからです。ただし、実際のパフォーマンスは、クエリが最初の数行の提供を開始するまでの時間を測定する必要があります。その時までに、オプティマイザはすでに実行パートを決定しており、DB はそのプランを実行しているためです。それでも、クエリが100行を返し、10秒かかる場合、実行計画に問題がある可能性があることに同意します。
私がしたことは、ダミーデータを作成したことです。それに対してクエリを実行しました。Table1で説明したのと同じ列番号とデータ型を持つ9M行のテーブルTest_CubeDataがあります。2番目のテーブルTable_Rejectには、列数とクエリから把握したデータ型を持つ80K行があります。この表の極端な側面をテストします。name 列には「smith」という値が 1 つだけあり、ID は 80K 行すべてで null です。そのため、内部左結合の結果に影響を与える可能性のある列の値は B2 と B3 になります。
これらのテストでは、両方のテーブルにインデックスがありません。どちらもヒープです。結果セットの許容範囲のデータで、結果はまだ数秒で表示されます。結果データセットが増えると、完了時間が長くなります。説明されたインデックスを作成すると、これらすべてのテストされたケースに対してインデックスシーク操作が可能になります。しかし、ある時点で、そのインデックスも使い果たされ、Index Scan になります。A8列のフィルター値がその列に存在する最小の日付値である場合が確実な例の1つです。その場合、オプティマイザは、9M 行すべてが内部選択と CUBE に参加する必要があることを認識し、多くのデータがメモリで処理されます。これは期待されています。一方、クエリの別の例を見てみましょう。A8列に一意の32873値があり、それらの値は9M行にほぼ均等に分散されています。したがって、単一の A8 値ごとに 260 ~ 300 行あります。クエリを実行すると単一の値の最小値、最大値、またはクエリ実行時間の間の値は変更しないでください。
下の各画像で強調表示されているテキストは、A8 フィルターの値が選択されていることを示しています。重要な列は、* を使用する代わりに選択リストにのみ表示されています。左内側の結合クエリに A8 フィルターが追加されています。両方のテーブルでの TableScan 操作を示す実行計画です。秒単位のクエリ実行時間、およびクエリによって返される行の総数。
これにより、クエリのパフォーマンスに関するいくつかの疑問が解消され、正しい期待値を設定するのに役立つことを願っています.
**Table Row Counts**
**TableScan_InnerLeftJoin**
**TableScan_FullQuery_248Rows**
**TableScan_FullQuery_5K**
**TableScan_FullQuery_56K**
**TableScan_FullQuery_480k**