Oracle EEのオプションで最も使うと思われるものがPartitioning Optionではないかと個人的に思っています。小幡さんのブログ(Storage Serverフィルタリング考察)にてPartition Viewという懐かしいモノが紹介されていました。7.2で鳴り物入りと書かれていましたが、すぐにPartitioning Tableがリリースされて陽の目を見なかったですね。。。
しかし、Partition ViewにはPartitioning Tableにない素晴らしい点があります。それは、EEじゃなくても使える。頑張って作りこめばPartitioning Optionみたいに使える(これは利点なのか...?)ことです。
というわけで、一回、Partition Viewをまとめてみます。
* 個人的には、昔、この機能を使いこなそうとかなり苦労しました。
まず、大前提です。
もう一度書きますが、あくまでもビューです。
では、普通のビューとどう違うのか?
それは、たった1つなのですが、現在のPartitioning TableのようにPartition ViewへのQueryの実行計画をPartitionを考慮して立ててくれること。です。
事前に準備すべき事は以下となります。
1のチェック制約を見て、ナルホドと思いますね。単純というか何と言うか...
では、一応、やってみます。
先程、書きましたが、通常のビューとパーティションビューの違いは、メンバーとなるテーブルにチェック制約がついているか否かの違いです。
では、データを入れますが、ビュー経由で直接データのinsertはできません、やりたいなら、(Partitioning Tableのように扱いたいなら)ビューに対してinstead triggerなどを仕込む必要があります。(今回は、面倒なので、テーブルにinsertしています)
では、一番大事な、SELECTの実行計画を見てみます。
全てのパーティション(あえてパーティションと呼びます)に適切なインデックスは作成していないので、T2010Q1パーティションのフルスキャンは許せますが、全パーティションにフルスキャンが発生しています。何とかしたいですよね。
続いてパーティションビューの実行計画を見てみます。
先程と違いFILTERオペレーションが追加されました。これは、FILTERの結果FALSEなら、後続のオペレーションを実行する。という意味なので。
P2010Q1パーティションは必ずフルスキャンを実行しますが、その他のパーティションには、FILTERがかかり、フルスキャンを実行しない(というかテーブルへのアクセスもしない)ということになります。
かなり、かなり限定的(もしくは、相当いじり倒せば)Partition Viewも活躍できる場がありそうです。皆様も困った時に思い出してみてください。
しかし、Partition ViewにはPartitioning Tableにない素晴らしい点があります。それは、EEじゃなくても使える。頑張って作りこめばPartitioning Optionみたいに使える(これは利点なのか...?)ことです。
というわけで、一回、Partition Viewをまとめてみます。
* 個人的には、昔、この機能を使いこなそうとかなり苦労しました。
まず、大前提です。
- 基本的には、Partitioning Tableのように論理的に一つのテーブルとして扱えません(あくまでも1つのビューです)
- なので、グローバルインデックスや、カラムの追加/削除、パーティションの追加/削除といったことは透過的に実行できません。
- さらに、DMLもビューに対して実行できません(union all viewなので)
もう一度書きますが、あくまでもビューです。
では、普通のビューとどう違うのか?
それは、たった1つなのですが、現在のPartitioning TableのようにPartition ViewへのQueryの実行計画をPartitionを考慮して立ててくれること。です。
事前に準備すべき事は以下となります。
- 各テーブルのPartition Keyとなるカラムにはチェック制約が必要
- 初期化パラメータ(partition_view_enabled)がTRUE(ただし、大昔から、このパラメータは無くなり_partition_view_enabledがデフォルトTRUEとなっていますので、余り気にしない)
1のチェック制約を見て、ナルホドと思いますね。単純というか何と言うか...
では、一応、やってみます。
-- 通常のビュー用
-- 2010 Q1
create table t2010q1 (term date
, id number
, text varchar2(4000));
-- 2010 Q2
create table t2010q2 (term date
, id number
, text varchar2(4000));
-- 2010 Q3
create table t2010q3 (term date
, id number
, text varchar2(4000));
-- 2010 Q4
create table t2010q4 (term date
, id number
, text varchar2(4000));
-- パーティションビュー用
-- 2010 Q1
create table p2010q1 (term date
, id number
, text varchar2(4000)
, constraint p2010q1_chk
check(term >= to_date('2010/01/01 00:00:00', 'yyyy/mm/dd hh24:mi:ss')
and term <= to_date('2010/03/31 23:59:59', 'yyyy/mm/dd hh24:mi:ss'))
);
-- 2010 Q2
create table p2010q2 (term date
, id number
, text varchar2(4000)
, constraint p2010q2_chk
check(term >= to_date('2010/04/01 00:00:00', 'yyyy/mm/dd hh24:mi:ss')
and term <= to_date('2010/06/30 23:59:59', 'yyyy/mm/dd hh24:mi:ss'))
);
-- 2010 Q3
create table p2010q3 (term date
, id number
, text varchar2(4000)
, constraint p2010q3_chk
check(term >= to_date('2010/07/01 00:00:00', 'yyyy/mm/dd hh24:mi:ss')
and term <= to_date('2010/09/30 23:59:59', 'yyyy/mm/dd hh24:mi:ss'))
);
-- 2010 Q4
create table p2010q4 (term date
, id number
, text varchar2(4000)
, constraint p2010q4_chk
check(term >= to_date('2010/10/01 00:00:00', 'yyyy/mm/dd hh24:mi:ss')
and term <= to_date('2010/12/31 23:59:59', 'yyyy/mm/dd hh24:mi:ss'))
);
-- 通常のビューの作成
create or replace view t2010 as
select * from t2010q1
union all
select * from t2010q2
union all
select * from t2010q3
union all
select * from t2010q4;
-- パーティションビューの作成
create or replace view p2010 as
select * from p2010q1
union all
select * from p2010q2
union all
select * from p2010q3
union all
select * from p2010q4;
先程、書きましたが、通常のビューとパーティションビューの違いは、メンバーとなるテーブルにチェック制約がついているか否かの違いです。
では、データを入れますが、ビュー経由で直接データのinsertはできません、やりたいなら、(Partitioning Tableのように扱いたいなら)ビューに対してinstead triggerなどを仕込む必要があります。(今回は、面倒なので、テーブルにinsertしています)
declare
dt date;
tbl varchar2(30);
begin
for dy in 0 .. 364 loop
dt := to_date('2010/01/01 00:00:00', 'yyyy/mm/dd hh24:mi:ss') + dy;
if dt >= to_date('2010/01/01 00:00:00', 'yyyy/mm/dd hh24:mi:ss') and
dt <= to_date('2010/03/31 23:59:59', 'yyyy/mm/dd hh24:mi:ss') then
tbl := '2010q1';
elsif dt >= to_date('2010/04/01 00:00:00', 'yyyy/mm/dd hh24:mi:ss') and
dt <= to_date('2010/06/30 23:59:59', 'yyyy/mm/dd hh24:mi:ss') then
tbl := '2010q2';
elsif dt >= to_date('2010/07/01 00:00:00', 'yyyy/mm/dd hh24:mi:ss') and
dt <= to_date('2010/09/30 23:59:59', 'yyyy/mm/dd hh24:mi:ss') then
tbl := '2010q3';
elsif dt >= to_date('2010/10/01 00:00:00', 'yyyy/mm/dd hh24:mi:ss') and
dt <= to_date('2010/12/31 23:59:59', 'yyyy/mm/dd hh24:mi:ss') then
tbl := '2010q4';
else
tbl := '';
end if;
if tbl is not null then
for h in 0 .. 23 loop
for m in 0 .. 60 loop
begin
execute immediate 'insert all ' ||
'into ' || 't' || tbl || ' values (:1, :2, :3) ' ||
'into ' || 'p' || tbl || ' values (:4, :5, :6) ' ||
'select * from dual'
using dt + h/24 + m/24/60
, dy + h/100 + m/10000
,'sample'
, dt + h/24 + m/24/60
, dy + h/100 + m/10000
,'sample';
exception
when others then
null;
end;
end loop;
commit;
end loop;
commit;
end if;
end loop;
commit;
end;
/
では、一番大事な、SELECTの実行計画を見てみます。
SQL> select count(*) from t2010 where term = to_date('2010/01/01','yyyy/mm/dd');
COUNT(*)
----------
1
実行計画
----------------------------------------------------------
Plan hash value: 709745821
--------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 9 | 548 (1)| 00:00:07 |
| 1 | SORT AGGREGATE | | 1 | 9 | | |
| 2 | VIEW | T2010 | 20 | 180 | 548 (1)| 00:00:07 |
| 3 | UNION-ALL | | | | | |
|* 4 | TABLE ACCESS FULL| T2010Q1 | 5 | 45 | 137 (1)| 00:00:02 |
|* 5 | TABLE ACCESS FULL| T2010Q2 | 5 | 45 | 137 (1)| 00:00:02 |
|* 6 | TABLE ACCESS FULL| T2010Q3 | 5 | 45 | 137 (1)| 00:00:02 |
|* 7 | TABLE ACCESS FULL| T2010Q4 | 5 | 45 | 137 (1)| 00:00:02 |
--------------------------------------------------------------------------------
全てのパーティション(あえてパーティションと呼びます)に適切なインデックスは作成していないので、T2010Q1パーティションのフルスキャンは許せますが、全パーティションにフルスキャンが発生しています。何とかしたいですよね。
続いてパーティションビューの実行計画を見てみます。
SQL> select count(*) from p2010 where term = to_date('2010/01/01','yyyy/mm/dd');
COUNT(*)
----------
1
実行計画
----------------------------------------------------------
Plan hash value: 3622780762
---------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 9 | 137 (1)| 00:00:02 |
| 1 | SORT AGGREGATE | | 1 | 9 | | |
| 2 | VIEW | P2010 | 8 | 72 | 137 (1)| 00:00:02 |
| 3 | UNION-ALL | | | | | |
|* 4 | TABLE ACCESS FULL | P2010Q1 | 5 | 45 | 137 (1)| 00:00:02 |
|* 5 | FILTER | | | | | |
|* 6 | TABLE ACCESS FULL| P2010Q2 | 5 | 45 | 137 (1)| 00:00:02 |
|* 7 | FILTER | | | | | |
|* 8 | TABLE ACCESS FULL| P2010Q3 | 5 | 45 | 137 (1)| 00:00:02 |
|* 9 | FILTER | | | | | |
|* 10 | TABLE ACCESS FULL| P2010Q4 | 5 | 45 | 137 (1)| 00:00:02 |
---------------------------------------------------------------------------------
先程と違いFILTERオペレーションが追加されました。これは、FILTERの結果FALSEなら、後続のオペレーションを実行する。という意味なので。
P2010Q1パーティションは必ずフルスキャンを実行しますが、その他のパーティションには、FILTERがかかり、フルスキャンを実行しない(というかテーブルへのアクセスもしない)ということになります。
かなり、かなり限定的(もしくは、相当いじり倒せば)Partition Viewも活躍できる場がありそうです。皆様も困った時に思い出してみてください。
コメント
コメントを投稿