Oracle 11g検証 隠れた新機能検証 その2
<Oracle 11g検証 隠れた新機能検証 その2>
ペンネーム: ぽっちゃりメタボン
皆様、ごぶさたしています。ぽっちゃりメタボンです。
久しぶりの登場となりますがはりきっていきましょう。
先週から、Oracle 11gで追加された機能の中でも、大々的には取り上げられ
てはないけど開発者や管理者にとってかゆいところに手が届く機能をピックアップして
その機能を検証しています。先週は開発者にとっても有益なPIVOT関数について取り上げてみました。
第2回目は、こちらも便利なUNPIVOT関数について検証をしてみたいと思います。
■環境
Red Hat Enterprise Linux ES v.4 Update 5
Oracle Database 11g Enterprise Edition Release 11.1.0.6.0 – Production
■UNPIVOTとは?
前回はOracle11gから追加された関数PIVOT関数をご紹介しました。
PIVOTについては動作がイメージしやすいと思いますが、UNPIVOTについては皆様いかがでしょうか。
簡単に説明をしてしまうと、クロス集計されているような複数の値列を単一の列に変更してくれる関数です。
では、前回の検証でピボット化したテーブルを参考にUNPIVOT関数がどのような動きをするのか
確認していくことにしましょう。
■通常のSQLとUNPIVOT関数を使用したSQL
さて、まずはこのデータを前回同様JOBとDNAMEごとに集計した結果を確認しておきます。
1)
SQL> select emp.deptno,dname,job,sum(sal) sum_sal 2 from emp,dept 3 where emp.deptno = dept.deptno 4 group by emp.deptno,dname,job order by emp.deptno,dname,job; DEPTNO DNAME JOB SUM_SAL ---------- ------------ ---------- ---------- 10 ACCOUNTING CLERK 1300 10 ACCOUNTING MANAGER 2450 10 ACCOUNTING PRESIDENT 5000 20 RESEARCH ANALYST 6000 20 RESEARCH CLERK 1900 20 RESEARCH MANAGER 2975 30 SALES CLERK 950 30 SALES MANAGER 2850 30 SALES SALESMAN 5600
前回はこの結果をクロス集計データにピボット化しましたが
これを表として作成、保存しておきます。
2)
SQL> create table pivot as 2 select * from ( select emp.deptno,dname,job,sal from emp,dept 3 where emp.deptno = dept.deptno ) 4 pivot ( sum(sal) for job 5 in ('CLERK' as CLERK,'MANAGER' as MANAGER,'PRESIDENT' as PRESIDENT, 6 'ANALYST' as ANALYST,'SALESMAN' as SALESMAN) ) 7 ;
3)
SQL> select * from pivot; DEPTNO DNAME CLERK MANAGER PRESIDENT ANALYST SALESMAN ------ ----------- ------- ---------- ----------- ---------- ---------- 10 ACCOUNTING 1300 2450 5000 20 RESEARCH 1900 2975 6000 30 SALES 950 2850 5600
3)の表について自前のSQLでUNPIVOTを行うのであれば以下のSQLで実行が可能です。
※UNPIVOTは1)で確認したクロス集計する前の集計イメージへ再構築します。
4)
SQL> SELECT 2 DEPTNO, DNAME, JOB, SUM_SAL 3 FROM ( 4 (SELECT DEPTNO, DNAME, 'CLERK' JOB, CLERK SUM_SAL 5 FROM PIVOT) 6 UNION ALL (SELECT DEPTNO, DNAME, 'MANAGER' JOB, MANAGER SUM_SAL 7 FROM PIVOT) 8 UNION ALL (SELECT DEPTNO, DNAME, 'PRESIDENT' JOB, PRESIDENT SUM_SAL 9 FROM PIVOT) 10 UNION ALL (SELECT DEPTNO, DNAME, 'ANALYST' JOB, ANALYST SUM_SAL 11 FROM PIVOT) 12 UNION ALL (SELECT DEPTNO, DNAME, 'SALESMAN' JOB, SALESMAN SUM_SAL 13 FROM PIVOT) 14 ) DEPTNO DNAME JOB SUM_SAL ---------- --------------- --------------------------- ---------- 10 ACCOUNTING ANALYST 10 ACCOUNTING CLERK 1300 10 ACCOUNTING MANAGER 2450 10 ACCOUNTING PRESIDENT 5000 10 ACCOUNTING SALESMAN 20 RESEARCH ANALYST 6000 20 RESEARCH CLERK 1300 20 RESEARCH MANAGER 2975 20 RESEARCH PRESIDENT 20 RESEARCH SALESMAN 30 SALES ANALYST 30 SALES CLERK 950 30 SALES MANAGER 2850 30 SALES PRESIDENT 30 SALES SALESMAN 5600 15行が選択されました。
このように、複数列の値をJOBという単一の列として再構築できました。
列から行に再構築するためには union allで各カラム分のSQLを記述する必要があります。
では、いよいよUNPIVOT関数を実行してみます。
SQL> select * from pivot 2 unpivot include nulls 3 (sal_total for job in (CLERK,MANAGER,PRESIDENT,ANALYST,SALESMAN)) DEPTNO DNAME JOB SUM_SAL ---------- --------------- --------------------------- ---------- 10 ACCOUNTING ANALYST 10 ACCOUNTING CLERK 1300 10 ACCOUNTING MANAGER 2450 10 ACCOUNTING PRESIDENT 5000 10 ACCOUNTING SALESMAN 20 RESEARCH ANALYST 6000 20 RESEARCH CLERK 1300 20 RESEARCH MANAGER 2975 20 RESEARCH PRESIDENT 20 RESEARCH SALESMAN 30 SALES ANALYST 30 SALES CLERK 950 30 SALES MANAGER 2850 30 SALES PRESIDENT 30 SALES SALESMAN 5600
UNPIVOT関数を使用することにより非常にシンプルにSQLを記述でき、
同様の結果を得ることができました。
※1)と同様の結果を抽出する場合には “include nulls” ではなく、
“exclude nulls”と記述します。
これにより、SUM_SALの値がNULLのものを除外して抽出します。
■UNPIVOT関数の内部SQLとは?
UNPIVOT関数は、内部的にどのような処理をしているのでしょうか。
PIVOT関数同様に確認することにしましょう。
ということで、まずはお馴染みのSQLトレースを取得して確認してみることにしましょう。
SQL> alter session set events '10046 trace name context forever,level 12'; Session altered.
※SQLトレースファイル抜粋(TKPROFで整形済み)
select * from pivot unpivot include nulls (sal_total for job in (CLERK,MANAGER,PRESIDENT,ANALYST,SALESMAN)) call count cpu elapsed disk query current rows ------- ------ -------- ---------- ---------- ---------- ---------- ---------- Parse 1 0.00 0.00 0 0 0 0 Execute 1 0.00 0.00 0 0 0 0 Fetch 2 0.00 0.00 0 4 0 15 ------- ------ -------- ---------- ---------- ---------- ---------- ---------- total 4 0.00 0.00 0 4 0 15 Misses in library cache during parse: 0 Optimizer mode: ALL_ROWS Parsing user id: 81 Rows Row Source Operation ------- --------------------------------------------------- 15 VIEW (cr=4 pr=0 pw=0 time=0 us cost=15 size=615 card=15) 15 UNPIVOT (cr=4 pr=0 pw=0 time=0 us) 3 TABLE ACCESS FULL PIVOT (cr=4 pr=0 pw=0 time=0 us cost=3 size=72 card=3)
今回もUNPIVOTというオペレーションが実行されている事は実行計画から確認
できましたが、どのようなSQLが実行されているかまでは確認できません。
では、こちらも前回同様にUNPIVOT関数実行時のオプティマイザトレースを取得し、
内部ではどのようなSQL文が実行されているのか確認してみましょう。
以下のSQL文を実行します。
SQL> alter session set events '10053 trace name context forever,level 1'; Session altered.
※抜粋
SELECT "from$_subquery$_002"."DEPTNO" "DEPTNO", "from$_subquery$_002"."DNAME" "DNAME", "from$_subquery$_002"."JOB" "JOB", "from$_subquery$_002"."JOB_TOTAL" "JOB_TOTAL" FROM ( (SELECT "PIVOT"."DEPTNO" "DEPTNO", "PIVOT"."DNAME" "DNAME", 'CLERK' "JOB", "PIVOT"."CLERK" "JOB_TOTAL" FROM "SCOTT"."PIVOT" "PIVOT") UNION ALL (SELECT "PIVOT"."DEPTNO" "DEPTNO", "PIVOT"."DNAME" "DNAME", 'MANAGER' "JOB", "PIVOT"."MANAGER" "JOB_TOTAL" FROM "SCOTT"."PIVOT" "PIVOT") UNION ALL (SELECT "PIVOT"."DEPTNO" "DEPTNO", "PIVOT". "DNAME" "DNAME", 'PRESIDENT' "JOB", "PIVOT"."PRESIDENT" "JOB_TOTAL" FROM "SCOTT"."PIVOT" "PIVOT") UNION ALL (SELECT "PIVOT"."DEPTNO" "DEPTNO", "PIVOT"."DNAME" "DNAME", 'ANALYST' "JOB", "PIVOT"."ANALYST" "JOB_TOTAL" FROM "SCOTT"."PIVOT" "PIVOT") UNION ALL (SELECT "PIVOT"."DEPTNO" "DEPTNO", "PIVOT"."DNAME" "DNAME", 'SALESMAN' "JOB", "PIVOT" ."SALESMAN" "JOB_TOTAL" FROM "SCOTT"."PIVOT" "PIVOT") ) "from$_subquery$_002"
ふーむ、4)で作成したSQL文と同様のものが実行されてるようです。
指定カラム数分をUNON ALLで連結しているので索引での絞り込みがされないかつ、
指定カラム数が多い場合は、安易にUNPIVOT関数を実行してしまうと負荷が気になりますね。
※上記SQLの実行計画を確認しましたが、FULL SCANがPIVOT表に対して5回実行されます。
Rows Row Source Operation ------- --------------------------------------------------- 15 VIEW (cr=16 pr=2 pw=0 time=0 us cost=15 size=615 card=15) 15 UNION-ALL (cr=16 pr=2 pw=0 time=0 us) 3 TABLE ACCESS FULL PIVOT (cr=4 pr=2 pw=0 time=0 us cost=3 size=48 card=3) 3 TABLE ACCESS FULL PIVOT (cr=3 pr=0 pw=0 time=0 us cost=3 size=48 card=3) 3 TABLE ACCESS FULL PIVOT (cr=3 pr=0 pw=0 time=0 us cost=3 size=42 card=3) 3 TABLE ACCESS FULL PIVOT (cr=3 pr=0 pw=0 time=0 us cost=3 size=42 card=3) 3 TABLE ACCESS FULL PIVOT (cr=3 pr=0 pw=0 time=0 us cost=3 size=42 card=3)
上記のように、Oracle内部ではIN句で指定したカラム数分、
UNION ALLを使用した形でSQLを再構築し、展開されていることが確認できます。
実際の開発の現場や、ちょっとした分析を行いたいユーザにとっては、
簡単に要求を実現できる機能としては待ち望まれていたものかもしれませんね。
かくいう自分も、以前はプログラムで問い合わせ結果を一度配列に格納し、、、再構築。
もしくはSQLを駆使してクロス集計を行っていた口であります。
PIVOT、UNPIVOTを使用したviewを作成しておけば、データの分析、
確認などもお手軽に実行できますよね。
以上、2回にわたり分析関数PIVOT、UNPIVOTについて検証してきました。
次回は仮想列について検証を行う予定です。
お楽しみに!!
では、またお会いする日まで。
暑くもなく、寒くもなく快眠ができる 茅ヶ崎より