このクエリは複雑すぎません。
select
trunc(created_date, 'MONTH') as created_date,
al.op_name,
al.region,
al.alarm_type,
COUNT(1) as total_new,
SUM(
(SELECT
COUNT(1)
from alarm_table ial
WHERE ial.status_alarm = 'SOLVED'
AND TRUNC(ial.solved_date, 'MONTH') = TRUNC(al.created_date, 'MONTH')
AND ial.region = al.region
AND ial.op_name = al.op_name
AND ial.alarm_type = al.alarm_type)
) as total_solved
FROM
alarm_table al
WHERE
created_date is not null
group by
trunc(al.created_date, 'MONTH'),
al.op_name,
al.region,
al.alarm_type
order by trunc(al.created_date, 'MONTH') desc
そしてここにその説明計画があります:
Plan
SELECT STATEMENT ALL_ROWSCost: 5,497
3 SORT AGGREGATE Bytes: 51 Cardinality: 1
2 TABLE ACCESS BY INDEX ROWID TABLE USER.alarm_table Cost: 22 Bytes: 51 Cardinality: 1
1 INDEX RANGE SCAN INDEX USER.IDX_alarm_table_RESU Cost: 3 Cardinality: 73
6 SORT ORDER BY Cost: 5,497 Bytes: 1,055,263 Cardinality: 24,541
5 HASH GROUP BY Cost: 5,497 Bytes: 1,055,263 Cardinality: 24,541
4 TABLE ACCESS FULL TABLE USER.alarm_table Cost: 3,025 Bytes: 11,696,387 Cardinality: 272,009
質問は:私は列を含むインデックスを持っていますal.op_name
、al.region
およびal.alarm_type
(それ IDX_alarm_table_RESU
、これも最初の部分で使用します)。
それ以上の参加がないので、なぜそれはFTSをしているのですか?
外部選択では、where
句_created_date is not null
_に一致するテーブル内のすべての行を検索する必要があります。その列はそのインデックスに含まれていないため、インデックスは(統計的に)役に立ちません。通常、テーブル全体をスキャンする方が、インデックスを介してすべての行にアクセスするよりもはるかに高速です。
その句に使用できる個別のインデックスがある場合でも、十分に選択的でない場合(つまり、null
作成日を含む行の大部分がない場合)は、そうではない可能性があります。
そのインデックスを拡張できる場合は、trunc(created_date, 'MONTH')
をそれに追加し、(外部)where句を変更してその関数も使用するようにしてください(null
は関数を介して「伝播」します)。
その後、ステータス列を追加して、テーブルを完全に回避することもできます。
関数のインデックス作成はここでは機能しないようですが、日付のインデックス作成は外部クエリに役立つはずです。
しかし、クエリをさらに詳しく見てみると、selectリストのsum(select count(1) ...)
の意味がわかりません。これは、最もコストのかかる部分です。これが意味のあるものを返すとは思いません(グループあたりの行数×グループあたり_status='SOLVED'
_の行数)。
各グループ内に_status_alarm = 'SOLVED'
_を含む行数が必要な場合(これは私には理にかなっています)、次のことができます。
_sum(case when status_alarm = 'SOLVED' then 1 else 0 end) as total_solved
_
それとカバーするインデックスを使用すると、クエリは単一のインデックス高速フルスキャンで応答されます。
_Connected to:
Oracle Database 11g Express Edition Release 11.2.0.2.0 - 64bit Production
SQL>
SQL> drop table foo;
Table dropped.
SQL> create table foo(
2 cd date
3 , p1 number not null
4 , p2 number not null
5 , p3 number not null
6 , st number
7 , stuff char(250));
Table created.
SQL>
SQL> insert /*+ append */ into foo
2 select
3 case when mod(rownum,20) = 0 then null else sysdate-(rownum/10000) end td
4 ,round(dbms_random.value(0, 5)) p1
5 ,round(dbms_random.value(0, 5)) p2
6 ,round(dbms_random.value(0, 5)) p3
7 ,round(dbms_random.value(0, 4)) st
8 ,'lets imagine there are lots more columns in the table'
9 from dual connect by level <= 500000;
500000 rows created.
SQL> commit;
Commit complete.
SQL> create index foo_ix1 on foo(p1, p2, p3);
Index created.
SQL> create index foo_ix2 on foo(cd, p1, p2, p3, st);
Index created.
SQL> exec dbms_stats.gather_table_stats(ownname => user, tabname => 'FOO');
PL/SQL procedure successfully completed.
_
_SQL>
SQL> set timing on
SQL> set autotrace traceonly
SQL> select
2 trunc(cd, 'MONTH') cm
3 ,p1
4 ,p2
5 ,p3
6 ,count(1) as oc
7 ,sum(
8 (select count(1)
9 from foo b
10 where b.st = 0
11 and trunc(b.cd, 'MONTH') = trunc(a.cd, 'MONTH')
12 and b.p1 = a.p1
13 and b.p2 = a.p2
14 and b.p3 = b.p3)
15 ) as st
16 from
17 foo a
18 where
19 trunc(cd, 'MONTH') is not null
20 group by
21 trunc(cd, 'MONTH')
22 ,p1
23 ,p2
24 ,p3
25 order by
26 trunc(cd, 'MONTH');
648 rows selected.
Elapsed: 00:04:15.83
Execution Plan
----------------------------------------------------------
Plan hash value: 1720639959
------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time |
------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 475K| 7885K| | 5901 (3)| 00:01:11 |
| 1 | SORT AGGREGATE | | 1 | 20 | | | |
|* 2 | INDEX FAST FULL SCAN | FOO_IX2 | 28 | 560 | | 583 (2)| 00:00:07 |
| 3 | SORT ORDER BY | | 475K| 7885K| 14M| 5901 (3)| 00:01:11 |
| 4 | HASH GROUP BY | | 475K| 7885K| 14M| 5901 (3)| 00:01:11 |
|* 5 | INDEX FAST FULL SCAN| FOO_IX2 | 475K| 7885K| | 614 (7)| 00:00:08 |
------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter("B"."P1"=:B1 AND "B"."P2"=:B2 AND "B"."ST"=0 AND
TRUNC(INTERNAL_FUNCTION("B"."CD"),'fmmonth')=:B3)
5 - filter(TRUNC(INTERNAL_FUNCTION("CD"),'fmmonth') IS NOT NULL)
Statistics
----------------------------------------------------------
1 recursive calls
0 db block gets
22699250 consistent gets
3 physical reads
0 redo size
22461 bytes sent via SQL*Net to client
996 bytes received via SQL*Net from client
45 SQL*Net roundtrips to/from client
1 sorts (memory)
0 sorts (disk)
648 rows processed
_
それは多くの取得です。
_SQL>
SQL> select
2 trunc(cd, 'MONTH') cm
3 ,p1
4 ,p2
5 ,p3
6 ,count(1) as oc
7 ,sum(case when st = 0 then 1 else 0 end) as sc
8 from
9 foo a
10 where
11 trunc(cd, 'MONTH') is not null
12 group by
13 trunc(cd, 'MONTH')
14 ,p1
15 ,p2
16 ,p3
17 order by
18 trunc(cd, 'MONTH');
648 rows selected.
Elapsed: 00:00:00.18
Execution Plan
----------------------------------------------------------
Plan hash value: 4221217160
------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time |
------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 475K| 9277K| | 6438 (2)| 00:01:18 |
| 1 | SORT ORDER BY | | 475K| 9277K| 16M| 6438 (2)| 00:01:18 |
| 2 | HASH GROUP BY | | 475K| 9277K| 16M| 6438 (2)| 00:01:18 |
|* 3 | INDEX FAST FULL SCAN| FOO_IX2 | 475K| 9277K| | 614 (7)| 00:00:08 |
------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
3 - filter(TRUNC(INTERNAL_FUNCTION("CD"),'fmmonth') IS NOT NULL)
Statistics
----------------------------------------------------------
1 recursive calls
0 db block gets
2125 consistent gets
0 physical reads
0 redo size
21304 bytes sent via SQL*Net to client
996 bytes received via SQL*Net from client
45 SQL*Net roundtrips to/from client
1 sorts (memory)
0 sorts (disk)
648 rows processed
_
(インデックスがない場合でも、このバージョンは最初のバージョンよりも桁違いに効率的であることに注意してください。)