マテリアライズドビュー検証 まて マテ マテビュー その8
<マテリアライズドビュー検証 まて マテ マテビュー その8>
ペンネーム:クリープ
今回も引き続きクエリーリライトについて見て行きましょう。
最初に前回のクエリーリライト結果を確認して、その後にディメンションを利
用したクエリーリライトを見ていきます。
※前回の検証で作成したmv_emp_200というマテビューを作成してましたが、今
回の検証では必要のないマテビューでした。
その為、今回の検証ではこのマテビューは割愛しております。
■■■■■今回のあらすじ■■■■■
1)クエリーリライト:例3-2
2)クエリーリライト:例4(ディメンション)
■環境
Microsoft Windows XP Pro
Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 – Production
1)クエリーリライト:例3-2
早速、前回の確認から始めましょう!
前回作成したマテビューと実行した問合せは以下の通り。
□マテビュー
SQL> create materialized view mv_emp_1 enable query rewrite as SELECT job,
sum(sal) FROM emp WHERE sal BETWEEN 1 And 99 GROUP BY job;
SQL> create materialized view mv_emp_100 enable query rewrite as SELECT job,
sum(sal) FROM emp WHERE sal BETWEEN 100 And 199 GROUP BY job;
□実行した問合せ
SQL> SELECT job, sum(sal) FROM emp WHERE sal BETWEEN 1 And 200 GROUP BY job;
前回の検証では、実行した問合せのコストよりリライトしたコストの方が少な
い所まで確認しました。一体どのようなリライトが行われていたのでしょうか?
早速リライトされたSQL文を確認!
SQL> select rewritten_txt from rewrite_table where statement_id = 'REWRITE_TEST7' and sequence = 1; REWRITTEN_TXT --------------------------------------------------------------------- SELECT JOB JOB,SUM(VW_COL_1) SUM(SAL) FROM ( (SELECT /*+ */ MV_EMP_1 00.SUM(SAL),MV_EMP_100.JOB JOB FROM SCOTT.MV_EMP_100 MV_EMP_100) UNION ALL (SELECT /*+ */MV_EMP_1.SUM(SAL),MV_EMP_1.JOB JOB FROM SCOTT.MV_EMP_1 MV_EMP_1) UNION ALL (SELECT /*+ */ SUM(SAL),JOB JOB FROM EMP EMP WHERE SAL>99 AND SAL<100 OR SAL>199 AND SAL<=200 GROUP BY JOB)) $kkqs_mmv_ivview GROUP BY JOB
なんと!マテビューをUNION ALLで結合して取得しています。
しかも、マテビューだけでは取得できない値を元表であるEMPテーブルを集計
して取得しています。以下参照。
SALの値が、 ・0以上99以下の値 :mv_emp1 ・99より大きく100より小さい値 :emp ・100以上199以下の値 :mv_emp100 ・199より大きく200以下の値 :emp
もちろん、リライトされることでレスポンスが必ず向上する、とは言えません
が、マテビューの方が取得するデータ量が少なくなる可能性が高い、というこ
とは言えるでしょう。
それにしても、すごいリライト文です。。。
2)クエリーリライト:例4(ディメンション)
最後にディメンションを利用したクエリーリライトについて見てみましょう。
ディメンションとは、項目の親子関係を定義することができるオブジェクトで
す。ディメンションで親子関係が定義されていると、この親子関係を利用して
クエリーリライトすることが可能になります。
では、ディメンションを利用したクエリーリライトとはどのようなものなので
しょうか。実際に確認してみましょう。
まずは環境作成。ディメンションを利用する場合は初期化パラメータQUERY_RE
WRITE_INTEGRITYをTRUSTEDまたはSTALE_TOLERATEDに変更する必要があります。
SQL> ALTER SYSTEM SET QUERY_REWRITE_INTEGRITY='TRUSTED';
今回はテーブルも作成しましょう。
SQL> CREATE TABLE category ( job VARCHAR2(9) CONSTRAINT job_pkey PRIMARY KEY, job_category VARCHAR2(20) CONSTRAINT job_category_nn NOT NULL, job_sub_category VARCHAR2(20) CONSTRAINT job_sub_category_nn NOT NULL );
JOBをカテゴリー分けするテーブルを作成してみました。このテーブルは、
job_category(親) >> job_sub_category(子) >> job(孫)
という関係を意図して作成しております。
では、この関係をもとにディメンションを作成。
SQL> CREATE DIMENSION job_dim LEVEL mago IS (category.job) LEVEL ko IS (category.job_sub_category) LEVEL oya IS (category.job_category) HIERARCHY job_rollup ( mago CHILD OF ko CHILD OF oya);
LEVEL句で階層を定義し、HIERARCHY句で階層関係(親子関係)を定義していま
す。これでただの単体の項目から項目同士が親子関係を結んだ、ということに
なります。
環境が整ったところで、ディメンションを利用したクエリーリライトを見てみ
ましょう。
作成するマテビューは、EMPテーブルとCATEGORYテーブルをJOBで結合して、
JOB_SUB_CATEGORYで集計してみます。
実行する問合せはJOB_CATEGORYで集計します。
SQL> CREATE MATERIALIZED VIEW mv_job ENABLE QUERY REWRITE AS SELECT j.job_category, j.job_sub_category, SUM(e.sal) AS sum_sal FROM emp e, category j WHERE e.job = j.job GROUP BY j.job_category, j.job_sub_category; SQL> EXEC DBMS_MVIEW.EXPLAIN_REWRITE('SELECT j.job_category, SUM(e.sal) AS sum_sal FROM emp e, category j WHERE e.job = j.job GROUP BY j.job_category', statement_id => 'REWRITE_TEST8' ); SQL> select rewritten_txt from rewrite_table where statement_id = 'REWRITE_TEST8' and sequence = 1; REWRITTEN_TXT --------------------------------------------------------------------- SELECT MV_JOB.JOB_CATEGORY JOB_CATEGORY,SUM(MV_JOB.SUM_SAL) SUM_SAL FROM SCOTT.MV_JOB MV_JOB GROUP BY MV_JOB.JOB_CATEGORY
正常にリライトされました。。。
ん???
一体どこでディメンションが利用されているのでしょうか!???
一見ディメンションを参照しているように見えますが、実はこのクエリーリラ
イトはディメンション情報を参照していません。前に検証したクエリーリライ
トと同じリライトです。(まて マテ マテビュー その6参照)
では、ディメンションを利用したクエリーリライトを(今度は本当に)見てみ
ましょう。
SQL> DROP MATERIALIZED VIEW mv_job; SQL> CREATE MATERIALIZED VIEW mv_job ENABLE QUERY REWRITE AS SELECT j.job_sub_category, SUM(e.sal) AS sum_sal FROM emp e, category j WHERE e.job = j.job GROUP BY j.job_sub_category; SQL> EXEC DBMS_MVIEW.EXPLAIN_REWRITE('SELECT j.job_category, SUM(e.sal) AS sum_sal FROM emp e, category j WHERE e.job = j.job GROUP BY j.job_category', statement_id => 'REWRITE_TEST9' ); SQL> select rewritten_txt from rewrite_table where statement_id = 'REWRITE_TEST9' and sequence = 1; REWRITTEN_TXT --------------------------------------------------------------------- SELECT from$_subquery$_005.JOB_CATEGORY JOB_CATEGORY,SUM(MV_JOB.SUM_S AL) SUM_SAL FROM SCOTT.MV_JOB MV_JOB, (SELECT DISTINCT JOB_SUB_CATEGO RY JOB_SUB_CATEGORY,JOB_CATEGORY JOB_CATEGORY FROM CATEGORY CATEGORY) from$_subquery$_005 WHERE from$_subquery$_005.JOB_SUB_CATEGORY=MV_JO B.JOB_SUB_CATEGORY GROUP BY from$_subquery$_005.JOB_CATEGORY
リライトされたSQL文が非常に複雑になっています。。。
SQL文をみるとマテビューmv_jobにリライトされているようです。
では、解説。
まず、作成したマテビューは、JOB_SUB_CATEGORYのみを集計するように変更し
ております。一方、実行した問合せの方はJOB_CATEGORYで集計しています。
以下参照。
□マテビュー
SELECT job_sub_category, SUM(sal) FROM …
□問合せ
SELECT job_category, SUM(sal) FROM …
ディメンションが定義されていない場合、クエリーリライトではJOB_CATEGORY
の項目がマテビュー内に存在しない為、リライトすることができません。
しかし、ディメンションが定義されていると、JOB_SUB_CATEGORYの親がJOB_CA
TEGORYとして認識できるため、親の項目がマテビューになくてもリライトする
ことができます。
リライトされたSQL文を単純にすると以下のようになります。
SELECT JC.JOB_CATEGORY,SUM(MV.SUM_SAL) FROM MV_JOB MV, (SELECT DISTINCT JOB_SUB_CATEGORY, JOB_CATEGORY FROM CATEGORY ) JC WHERE JC.JOB_SUB_CATEGORY=MV.JOB_SUB_CATEGORY GROUP BY JC.JOB_CATEGORY
CATEGORYテーブルから親であるJOB_CATEGORYを引っ張り出して集計しています。
このように、ディメンションを利用することでマテビューに定義されていない
項目でもクエリーリライトすることができるようになります。
クエリーリライト、恐るべし。。。
以上、いくつかの例をもとにクエリーリライトを見てきました。
マテビューを使用していない方にはあまり馴染みのない機能だと思いますが、
Oracleが裏でいろいろやっているんだなぁ、ということは理解して頂けたこと
と思います。
次回は、マテビュー検証の総まとめをする予定です。
定義しないと築けない親子関係、何故か切なくなりました。 恵比寿にて