2024年9月 7日 (土)

VirtualBox-7.1.0_BETA2-164697 (2024-09-06T20:27:41Z) for macOS/ARM64における現時点でのOracle Database 21cの起動、停止時間の記録 (VM起動せず)

TestBuild Development Snapshotが 7.1.0_BETA2-164697 (2024-09-06T20:27:41Z) になっていましたが。前回、前々回同様、7.0の初期のころに先祖返りしたような感じで、x86系VMは以下のメッセージとともに起動できず。(起動時間計測が毎回の楽しみになってきたのでw、早く組み込んでもらいたいですね7.1.0 BETAにも :)

M1

oracle@Mac-Studio ~ % ./print_env.sh

*** mac info. ***
ProductName: macOS
ProductVersion: 14.6.1
BuildVersion: 23G93

*** maxOS ver. ***
Model Name: Mac Studio
Chip: Apple M1 Ultra
Total Number of Cores: 20 (16 performance and 4 efficiency)
Memory: 64 GB

*** VirtualBox ver. ***
7.1.0_BETA2r164697


20240907-70915

VMが起動するとかしないとか以前の状況、この部分だけみると先祖返りしちゃってるんで、組み込まれるまではしばらくかかりそうですね。
(7.1.0_BETAになった3度目の更新ですが....)

この状況は、以前のリリースで起動していたVMでも、VirtualBox-7.1.0_BETA2-164697 にインポートしたx86系VMでも同様です。

20240907-71555

次の更新を楽しみにして、じっと待つ:)



一瞬、秋?みたいな感じの気温だったが、真夏に逆戻りの東京より

ではまた。:)



MySQL 8.0.32 , PostgreSQL 13.4 and Oracle Database 21c on Oracle Linux 8 on VirtualBox for Apple Silicon Test Build 7.0.97_BETA5r160702
ySQL 8.0.32 , PostgreSQL 13.6 and Oracle Database 21c on Oracle Linux 8.5 on VirtualBox for Apple Silicon Test Build 7.0.97_BETA5r161342
MySQL 8.0.32 , PostgreSQL 13.6 and Oracle Database 21c on Oracle Linux 8.5 on VirtualBox for Apple Silicon Test Build 7.0.97_BETA5r161709
MySQL 8.0.36 , PostgreSQL 13.14, Oracle Database 21c, Oracle Database 23ai on VirtualBox for Apple Silicon Test Build 7.0.97_BETA r162957
VirtualBox TestBuild for macOS/ARM64における現時点でのOracle Database 21cの起動、停止時間の記録 / 7.0.97r162957(2024/4/26) / 7.0.97r163029(2024/5/3)
VirtualBox TestBuild 7.0.97r163376 (2024-05-28T15:08:56Z) for macOS/ARM64における現時点でのOracle Database 21cの起動、停止時間の記録
VirtualBox TestBuild 7.0.97r163425 (2024-06-05T13:13:46Z) for macOS/ARM64における現時点でのOracle Database 21cの起動、停止時間の記録
VirtualBox TestBuild 7.0.97r163606 (2024-06-21T11:55:16Z) for macOS/ARM64における現時点でのOracle Database 21cの起動、停止時間の記録
VirtualBox TestBuild 7.1.0_BETA1r164292 (2024-08-07T18:27:07Z) for macOS/ARM64における現時点でのOracle Database 21cの起動、停止時間の記録
VirtualBox TestBuild 7.1.0_BETA1r164387 (2024-08-15T17:27:33Z) for macOS/ARM64における現時点でのOracle Database 21cの起動、停止時間の記録

| | | コメント (0)

2024年8月16日 (金)

VirtualBox TestBuild 7.1.0_BETA1r164387 (2024-08-15T17:27:33Z) for macOS/ARM64における現時点でのOracle Database 21cの起動、停止時間の記録

VirtualBox 7.1.0_BETA1r164378が8/15に公開されていましたが、今回もGuestVM起動できず、計測不能でした。

20240816-33746

ちなみに、VirtualBox Extension PackもVersionが古く(7.0.97.163425なのでかなり古いですね)インストールできないミスマッチの状態となっているので、そのあたりも影響しているのかもしれません。TestBuildsですからね。長ーい目で見守りましょう。 7.1になってから二回目の更新ですし:)

20240816-40340

20240816-34235

 

20240816-40543

インストールされたVirtualBoxのリリースは、7.1.0_BETA1r164378

20240816-35226

ということで、強烈な台風が近づいている東京より。

みなさん、安全を最優先に:)

ではまた。

 


MySQL 8.0.32 , PostgreSQL 13.4 and Oracle Database 21c on Oracle Linux 8 on VirtualBox for Apple Silicon Test Build 7.0.97_BETA5r160702
ySQL 8.0.32 , PostgreSQL 13.6 and Oracle Database 21c on Oracle Linux 8.5 on VirtualBox for Apple Silicon Test Build 7.0.97_BETA5r161342
MySQL 8.0.32 , PostgreSQL 13.6 and Oracle Database 21c on Oracle Linux 8.5 on VirtualBox for Apple Silicon Test Build 7.0.97_BETA5r161709
MySQL 8.0.36 , PostgreSQL 13.14, Oracle Database 21c, Oracle Database 23ai on VirtualBox for Apple Silicon Test Build 7.0.97_BETA r162957
VirtualBox TestBuild for macOS/ARM64における現時点でのOracle Database 21cの起動、停止時間の記録 / 7.0.97r162957(2024/4/26) / 7.0.97r163029(2024/5/3)
VirtualBox TestBuild 7.0.97r163376 (2024-05-28T15:08:56Z) for macOS/ARM64における現時点でのOracle Database 21cの起動、停止時間の記録
VirtualBox TestBuild 7.0.97r163425 (2024-06-05T13:13:46Z) for macOS/ARM64における現時点でのOracle Database 21cの起動、停止時間の記録
VirtualBox TestBuild 7.0.97r163606 (2024-06-21T11:55:16Z) for macOS/ARM64における現時点でのOracle Database 21cの起動、停止時間の記録
VirtualBox TestBuild 7.1.0_BETA1r164292 (2024-08-07T18:27:07Z) for macOS/ARM64における現時点でのOracle Database 21cの起動、停止時間の記録

 



| | | コメント (0)

2024年8月 8日 (木)

VirtualBox TestBuild 7.1.0_BETA1r164292 (2024-08-07T18:27:07Z) for macOS/ARM64における現時点でのOracle Database 21cの起動、停止時間の記録

VirtualBox TestBuild 7.1.0_BETA1r164292 (2024-08-07T18:27:07Z) が公開されていました。

7.1になり、アイコンやスプラッシュも変更されたようですが、、、久しぶりに計測できず! (次回に期待したいと思います!)

 

20240808-50049


20240808-50147


20240808-50318

以下、M1/M2いずれもGuest VM起動できませんでした!

20240808-51648

 

M1

*** mac info. ***
ProductName: macOS
ProductVersion: 14.6.1
BuildVersion: 23G93

*** maxOS ver. ***
Model Name: Mac Studio
Chip: Apple M1 Ultra
Total Number of Cores: 20 (16 performance and 4 efficiency)
Memory: 64 GB

*** VirtualBox ver. ***
7.1.0_BETA1r164292

 

M2

*** mac info. ***
Model Name: MacBook Air
Chip: Apple M2
Total Number of Cores: 8 (4 performance and 4 efficiency)
Memory: 24 GB

*** macOS ver. ***
ProductName: macOS
ProductVersion: 14.5
BuildVersion: 23F79

*** VirtualBox ver. ***
7.1.0_BETA1r164292

7.1になった影響だろうか。。。
なお、今回は旧リリースのVirtualBox TestBuild 7.0.97r163779 (2024-07-04T18:53:02Z) をアップデートしただけ(本来それで良いはずだが)なので、VMのインポートし直した場合も同様の結果、No Supported 。どうなってるんだろう。どうなるかまでは未確認です。
(検証後、本エントリーへ追加する予定)


しかし、酷暑と夕方のCloud 9もくもく後のゲリラ豪雨が、夏のニューノーマルになってしまうと夏のイベントは秋にでもしないと無理かもしれないですねー。花笠祭りも影響受けたようですし。
ちなみに、多摩川花火大会は、何年か前のゲリラ豪雨以後、10月開催に切り替えた経緯がありますよね。。

ではまた。

 



MySQL 8.0.32 , PostgreSQL 13.4 and Oracle Database 21c on Oracle Linux 8 on VirtualBox for Apple Silicon Test Build 7.0.97_BETA5r160702
ySQL 8.0.32 , PostgreSQL 13.6 and Oracle Database 21c on Oracle Linux 8.5 on VirtualBox for Apple Silicon Test Build 7.0.97_BETA5r161342
MySQL 8.0.32 , PostgreSQL 13.6 and Oracle Database 21c on Oracle Linux 8.5 on VirtualBox for Apple Silicon Test Build 7.0.97_BETA5r161709
MySQL 8.0.36 , PostgreSQL 13.14, Oracle Database 21c, Oracle Database 23ai on VirtualBox for Apple Silicon Test Build 7.0.97_BETA r162957
VirtualBox TestBuild for macOS/ARM64における現時点でのOracle Database 21cの起動、停止時間の記録 / 7.0.97r162957(2024/4/26) / 7.0.97r163029(2024/5/3)
VirtualBox TestBuild 7.0.97r163376 (2024-05-28T15:08:56Z) for macOS/ARM64における現時点でのOracle Database 21cの起動、停止時間の記録
VirtualBox TestBuild 7.0.97r163425 (2024-06-05T13:13:46Z) for macOS/ARM64における現時点でのOracle Database 21cの起動、停止時間の記録
VirtualBox TestBuild 7.0.97r163606 (2024-06-21T11:55:16Z) for macOS/ARM64における現時点でのOracle Database 21cの起動、停止時間の記録
VirtualBox TestBuild 7.0.97r163779 (2024-07-04T18:53:02Z) for macOS/ARM64における現時点でのOracle Database 21cの起動、停止時間の記録

 

| | | コメント (0)

2024年7月10日 (水)

帰ってきた! 標準はあるにはあるが癖の多いSQL #15 - 実行計画でスカラー副問合せの見せ方にも癖がでる

さて、今日はまた、癖の話をしたいと思います!
今回のネタには標準があるわけではないですが、SELECTリストに記述するスカラー副問合せの実行計画上の見せ方の癖というか違いw

実は、このネタ、2020年ぐらいに、目黒方面(ご存知の方だけwww)にある某所で定期開催される内部勉強会的なLT大会で使ったネタだったのですが、そのあとゴタゴタしていて、ブログで書き漏らしていたことを、昨日ネタリストを纏めていた時に思い出した次いでに小ネタとして書いておきます。 (その時のKeynoteのタイトルページだけ載せておきますw)

20240710-141853


この癖を把握していれば、SELECTリストに記述されたスカラー副問合せチューニングするような案件に遭遇してしまったときでも何かの役に立つかもしれません。
(少なくとも実行計画を見ただけで、これはSELECTリストにスカラー副問合せがある! ということは一瞬で理解できるようになるはず。。。)

では早速見てみましょう。(Oracle Databaseではお馴染みの表とデータをMySQL/PostgreSQLでも事前に作成してあります)

SCOTT@orclpdb1> select * from dept;

DEPTNO DNAME LOC
---------- ------------------------------------------ ---------------------------------------
10 ACCOUNTING NEW YORK
20 RESEARCH DALLAS
30 SALES CHICAGO
40 OPERATIONS BOSTON

SCOTT@orclpdb1> select * from emp;

EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
---------- ------------------------------ --------------------------- ---------- -------- ---------- ---------- ----------
7369 SMITH CLERK 7902 80-12-17 800 20
7499 ALLEN SALESMAN 7698 81-02-20 1600 300 30
7521 WARD SALESMAN 7698 81-02-22 1250 500 30
7566 JONES MANAGER 7839 81-04-02 2975 20
7654 MARTIN SALESMAN 7698 81-09-28 1250 1400 30
7698 BLAKE MANAGER 7839 81-05-01 2850 30
7782 CLARK MANAGER 7839 81-06-09 2450 10
7839 KING PRESIDENT 81-11-17 5000 10
7844 TURNER SALESMAN 7698 81-09-08 1500 0 30
7900 JAMES CLERK 7698 81-12-03 950 30
7902 FORD ANALYST 7566 81-12-03 3000 20
7934 MILLER CLERK 7782 82-01-23 1300 10

実行計画で見えるSELECT中のスカラー副問合せの位置に注目してください。(赤字にしてあります)

Oracle Databaseでは本体のクエリーより上に表示されますが、PostgreSQL/MySQLでは逆で、下に表示されます。

このような見せ方の違いが逆になるのって以前もご紹介したの覚えているでしょうか?
そう、帰ってきた! 標準はあるにはあるが癖の多いSQL #7 - Hash Joinの実行計画の見せ方にも癖がでるで紹介した癖ですね。
HASH JOINのBUILD/PROBEは実行計画上、Oracle DatabaseとPostgreSQL/MySQLでは順序が逆に表現されていましたよね!

これに気づけば、あなたも、道にまようこともなく実行計画を追っていけるはず!! :)

Oracle Database (21c)
(このようにスカラー副問合せ部分が性能上ネックになりそうな場合、Oracle Databaseのオプティマイザは、スカラー副問合せを結合に書き換えて最適化することがあるため、この例ではそれを無効化するNO_UNNESTヒントを利用しています。)

Oracle Database 21c Enterprise Edition Release 21.0.0.0.0 - Production
Version 21.3.0.0.0
に接続されました。
SCOTT@orclpdb1> !cat scalar_subquery_plan.sql
SELECT
deptno
,dname
,(
SELECT
/*+ NO_UNNEST */
MAX(sal)
FROM
emp
WHERE
emp.deptno = dept.deptno
) AS max_sal
FROM
dept
ORDER BY
deptno
;

SCOTT@orclpdb1> set autot trace exp stat
SCOTT@orclpdb1> @scalar_subquery_plan.sql

経過: 00:00:00.18

実行計画
----------------------------------------------------------
Plan hash value: 1445953226

------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 5 | 65 | 9 (0)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | 7 | | |
| 2 | TABLE ACCESS BY INDEX ROWID BATCHED| EMP | 4 | 28 | 2 (0)| 00:00:01 |
|* 3 | INDEX RANGE SCAN | IX_DEPT | 4 | | 1 (0)| 00:00:01 |
| 4 | TABLE ACCESS BY INDEX ROWID | DEPT | 5 | 65 | 3 (0)| 00:00:01 |
| 5 | INDEX FULL SCAN | PK_DEPT | 5 | | 1 (0)| 00:00:01 |
------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

3 - access("EMP"."DEPTNO"=:B1)


見ての通り、PostgreSQL/MySQLはスカラー副問合せ部分の実行計画の位置がOracle Databaseのそれとは異なることがわかると思います。:)
PostgreSQL(13.14)

perftestdb=> \! cat scalar_subquery_plan.sql
EXPLAIN ANALYZE
SELECT
deptno
,dname
,(
SELECT
MAX(sal)
FROM
emp
WHERE
emp.deptno = dept.deptno
) AS max_sal
FROM
dept
ORDER BY
deptno
;
perftestdb=> \i scalar_subquery_plan.sql
QUERY PLAN
-----------------------------------------------------------------------------------------------------------------
Sort (cost=5.87..5.88 rows=4 width=46) (actual time=0.246..0.247 rows=4 loops=1)
Sort Key: dept.deptno
Sort Method: quicksort Memory: 25kB
-> Seq Scan on dept (cost=0.00..5.83 rows=4 width=46) (actual time=0.065..0.095 rows=4 loops=1)
SubPlan 1
-> Aggregate (cost=1.19..1.20 rows=1 width=32) (actual time=0.016..0.017 rows=1 loops=4)
-> Seq Scan on emp (cost=0.00..1.18 rows=5 width=5) (actual time=0.003..0.006 rows=4 loops=4)
Filter: (deptno = dept.deptno)
Rows Removed by Filter: 10
Planning Time: 1.916 ms
Execution Time: 0.843 ms
(11 行)


MySQL(8.0.36)

mysql> \! cat scalar_subquery_plan.sql
EXPLAIN FORMAT=tree
SELECT
deptno
,dname
,(
SELECT
MAX(sal)
FROM
emp
WHERE
emp.deptno = dept.deptno
) AS max_sal
FROM
dept
ORDER BY
deptno
;

mysql> \. scalar_subquery_plan.sql
+----------------------------------------------------------------------+
| EXPLAIN |
+----------------------------------------------------------------------+
| -> Index scan on dept using PRIMARY (cost=0.65 rows=4)
-> Select #2 (subquery in projection; dependent)
-> Aggregate: max(emp.sal) (cost=1.28 rows=1)
-> Filter: (emp.deptno = dept.deptno) (cost=1.14 rows=1.4)
-> Table scan on emp (cost=1.14 rows=14)
|
+----------------------------------------------------------------------+
1 row in set, 1 warning (0.05 sec)
mysql> show warnings;
+-------+------+------------------------------------------------------------------------------------+
| Level | Code | Message |
+-------+------+------------------------------------------------------------------------------------+
| Note | 1276 | Field or reference 'perftestdb.dept.deptno' of SELECT #2 was resolved in SELECT #1 |
+-------+------+------------------------------------------------------------------------------------+
1 row in set (0.01 sec)


ただし、Oracle DatabaseだけはSELECTリストのスカラー副問合せをUNNESTして結合に書き換える最適化を行うこともあるので、実行計画だけだと元のSQL文に記述されているSELECTリスト中のスカラー副問合せに気付けないこともあります.
とはいえ、一般的には、そこに至るまでの間に、SQL文は抜き出せているでしょうから困ることはないでしょうね。(現場がリモートで、実行計画だけ送られてきた!なんてことでもなければw)

SELECTリスト中に記載したスカラー副問合せがUNNESTされてMERGE JOINに書き換えられた例(UNNESTヒント利用)
2013年、Oracle Database 12cR1で実装された最適化機能で、Scalar Subquery Unnesting Transformation (Oracle Database 12c R1 New Feature)でも説明していますので、詳しく知りたい方は参考にしてみてください。

SCOTT@orclpdb1> !cat scalar_subquery_unnest.sql
SELECT
deptno
,dname
,(
SELECT
/*+ UNNEST */
MAX(sal)
FROM
emp
WHERE
emp.deptno = dept.deptno
) AS max_sal
FROM
dept
ORDER BY
deptno
;

SCOTT@orclpdb1> @scalar_subquery_unnest.sql

経過: 00:00:00.17

実行計画
----------------------------------------------------------
Plan hash value: 2834279049

-----------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 5 | 145 | 11 (19)| 00:00:01 |
| 1 | MERGE JOIN OUTER | | 5 | 145 | 11 (19)| 00:00:01 |
| 2 | TABLE ACCESS BY INDEX ROWID| DEPT | 5 | 65 | 3 (0)| 00:00:01 |
| 3 | INDEX FULL SCAN | PK_DEPT | 5 | | 1 (0)| 00:00:01 |
|* 4 | SORT JOIN | | 4 | 64 | 8 (25)| 00:00:01 |
| 5 | VIEW | VW_SSQ_1 | 4 | 64 | 7 (15)| 00:00:01 |
| 6 | HASH GROUP BY | | 4 | 28 | 7 (15)| 00:00:01 |
| 7 | TABLE ACCESS FULL | EMP | 14 | 98 | 6 (0)| 00:00:01 |
-----------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

4 - access("ITEM_1"(+)="DEPT"."DEPTNO")
filter("ITEM_1"(+)="DEPT"."DEPTNO")


Enjoy SQL! and 癖

ではまた。






関連エントリー
標準はあるにはあるが癖の多いSQL 全部俺 #1 Pagination
標準はあるにはあるが癖の多いSQL 全部俺 #2 関数名は同じでも引数が逆の罠!
標準はあるにはあるが癖の多いSQL 全部俺 #3 データ型確認したい時あるんです
標準はあるにはあるが癖の多いSQL 全部俺 #4 リテラル値での除算の内部精度も違うのよ!
標準はあるにはあるが癖の多いSQL 全部俺 #5 和暦変換機能ある方が少数派
標準はあるにはあるが癖の多いSQL 全部俺 #6 時間厳守!
標準はあるにはあるが癖の多いSQL 全部俺 #7 期間リテラル!
標準はあるにはあるが癖の多いSQL 全部俺 #8 翌月末日って何日?
標準はあるにはあるが癖の多いSQL 全部俺 #9 部分文字列の扱いでも癖が出る><
標準はあるにはあるが癖の多いSQL 全部俺 #10 文字列連結の罠(有名なやつ)
標準はあるにはあるが癖の多いSQL 全部俺 #11 デュエル、じゃなくて、デュアル
標準はあるにはあるが癖の多いSQL 全部俺 #12 文字[列]探すにも癖がある
標準はあるにはあるが癖の多いSQL 全部俺 #13 あると便利ですが意外となかったり
標準はあるにはあるが癖の多いSQL 全部俺 #14 連番の集合を返すにも癖がある
標準はあるにはあるが癖の多いSQL 全部俺 #15 SQL command line client
標準はあるにはあるが癖の多いSQL 全部俺 #16 SQLのレントゲンを撮る方法
標準はあるにはあるが癖の多いSQL 全部俺 #17 その空白は許されないのか?
標準はあるにはあるが癖の多いSQL 全部俺 #18 (+)の外部結合は方言
標準はあるにはあるが癖の多いSQL 全部俺 #19 帰ってきた、部分文字列の扱いでも癖w
標準はあるにはあるが癖の多いSQL 全部俺 #20 結果セットを単一列に連結するにも癖がある
標準はあるにはあるが癖の多いSQL 全部俺 #21 演算結果にも癖がある
標準はあるにはあるが癖の多いSQL 全部俺 #22 集合演算にも癖がある
標準はあるにはあるが癖の多いSQL 全部俺 #23 複数行INSERTにも癖がある
標準はあるにはあるが癖の多いSQL 全部俺 #24 乱数作るにも癖がある
標準はあるにはあるが癖の多いSQL 全部俺 #25 SQL de Fractalsにも癖がある:)
標準はあるにはあるが癖の多いSQL 全部俺 おまけ SQL de 湯婆婆やるにも癖がでるw
帰ってきた! 標準はあるにはあるが癖の多いSQL #1 SQL de ROT13 やるにも癖が出るw
帰ってきた! 標準はあるにはあるが癖の多いSQL #2 Actual Plan取得中のキャンセルでも癖が出る
帰ってきた! 標準はあるにはあるが癖の多いSQL #3 オプティマイザの結合順評価テーブル数上限にも癖が出る
帰ってきた! 標準はあるにはあるが癖の多いSQL #4 Optimizer Traceの取得でも癖がでる
帰ってきた! 標準はあるにはあるが癖の多いSQL #5 - Optimizer Hint でも癖が多い
帰ってきた! 標準はあるにはあるが癖の多いSQL #6 - Hash Joinの結合ツリーにも癖がでる
帰ってきた! 標準はあるにはあるが癖の多いSQL #7 - Hash Joinの実行計画にも癖がでる
帰ってきた! 標準はあるにはあるが癖の多いSQL #8 - Hash Joinさせるにも癖が出る
帰ってきた! 標準はあるにはあるが癖の多いSQL #9、BOOLEAN型にも癖が出る
帰ってきた! 標準はあるにはあるが癖の多いSQL #10、BOOLEAN型にも癖が出る(後編)
帰ってきた! 標準はあるにはあるが癖の多いSQL #10、BOOLEAN型にも癖が出る(後編)の おまけ - SQL*PlusのautotraceでSQL Analysis Reportが出力される! (23ai〜)
帰ってきた! 標準はあるにはあるが癖の多いSQL #11 - 引用符にも癖がでるし、NULLのソート構文にも癖がある!(前編)
帰ってきた! 標準はあるにはあるが癖の多いSQL #12 - 引用符にも癖がでるし、NULLのソート構文にも癖がある!(後編)ー 列エイリアスの扱いにも癖がある!
帰ってきた! 標準はあるにはあるが癖の多いSQL #13 - コメント書くにも癖がある
帰ってきた! 標準はあるにはあるが癖の多いSQL #14 - コメントを書く位置にも癖がでる (SQL Clientにも癖がある)

| | | コメント (0)

2024年7月 8日 (月)

VirtualBox TestBuild 7.0.97r163779 (2024-07-04T18:53:02Z) for macOS/ARM64における現時点でのOracle Database 21cの起動、停止時間の記録

2024-07-04T18:53:02Z に最新のTestBuild ( development revision 163779 ) が公開されていました。


20240708-101041

恒例のOracle Database 21c on VirtualBox TestBuild for macOS/ARM64 の起動時間の記録です。

今回は、M1/M2とも前回とほぼ同じぐらい。改善は次回に期待 :) :) :) :) :)
とはいえ、そろそろ大詰め? な感じもしなくもない。。。。

M1

oracle@Mac-Studio ~ % ./print_env.sh 

*** mac info. ***
ProductName: macOS
ProductVersion: 14.5
BuildVersion: 23F79

*** maxOS ver. ***
Model Name: Mac Studio
Chip: Apple M1 Ultra
Total Number of Cores: 20 (16 performance and 4 efficiency)
Memory: 64 GB

*** VirtualBox ver. ***
7.0.97r163779

起動1回目 : 168 sec
停止1回目 : 77 sec
起動2回目 : 156 sec
停止2回目 : 48 sec

M2

oracle@angelfish ~ % ./print_env.sh

*** mac info. ***
Model Name: MacBook Air
Chip: Apple M2
Total Number of Cores: 8 (4 performance and 4 efficiency)
Memory: 24 GB

*** macOS ver. ***
ProductName: macOS
ProductVersion: 14.5
BuildVersion: 23F79

*** VirtualBox ver. ***
7.0.97r163779

起動1回目 :  93 sec
停止1回目 : 33 sec
起動2回目 : 95 sec
停止2回目 : 55 sec


VMのOSバージョンなどは過去のエントリーを見ていただくとして、M1/M2 それぞれ以下のPostgreSQL/MySQL/Oracle Databaseが起動することを確認。ルーティーン :)

MySQL

[master@localhost ~]$ mysql -u scott -D perftestdb -p -h localhost -e 'select version();'
Enter password:
+-----------+
| version() |
+-----------+
| 8.0.36 |
+-----------+

PostgreSQL

[master@localhost ~]$ sudo su - postgres -c 'psql -d perftestdb -U discus -p 5432 -W -h localhost -c "select version()"'
パスワード:
version
----------------------------------------------------------------------------------------------------------
PostgreSQL 13.14 on x86_64-pc-linux-gnu, compiled by gcc (GCC) 8.5.0 20210514 (Red Hat 8.5.0-20), 64-bit
(1 行)

Oracle Database (21c)

[oracle@localhost ~]$ sqlplus / as sysdba @version

....中略....

BANNER_FULL
-----------------------------------------------------------------------
Oracle Database 21c Enterprise Edition Release 21.0.0.0.0 - Production
Version 21.3.0.0.0

Oracle Database (23ai)

[oracle@localhost ~]$ sqlplus hr/oracle@localhost:1521/freepdb1 @version

....中略....

BANNER_FULL
--------------------------------------------------------------------------------
Oracle Database 23ai Free Release 23.0.0.0.0 - Develop, Learn, and Run for Free
Version 23.4.0.24.05


では、次回の起動停止時間ログをお楽しみに:)
最近のペースだと、7月の後半にありそうですよね.





MySQL 8.0.32 , PostgreSQL 13.4 and Oracle Database 21c on Oracle Linux 8 on VirtualBox for Apple Silicon Test Build 7.0.97_BETA5r160702
ySQL 8.0.32 , PostgreSQL 13.6 and Oracle Database 21c on Oracle Linux 8.5 on VirtualBox for Apple Silicon Test Build 7.0.97_BETA5r161342
MySQL 8.0.32 , PostgreSQL 13.6 and Oracle Database 21c on Oracle Linux 8.5 on VirtualBox for Apple Silicon Test Build 7.0.97_BETA5r161709
MySQL 8.0.36 , PostgreSQL 13.14, Oracle Database 21c, Oracle Database 23ai on VirtualBox for Apple Silicon Test Build 7.0.97_BETA r162957
VirtualBox TestBuild for macOS/ARM64における現時点でのOracle Database 21cの起動、停止時間の記録 / 7.0.97r162957(2024/4/26) / 7.0.97r163029(2024/5/3)
VirtualBox TestBuild 7.0.97r163376 (2024-05-28T15:08:56Z) for macOS/ARM64における現時点でのOracle Database 21cの起動、停止時間の記録
VirtualBox TestBuild 7.0.97r163425 (2024-06-05T13:13:46Z) for macOS/ARM64における現時点でのOracle Database 21cの起動、停止時間の記録
VirtualBox TestBuild 7.0.97r163606 (2024-06-21T11:55:16Z) for macOS/ARM64における現時点でのOracle Database 21cの起動、停止時間の記録

| | | コメント (0)

2024年6月23日 (日)

VirtualBox TestBuild 7.0.97r163606 (2024-06-21T11:55:16Z) for macOS/ARM64における現時点でのOracle Database 21cの起動、停止時間の記録

2024-06-21に最新のTestBuildが公開されていました。


20240623-112941

恒例のOracle Database 21c on VirtualBox TestBuild for macOS/ARM64 の起動時間の記録です。

 

oracle@Mac-Studio ~ % ./print_env.sh

*** mac info. ***
ProductName: macOS
ProductVersion: 14.5
BuildVersion: 23F79

*** maxOS ver. ***
Model Name: Mac Studio
Chip: Apple M1 Ultra
Total Number of Cores: 20 (16 performance and 4 efficiency)
Memory: 64 GB

*** VirtualBox ver. ***
7.0.97r163606

 

M1で停止時間が2桁秒台になったほか、起動時間も改善してますね!

起動1回目 : 130 sec
停止1回目 : 66 sec
起動2回目 : 145 sec
停止2回目 : 45 sec

 

 

oracle@angelfish ~ % ./print_env.sh

*** mac info. ***
Model Name: MacBook Air
Chip: Apple M2
Total Number of Cores: 8 (4 performance and 4 efficiency)
Memory: 24 GB

*** macOS ver. ***
ProductName: macOS
ProductVersion: 14.5
BuildVersion: 23F79

*** VirtualBox ver. ***
7.0.97r163606

 

 

起動停止時間の記録をとり始めてから、M2でも最短記録ですね!!!! 

起動1回目 : 108 sec
停止1回目 : 34 sec
起動2回目 : 91 sec
停止2回目 : 49 sec

 

今回は、起動停止時間ともこれまでの最速値です。(^^) (^^) (^^)

次回のリリースが楽しみですね。。。

 

VMのOSバージョンなどは過去のエントリーを見ていただくとして、M1/M2 それぞれ以下のPostgreSQL/MySQL/Oracle Databaseが起動することを確認。

 

PostgreSQL

[master@localhost ~]$ sudo su - postgres -c 'psql -d perftestdb -U discus -p 5432 -W -h localhost -c "select version()"'

version
----------------------------------------------------------------------------------------------------------
PostgreSQL 13.14 on x86_64-pc-linux-gnu, compiled by gcc (GCC) 8.5.0 20210514 (Red Hat 8.5.0-20), 64-bit
(1 行)

 

MySQL

[master@localhost ~]$ mysql -u scott -D perftestdb -p -h localhost -e 'select version();'

+-----------+
| version() |
+-----------+
| 8.0.36 |
+-----------+

 

Oracle Database 21c

[oracle@localhost ~]$ sqlplus / as sysdba @version

...略...

BANNER_FULL
----------------------------------------------------------------------
Oracle Database 21c Enterprise Edition Release 21.0.0.0.0 - Production
Version 21.3.0.0.0

 

Oracle Database 23ai

[oracle@localhost ~]$ sql hr/oracle@localhost:1521/freepdb1 @version

...略...

BANNER_FULL
________________________________________________________________________________
Oracle Database 23ai Free Release 23.0.0.0.0 - Develop, Learn, and Run for Free
Version 23.4.0.24.05

 

VirtualBox Team がんばれ〜〜〜〜〜 :)

では、次回の起動停止時間ログをお楽しみに:)

 

 



MySQL 8.0.32 , PostgreSQL 13.4 and Oracle Database 21c on Oracle Linux 8 on VirtualBox for Apple Silicon Test Build 7.0.97_BETA5r160702
ySQL 8.0.32 , PostgreSQL 13.6 and Oracle Database 21c on Oracle Linux 8.5 on VirtualBox for Apple Silicon Test Build 7.0.97_BETA5r161342
MySQL 8.0.32 , PostgreSQL 13.6 and Oracle Database 21c on Oracle Linux 8.5 on VirtualBox for Apple Silicon Test Build 7.0.97_BETA5r161709
MySQL 8.0.36 , PostgreSQL 13.14, Oracle Database 21c, Oracle Database 23ai on VirtualBox for Apple Silicon Test Build 7.0.97_BETA r162957
VirtualBox TestBuild for macOS/ARM64における現時点でのOracle Database 21cの起動、停止時間の記録 / 7.0.97r162957(2024/4/26) / 7.0.97r163029(2024/5/3)
VirtualBox TestBuild 7.0.97r163376 (2024-05-28T15:08:56Z) for macOS/ARM64における現時点でのOracle Database 21cの起動、停止時間の記録
VirtualBox TestBuild 7.0.97r163425 (2024-06-05T13:13:46Z) for macOS/ARM64における現時点でのOracle Database 21cの起動、停止時間の記録

 

 

| | | コメント (0)

2024年6月15日 (土)

VirtualBox TestBuild 7.0.97r163425 (2024-06-05T13:13:46Z) for macOS/ARM64における現時点でのOracle Database 21cの起動、停止時間の記録

さて、恒例のOracle Database 21c on VirtualBox TestBuild for macOS/ARM64 の起動時間の記録です。
2024-06-05T13:13:46Zに公開されていた。起動自体は非常に安定してきましたね。細かいところは色々あるようですが、正式リリースが待ち遠しい。

oracle@Mac-Studio ~ % ./print_env.sh 

*** mac info. ***
ProductName: macOS
ProductVersion: 14.5
BuildVersion: 23F79

*** maxOS ver. ***
Model Name: Mac Studio
Chip: Apple M1 Ultra
Total Number of Cores: 20 (16 performance and 4 efficiency)
Memory: 64 GB

*** VirtualBox ver. ***
7.0.97r163425


Oracle Database 21c / Mac Studio M1
微妙な差なので変化なしという感じですね。

起動1回目 : 202 sec
停止1回目 : 86 sec
起動2回目 : 163 sec
停止2回目 : 143 sec


oracle@angelfish ~ % ./print_env.sh

*** mac info. ***
Model Name: MacBook Air
Chip: Apple M2
Total Number of Cores: 8 (4 performance and 4 efficiency)
Memory: 24 GB

*** macOS ver. ***
ProductName: macOS
ProductVersion: 14.5
BuildVersion: 23F79

*** VirtualBox ver. ***
7.0.97r163425


Oracle Database 21c / MacBook Air M2
若干、前回公開されたTestBuildより遅くなってる気がしますよね。(たった二回しか起動停止させてないので、参考記録程度なわけですけども)

起動1回目 : 244 sec
停止1回目 : 136 sec
起動2回目 : 201 sec
停止2回目 : 101 sec


Virtualbox-20240605-7097r163425

その他、いつもの起動確認。
PostgreSQL 13.14 / MySQL 8.0.36 / Oracle Database 21c 及び、 23ai (M1/M2それぞれ起動)
GuestOSのバージョンなどはこれまでと同じなので省略して、それぞれのバージョン確認ログで起動確認。

[master@localhost ~]$ mysql -u scott -D perftestdb -p -h localhost -e 'select version();'
Enter password:
+-----------+
| version() |
+-----------+
| 8.0.36 |
+-----------+

[master@localhost ~]$ sudo su - postgres -c 'psql -d perftestdb -U discus -p 5432 -W -h localhost -c "select version()"'
パスワード:
version
----------------------------------------------------------------------------------------------------------
PostgreSQL 13.14 on x86_64-pc-linux-gnu, compiled by gcc (GCC) 8.5.0 20210514 (Red Hat 8.5.0-20), 64-bit
(1 行)

[oracle@localhost ~]$ sqlplus scott@orclpdb1 @version

...略...

BANNER_FULL
-----------------------------------------------------------------------
Oracle Database 21c Enterprise Edition Release 21.0.0.0.0 - Production
Version 21.3.0.0.0


[oracle@localhost ~]$ sql hr@192.168.1.138:1521/freepdb1 @version

...略...

BANNER_FULL
________________________________________________________________________________
Oracle Database 23ai Free Release 23.0.0.0.0 - Develop, Learn, and Run for Free
Version 23.4.0.24.05
[oracle@localhost ~]$ cat version.sql
select banner_full from v$version;
exit


これ、ルーティーンになりそうw

ではまた。




MySQL 8.0.32 , PostgreSQL 13.4 and Oracle Database 21c on Oracle Linux 8 on VirtualBox for Apple Silicon Test Build 7.0.97_BETA5r160702
ySQL 8.0.32 , PostgreSQL 13.6 and Oracle Database 21c on Oracle Linux 8.5 on VirtualBox for Apple Silicon Test Build 7.0.97_BETA5r161342
MySQL 8.0.32 , PostgreSQL 13.6 and Oracle Database 21c on Oracle Linux 8.5 on VirtualBox for Apple Silicon Test Build 7.0.97_BETA5r161709
MySQL 8.0.36 , PostgreSQL 13.14, Oracle Database 21c, Oracle Database 23ai on VirtualBox for Apple Silicon Test Build 7.0.97_BETA r162957
VirtualBox TestBuild for macOS/ARM64における現時点でのOracle Database 21cの起動、停止時間の記録 / 7.0.97r162957(2024/4/26) / 7.0.97r163029(2024/5/3)
VirtualBox TestBuild 7.0.97r163376 (2024-05-28T15:08:56Z) for macOS/ARM64における現時点でのOracle Database 21cの起動、停止時間の記録


| | | コメント (0)

2024年5月31日 (金)

VirtualBox TestBuild 7.0.97r163376 (2024-05-28T15:08:56Z) for macOS/ARM64における現時点でのOracle Database 21cの起動、停止時間の記録

VirtualBox TestBuild 7.0.97r163376 (2024-05-28T15:08:56Z) / macOS/ARM64 Dev Previewがリリースされていたので、いつもの、起動確認と、Oracle Database 21cの起動時間比較を。
前回の記録は、VirtualBox TestBuild for macOS/ARM64における現時点でのOracle Database 21cの起動、停止時間の記録 / 7.0.97r162957(2024/4/26) / 7.0.97r163029(2024/5/3)を見てもらうとして、結果的には大きくな変化なし!。

頑張って! :) 

oracle@Mac-Studio ~ % ./print_env.sh 

*** mac info. ***
ProductName: macOS
ProductVersion: 14.5
BuildVersion: 23F79

*** maxOS ver. ***
Model Name: Mac Studio
Chip: Apple M1 Ultra
Total Number of Cores: 20 (16 performance and 4 efficiency)
Memory: 64 GB

*** VirtualBox ver. ***
7.0.97r163376

Oracle Database 21c Mac Studio M1

起動1回目 : 217sec
停止1回目 : 153sec
起動2回目 : 186sec
停止2回目 : 119sec


oracle@angelfish ~ % ./print_env.sh 

*** mac info. ***
Model Name: MacBook Air
Chip: Apple M2
Total Number of Cores: 8 (4 performance and 4 efficiency)
Memory: 24 GB

*** macOS ver. ***
ProductName: macOS
ProductVersion: 14.5
BuildVersion: 23F79

*** VirtualBox ver. ***
7.0.97r163376

Oracle Database 21c MacBook Air M2

起動1回目 : 138sec
停止1回目 : 108sec
起動2回目 : 128sec
停止2回目 : 83sec



20240531-81713

その他、いつもの起動確認。
PostgreSQL 13.14 / MySQL 8.0.36 / Oracle Database 21c 及び、 23ai 、それぞれ、VirtualBox TestBuild 7.0.97r163376 (024-05-28T15:08:56Z)でも起動した! (このあたりはマジで安定してきた)

oracle@Mac-Studio ~ % ./print_env.sh 

*** mac info. ***
ProductName: macOS
ProductVersion: 14.5
BuildVersion: 23F79

*** maxOS ver. ***
Model Name: Mac Studio
Chip: Apple M1 Ultra
Total Number of Cores: 20 (16 performance and 4 efficiency)
Memory: 64 GB

*** VirtualBox ver. ***
7.0.97r163376

[master@localhost ~]$ cat /etc/*release*
Oracle Linux Server release 8.5
NAME="Oracle Linux Server"
VERSION="8.5"
ID="ol"
ID_LIKE="fedora"
VARIANT="Server"
VARIANT_ID="server"
VERSION_ID="8.5"
PLATFORM_ID="platform:el8"
PRETTY_NAME="Oracle Linux Server 8.5"
ANSI_COLOR="0;31"
CPE_NAME="cpe:/o:oracle:linux:8:5:server"
HOME_URL="https://linux.oracle.com/"
BUG_REPORT_URL="https://bugzilla.oracle.com/"

ORACLE_BUGZILLA_PRODUCT="Oracle Linux 8"
ORACLE_BUGZILLA_PRODUCT_VERSION=8.5
ORACLE_SUPPORT_PRODUCT="Oracle Linux"
ORACLE_SUPPORT_PRODUCT_VERSION=8.5
Red Hat Enterprise Linux release 8.5 (Ootpa)
Oracle Linux Server release 8.5
cpe:/o:oracle:linux:8:5:server
[master@localhost ~]$


PostgreSQL 13.14 - 起動した!

[master@localhost ~]$ sudo su - postgres
[postgres@localhost ~]$ psql -d perftestdb -U discus -p 5432 -W -h localhost
パスワード:
psql (13.14)
"help"でヘルプを表示します。

perftestdb=> select version();
version
----------------------------------------------------------------------------------------------------------
PostgreSQL 13.14 on x86_64-pc-linux-gnu, compiled by gcc (GCC) 8.5.0 20210514 (Red Hat 8.5.0-20), 64-bit
(1 行)

perftestdb=> exit


MySQL 8.0.36 - 起動した!

[master@localhost ~]$ mysql -u scott -D perftestdb -p -h 192.168.1.125
Enter password:
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 8
Server version: 8.0.36 Source distribution

Copyright (c) 2000, 2024, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> select version();
+-----------+
| version() |
+-----------+
| 8.0.36 |
+-----------+
1 row in set (0.01 sec)

mysql> exit
Bye


Oracle Database 21c - 起動した!

[oracle@localhost ~]$ cat /etc/*release*
Oracle Linux Server release 8.4
NAME="Oracle Linux Server"
VERSION="8.4"
ID="ol"
ID_LIKE="fedora"
VARIANT="Server"
VARIANT_ID="server"
VERSION_ID="8.4"
PLATFORM_ID="platform:el8"
PRETTY_NAME="Oracle Linux Server 8.4"
ANSI_COLOR="0;31"
CPE_NAME="cpe:/o:oracle:linux:8:4:server"
HOME_URL="https://linux.oracle.com/"
BUG_REPORT_URL="https://bugzilla.oracle.com/"

ORACLE_BUGZILLA_PRODUCT="Oracle Linux 8"
ORACLE_BUGZILLA_PRODUCT_VERSION=8.4
ORACLE_SUPPORT_PRODUCT="Oracle Linux"
ORACLE_SUPPORT_PRODUCT_VERSION=8.4
Red Hat Enterprise Linux release 8.4 (Ootpa)
Oracle Linux Server release 8.4
cpe:/o:oracle:linux:8:4:server
[oracle@localhost ~]$
[oracle@localhost ~]$ sqlplus / as sysdba

SYS@ORCLCDB> select banner_full from v$version;

BANNER_FULL
-----------------------------------------------------------------------
Oracle Database 21c Enterprise Edition Release 21.0.0.0.0 - Production
Version 21.3.0.0.0

SYS@ORCLCDB> exit


Oracle Database 23ai - 起動した!

[oracle@localhost ~]$ cat /etc/*release*
Oracle Linux Server release 8.9
NAME="Oracle Linux Server"
VERSION="8.9"
ID="ol"
ID_LIKE="fedora"
VARIANT="Server"
VARIANT_ID="server"
VERSION_ID="8.9"
PLATFORM_ID="platform:el8"
PRETTY_NAME="Oracle Linux Server 8.9"
ANSI_COLOR="0;31"
CPE_NAME="cpe:/o:oracle:linux:8:9:server"
HOME_URL="https://linux.oracle.com/"
BUG_REPORT_URL="https://github.com/oracle/oracle-linux"

ORACLE_BUGZILLA_PRODUCT="Oracle Linux 8"
ORACLE_BUGZILLA_PRODUCT_VERSION=8.9
ORACLE_SUPPORT_PRODUCT="Oracle Linux"
ORACLE_SUPPORT_PRODUCT_VERSION=8.9
Red Hat Enterprise Linux release 8.9 (Ootpa)
Oracle Linux Server release 8.9
cpe:/o:oracle:linux:8:9:server
[oracle@localhost ~]$ sql scott/@192.168.1.138:1521/freepdb1


SQL> select banner_full from v$version;

BANNER_FULL
_______________________________________________________________________________
Oracle Database 23ai Free Release 23.0.0.0.0 - Develop, Learn, and Run for Free
Version 23.4.0.24.05

SQL>


これが、本当の5月最後の投稿ということでw

では、また。





MySQL 8.0.32 , PostgreSQL 13.4 and Oracle Database 21c on Oracle Linux 8 on VirtualBox for Apple Silicon Test Build 7.0.97_BETA5r160702
ySQL 8.0.32 , PostgreSQL 13.6 and Oracle Database 21c on Oracle Linux 8.5 on VirtualBox for Apple Silicon Test Build 7.0.97_BETA5r161342
MySQL 8.0.32 , PostgreSQL 13.6 and Oracle Database 21c on Oracle Linux 8.5 on VirtualBox for Apple Silicon Test Build 7.0.97_BETA5r161709
MySQL 8.0.36 , PostgreSQL 13.14, Oracle Database 21c, Oracle Database 23ai on VirtualBox for Apple Silicon Test Build 7.0.97_BETA r162957
VirtualBox TestBuild for macOS/ARM64における現時点でのOracle Database 21cの起動、停止時間の記録 / 7.0.97r162957(2024/4/26) / 7.0.97r163029(2024/5/3)

| | | コメント (0)

2024年5月16日 (木)

GROUP BY列の別名または位置の指定が可能に! / 23ai〜 / SQL / FAQ

23c 改め、23ai になった Oracle Database 23aiですが、SQLの使い勝手の改善がいくつか。
有名なのは、from dual を書かなくても良くなったこと。ですが、有名すぎるのであえて書きません!w

ということで、ちょっとマイナーだけど便利ですよね! という 「GROUP BY列の別名または位置の指定が可能に! / 23ai〜」 というお話。

参考 ー Oracle Databaseリリース23cの変更点
https://docs.oracle.com/cd/F82042_01/sqlrf/Changes-in-This-Release-for-Oracle-Database-SQL-Language-Reference.html

自分用アップデートメモでもありますw

まずこれまでのおさらいということで、Oracle Database 21c EEで挙動を確認しておきます。

SCOTT@orclpdb1> select banner_full from v$version;

BANNER_FULL
-----------------------------------------------------------------------
Oracle Database 21c Enterprise Edition Release 21.0.0.0.0 - Production
Version 21.3.0.0.0


SCOTT@orclpdb1> select * from emp;

EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
---------- ---------- --------- ---------- --------- ---------- ---------- ----------
7369 SMITH CLERK 7902 17-DEC-80 800 20
7499 ALLEN SALESMAN 7698 20-FEB-81 1600 300 30
7521 WARD SALESMAN 7698 22-FEB-81 1250 500 30
7566 JONES MANAGER 7839 02-APR-81 2975 20
7654 MARTIN SALESMAN 7698 28-SEP-81 1250 1400 30
7698 BLAKE MANAGER 7839 01-MAY-81 2850 30
7782 CLARK MANAGER 7839 09-JUN-81 2450 10
7788 SCOTT ANALYST 7566 19-APR-87 3000 20
7839 KING PRESIDENT 17-NOV-81 5000 10
7844 TURNER SALESMAN 7698 08-SEP-81 1500 0 30
7876 ADAMS CLERK 7788 23-MAY-87 1100 20
7900 JAMES CLERK 7698 03-DEC-81 950 30
7902 FORD ANALYST 7566 03-DEC-81 3000 20
7934 MILLER CLERK 7782 23-JAN-82 1300 10

14 rows selected.

group by 別名指定。。見事にエラーになります!

SCOTT@orclpdb1> l
1 SELECT
2 TO_CHAR(hiredate,'YYYY') AS year
3 , COUNT(1) AS hired
4 FROM
5 emp
6 GROUP BY
7 year
8 ORDER BY
9* year
SCOTT@orclpdb1> /
year
*
行7でエラーが発生しました。:
ORA-00904: "YEAR": 無効な識別子です。


group by 位置指定。。これも間違いなくエラーです!。。。

SCOTT@orclpdb1> l
1 SELECT
2 TO_CHAR(hiredate,'YYYY') AS year
3 , COUNT(1) AS hired
4 FROM
5 emp
6 GROUP BY
7 1
8 ORDER BY
9* year
SCOTT@orclpdb1> /
TO_CHAR(hiredate,'YYYY') AS year
*
行2でエラーが発生しました。:
ORA-00979: GROUP BYの式ではありません。


ということで、これまではこんな面倒が書き方してたわけです。はい。。。

SCOTT@orclpdb1> l
1 SELECT
2 TO_CHAR(hiredate,'YYYY') AS year
3 , COUNT(1) AS hired
4 FROM
5 emp
6 GROUP BY
7 TO_CHAR(hiredate,'YYYY')
8 ORDER BY
9* year
SCOTT@orclpdb1> /

YEAR HIRED
------------ ----------
1980 1
1981 10
1982 1
1987 2


これまでは、こんな感じ。まあ面倒臭いですよね。


しかーーーーし、23ai以降では、そんな面倒は忘れてください。

SCOTT/freepdb1> select banner_full from v$version;

BANNER_FULL
-------------------------------------------------------------------------------
Oracle Database 23ai Free Release 23.0.0.0.0 - Develop, Learn, and Run for Free
Version 23.4.0.24.05


SCOTT/freepdb1> select * from emp;

EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
---------- ---------- --------- ---------- --------- ---------- ---------- ----------
7369 SMITH CLERK 7902 17-DEC-80 800 20
7499 ALLEN SALESMAN 7698 20-FEB-81 1600 300 30
7521 WARD SALESMAN 7698 22-FEB-81 1250 500 30
7566 JONES MANAGER 7839 02-APR-81 2975 20
7654 MARTIN SALESMAN 7698 28-SEP-81 1250 1400 30
7698 BLAKE MANAGER 7839 01-MAY-81 2850 30
7782 CLARK MANAGER 7839 09-JUN-81 2450 10
7788 SCOTT ANALYST 7566 19-APR-87 3000 20
7839 KING PRESIDENT 17-NOV-81 5000 10
7844 TURNER SALESMAN 7698 08-SEP-81 1500 0 30
7876 ADAMS CLERK 7788 23-MAY-87 1100 20
7900 JAMES CLERK 7698 03-DEC-81 950 30
7902 FORD ANALYST 7566 03-DEC-81 3000 20
7934 MILLER CLERK 7782 23-JAN-82 1300 10

14 rows selected.


group by 別名指定。おおおおおおーーぅ!  できた。

SCOTT/freepdb1> l
1 SELECT
2 TO_CHAR(hiredate,'YYYY') AS year
3 , COUNT(1) AS hired
4 FROM
5 emp
6 GROUP BY
7 year
8 ORDER BY
9* year
SCOTT/freepdb1> /

YEAR HIRED
---- ----------
1980 1
1981 10
1982 1
1987 2


group by 位置指定....? 

SCOTT/freepdb1> l
1 SELECT
2 TO_CHAR(hiredate,'YYYY') AS year
3 , COUNT(1) AS hired
4 FROM
5 emp
6 GROUP BY
7 1
8 ORDER BY
9 year
10*
SCOTT/freepdb1> /
TO_CHAR(hiredate,'YYYY') AS year
*
ERROR at line 2:
ORA-03162: "HIREDATE": must appear in the GROUP BY clause or be used in an aggregate function as 'group_by_position_enabled' is FALSE
Help: https://docs.oracle.com/error-help/db/ora-03162/


なんと、23ai free developerではデフォルトで無効化されてる!?。。。とは言っても、位置指定は、order by でも使わない場合が多いので、デフォルトオフでも影響はないですかね。一般的には。

SCOTT/freepdb1> show parameter group_by_position_enabled
NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
group_by_position_enabled boolean FALSE

SCOTT/freepdb1> alter session set group_by_position_enabled = true;

Session altered.

SCOTT/freepdb1> show parameter group_by_position_enabled

NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
group_by_position_enabled boolean TRUE

SCOTT/freepdb1> l
1 SELECT
2 TO_CHAR(hiredate,'YYYY') AS year
3 , COUNT(1) AS hired
4 FROM
5 emp
6 GROUP BY
7 1
8 ORDER BY
9 year
10*
SCOTT/freepdb1> /

YEAR HIRED
---- ----------
1980 1
1981 10
1982 1
1987 2


strong>最後に、従来の面倒臭い構文の確認。

SCOTT/freepdb1> l
1 SELECT
2 TO_CHAR(hiredate,'YYYY') AS year
3 , COUNT(1) AS hired
4 FROM
5 emp
6 GROUP BY
7 TO_CHAR(hiredate,'YYYY')
8 ORDER BY
9* year
SCOTT/freepdb1> /

YEAR HIRED
---- ----------
1980 1
1981 10
1982 1
1987 2

Enjoy SQL!

では、また

| | | コメント (0)

2024年5月 9日 (木)

VirtualBox TestBuild for macOS/ARM64における現時点でのOracle Database 21cの起動、停止時間の記録 #2 / 7.0.97r163068 ( 2024-5-07T20:38:44Z )

2025-05-03にTestBuildが更新されていたわけですが、なんと、2024-5-07T20:38:44Zに更新されていました。(テストビルドって、月に何回更新されてるのだろう?...)

Oracle Database 23ai Free Developer、Oracle Database 21c EE 、MySQL 8.0.36 そして PostgreSQL 13.14
は問題なく起動(最近安定して起動するのでログは省略)。

ということで、Oracle Database 21cの起動、停止時間の記録だけメモしておきます。

起動停止時間は大きく変わってないように思います(ブレはある程度あるにしても)が、若干速くなってる気もしますね。特に、M1で。次のアップデートが楽しみですね。

Mac Studio M1

** macOS ver. ***
ProductName: macOS
ProductVersion: 14.4.1
BuildVersion: 23E224

*** mac info. ***
Model Name: Mac Studio
Chip: Apple M1 Ultra
Total Number of Cores: 20 (16 performance and 4 efficiency)
Memory: 64 GB

*** VirtualBox ver. ***
7.0.97r163068

VirtualBox TestBuild 7.0.97r163068 ( 2024-5-07T20:38:44Z ) / Mac Studio M1

起動1回目 : 211sec
停止1回目 : 90sec
起動2回目 : 159sec
停止2回目 : 104sec

MacBook Air M2

*** macOS ver. ***
Model Name: MacBook Air
Chip: Apple M2
Total Number of Cores: 8 (4 performance and 4 efficiency)
Memory: 24 GB

*** mac info. ***
ProductName: macOS
ProductVersion: 14.4.1
BuildVersion: 23E224

*** VirtualBox ver. ***
7.0.97r163068

VirtualBox TestBuild 7.0.97r163068 ( 2024-5-07T20:38:44Z ) / MacBook Air M2

起動1回目 : 133sec
停止1回目 : 20sec
起動2回目 : 152sec
停止2回目 : 106sec

ではまた



Oracle Linux 8 and MySQL 8.0.32 on VirtualBox for Apple Silicon Test Build 7.0.97_BETA r160167
MySQL 8.0.32 , PostgreSQL 13.4 and Oracle Database 21c on Oracle Linux 8 on VirtualBox for Apple Silicon Test Build 7.0.97_BETA r160702
MySQL 8.0.32 , PostgreSQL 13.6 and Oracle Database 21c on Oracle Linux 8.5 on VirtualBox for Apple Silicon Test Build 7.0.97_BETA r161342
MySQL 8.0.32 , PostgreSQL 13.6 and Oracle Database 21c on Oracle Linux 8.5 on VirtualBox for Apple Silicon Test Build 7.0.97_BETA r161709
MySQL 8.0.36 , PostgreSQL 13.14, Oracle Database 21c, Oracle Database 23ai on VirtualBox for Apple Silicon Test Build 7.0.97_BETA r162957
VirtualBox TestBuild for macOS/ARM64における現時点でのOracle Database 21cの起動、停止時間の記録 / 7.0.97r162957(2024/4/26) / 7.0.97r163029(2024/5/3)

| | | コメント (0)

2024年5月 7日 (火)

VirtualBox TestBuild for macOS/ARM64における現時点でのOracle Database 21cの起動、停止時間の記録 / 7.0.97r162957(2024/4/26) / 7.0.97r163029(2024/5/3)

さて、ここのところVirtualBoxの話題が多いですが、安定して起動するようになったVirtualBox TestBuild for macOS/ARM64。気になるのも当然です。Intel Macいつ捨てるんだよって話もあるわけでw

 

という個人的な都合は置いておいてw

 

以下にも記載されているように、現状は、性能面含めた問題があることもあり、Intel版macのVirtualBoxと完全にお別れすることもできない状況ではあります。
https://www.virtualbox.org/wiki/Testbuilds “The test builds for macOS/ARM64 work in principle on Macs with M1, M2 or M3 CPU. However, they are developer previews with known issues (including serious performance ones) with all recent guest operating systems.”

 

ただ、最近のTestBuildでは安定して起動するようにところまで改善してきておりいつ正式リリースだろう。。。と気になってしょうがない状況ではありますwww

 

と、いうことで、
現時点のApple Silicon版VirtualBoxで安定して起動するようになったOracle Database 21c EEの起動停止速度をざっくり確認しておこうと思います。
(今後のVirtualBoxのリリースで、どう改善したのか確認するネタとしても大切なので)

 

起動提示時間の確認方法は、それぞれのmacで、同じ方法で行いました。

 

前提 同じVMをそれぞれインポートして実施
1. VirtualBoxのVMを起動(Oracleは自動起動にしていない)
2. LSNRCTL for Linuxの起動
3. Oracle Database 21cの起動
4. Oracle Database 21cの停止
5. Oracle Database 21cの起動
6. Oracle Database 21cの停止

 

を行い、どの程度の時間で起動停止できるのかメモっておいた。Apple SiliconのVirtualBoxもIntel版レベルに近づいて欲しいところではある。。。が現時点では桁が違いますね。。。

 

ただ、7.0.97r162957(2024/4/26)版のTestBuildと7.0.97r163029(2024/5/3)版のTestBuildだと、若干、7.0.97r163029(2024/5/3)版の方が速くなって気はしますよね。。。。若干ですが。

比較しやすいように、Intel版のVirtualBoxでも同様の手順で実施して記録を残しておきました。
VirtualBox TestBuild 7.0.97r162957(2024/4/26) / MacBook AIR M2

 起動1回目 : 303sec
停止1回目 : 77sec
起動2回目 : 147sec
停止2回目 : 77sec

 

VirtualBox TestBuild 7.0.97r163029(2024/5/3) / MacBook AIR M2

 起動1回目 : 140sec
停止1回目 : 78sec
起動2回目 : 128sec
停止2回目 : 57sec


VirtualBox TestBuild 7.0.97r162957(2024/4/26) / Mac Studio M1

 起動1回目 : 315sec
停止1回目 : 156sec
起動2回目 : 242sec
停止2回目 : 175sec


VirtualBox TestBuild 7.0.97r163029(2024/5/3) / Mac Studio M1

 起動1回目 : 182sec
停止1回目 : 101sec
起動2回目 : 206sec
停止2回目 : 111sec


VirtualBox 7.0.10r158379 / MacBook Intel

 起動1回目 :  20sec
停止1回目 : 42sec
起動2回目 : 13sec
停止2回目 : 36sec


VirtualBox 6.1.26r145957 / Mac Pro Intel

 起動1回目 :  22sec
停止1回目 : 35sec
起動2回目 : 14sec
停止2回目 : 38sec

 

 

以下、各ホストの情報
MacBook AIR M2 - VirtualBox TestBuild for Apple Silicon

*** macOS ver. ***
Model Name: MacBook Air
Chip: Apple M2
Total Number of Cores: 8 (4 performance and 4 efficiency)
Memory: 24 GB

*** mac info. ***
ProductName: macOS
ProductVersion: 14.4.1
BuildVersion: 23E224

*** VirtualBox ver. ***
7.0.97r162957

 

 

MacBook AIR M2 - VirtualBox TestBuild for Apple Silicon


...略...

*** VirtualBox ver. ***
7.0.97r163029

 

Mac Studio M1 - VirtualBox TestBuild for Apple Silicon

*** maxOS ver. ***
ProductName: macOS
ProductVersion: 14.4.1
BuildVersion: 23E224

*** mac info. ***
Model Name: Mac Studio
Chip: Apple M1 Ultra
Total Number of Cores: 20 (16 performance and 4 efficiency)
Memory: 64 GB

*** VirtualBox ver. ***
7.0.97r162957

 

Mac Studio M1 - VirtualBox TestBuild for Apple Silicon


...略...

*** VirtualBox ver. ***
7.0.97r163029

 

 

MacBook Intel

*** maxOS ver. ***
ProductName: macOS
ProductVersion: 12.7.4
BuildVersion: 21H1123

*** mac info. ***
Model Name: MacBook
Processor Name: Dual-Core Intel Core m5
Processor Speed: 1.2 GHz
Number of Processors: 1
Total Number of Cores: 2
Memory: 8 GB

*** VirtualBox ver. ***
7.0.10r158379

 

Mac Pro Intel

*** maxOS ver. ***
ProductName: Mac OS X
ProductVersion: 10.14.6
BuildVersion: 18G9323

*** mac info. ***
Model Name: Mac Pro
Processor Name: 6-Core Intel Xeon
Processor Speed: 2.4 GHz
Number of Processors: 2
Total Number of Cores: 12
L3 Cache (per Processor): 12 MB
Memory: 32 GB

*** VirtualBox ver. ***
6.1.26r145957

 

 

 

手順例(参考)

[oracle@localhost ~]$ sqlplus / as sysdba

SQL*Plus: Release 21.0.0.0.0 - Production on 火 5月 6 16:07:02 2024
Version 21.3.0.0.0

Copyright (c) 1982, 2021, Oracle. All rights reserved.

アイドル・インスタンスに接続しました。

16:07:02 SYS@ORCLCDB>
16:07:10 SYS@ORCLCDB> startup
ORACLEインスタンスが起動しました。

Total System Global Area 536867744 bytes
Fixed Size 9687968 bytes
Variable Size 360710144 bytes
Database Buffers 54525952 bytes
Redo Buffers 7086080 bytes
In-Memory Area 104857600 bytes
データベースがマウントされました。
データベースがオープンされました。
16:09:30 SYS@ORCLCDB>
16:10:27 SYS@ORCLCDB> shutdown immediate
データベースがクローズされました。
データベースがディスマウントされました。
ORACLEインスタンスがシャットダウンされました。
16:11:35 SYS@ORCLCDB>
16:12:23 SYS@ORCLCDB>
16:12:23 SYS@ORCLCDB> startup
ORACLEインスタンスが起動しました。

Total System Global Area 536867744 bytes
Fixed Size 9687968 bytes
Variable Size 360710144 bytes
Database Buffers 54525952 bytes
Redo Buffers 7086080 bytes
In-Memory Area 104857600 bytes
データベースがマウントされました。
データベースがオープンされました。
16:14:31 SYS@ORCLCDB>
16:15:35 SYS@ORCLCDB> shutdown immediate
データベースがクローズされました。
データベースがディスマウントされました。
ORACLEインスタンスがシャットダウンされました。
16:16:32 SYS@ORCLCDB>

 

少しずずIntel版の速度に近づいて欲しいものですね。VirtualBoxチーム頑張って〜〜〜っ!

 

 

では、また。

 


Oracle Linux 8 and MySQL 8.0.32 on VirtualBox for Apple Silicon Test Build 7.0.97_BETA r160167
MySQL 8.0.32 , PostgreSQL 13.4 and Oracle Database 21c on Oracle Linux 8 on VirtualBox for Apple Silicon Test Build 7.0.97_BETA r160702
MySQL 8.0.32 , PostgreSQL 13.6 and Oracle Database 21c on Oracle Linux 8.5 on VirtualBox for Apple Silicon Test Build 7.0.97_BETA r161342
MySQL 8.0.32 , PostgreSQL 13.6 and Oracle Database 21c on Oracle Linux 8.5 on VirtualBox for Apple Silicon Test Build 7.0.97_BETA r161709
MySQL 8.0.36 , PostgreSQL 13.14, Oracle Database 21c, Oracle Database 23ai on VirtualBox for Apple Silicon Test Build 7.0.97_BETA r162957

| | | コメント (0)

2024年5月 4日 (土)

MySQL 8.0.36 , PostgreSQL 13.14, Oracle Database 21c, Oracle Database 23ai on VirtualBox for Apple Silicon Test Build 7.0.97_BETA r162957

Oracle Database 23c 改め、23ai となったのと、4/26日版 VirtualBox Test builds Development snapshotsがリリースされていた(だが、5/3版がすでに公開されていたw)
https://www.virtualbox.org/wiki/Testbuilds


20240503-95842


20240503-85117

M2 MBAでの確認情報だけで、M1はどうよ?とこともあるので、今回は、M1側で検証してみた。(本当はこちらでバシバシ使いたいわけですけども、まだまだ遅いので確認だけw)

*** mac info. ***
ProductName: macOS
ProductVersion: 14.4.1
BuildVersion: 23E224

*** maxOS ver. ***
Model Name: Mac Studio
Chip: Apple M1 Ultra
Total Number of Cores: 20 (16 performance and 4 efficiency)
Memory: 64 GB

*** VirtualBox ver. ***
7.0.97r162957
(VirtualBox 4/26 Test-Builds Developer Snapshot)


公開されたばかりの、Oracle Database 23ai Free DeveloperのVirtualBox pre-Build VMでの確認。
https://www.oracle.com/database/technologies/databaseappdev-vm.html

Oracle Database 23ai Free Developer (VirtualBox pre-build VM) / Oracle Linux 8.9

相変わらずもっさり感は強いもののなんとか起動します! 

[oracle@localhost ~]$ cat /etc/*release
Oracle Linux Server release 8.9
NAME="Oracle Linux Server"
VERSION="8.9"
ID="ol"
ID_LIKE="fedora"
VARIANT="Server"
VARIANT_ID="server"
VERSION_ID="8.9"
PLATFORM_ID="platform:el8"
PRETTY_NAME="Oracle Linux Server 8.9"
ANSI_COLOR="0;31"
CPE_NAME="cpe:/o:oracle:linux:8:9:server"
HOME_URL="https://linux.oracle.com/"
BUG_REPORT_URL="https://github.com/oracle/oracle-linux"

ORACLE_BUGZILLA_PRODUCT="Oracle Linux 8"
ORACLE_BUGZILLA_PRODUCT_VERSION=8.9
ORACLE_SUPPORT_PRODUCT="Oracle Linux"
ORACLE_SUPPORT_PRODUCT_VERSION=8.9
Red Hat Enterprise Linux release 8.9 (Ootpa)
Oracle Linux Server release 8.9

[oracle@localhost ~]$ sql hr/oracle@192.168.1.138:1521/freepdb1

SQLcl: 土 5月 04 01:14:44 2024のリリース24.1 Production

Copyright (c) 1982, 2024, Oracle. All rights reserved.

接続先:
Oracle Database 23ai Free Release 23.0.0.0.0 - Develop, Learn, and Run for Free
Version 23.4.0.24.05

SQL> select banner_full from V$version;

BANNER_FULL 
_______________________________________________________________________________
Oracle Database 23ai Free Release 23.0.0.0.0 - Develop, Learn, and Run for Free
Version 23.4.0.24.05

SQL> exit
Oracle Database 23ai Free Release 23.0.0.0.0 - Develop, Learn, and Run for Free
Version 23.4.0.24.05から切断されました
[oracle@localhost ~]$ sudo service oracle status
[sudo] oracle のパスワード:

LSNRCTL for Linux: Version 23.0.0.0.0 - Production on 04-MAY-2024 01:26:55

Copyright (c) 1991, 2024, Oracle. All rights reserved.

Connecting to (DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=localhost)(PORT=1521)))
STATUS of the LISTENER
------------------------
Alias LISTENER
Version TNSLSNR for Linux: Version 23.0.0.0.0 - Production
Start Date 04-MAY-2024 00:49:21
Uptime 0 days 0 hr. 37 min. 34 sec
Trace Level off
Security ON: Local OS Authentication
SNMP OFF
Default Service FREE
Listener Parameter File /opt/oracle/product/23ai/dbhomeFree/network/admin/listener.ora
Listener Log File /opt/oracle/diag/tnslsnr/localhost/listener/alert/log.xml
Listening Endpoints Summary...
(DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=localhost)(PORT=1521)))
(DESCRIPTION=(ADDRESS=(PROTOCOL=ipc)(KEY=EXTPROC1521)))
Services Summary...
Service "176858bcadf91ba6e0630100007f7de0" has 1 instance(s).
Instance "FREE", status READY, has 1 handler(s) for this service...
Service "FREE" has 2 instance(s).
Instance "FREE", status UNKNOWN, has 1 handler(s) for this service...
Instance "FREE", status READY, has 1 handler(s) for this service...
Service "FREEXDB" has 1 instance(s).
Instance "FREE", status READY, has 1 handler(s) for this service...
Service "freepdb1" has 1 instance(s).
Instance "FREE", status READY, has 1 handler(s) for this service...
The command completed successfully
[oracle@localhost ~]$ sudo service oracle stop
Stopping oracle (via systemctl): [ OK ]


続いて、いつもの 21c。 こちらは、 Oracle Linux 8.4に載せています

Oracle Database 21c EE / Oracle Linux 8.4

Oracle Database 21c EE / Oracle Linux 8.4
[master@localhost ~]$ cat /etc/*release
Oracle Linux Server release 8.4
NAME="Oracle Linux Server"
VERSION="8.4"
ID="ol"
ID_LIKE="fedora"
VARIANT="Server"
VARIANT_ID="server"
VERSION_ID="8.4"
PLATFORM_ID="platform:el8"
PRETTY_NAME="Oracle Linux Server 8.4"
ANSI_COLOR="0;31"
CPE_NAME="cpe:/o:oracle:linux:8:4:server"
HOME_URL="https://linux.oracle.com/"
BUG_REPORT_URL="https://bugzilla.oracle.com/"

ORACLE_BUGZILLA_PRODUCT="Oracle Linux 8"
ORACLE_BUGZILLA_PRODUCT_VERSION=8.4
ORACLE_SUPPORT_PRODUCT="Oracle Linux"
ORACLE_SUPPORT_PRODUCT_VERSION=8.4
Red Hat Enterprise Linux release 8.4 (Ootpa)
Oracle Linux Server release 8.4

[master@localhost ~]$ sudo su - oracle
[oracle@localhost ~]$ lsnrctl start

LSNRCTL for Linux: Version 21.0.0.0.0 - Production on 04-5月 -2024 08:54:58

Copyright (c) 1991, 2021, Oracle. All rights reserved.

/opt/oracle/product/21c/dbhome_1/bin/tnslsnrを起動しています。お待ちください...

TNSLSNR for Linux: Version 21.0.0.0.0 - Production
システム・パラメータ・ファイルは/opt/oracle/homes/OraDBHome21cEE/network/admin/listener.oraです。
ログ・メッセージを/opt/oracle/diag/tnslsnr/localhost/listener/alert/log.xmlに書き込みました。
リスニングしています: (DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=localhost)(PORT=1521)))
リスニングしています: (DESCRIPTION=(ADDRESS=(PROTOCOL=ipc)(KEY=EXTPROC1521)))

(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=localhost)(PORT=1521)))に接続中
リスナーのステータス
------------------------
別名 LISTENER
バージョン TNSLSNR for Linux: Version 21.0.0.0.0 - Production
開始日 04-5月 -2024 08:55:00
稼働時間 0 日 0 時間 0 分 0 秒
トレース・レベル off
セキュリティ ON: Local OS Authentication
SNMP OFF
パラメータ・ファイル /opt/oracle/homes/OraDBHome21cEE/network/admin/listener.ora
ログ・ファイル /opt/oracle/diag/tnslsnr/localhost/listener/alert/log.xml
リスニング・エンドポイントのサマリー...
(DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=localhost)(PORT=1521)))
(DESCRIPTION=(ADDRESS=(PROTOCOL=ipc)(KEY=EXTPROC1521)))
リスナーはサービスをサポートしていません。
コマンドは正常に終了しました。
[oracle@localhost ~]$
[oracle@localhost ~]$
[oracle@localhost ~]$ sqlplus / as sysdba

SQL*Plus: Release 21.0.0.0.0 - Production on 土 5月 4 08:55:08 2024
Version 21.3.0.0.0

Copyright (c) 1982, 2021, Oracle. All rights reserved.

アイドル・インスタンスに接続しました。

08:55:10 SYS@ORCLCDB> startup
ORACLEインスタンスが起動しました。

Total System Global Area 1073740720 bytes
Fixed Size 9694128 bytes
Variable Size 910163968 bytes
Database Buffers 41943040 bytes
Redo Buffers 7081984 bytes
In-Memory Area 104857600 bytes
データベースがマウントされました。
データベースがオープンされました。
08:58:23 SYS@ORCLCDB> select banner_full from v$version;

BANNER_FULL
----------------------------------------------------------------------
Oracle Database 21c Enterprise Edition Release 21.0.0.0.0 - Production
Version 21.3.0.0.0


経過: 00:00:00.32
08:58:36 SYS@ORCLCDB> exit
Oracle Database 21c Enterprise Edition Release 21.0.0.0.0 - Production
Version 21.3.0.0.0との接続が切断されました。
[oracle@localhost ~]$ sqlplus / as sysdba

SQL*Plus: Release 21.0.0.0.0 - Production on 土 5月 4 08:58:46 2024
Version 21.3.0.0.0

Copyright (c) 1982, 2021, Oracle. All rights reserved.

08:58:55 SYS@ORCLCDB> shutdown immediate
データベースがクローズされました。
データベースがディスマウントされました。
ORACLEインスタンスがシャットダウンされました。
09:00:51 SYS@ORCLCDB>


最後に、安定して起動しているMySQL/PostgreSQL
MySQL 8.0.36 and PostgreSQL 13.14 / Oracle Linux 8.5

[master@localhost ~]$ cat /etc/*release
Oracle Linux Server release 8.5
NAME="Oracle Linux Server"
VERSION="8.5"
ID="ol"
ID_LIKE="fedora"
VARIANT="Server"
VARIANT_ID="server"
VERSION_ID="8.5"
PLATFORM_ID="platform:el8"
PRETTY_NAME="Oracle Linux Server 8.5"
ANSI_COLOR="0;31"
CPE_NAME="cpe:/o:oracle:linux:8:5:server"
HOME_URL="https://linux.oracle.com/"
BUG_REPORT_URL="https://bugzilla.oracle.com/"

ORACLE_BUGZILLA_PRODUCT="Oracle Linux 8"
ORACLE_BUGZILLA_PRODUCT_VERSION=8.5
ORACLE_SUPPORT_PRODUCT="Oracle Linux"
ORACLE_SUPPORT_PRODUCT_VERSION=8.5
Red Hat Enterprise Linux release 8.5 (Ootpa)
Oracle Linux Server release 8.5

MySQL 8.0.36

Redirecting to /bin/systemctl status mysqld.service
● mysqld.service - MySQL 8.0 database server
Loaded: loaded (/usr/lib/systemd/system/mysqld.service; enabled; vendor preset: disabled)
Active: active (running) since Fri 2024-05-03 05:34:51 EDT; 53min ago
Main PID: 1119 (mysqld)
Status: "Server is operational"
Tasks: 38 (limit: 22947)
Memory: 34.5M
CGroup: /system.slice/mysqld.service
└─1119 /usr/libexec/mysqld --basedir=/usr

5月 03 05:34:04 localhost.localdomain systemd[1]: Starting MySQL 8.0 database server...
5月 03 05:34:07 localhost.localdomain mysql-check-socket[1034]: Socket file /var/lib/mysql/mysql.sock exists.
5月 03 05:34:08 localhost.localdomain mysql-check-socket[1034]: No process is using /var/lib/mysql/mysql.sock, which means it is a garbage, so it will be removed automatically.
5月 03 05:34:51 localhost.localdomain systemd[1]: Started MySQL 8.0 database server.
[master@localhost ~]$
[master@localhost ~]$
5月 03 05:34:47 localhost.localdomain systemd[1]: Started PostgreSQL 13 database server.

[master@localhost ~]$ mysql -u scott -D perftestdb -p -h 192.168.1.125
Enter password:
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 10
Server version: 8.0.36 Source distribution

Copyright (c) 2000, 2024, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> select version();
+-----------+
| version() |
+-----------+
| 8.0.36 |
+-----------+
1 row in set (0.02 sec)

mysql> exit
Bye
[master@localhost ~]$ sudo service mysqld stop
Redirecting to /bin/systemctl stop mysqld.service
[master@localhost ~]$ sudo service mysqld status
Redirecting to /bin/systemctl status mysqld.service
● mysqld.service - MySQL 8.0 database server
Loaded: loaded (/usr/lib/systemd/system/mysqld.service; enabled; vendor preset: disabled)
Active: inactive (dead) since Fri 2024-05-03 06:30:03 EDT; 8s ago
Process: 7704 ExecStopPost=/usr/libexec/mysql-wait-stop (code=exited, status=0/SUCCESS)
Process: 1119 ExecStart=/usr/libexec/mysqld --basedir=/usr (code=exited, status=0/SUCCESS)
Main PID: 1119 (code=exited, status=0/SUCCESS)
Status: "Server shutdown complete"

5月 03 05:34:04 localhost.localdomain systemd[1]: Starting MySQL 8.0 database server...
5月 03 05:34:07 localhost.localdomain mysql-check-socket[1034]: Socket file /var/lib/mysql/mysql.sock exists.
5月 03 05:34:08 localhost.localdomain mysql-check-socket[1034]: No process is using /var/lib/mysql/mysql.sock, which means it is a garbage, so it will be removed automatically.
5月 03 05:34:51 localhost.localdomain systemd[1]: Started MySQL 8.0 database server.
5月 03 06:29:56 localhost.localdomain systemd[1]: Stopping MySQL 8.0 database server...
5月 03 06:30:03 localhost.localdomain systemd[1]: mysqld.service: Succeeded.
5月 03 06:30:03 localhost.localdomain systemd[1]: Stopped MySQL 8.0 database server.

PostgreSQL 13.14

[master@localhost ~]$ sudo service postgresql-13 status
Redirecting to /bin/systemctl status postgresql-13.service
● postgresql-13.service - PostgreSQL 13 database server
Loaded: loaded (/usr/lib/systemd/system/postgresql-13.service; enabled; vendor preset: disabled)
Drop-In: /etc/systemd/system/postgresql-13.service.d
└─local.conf
Active: active (running) since Fri 2024-05-03 05:34:47 EDT; 54min ago
Docs: https://www.postgresql.org/docs/13/static/
Main PID: 1343 (postmaster)
Tasks: 9 (limit: 22947)
Memory: 19.7M
CGroup: /system.slice/postgresql-13.service
├─1343 /usr/pgsql-13/bin/postmaster -D /pg/pgdata/data
├─1411 postgres: logger
├─1591 postgres: checkpointer
├─1592 postgres: background writer
├─1593 postgres: walwriter
├─1594 postgres: autovacuum launcher
├─1596 postgres: archiver
├─1597 postgres: stats collector
└─1598 postgres: logical replication launcher

5月 03 05:34:25 localhost.localdomain systemd[1]: Starting PostgreSQL 13 database server...
5月 03 05:34:33 localhost.localdomain postmaster[1343]: 2024-05-03 05:34:33.304 EDT [1343] LOG: redirecting log output to logging collector process
5月 03 05:34:33 localhost.localdomain postmaster[1343]: 2024-05-03 05:34:33.304 EDT [1343] HINT: Future log output will appear in directory "log".

[postgres@localhost ~]$ psql -d perftestdb -U discus -p 5432 -W -h localhost
パスワード:
psql (13.14)
"help"でヘルプを表示します。

perftestdb=> select version();
version
----------------------------------------------------------------------------------------------------------
PostgreSQL 13.14 on x86_64-pc-linux-gnu, compiled by gcc (GCC) 8.5.0 20210514 (Red Hat 8.5.0-20), 64-bit
(1 行)

perftestdb=> exit
[postgres@localhost ~]$ exit
ログアウト
[master@localhost ~]$ sudo service postgresql-13 stop
Redirecting to /bin/systemctl stop postgresql-13.service
[master@localhost ~]$ sudo service postgresql-13 status
Redirecting to /bin/systemctl status postgresql-13.service
● postgresql-13.service - PostgreSQL 13 database server
Loaded: loaded (/usr/lib/systemd/system/postgresql-13.service; enabled; vendor preset: disabled)
Drop-In: /etc/systemd/system/postgresql-13.service.d
└─local.conf
Active: inactive (dead) since Fri 2024-05-03 06:31:04 EDT; 6s ago
Docs: https://www.postgresql.org/docs/13/static/
Process: 1343 ExecStart=/usr/pgsql-13/bin/postmaster -D ${PGDATA} (code=exited, status=0/SUCCESS)
Main PID: 1343 (code=exited, status=0/SUCCESS)

5月 03 05:34:25 localhost.localdomain systemd[1]: Starting PostgreSQL 13 database server...
5月 03 05:34:33 localhost.localdomain postmaster[1343]: 2024-05-03 05:34:33.304 EDT [1343] LOG: redirecting log output to logging collector process
5月 03 05:34:33 localhost.localdomain postmaster[1343]: 2024-05-03 05:34:33.304 EDT [1343] HINT: Future log output will appear in directory "log".
5月 03 05:34:47 localhost.localdomain systemd[1]: Started PostgreSQL 13 database server.
5月 03 06:31:03 localhost.localdomain systemd[1]: Stopping PostgreSQL 13 database server...
5月 03 06:31:04 localhost.localdomain systemd[1]: postgresql-13.service: Killing process 1411 (postmaster) with signal SIGKILL.
5月 03 06:31:04 localhost.localdomain systemd[1]: postgresql-13.service: Succeeded.
5月 03 06:31:04 localhost.localdomain systemd[1]: Stopped PostgreSQL 13 database server.

残る課題は処理速度改善だろうとは思うのですが、頑張って欲しいですね:)

そして、ゴールデンウィークなのに、真夏みたいな気温とか、異常すぎる。。。
体調管理に気を遣いつつも、こんな気候だと、まじで今年の夏はどうなることやら。。。。

ではまた。



Oracle Linux 8 and MySQL 8.0.32 on VirtualBox for Apple Silicon Test Build 7.0.97_BETA r160167
MySQL 8.0.32 , PostgreSQL 13.4 and Oracle Database 21c on Oracle Linux 8 on VirtualBox for Apple Silicon Test Build 7.0.97_BETA r160702
MySQL 8.0.32 , PostgreSQL 13.6 and Oracle Database 21c on Oracle Linux 8.5 on VirtualBox for Apple Silicon Test Build 7.0.97_BETA r161342
MySQL 8.0.32 , PostgreSQL 13.6 and Oracle Database 21c on Oracle Linux 8.5 on VirtualBox for Apple Silicon Test Build 7.0.97_BETA r161709

| | | コメント (0)

2023年9月 1日 (金)

Oracle Database 23c Free Developer Releaseの”_optimizer_max_permutations” parameterの設定値について

Previously on Mac De Oracle..
前回のお話は、帰ってきた! 標準はあるにはあるが癖の多いSQL #2 Actual Plan取得中のキャンセルでも癖が出るでした。Oracle/PostgreSQL/MySQLそれぞれ、再帰問合せで試してみましたが、興味深い違いが出ました。思わず、PostgreSQLのソースコード読み始めてしまいましたwwww

ということで、本日は、その流れで気づいてOracle 23c Freeのひみつ!


たまたま気づいたのですけど、 Oracle Database 23c Free Developer Release で、
under scored parameterの "_optimizer_max_permutations" って、 300なんですね。随分少ない設定にされていました。

これ

5! (120) < 6! (720) ということを意味するので、6表以上の結合では、通常のOracleより実行計画をミスりやすいということを意味しています。
(なぜなのでしょう、Free Developer Releaseだからではないか? というコメントももらいましたが、そうなのですかねぇ。でもそうかもしれないw。理由はなぜなのかわからんので何とも言えないですね)
なので、多数の結合を伴うSQLの検証には注意した方が良いですね。もしくは、通常の 2000 ぐらいまであげて試すとかしておいた方が良いかもね。
FreeのDeveloper Releaseだから 300 になっているのか確認できる資料は見つからなかったけど。


念の為、調べてみるとやはり、23c Free Developer Releaseのみ少なく設定されていました。

SYS@free> select banner from v$version;
BANNER
--------------------------------------------------------------------------------
Oracle Database 23c Free, Release 23.0.0.0.0 - Developer-Release

parameter name parameter value
-------------------------------- ------------------------------
_optimizer_max_permutations 300
_optimizer_search_limit 5



BANNER
----------------------------------------------------------------------
Oracle Database 21c Enterprise Edition Release 21.0.0.0.0 - Production

parameter name parameter value
------------------------------ ------------------------------
_optimizer_max_permutations 2000
_optimizer_search_limit 5


BANNER
--------------------------------------------------------------------------------
Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production

parameter name parameter value
------------------------------ ------------------------------
optimizer_max_permutations 2000
_optimizer_search_limit 5


BANNER
--------------------------------------------------------------------------------
Oracle Database 18c Enterprise Edition Release 18.0.0.0.0 - Production

parameter name parameter value
------------------------------ ------------------------------
_optimizer_max_permutations 2000
_optimizer_search_limit 5


BANNER
--------------------------------------------------------------------------------
Oracle Database 12c Enterprise Edition Release 12.2.0.1.0 - 64bit Production
PL/SQL Release 12.2.0.1.0 - Production
CORE 12.2.0.1.0 Production
TNS for Linux: Version 12.2.0.1.0 - Production
NLSRTL Version 12.2.0.1.0 - Production

parameter name parameter value
------------------------------ ------------------------------
_optimizer_max_permutations 2000
_optimizer_search_limit 5


Oracle 23c の正式版がリリースされたら皆さんも、2000になっているか確認しましょうね!(多分、2000になっていると思うけどw)

東京の8月が毎日真夏日だったなんで、話題。来年は毎日、猛暑日じゃなければ良いのですけども。。。
残暑厳しい東京からお送りしました。

では、また。

| | | コメント (0)

2023年1月27日 (金)

SQL*Plus -Fastオプション / FAQ

Previously on Mac De Oracle.
前回は、アドベントカレンダーのおまけのおまけwでした

今日は、そこで仕込んでおいたネタを使い、SQL*Plusも機能拡張されてたのすっかり忘れていた! ので、
高Fetch圧症の話に絡めてSQL*Plusの-F[ast]オプション書いておこうと思います。

軽めですが。

Fetch回数削減に効果があるので、多数の行をFetchするような時は思い出すと良いですね。
Client/Server間のrount tripが減ることに繋がるわけで、そこが慢性病の原因なら少しでも楽になれたら良いと思いますし。
(ということで、Fetch Sizeも忘れないでね。という気持ちを込めて。)

最初は、-Fastオプションなしで。arraysizeのデフォルトは 15です。なお、この -F[ast]オプションは、Oracle Database 12c 12.2以降でサポートされています。

[oracle@localhost ~]$ sqlplus scott/tiger@orclpdb1

...略...

Oracle Database 21c Enterprise Edition Release 21.0.0.0.0 - Production
Version 21.3.0.0.0
に接続されました。
SCOTT@orclpdb1> @dayx2
1 WITH
2 t1 AS
3 (
4 SELECT
5 pkey
6 , CASE
7 WHEN col2 IS NULL
8 THEN col1
9 ELSE col2
10 END AS join_key
11 ,description
12 FROM
13 nikoichi_mitaina_subtype
14 WHERE
15 col1 IS NOT NULL
16 OR col2 IS NOT NULL
17 )
18 SELECT *
19 FROM
20 supertype st
21 LEFT OUTER JOIN t1
22 ON
23* st.pkey = t1.join_key

1000001行が選択されました。

経過: 00:02:18.83

実行計画
----------------------------------------------------------
Plan hash value: 2223315184

-------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time |
-------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1000K| 1451M| | 119K (1)| 00:00:05 |
|* 1 | HASH JOIN OUTER | | 1000K| 1451M| 497M| 119K (1)| 00:00:05 |
| 2 | TABLE ACCESS FULL| SUPERTYPE | 1000K| 486M| | 19593 (1)| 00:00:01 |
|* 3 | TABLE ACCESS FULL| NIKOICHI_MITAINA_SUBTYPE | 750K| 723M| | 38796 (1)| 00:00:02 |
-------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

1 - access("ST"."PKEY"=CASE WHEN (ROWID(+) IS NOT NULL) THEN CASE WHEN ("COL2"(+) IS
NULL) THEN "COL1"(+) ELSE "COL2"(+) END ELSE NULL END )
3 - filter("COL1"(+) IS NOT NULL OR "COL2"(+) IS NOT NULL)


統計
----------------------------------------------------------
1297 recursive calls
0 db block gets
229599 consistent gets
374715 physical reads
0 redo size
1551273711 bytes sent via SQL*Net to client
735146 bytes received via SQL*Net from client
66668 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1000001 rows processed


1 WITH
2 t1 AS
3 (
4 SELECT
5 pkey
6 , CASE
7 WHEN col2 IS NULL
8 THEN col1
9 ELSE col2
10 END AS join_key
11 ,description
12 FROM
13 nikoichi_mitaina_subtype
14 WHERE
15 col1 IS NOT NULL
16 OR col2 IS NOT NULL
17 )
18 SELECT /*+ MONITOR */ *
19 FROM
20 supertype st
21 LEFT OUTER JOIN t1
22 ON
23* st.pkey = t1.join_key

DBMS_SQLTUNE.REPORT_SQL_MONITOR(SQL_ID=>NULL,TYPE=>'TEXT')
---------------------------------------------------------------------
SQL Monitoring Report

SQL Text
------------------------------
WITH t1 AS ( SELECT pkey , CASE WHEN col2 IS NULL THEN col1 ELSE col2 END AS join_key ,description
FROM nikoichi_mitaina_subtype WHERE col1 IS NOT NULL OR col2 IS NOT NULL ) SELECT /*+ MONITOR */ *
FROM supertype st LEFT OUTER JOIN t1 ON st.pkey = t1.join_key

Global Information
------------------------------

...略...

Duration : 173s

...略...

Fetch Calls : 66668

Global Stats
===========================================================================================
| Elapsed | Cpu | IO | Other | Fetch | Buffer | Read | Read | Write | Write |
| Time(s) | Time(s) | Waits(s) | Waits(s) | Calls | Gets | Reqs | Bytes | Reqs | Bytes |
===========================================================================================
| 17 | 15 | 1.59 | 0.84 | 66668 | 230K | 6878 | 3GB | 5169 | 1GB |
===========================================================================================

SQL Plan Monitoring Details (Plan Hash Value=2223315184)
==============================================================================================================================================================================================================
| Id | Operation | Name | Rows | Cost | Time | Start | Execs | Rows | Read | Read | Write | Write | Mem | Temp | Activity | Activity Detail |
| | | | (Estim) | | Active(s) | Active | | (Actual) | Reqs | Bytes | Reqs | Bytes | (Max) | (Max) | (%) | (# samples) |
==============================================================================================================================================================================================================
| 0 | SELECT STATEMENT | | | | 172 | +2 | 1 | 1M | | | | | . | . | | |
| 1 | HASH JOIN OUTER | | 1M | 119K | 173 | +1 | 1 | 1M | 5169 | 1GB | 5169 | 1GB | 184MB | 1GB | 76.92 | Cpu (9) |
| | | | | | | | | | | | | | | | | SQL*Net more data to client (1) |
| 2 | TABLE ACCESS FULL | SUPERTYPE | 1M | 19593 | 1 | +2 | 1 | 1M | 575 | 559MB | | | . | . | | |
| 3 | TABLE ACCESS FULL | NIKOICHI_MITAINA_SUBTYPE | 750K | 38796 | 47 | +2 | 1 | 1M | 1134 | 1GB | | | . | . | 15.38 | Cpu (2) |
==============================================================================================================================================================================================================


次に、-F[ast]オプションで接続します。このオプションにより、ARRAYSIZE = 100に設定されます。それ以外にも3.5.1.5 FASTオプションいくつかの設定が変更されます。

[oracle@localhost ~]$ sqlplus -Fast scott/tiger@orclpdb1

...略...

Oracle Database 21c Enterprise Edition Release 21.0.0.0.0 - Production
Version 21.3.0.0.0
に接続されました。
SCOTT@orclpdb1> @dayx2
1 WITH
2 t1 AS
3 (
4 SELECT
5 pkey
6 , CASE
7 WHEN col2 IS NULL
8 THEN col1
9 ELSE col2
10 END AS join_key
11 ,description
12 FROM
13 nikoichi_mitaina_subtype
14 WHERE
15 col1 IS NOT NULL
16 OR col2 IS NOT NULL
17 )
18 SELECT *
19 FROM
20 supertype st
21 LEFT OUTER JOIN t1
22 ON
23* st.pkey = t1.join_key

1000001行が選択されました。

経過: 00:01:55.03

実行計画
----------------------------------------------------------
Plan hash value: 2223315184

-------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time |
-------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1000K| 1451M| | 119K (1)| 00:00:05 |
|* 1 | HASH JOIN OUTER | | 1000K| 1451M| 497M| 119K (1)| 00:00:05 |
| 2 | TABLE ACCESS FULL| SUPERTYPE | 1000K| 486M| | 19593 (1)| 00:00:01 |
|* 3 | TABLE ACCESS FULL| NIKOICHI_MITAINA_SUBTYPE | 750K| 723M| | 38796 (1)| 00:00:02 |
-------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

1 - access("ST"."PKEY"=CASE WHEN (ROWID(+) IS NOT NULL) THEN CASE WHEN ("COL2"(+) IS
NULL) THEN "COL1"(+) ELSE "COL2"(+) END ELSE NULL END )
3 - filter("COL1"(+) IS NOT NULL OR "COL2"(+) IS NOT NULL)


統計
----------------------------------------------------------
1297 recursive calls
0 db block gets
216797 consistent gets
374715 physical reads
0 redo size
1539940308 bytes sent via SQL*Net to client
110262 bytes received via SQL*Net from client
10001 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1000001 rows processed


1 WITH
2 t1 AS
3 (
4 SELECT
5 pkey
6 , CASE
7 WHEN col2 IS NULL
8 THEN col1
9 ELSE col2
10 END AS join_key
11 ,description
12 FROM
13 nikoichi_mitaina_subtype
14 WHERE
15 col1 IS NOT NULL
16 OR col2 IS NOT NULL
17 )
18 SELECT /*+ MONITOR */ *
19 FROM
20 supertype st
21 LEFT OUTER JOIN t1
22 ON
23* st.pkey = t1.join_key

DBMS_SQLTUNE.REPORT_SQL_MONITOR(SQL_ID=>NULL,TYPE=>'TEXT')
----------------------------------------------------------------
SQL Monitoring Report

SQL Text
------------------------------
WITH t1 AS ( SELECT pkey , CASE WHEN col2 IS NULL THEN col1 ELSE col2 END AS join_key ,description
FROM nikoichi_mitaina_subtype WHERE col1 IS NOT NULL OR col2 IS NOT NULL ) SELECT /*+ MONITOR */ *
FROM supertype st LEFT OUTER JOIN t1 ON st.pkey = t1.join_key

Global Information
------------------------------

...略...

Duration : 146s

...略...

Fetch Calls : 10001

Global Stats
============================================================================================
| Elapsed | Cpu | IO | Other | Fetch | Buffer | Read | Read | Write | Write |
| Time(s) | Time(s) | Waits(s) | Waits(s) | Calls | Gets | Reqs | Bytes | Reqs | Bytes |
============================================================================================
| 17 | 14 | 1.76 | 1.72 | 10001 | 216K | 6878 | 3GB | 5169 | 1GB |
============================================================================================

SQL Plan Monitoring Details (Plan Hash Value=2223315184)
==============================================================================================================================================================================================================
| Id | Operation | Name | Rows | Cost | Time | Start | Execs | Rows | Read | Read | Write | Write | Mem | Temp | Activity | Activity Detail |
| | | | (Estim) | | Active(s) | Active | | (Actual) | Reqs | Bytes | Reqs | Bytes | (Max) | (Max) | (%) | (# samples) |
==============================================================================================================================================================================================================
| 0 | SELECT STATEMENT | | | | 145 | +2 | 1 | 1M | | | | | . | . | | |
| 1 | HASH JOIN OUTER | | 1M | 119K | 146 | +1 | 1 | 1M | 5169 | 1GB | 5169 | 1GB | 184MB | 1GB | 100.00 | Cpu (14) |
| | | | | | | | | | | | | | | | | SQL*Net more data to client (4) |
| 2 | TABLE ACCESS FULL | SUPERTYPE | 1M | 19593 | 1 | +2 | 1 | 1M | 575 | 559MB | | | . | . | | |
| 3 | TABLE ACCESS FULL | NIKOICHI_MITAINA_SUBTYPE | 750K | 38796 | 42 | +2 | 1 | 1M | 1134 | 1GB | | | . | . | | |
==============================================================================================================================================================================================================


-Fastオプションなしの場合と比較してみるとSQL*Net roundtrips to/from clientなど減ってますよね:)
このround tripは、待機イベントSQL*Net more data to clientなどで現れます。(SQL監視のActivity Detailsにも現れていますので、覚えておくと良いと思います)

-Fastオプションなし(auto trace)

1551273711  bytes sent via SQL*Net to client
735146 bytes received via SQL*Net from client
66668 SQL*Net roundtrips to/from client

-Fastオプションあり(auto trace)

1539940308  bytes sent via SQL*Net to client
110262 bytes received via SQL*Net from client
10001 SQL*Net roundtrips to/from client

-Fastオプションなし(SQL監視)

Global Information
------------------------------
...略...
Duration : 173s
...略...
Fetch Calls : 66668

-Fastオプションあり(auto trace)

Global Information
------------------------------
...略...
Dration : 146s
...略...
Fetch Calls : 10001

早く、ポカポカ陽気にならないかなぁ。

と思う寒い日々。

では、また。

| | | コメント (0)

2023年1月16日 (月)

実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 / No.61 / ANSI JOINのおまけのおまけ

年を跨いで, ”実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 / No.61 / ANSI JOINのおまけ”のおまけです.

前回の投稿から間隔が空いていたので, まずは, 簡単な復習から.

ANSI構文のON句の結合条件でORが利用されているという, スーパータイプ, サブタイプテーブルの実装崩れというか, 大人の事情に押し切られて負けた感じありありの半端な状態.
あ, そうだ, Oralceの外部結合だとOR使えないけど, ANSIなら使えるじゃん!
という流れを感じるSQL文を, Oracleのオプティマイザは, LATERALへの書き換え(VW_LAT_E87C3AAF)や, OR EXPANDの書き換え(VW_ORE_FDF394AE)を駆使して, 物凄い最適化を行っていました.

この例では, 外部表, 内部表の多重度は, 1:0..1. かつ, スーパータイプ, サブタイプでいうところの不完全なサブタイプ.
さらに, 内部表は, 単純にニコイチにしただけのようなサブタイプテーブルで外部表との結合列が2列(おそらく本来同一列に統合されていただろう. . と思われる)ある. 惜しい!という感じのモデル.
比較的軽度のモデリング障害ではあるので, このまま使うのであれば, LATERAL変換されるのを避けるような書き換え, 比較的単純な HASH JOIN なるようにすればそこそこ改善できそうな感じはしますよね(いわゆるTemp落ちはある程度発生する前提で)

なお, この例で AUTO TRACEでの実行時間と, SQL MONITORの実行時間(DB内部)に差異があることに気づいた方もいると思いますが. これ, クライアントがデータをFETCHしている時間ですね. 行数が多いので. SQL*Plusの場合, デフォルトのFETCH SIZEが15なので行数が多いと, FETCHの際, サーバーからの受信で時間がかかります.
(この症状は以前, 高フェッチ圧症として紹介したこともあるので, 覚えている方も多いのではないかと思います. この例では1行の行サイズも大きめかつ, 行数も多めにして SELECT * にしているのでそこそこ目立つ時間になるようにしています. これも別のエントリーでネタにするための仕込みではあるのですが, 今回の記事では気にしないでください. SQLモニターのサーバー内部での純粋な処理時間だけで, 書き換え前後での差を見て行きます!)

SCOTT@orclpdb1> @dayx
1 SELECT *
2 FROM
3 supertype st
4 LEFT OUTER JOIN nikoichi_mitaina_subtype nmst
5 ON
6 st.pkey = nmst.col1
7* OR st.pkey = nmst.col2

10001行が選択されました.

経過: 00:00:01.41

実行計画
----------------------------------------------------------
Plan hash value: 2133431102

-------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 20002 | 20M| 40226 (1)| 00:00:02 |
| 1 | MERGE JOIN OUTER | | 20002 | 20M| 40226 (1)| 00:00:02 |
| 2 | TABLE ACCESS FULL | SUPERTYPE | 10001 | 4971K| 204 (0)| 00:00:01 |
| 3 | BUFFER SORT | | 2 | 1082 | 40021 (1)| 00:00:02 |
| 4 | VIEW | VW_LAT_E87C3AAF | 2 | 1082 | 4 (0)| 00:00:01 |
| 5 | VIEW | VW_ORE_FDF394AE | 2 | 1082 | 4 (0)| 00:00:01 |
| 6 | UNION-ALL | | | | | |
| 7 | TABLE ACCESS BY INDEX ROWID| NIKOICHI_MITAINA_SUBTYPE | 1 | 1009 | 2 (0)| 00:00:01 |
|* 8 | INDEX UNIQUE SCAN | UK1 | 1 | | 1 (0)| 00:00:01 |
|* 9 | TABLE ACCESS BY INDEX ROWID| NIKOICHI_MITAINA_SUBTYPE | 1 | 1009 | 2 (0)| 00:00:01 |
|* 10 | INDEX UNIQUE SCAN | UK2 | 1 | | 1 (0)| 00:00:01 |
-------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

8 - access("ST"."PKEY"="NMST"."COL1")
filter("NMST"."COL1" IS NOT NULL)
9 - filter(LNNVL("ST"."PKEY"="NMST"."COL1"))
10 - access("ST"."PKEY"="NMST"."COL2")
filter("NMST"."COL2" IS NOT NULL)

統計
----------------------------------------------------------
0 recursive calls
0 db block gets
32231 consistent gets
0 physical reads
0 redo size
15493776 bytes sent via SQL*Net to client (別エントリ向け)
7378 bytes received via SQL*Net from client
668 SQL*Net roundtrips to/from client (別エントリ向け)
10001 sorts (memory)
0 sorts (disk)
10001 rows processed


1 SELECT /*+ MONITOR */ *
2 FROM
3 supertype st
4 LEFT OUTER JOIN nikoichi_mitaina_subtype nmst
5 ON
6 st.pkey = nmst.col1
7* OR st.pkey = nmst.col2

DBMS_SQLTUNE.REPORT_SQL_MONITOR(SQL_ID=>NULL,TYPE=>'TEXT')
--------------------------------------------------------------------------------------------------------------------------------------
SQL Monitoring Report

SQL Text
------------------------------
SELECT /*+ MONITOR */ * FROM supertype st LEFT OUTER JOIN nikoichi_mitaina_subtype nmst ON st.pkey = nmst.col1 OR st.pkey = nmst.col2

Global Information
------------------------------
Status : DONE (ALL ROWS)

...略...

Duration : 3s(別ネタ向け仕込み)

...略...

Global Stats
=================================================
| Elapsed | Cpu | Other | Fetch | Buffer |
| Time(s) | Time(s) | Waits(s) | Calls | Gets |
=================================================
| 0.37 | 0.31 | 0.06 | 668 | 32231 |
=================================================

SQL Plan Monitoring Details (Plan Hash Value=2133431102)
=====================================================================================================================================================================
| Id | Operation | Name | Rows | Cost | Time | Start | Execs | Rows | Mem | Activity | Activity Detail |
| | | | (Estim) | | Active(s) | Active | | (Actual) | (Max) | (%) | (# samples) |
=====================================================================================================================================================================
| 0 | SELECT STATEMENT | | | | 4 | +0 | 1 | 10001 | . | | |
| 1 | MERGE JOIN OUTER | | 20002 | 40226 | 4 | +0 | 1 | 10001 | . | | |
| 2 | TABLE ACCESS FULL | SUPERTYPE | 10001 | 204 | 4 | +0 | 1 | 10001 | . | | |
| 3 | BUFFER SORT | | 2 | 40021 | 4 | +0 | 10001 | 10000 | 2048 | | |
| 4 | VIEW | VW_LAT_E87C3AAF | 2 | 4 | 4 | +0 | 10001 | 10000 | . | | |
| 5 | VIEW | VW_ORE_FDF394AE | 2 | 4 | 4 | +0 | 10001 | 10000 | . | | |
| 6 | UNION-ALL | | | | 4 | +0 | 10001 | 10000 | . | | |
| 7 | TABLE ACCESS BY INDEX ROWID | NIKOICHI_MITAINA_SUBTYPE | 1 | 2 | 4 | +0 | 10001 | 5000 | . | | |
| 8 | INDEX UNIQUE SCAN | UK1 | 1 | 1 | 4 | +0 | 10001 | 5000 | . | | |
| 9 | TABLE ACCESS BY INDEX ROWID | NIKOICHI_MITAINA_SUBTYPE | 1 | 2 | 4 | +0 | 10001 | 5000 | . | | |
| 10 | INDEX UNIQUE SCAN | UK2 | 1 | 1 | 4 | +0 | 10001 | 5000 | . | | |
=====================================================================================================================================================================

では, 書き換えて, LATERAL変換を避け, HASH JOINになるようにしてみましょう. (WITH句を利用していますが, 再利用ではなく読みやすさ狙いです. Oracleもそれを理解できるのでインラインビューとして扱われます)
今回のようなデータモデル障害の場合は, 治療もシンプルで良いのですがw(例に取り上げるのがメンドクサイやつだと, 解説するのもメンドクサイし良いことないので)

現場どのようになっているかを理解する必要があります. この例では, col1列とcol2列は実は同一列で良いだろうということになるので, 以下のように書き換えれば, JOIN ON ... OR なんて現時点のオプティマイザでは, ほぼ危険な感じしかしない実行計画になるようなSQLへの書き換えも回避できるのではないでしょうか?
結果は見ての通り, 別エントリ向けの仕込みであるFETCH時間を除いたデータベース内部のみの処理時間は, 0.37sec から 0.15secと62%ほど改善しています(ただ, このデータ量で私の環境だとPGA内に収まっているのでTemp落ちの影響は見えないですね. オンメモリなら勝ちは確実ですが)

  1  WITH
2 t1 AS
3 (
4 SELECT
5 pkey
6 , CASE
7 WHEN col2 IS NULL
8 THEN col1
9 ELSE col2
10 END AS join_key
11 ,description
12 FROM
13 nikoichi_mitaina_subtype
14 WHERE
15 col1 IS NOT NULL
16 OR col2 IS NOT NULL
17 )
18 SELECT *
19 FROM
20 supertype st
21 LEFT OUTER JOIN t1
22 ON
23* st.pkey = t1.join_key

10001行が選択されました.

経過: 00:00:01.28

実行計画
----------------------------------------------------------
Plan hash value: 2223315184

-------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time |
-------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 10001 | 14M| | 1224 (1)| 00:00:01 |
|* 1 | HASH JOIN OUTER | | 10001 | 14M| 5096K| 1224 (1)| 00:00:01 |
| 2 | TABLE ACCESS FULL| SUPERTYPE | 10001 | 4971K| | 204 (0)| 00:00:01 |
|* 3 | TABLE ACCESS FULL| NIKOICHI_MITAINA_SUBTYPE | 7500 | 7390K| | 410 (1)| 00:00:01 |
-------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

1 - access("ST"."PKEY"=CASE WHEN (ROWID(+) IS NOT NULL) THEN CASE WHEN ("COL2"(+) IS
NULL) THEN "COL1"(+) ELSE "COL2"(+) END ELSE NULL END )
3 - filter("COL1"(+) IS NOT NULL OR "COL2"(+) IS NOT NULL)

統計
----------------------------------------------------------
0 recursive calls
0 db block gets
2748 consistent gets
0 physical reads
0 redo size
15483707 bytes sent via SQL*Net to client(別ネタ向け仕込み)
7378 bytes received via SQL*Net from client
668 SQL*Net roundtrips to/from client(別ネタ向け仕込み)
0 sorts (memory)
0 sorts (disk)
10001 rows processed


1 WITH
2 t1 AS
3 (
4 SELECT
5 pkey
6 , CASE
7 WHEN col2 IS NULL
8 THEN col1
9 ELSE col2
10 END AS join_key
11 ,description
12 FROM
13 nikoichi_mitaina_subtype
14 WHERE
15 col1 IS NOT NULL
16 OR col2 IS NOT NULL
17 )
18 SELECT /*+ MONITOR */ *
19 FROM
20 supertype st
21 LEFT OUTER JOIN t1
22 ON
23* st.pkey = t1.join_key

DBMS_SQLTUNE.REPORT_SQL_MONITOR(SQL_ID=>NULL,TYPE=>'TEXT')
----------------------------------------------------------------------------------------------------------------
SQL Monitoring Report

SQL Text
------------------------------
WITH t1 AS ( SELECT pkey , CASE WHEN col2 IS NULL THEN col1 ELSE col2 END AS join_key ,description
FROM nikoichi_mitaina_subtype WHERE col1 IS NOT NULL OR col2 IS NOT NULL ) SELECT /*+ MONITOR */ *
FROM supertype st LEFT OUTER JOIN t1 ON st.pkey = t1.join_key

Global Information
------------------------------
Status : DONE (ALL ROWS)

...略...

Duration : 2s(別ネタ向け仕込み)

...略...

Global Stats
=================================================
| Elapsed | Cpu | Other | Fetch | Buffer |
| Time(s) | Time(s) | Waits(s) | Calls | Gets |
=================================================
| 0.15 | 0.13 | 0.02 | 668 | 2748 |
=================================================

SQL Plan Monitoring Details (Plan Hash Value=2223315184)
======================================================================================================================================================
| Id | Operation | Name | Rows | Cost | Time | Start | Execs | Rows | Mem | Activity | Activity Detail |
| | | | (Estim) | | Active(s) | Active | | (Actual) | (Max) | (%) | (# samples) |
======================================================================================================================================================
| 0 | SELECT STATEMENT | | | | 3 | +0 | 1 | 10001 | . | | |
| 1 | HASH JOIN OUTER | | 10001 | 1224 | 3 | +0 | 1 | 10001 | 7MB | | |
| 2 | TABLE ACCESS FULL | SUPERTYPE | 10001 | 204 | 1 | +0 | 1 | 10001 | . | | |
| 3 | TABLE ACCESS FULL | NIKOICHI_MITAINA_SUBTYPE | 7500 | 410 | 3 | +0 | 1 | 10000 | . | | |
======================================================================================================================================================

将来のデータ量が100倍だとして. . . . HASH JOIN化してTemp落ちの影響も含めて見ておきましょう

SCOTT@orclpdb1> @dayx-1
1* DROP TABLE supertype

表が削除されました.

経過: 00:00:00.47
1 CREATE TABLE supertype
2 (
3 pkey NUMBER PRIMARY KEY
4 , attr1 NUMBER NOT NULL
5 , attr2 NUMBER NOT NULL
6 , note VARCHAR2(500)
7* )

表が作成されました.

経過: 00:00:00.15
1* DROP TABLE nikoichi_mitaina_subtype

表が削除されました.

経過: 00:00:00.05
1 CREATE TABLE nikoichi_mitaina_subtype
2 (
3 pkey NUMBER PRIMARY KEY
4 , col1 NUMBER
5 , col2 NUMBER
6 , description VARCHAR2(1000)
7 , CONSTRAINT uk1 unique (col1) USING INDEX
8 , CONSTRAINT uk2 unique (col2) USING INDEX
9* )

表が作成されました.

経過: 00:00:00.03
1 DECLARE
2 cMAX_ROWS CONSTANT NUMBER := 1000000;
3 BEGIN
4 FOR i IN 1..cMAX_ROWS LOOP
5 INSERT INTO supertype VALUES(i,0,0,LPAD(i,500,'*'));
6 INSERT INTO nikoichi_mitaina_subtype VALUES(
7 i
8 , CASE WHEN MOD(i,2) = 0 THEN i ELSE null END
9 , CASE WHEN MOD(i,2) = 1 THEN i ELSE null END
10 , LPAD(i,1000,'*')
11 );
12 IF MOD(i,100) = 0 THEN COMMIT; END IF;
13 END LOOP;
14 INSERT INTO supertype VALUES(cMAX_ROWS+1,0,0,null);
15 COMMIT;
16 DBMS_STATS.GATHER_TABLE_STATS(ownname=>'SCOTT',tabname=>'SUPERTYPE',no_invalidate=>false,cascade=>true);
17 DBMS_STATS.GATHER_TABLE_STATS(ownname=>'SCOTT',tabname=>'NIKOICHI_MITAINA_SUBTYPE',no_invalidate=>false,cascade=>true);
18* END;

PL/SQLプロシージャが正常に完了しました.

経過: 00:04:37.66


まず元ネタのLATERALとOR EXPAND書き換えされている方はどうか. . SQLモニターのExecが綺麗に増加(当然ですが)

SCOTT@orclpdb1> @dayx
1 SELECT *
2 FROM
3 supertype st
4 LEFT OUTER JOIN nikoichi_mitaina_subtype nmst
5 ON
6 st.pkey = nmst.col1
7* OR st.pkey = nmst.col2

1000001行が選択されました.

経過: 00:02:23.03

実行計画
----------------------------------------------------------
Plan hash value: 2133431102

-------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 2000K| 2004M| 6022K (1)| 00:03:56 |
| 1 | MERGE JOIN OUTER | | 2000K| 2004M| 6022K (1)| 00:03:56 |
| 2 | TABLE ACCESS FULL | SUPERTYPE | 1000K| 486M| 19524 (1)| 00:00:01 |
| 3 | BUFFER SORT | | 2 | 1082 | 6002K (1)| 00:03:55 |
| 4 | VIEW | VW_LAT_E87C3AAF | 2 | 1082 | 6 (0)| 00:00:01 |
| 5 | VIEW | VW_ORE_FDF394AE | 2 | 1082 | 6 (0)| 00:00:01 |
| 6 | UNION-ALL | | | | | |
| 7 | TABLE ACCESS BY INDEX ROWID| NIKOICHI_MITAINA_SUBTYPE | 1 | 1012 | 3 (0)| 00:00:01 |
|* 8 | INDEX UNIQUE SCAN | UK1 | 1 | | 2 (0)| 00:00:01 |
|* 9 | TABLE ACCESS BY INDEX ROWID| NIKOICHI_MITAINA_SUBTYPE | 1 | 1012 | 3 (0)| 00:00:01 |
|* 10 | INDEX UNIQUE SCAN | UK2 | 1 | | 2 (0)| 00:00:01 |
-------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

8 - access("ST"."PKEY"="NMST"."COL1")
filter("NMST"."COL1" IS NOT NULL)
9 - filter(LNNVL("ST"."PKEY"="NMST"."COL1"))
10 - access("ST"."PKEY"="NMST"."COL2")
filter("NMST"."COL2" IS NOT NULL)

統計
----------------------------------------------------------
0 recursive calls
0 db block gets
3561836 consistent gets
71485 physical reads
0 redo size
1552273780 bytes sent via SQL*Net to client(別ネタ向け仕込み)
734925 bytes received via SQL*Net from client
66668 SQL*Net roundtrips to/from client(別ネタ向け仕込み)
1000001 sorts (memory)
0 sorts (disk)
1000001 rows processed


1 SELECT /*+ MONITOR */ *
2 FROM
3 supertype st
4 LEFT OUTER JOIN nikoichi_mitaina_subtype nmst
5 ON
6 st.pkey = nmst.col1
7* OR st.pkey = nmst.col2

DBMS_SQLTUNE.REPORT_SQL_MONITOR(SQL_ID=>NULL,TYPE=>'TEXT')
-----------------------------------------------------------------------------------------
SQL Monitoring Report

SQL Text
------------------------------
SELECT /*+ MONITOR */ * FROM supertype st LEFT OUTER JOIN nikoichi_mitaina_subtype nmst
ON st.pkey = nmst.col1 OR st.pkey = nmst.col2

Global Information
------------------------------
Status : DONE (ALL ROWS)

...略...

Duration : 219s(別ネタ向け仕込み)

...略...

Global Stats
===========================================================================
| Elapsed | Cpu | IO | Other | Fetch | Buffer | Read | Read |
| Time(s) | Time(s) | Waits(s) | Waits(s) | Calls | Gets | Reqs | Bytes |
===========================================================================
| 37 | 32 | 0.22 | 4.20 | 66668 | 4M | 573 | 558MB |
===========================================================================

SQL Plan Monitoring Details (Plan Hash Value=2133431102)
====================================================================================================================================================================================
| Id | Operation | Name | Rows | Cost | Time | Start | Execs | Rows | Read | Read | Mem | Activity | Activity Detail |
| | | | (Estim) | | Active(s) | Active | | (Actual) | Reqs | Bytes | (Max) | (%) | (# samples) |
====================================================================================================================================================================================
| 0 | SELECT STATEMENT | | | | 220 | +0 | 1 | 1M | | | . | | |
| 1 | MERGE JOIN OUTER | | 2M | 6M | 220 | +0 | 1 | 1M | | | . | 6.90 | Cpu (2) |
| 2 | TABLE ACCESS FULL | SUPERTYPE | 1M | 19524 | 220 | +0 | 1 | 1M | 573 | 558MB | . | 10.34 | Cpu (3) |
| 3 | BUFFER SORT | | 2 | 6M | 220 | +0 | 1M | 1M | | | 2048 | 17.24 | Cpu (5) |
| 4 | VIEW | VW_LAT_E87C3AAF | 2 | 6 | 220 | +0 | 1M | 1M | | | . | | |
| 5 | VIEW | VW_ORE_FDF394AE | 2 | 6 | 220 | +0 | 1M | 1M | | | . | | |
| 6 | UNION-ALL | | | | 220 | +0 | 1M | 1M | | | . | 6.90 | Cpu (2) |
| 7 | TABLE ACCESS BY INDEX ROWID | NIKOICHI_MITAINA_SUBTYPE | 1 | 3 | 220 | +0 | 1M | 500K | | | . | | |
| 8 | INDEX UNIQUE SCAN | UK1 | 1 | 2 | 220 | +0 | 1M | 500K | | | . | 17.24 | Cpu (5) |
| 9 | TABLE ACCESS BY INDEX ROWID | NIKOICHI_MITAINA_SUBTYPE | 1 | 3 | 220 | +0 | 1M | 500K | | | . | | |
| 10 | INDEX UNIQUE SCAN | UK2 | 1 | 2 | 220 | +0 | 1M | 500K | | | . | 6.90 | Cpu (2) |
====================================================================================================================================================================================


LATERAL変換を避け, HASH JOINにしてくれるような書き換えを行った方はどうかというと.
やはり, PGA内に収まっていたHASH JOINと比較して, Temp落ち(1GBほど)の影響で改善幅は減っていますが, 37sec が 32secと, 15%程度は勝っていますね. Temp落ちは避けられないですからね.

であれば, Temp落ちの落ちている先を速くすれば良いではないか. . . ということで, メモリにさえ余裕があれば, 使いすぎないようにした上で, tmpfs を使ってみましょうか. (一時表領域はなければOracleが再作成してくれるので)

  1  WITH
2 t1 AS
3 (
4 SELECT
5 pkey
6 , CASE
7 WHEN col2 IS NULL
8 THEN col1
9 ELSE col2
10 END AS join_key
11 ,description
12 FROM
13 nikoichi_mitaina_subtype
14 WHERE
15 col1 IS NOT NULL
16 OR col2 IS NOT NULL
17 )
18 SELECT *
19 FROM
20 supertype st
21 LEFT OUTER JOIN t1
22 ON
23* st.pkey = t1.join_key

1000001行が選択されました.

経過: 00:02:24.20

実行計画
----------------------------------------------------------
Plan hash value: 2223315184

-------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time |
-------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1000K| 1451M| | 120K (1)| 00:00:05 |
|* 1 | HASH JOIN OUTER | | 1000K| 1451M| 497M| 120K (1)| 00:00:05 |
| 2 | TABLE ACCESS FULL| SUPERTYPE | 1000K| 486M| | 19524 (1)| 00:00:01 |
|* 3 | TABLE ACCESS FULL| NIKOICHI_MITAINA_SUBTYPE | 750K| 723M| | 39559 (1)| 00:00:02 |
-------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

1 - access("ST"."PKEY"=CASE WHEN (ROWID(+) IS NOT NULL) THEN CASE WHEN ("COL2"(+) IS
NULL) THEN "COL1"(+) ELSE "COL2"(+) END ELSE NULL END )
3 - filter("COL1"(+) IS NOT NULL OR "COL2"(+) IS NOT NULL)

統計
----------------------------------------------------------
1297 recursive calls
0 db block gets
229696 consistent gets
374740 physical reads
0 redo size
1551273711 bytes sent via SQL*Net to client(別ネタ向け仕込み)
734925 bytes received via SQL*Net from client
66668 SQL*Net roundtrips to/from client(別ネタ向け仕込み)
0 sorts (memory)
0 sorts (disk)
1000001 rows processed


1 WITH
2 t1 AS
3 (
4 SELECT
5 pkey
6 , CASE
7 WHEN col2 IS NULL
8 THEN col1
9 ELSE col2
10 END AS join_key
11 ,description
12 FROM
13 nikoichi_mitaina_subtype
14 WHERE
15 col1 IS NOT NULL
16 OR col2 IS NOT NULL
17 )
18 SELECT /*+ MONITOR */ *
19 FROM
20 supertype st
21 LEFT OUTER JOIN t1
22 ON
23* st.pkey = t1.join_key

DBMS_SQLTUNE.REPORT_SQL_MONITOR(SQL_ID=>NULL,TYPE=>'TEXT')
----------------------------------------------------------------------------------------------
SQL Monitoring Report

SQL Text
------------------------------
WITH t1 AS ( SELECT pkey , CASE WHEN col2 IS NULL THEN col1 ELSE col2 END AS join_key
,description FROM nikoichi_mitaina_subtype WHERE col1 IS NOT NULL OR col2 IS NOT NULL )
SELECT /*+ MONITOR */ * FROM supertype st LEFT OUTER JOIN t1 ON st.pkey = t1.join_key

Global Information
------------------------------
Status : DONE (ALL ROWS)

...略...

Duration : 223s

...略...

Global Stats
================================================================================
| Elapsed | Cpu | IO | Fetch | Buffer | Read | Read | Write | Write |
| Time(s) | Time(s) | Waits(s) | Calls | Gets | Reqs | Bytes | Reqs | Bytes |
================================================================================
| 32 | 17 | 15 | 66668 | 230K | 6887 | 3GB | 5169 | 1GB |
================================================================================

SQL Plan Monitoring Details (Plan Hash Value=2223315184)
==============================================================================================================================================================================================================
| Id | Operation | Name | Rows | Cost | Time | Start | Execs | Rows | Read | Read | Write | Write | Mem | Temp | Activity | Activity Detail |
| | | | (Estim) | | Active(s) | Active | | (Actual) | Reqs | Bytes | Reqs | Bytes | (Max) | (Max) | (%) | (# samples) |
==============================================================================================================================================================================================================
| 0 | SELECT STATEMENT | | | | 222 | +2 | 1 | 1M | | | | | . | . | | |
| 1 | HASH JOIN OUTER | | 1M | 120K | 223 | +1 | 1 | 1M | 5169 | 1GB | 5169 | 1GB | 184MB | 1GB | 90.62 | Cpu (9) |
| | | | | | | | | | | | | | | | | SQL*Net more data to client (7) |
| | | | | | | | | | | | | | | | | direct path write temp (13) |
| 3 | TABLE ACCESS FULL | NIKOICHI_MITAINA_SUBTYPE | 750K | 39559 | 67 | +7 | 1 | 1M | 1145 | 1GB | | | . | . | 6.25 | Cpu (2) |
==============================================================================================================================================================================================================


ということで, メモリに余裕があるので tmpfsを使って遊んでみましょう. 2GB固定サイズの一時表領域を作成して, SCOTTユーザーのデフォルト一時表領域にしました

[master@localhost ~]$ df -TH
ファイルシス タイプ サイズ 使用 残り 使用% マウント位置
tmpfs tmpfs 9.3G 17k 9.3G 1% /dev/shm
tmpfs tmpfs 9.3G 9.7M 9.3G 1% /run
tmpfs tmpfs 9.3G 0 9.3G 0% /sys/fs/cgroup
/dev/mapper/ol-root xfs 48G 44G 4.3G 92% /
/dev/mapper/ol-work xfs 11G 109M 11G 2% /work

...略...

[master@localhost ~]$ sudo mkdir /oratemp
...略...
[master@localhost ~]$ ls -l / | grep oratemp
drwxrwxrwt. 2 root root 60 1月 14 12:03 oratemp
[master@localhost ~]$ sudo mount -t tmpfs tmpfs /oratemp
[sudo] master のパスワード:
[master@localhost ~]$ df -TH
ファイルシス タイプ サイズ 使用 残り 使用% マウント位置
devtmpfs devtmpfs 9.3G 0 9.3G 0% /dev
tmpfs tmpfs 9.3G 17k 9.3G 1% /dev/shm
tmpfs tmpfs 9.3G 9.7M 9.3G 1% /run
tmpfs tmpfs 9.3G 0 9.3G 0% /sys/fs/cgroup
/dev/mapper/ol-root xfs 48G 44G 4.3G 92% /
/dev/mapper/ol-work xfs 11G 109M 11G 2% /work

...略...

tmpfs tmpfs 9.3G 0 9.3G 0% /oratemp
一時表領域を作成して, scottのデフォルト一時表領域にする
...略...
SYS@orclpdb1> create temporary tablespace hogetemp tempfile '/oratemp/hogetmp.dbf' size 2g;

表領域が作成されました.

SYS@orclpdb1> alter user scott temporary tablespace hogetemp;

ユーザーが変更されました.


では, オリジナルから. こちらそもそもTemp落ちしないので, LATERALビューへのアクセス回数が積み上がるだけなので, 該当表の物理読み込みが影響しなければほぼCPUタイムですね

SCOTT@orclpdb1> @dayx
1 SELECT /*+ MONITOR */ *
2 FROM
3 supertype st
4 LEFT OUTER JOIN nikoichi_mitaina_subtype nmst
5 ON
6 st.pkey = nmst.col1
7* OR st.pkey = nmst.col2

DBMS_SQLTUNE.REPORT_SQL_MONITOR(SQL_ID=>NULL,TYPE=>'TEXT')
------------------------------------------------------------------------------------------
SQL Monitoring Report

SQL Text
------------------------------
SELECT /*+ MONITOR */ * FROM supertype st LEFT OUTER JOIN nikoichi_mitaina_subtype nmst
ON st.pkey = nmst.col1 OR st.pkey = nmst.col2

Global Information
------------------------------
Status : DONE (ALL ROWS)

...略...

Duration : 188s(別ネタ向け仕込み)

...略...

Global Stats
===========================================================================
| Elapsed | Cpu | IO | Other | Fetch | Buffer | Read | Read |
| Time(s) | Time(s) | Waits(s) | Waits(s) | Calls | Gets | Reqs | Bytes |
===========================================================================
| 39 | 34 | 0.21 | 4.62 | 66668 | 4M | 575 | 559MB |
===========================================================================

SQL Plan Monitoring Details (Plan Hash Value=2133431102)
=========================================================================================================================================================================================
| Id | Operation | Name | Rows | Cost | Time | Start | Execs | Rows | Read | Read | Mem | Activity | Activity Detail |
| | | | (Estim) | | Active(s) | Active | | (Actual) | Reqs | Bytes | (Max) | (%) | (# samples) |
=========================================================================================================================================================================================
| 0 | SELECT STATEMENT | | | | 189 | +0 | 1 | 1M | | | . | | |
| 1 | MERGE JOIN OUTER | | 2M | 6M | 189 | +0 | 1 | 1M | | | . | 2.78 | Cpu (1) |
| 2 | TABLE ACCESS FULL | SUPERTYPE | 1M | 19593 | 189 | +0 | 1 | 1M | 575 | 559MB | . | 13.89 | Cpu (4) |
| | | | | | | | | | | | | | direct path read (1) |
| 3 | BUFFER SORT | | 2 | 6M | 189 | +0 | 1M | 1M | | | 2048 | 22.22 | Cpu (8) |
| 4 | VIEW | VW_LAT_E87C3AAF | 2 | 6 | 189 | +0 | 1M | 1M | | | . | | |
| 5 | VIEW | VW_ORE_FDF394AE | 2 | 6 | 189 | +0 | 1M | 1M | | | . | | |
| 6 | UNION-ALL | | | | 189 | +0 | 1M | 1M | | | . | 2.78 | Cpu (1) |
| 7 | TABLE ACCESS BY INDEX ROWID | NIKOICHI_MITAINA_SUBTYPE | 1 | 3 | 189 | +0 | 1M | 500K | | | . | 8.33 | Cpu (3) |
| 8 | INDEX UNIQUE SCAN | UK1 | 1 | 2 | 189 | +0 | 1M | 500K | | | . | 5.56 | Cpu (2) |
| 9 | TABLE ACCESS BY INDEX ROWID | NIKOICHI_MITAINA_SUBTYPE | 1 | 3 | 189 | +0 | 1M | 500K | | | . | 8.33 | Cpu (3) |
| 10 | INDEX UNIQUE SCAN | UK2 | 1 | 2 | 189 | +0 | 1M | 500K | | | . | 13.89 | Cpu (5) |
=========================================================================================================================================================================================


では, HASH JOINになるように書き換えた方のTemp落ちの時間は...想定通り短縮していますね. 15secほどあったIO Waits(s)ものが1/15程度まで減っています.
結果的に, 39sec -> 21secとなりました. Temp落ちする前提だから落ちた先のIOレイテンシーが小さければこうなるわけですけども. 逆に落ちた先のIOレイテンシーが大きければ影響も大きくなりますよね.

  1  WITH
2 t1 AS
3 (
4 SELECT
5 pkey
6 , CASE
7 WHEN col2 IS NULL
8 THEN col1
9 ELSE col2
10 END AS join_key
11 ,description
12 FROM
13 nikoichi_mitaina_subtype
14 WHERE
15 col1 IS NOT NULL
16 OR col2 IS NOT NULL
17 )
18 SELECT /*+ MONITOR */ *
19 FROM
20 supertype st
21 LEFT OUTER JOIN t1
22 ON
23* st.pkey = t1.join_key

DBMS_SQLTUNE.REPORT_SQL_MONITOR(SQL_ID=>NULL,TYPE=>'TEXT')
--------------------------------------------------------------------------------------------
SQL Monitoring Report

SQL Text
------------------------------
WITH t1 AS ( SELECT pkey , CASE WHEN col2 IS NULL THEN col1 ELSE col2 END AS join_key
,description FROM nikoichi_mitaina_subtype WHERE col1 IS NOT NULL OR col2 IS NOT NULL )
SELECT /*+ MONITOR */ * FROM supertype st LEFT OUTER JOIN t1 ON st.pkey = t1.join_key

Global Information
------------------------------
Status : DONE (ALL ROWS)

...略...

Duration : 211s(別ネタ向け仕込み)

...略...

Global Stats
===========================================================================================
| Elapsed | Cpu | IO | Other | Fetch | Buffer | Read | Read | Write | Write |
| Time(s) | Time(s) | Waits(s) | Waits(s) | Calls | Gets | Reqs | Bytes | Reqs | Bytes |
===========================================================================================
| 21 | 16 | 1.65 | 3.28 | 66668 | 247K | 5566 | 3GB | 3855 | 934MB |
===========================================================================================

SQL Plan Monitoring Details (Plan Hash Value=2223315184)
==============================================================================================================================================================================================================
| Id | Operation | Name | Rows | Cost | Time | Start | Execs | Rows | Read | Read | Write | Write | Mem | Temp | Activity | Activity Detail |
| | | | (Estim) | | Active(s) | Active | | (Actual) | Reqs | Bytes | Reqs | Bytes | (Max) | (Max) | (%) | (# samples) |
==============================================================================================================================================================================================================
| 0 | SELECT STATEMENT | | | | 210 | +2 | 1 | 1M | | | | | . | . | | |
| 1 | HASH JOIN OUTER | | 1M | 119K | 211 | +1 | 1 | 1M | 3855 | 934MB | 3855 | 934MB | 367MB | 1GB | 85.71 | sort segment request (1) |
| | | | | | | | | | | | | | | | | Cpu (10) |
| | | | | | | | | | | | | | | | | SQL*Net message to client (1) |
| | | | | | | | | | | | | | | | | SQL*Net more data to client (6) |
| 2 | TABLE ACCESS FULL | SUPERTYPE | 1M | 19593 | 3 | +2 | 1 | 1M | 575 | 559MB | | | . | . | | |
| 3 | TABLE ACCESS FULL | NIKOICHI_MITAINA_SUBTYPE | 750K | 38796 | 120 | +4 | 1 | 1M | 1134 | 1GB | | | . | . | 14.29 | Cpu (2) |
| | | | | | | | | | | | | | | | | direct path read (1) |
==============================================================================================================================================================================================================


既存表定義を変えないでということになるとこの辺りが限界でしょうね.

オプティマイザは進化し続けていますが, モデル起因だったり構文起因だったり, まだまだ頑張っているけど, 何でもかんでもい感じに最適化できるわけではないので, モデリング頑張りましょうね. というのは不変ですよね. と思います.
今回の例は比較的単純かしていますが, 多重度が 1:* で結合カーディナリティが多くなるタイプや, スーパータイプ, サブタイプの共存的サブタイプだとさらに結合カーディナリティが増加するので, UNIONに分割してあげるなど別の手を駆使しないと対応しにくいタイプもあるので, 頭の片隅に置いておくと良さそうです.

2022年分のおまけのおまけ. これで, おしまい.

では, また.



Related article on Mac De Oracle

・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 1 / TABLE FULL SCAN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 2 / INDEX UNIQUE SCAN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 3 / INDEX RANGE SCAN, Index Only Scan
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 4 / INDEX RANGE SCAN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 5 / INDEX RANGE SCAN, INLIST ITERATOR
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 6 / INDEX FAST SCAN, Index Only Scan
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 7 / INDEX FULL SCAN,Index Only Scan
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 8 / INDEX SKIP SCAN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 9 / TABLE ACCESS INMEMORY FULL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 10 / NESTED LOOP JOIN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 11 / MERGE JOIN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 12 / HASH JOIN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 13 / HASH JOIN OUTER
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 14 / HASH JOIN FULL OUTER
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 15 / PX, TABLE ACCESS FULL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 16 / CONCATENATION
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 17 / SORT UNIQUE, UNION-ALL = UNION
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 18 / UNION-ALL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 19 / INTERSECTION
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 20 / MINUS
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 21 / WINDOW NOSORT STOPKEY
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 22 / COUNT STOPKEY
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 23 / HASH JOIN - LEFT-DEEP JOIN vs RIGHT-DEEP JOIN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 24 / CONNECT BY NO FILTERING WITH START-WITH
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 25 / UNION ALL (RECURSIVE WITH) DEPTH FIRST, RECURSIVE WITH PUMP
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - おまけ#1 / STAR TRANSFORM, VECTOR TRANSFORM (DWH向け)
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - おまけ#2 / MERGE (UPSERT)
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - おまけ#3 / RDFView
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - おまけ#4 / INDEX FULL SCAN (MIN/MAX) - Index Only Scan
・実行計画は, SQL文のレントゲン写真だ! No.30 - LOAD TABLE CONVENTIONAL vs. LOAD AS SELECT
・実行計画は, SQL文のレントゲン写真だ! No.31 - TEMP TABLE TRANSFORMATION LOAD AS SELECT (CURSOR DURATION MEMORY)
・実行計画は, SQL文のレントゲン写真だ! No.32 - EXTERNAL TABLE ACCESS FULL / INMEMORY FULL
・実行計画は, SQL文のレントゲン写真だ! No.33 - BITMAP CONVERSION TO ROWIDS
・実行計画は, SQL文のレントゲン写真だ! No.34 - 似て非なるもの USE_CONCAT と OR_EXPAND ヒント と 手書きSQLのレントゲンの見分け方
・実行計画は, SQL文のレントゲン写真だ! No.35 - 似て非なるもの USE_CONCAT と OR_EXPANDヒントとパラレルクエリー
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 1 / No.36 / INTERSECT ALL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 2 / No.37 / MINUS ALL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 3 / No.38 / EXCEPT and EXCEPT ALL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 4 / No.39 / In-Memory Hybrid Scans
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 5 / No.40 / PIVOT and UNPIVOT
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 6 / No.41 / In-Memory Vectorized Join
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 7 / No.42 / INDEX RANGE SCAN (MULTI VALUE)
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 8 / No.43 / TABLE ACCESS BY INDEX ROWID BATCHED
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 9 / No.44 / COLLECTION ITERATOR PICKLER FETCH
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 10 / No.45 / MAT_VIEW REWRITE ACCESS FULL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 11 / No.46 / GROUPING SETS, ROLLUP, CUBE
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 12 / No.47 / TEMP TABLE TRANSFORMATION
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 13 / No.48 / MULTI-TABLE INSERT
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 14 / No.49 / the DUAL Table
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 15 / No.50 / REMOTE
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 16 / No.51 / Concurrent Execution of Union All and Union
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 17 / No.52 / Order by Elimination
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 18 / No.53 / Join Elimination
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 19 / No.54 / Group by Elimination
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 20 / No.55 / DISTINCT Elimination
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 21 / No.56 / INLIST ITERATOR と Sub Query と STATISTICS COLLECTOR
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 22 / No.57 / Subquery Unnesting
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 23 / No.58 / ANTI JOIN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 24 / No.59 / SQL MACRO (19.7〜)
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 25 / No.60 / ANSI JOIN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 / No.60 / ANSI JOINのおまけ

| | | コメント (0)

2022年12月26日 (月)

実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 / No.60 / ANSI JOINのおまけ

さて, 恒例のアドベントカレンダーのおまけw

Day25で, 性能面で気になる部分のコメントしていた点を思い出してください. INDEX UNIQUE SCANを繰り返している点. 問題にならないなら良いのですが, (データ件数がそれ以上増加しなければ, 安定した処理時間にはなるわけですが....)
データ量次第の危さを感じますとコメントしていた点を思い出してください.

では, 私が, 懸念しているINDEX UNIQUE SCANの回数をSQLモニターという名の内視鏡的な方法で診ていきましょう.
VW_LAT_E87C3AAFのLATERALビューに変換されている操作以降がSUPERTYPE表のヒット件数分繰り返されています. この部分こそ, "データ量次第の危さ”と言った理由です.

 

1  SELECT /*+ MONITOR */ *
2 FROM
3 supertype st
4 LEFT OUTER JOIN nikoichi_mitaina_subtype nmst
5 ON
6 st.pkey = nmst.col1
7* OR st.pkey = nmst.col2

DBMS_SQLTUNE.REPORT_SQL_MONITOR(SQL_ID=>NULL,TYPE=>'TEXT')
--------------------------------------------------------------
SQL Monitoring Report

SQL Text
------------------------------
SELECT /*+ MONITOR */ * FROM supertype st LEFT OUTER JOIN nikoichi_mitaina_subtype nmst ON st.pkey = nmst.col1 OR st.pkey = nmst.col2

...略...

Global Stats
=================================================
| Elapsed | Cpu | Other | Fetch | Buffer |
| Time(s) | Time(s) | Waits(s) | Calls | Gets |
=================================================
| 0.42 | 0.37 | 0.06 | 668 | 32231 |
=================================================

SQL Plan Monitoring Details (Plan Hash Value=2133431102)
=====================================================================================================================================================================
| Id | Operation | Name | Rows | Cost | Time | Start | Execs | Rows | Mem | Activity | Activity Detail |
| | | | (Estim) | | Active(s) | Active | | (Actual) | (Max) | (%) | (# samples) |
=====================================================================================================================================================================
| 0 | SELECT STATEMENT | | | | 3 | +0 | 1 | 10001 | . | | |
| 1 | MERGE JOIN OUTER | | 20002 | 40226 | 3 | +0 | 1 | 10001 | . | | |
| 2 | TABLE ACCESS FULL | SUPERTYPE | 10001 | 204 | 3 | +0 | 1 | 10001 | . | | |
| 3 | BUFFER SORT | | 2 | 40021 | 3 | +0 | 10001 | 10000 | 2048 | | |
| 4 | VIEW | VW_LAT_E87C3AAF | 2 | 4 | 3 | +0 | 10001 | 10000 | . | | |
| 5 | VIEW | VW_ORE_FDF394AE | 2 | 4 | 3 | +0 | 10001 | 10000 | . | | |
| 6 | UNION-ALL | | | | 3 | +0 | 10001 | 10000 | . | | |
| 7 | TABLE ACCESS BY INDEX ROWID | NIKOICHI_MITAINA_SUBTYPE | 1 | 2 | 3 | +0 | 10001 | 5000 | . | | |
| 8 | INDEX UNIQUE SCAN | UK1 | 1 | 1 | 3 | +0 | 10001 | 5000 | . | | |
| 9 | TABLE ACCESS BY INDEX ROWID | NIKOICHI_MITAINA_SUBTYPE | 1 | 2 | 3 | +0 | 10001 | 5000 | . | | |
| 10 | INDEX UNIQUE SCAN | UK2 | 1 | 1 | 3 | +0 | 10001 | 5000 | . | | |
=====================================================================================================================================================================

 

今回のケースでは, CPUバウンドになっていますが, キャッシュヒット率が高ければ, CPUバンドでしょうし, 乗り切らないほど巨大であれば, IOバウンドになって現れそうですよね.

どちらの表のデータ件数も今以上に増加(現時点の処理時間が想定範囲内であることを前提としています)する可能性があり, 読みきれない部分があるのであれば, LATERALビュー変換されたこの実行計画は避けた方が良いだろうという意見に反対される方は少ないのではないでしょうか.

であれば, 方法は一つ.
そう, 自分で, 書き換えれば良いですね. データ量が増加しても安定して, 多少無駄なアクセスがあっても処理時間が安定しやすい方向へ最適化が行われるSQL構文へ. (多少, SQL文が長くなってたとしても)

ということで, どう構文変更して書き換えたらいい感じになりそうか考えてみてね, 冬休みの頭の体操になるのではないかと思います:)
(答え合わせはしませんよ)

 

ではまた. (Oracleネタとしては, 今年はここまで) また来年お会いしましょう. みなさん, 良いお年を!


Related article on Mac De Oracle
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 1 / TABLE FULL SCAN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 2 / INDEX UNIQUE SCAN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 3 / INDEX RANGE SCAN, Index Only Scan
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 4 / INDEX RANGE SCAN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 5 / INDEX RANGE SCAN, INLIST ITERATOR
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 6 / INDEX FAST SCAN, Index Only Scan
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 7 / INDEX FULL SCAN,Index Only Scan
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 8 / INDEX SKIP SCAN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 9 / TABLE ACCESS INMEMORY FULL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 10 / NESTED LOOP JOIN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 11 / MERGE JOIN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 12 / HASH JOIN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 13 / HASH JOIN OUTER
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 14 / HASH JOIN FULL OUTER
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 15 / PX, TABLE ACCESS FULL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 16 / CONCATENATION
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 17 / SORT UNIQUE, UNION-ALL = UNION
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 18 / UNION-ALL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 19 / INTERSECTION
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 20 / MINUS
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 21 / WINDOW NOSORT STOPKEY
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 22 / COUNT STOPKEY
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 23 / HASH JOIN - LEFT-DEEP JOIN vs RIGHT-DEEP JOIN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 24 / CONNECT BY NO FILTERING WITH START-WITH
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 25 / UNION ALL (RECURSIVE WITH) DEPTH FIRST, RECURSIVE WITH PUMP
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - おまけ#1 / STAR TRANSFORM, VECTOR TRANSFORM (DWH向け)
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - おまけ#2 / MERGE (UPSERT)
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - おまけ#3 / RDFView
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - おまけ#4 / INDEX FULL SCAN (MIN/MAX) - Index Only Scan
・実行計画は, SQL文のレントゲン写真だ! No.30 - LOAD TABLE CONVENTIONAL vs. LOAD AS SELECT
・実行計画は, SQL文のレントゲン写真だ! No.31 - TEMP TABLE TRANSFORMATION LOAD AS SELECT (CURSOR DURATION MEMORY)
・実行計画は, SQL文のレントゲン写真だ! No.32 - EXTERNAL TABLE ACCESS FULL / INMEMORY FULL
・実行計画は, SQL文のレントゲン写真だ! No.33 - BITMAP CONVERSION TO ROWIDS
・実行計画は, SQL文のレントゲン写真だ! No.34 - 似て非なるもの USE_CONCAT と OR_EXPAND ヒント と 手書きSQLのレントゲンの見分け方
・実行計画は, SQL文のレントゲン写真だ! No.35 - 似て非なるもの USE_CONCAT と OR_EXPANDヒントとパラレルクエリー
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 1 / No.36 / INTERSECT ALL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 2 / No.37 / MINUS ALL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 3 / No.38 / EXCEPT and EXCEPT ALL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 4 / No.39 / In-Memory Hybrid Scans
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 5 / No.40 / PIVOT and UNPIVOT
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 6 / No.41 / In-Memory Vectorized Join
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 7 / No.42 / INDEX RANGE SCAN (MULTI VALUE)
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 8 / No.43 / TABLE ACCESS BY INDEX ROWID BATCHED
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 9 / No.44 / COLLECTION ITERATOR PICKLER FETCH
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 10 / No.45 / MAT_VIEW REWRITE ACCESS FULL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 11 / No.46 / GROUPING SETS, ROLLUP, CUBE
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 12 / No.47 / TEMP TABLE TRANSFORMATION
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 13 / No.48 / MULTI-TABLE INSERT
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 14 / No.49 / the DUAL Table
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 15 / No.50 / REMOTE
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 16 / No.51 / Concurrent Execution of Union All and Union
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 17 / No.52 / Order by Elimination
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 18 / No.53 / Join Elimination
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 19 / No.54 / Group by Elimination
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 20 / No.55 / DISTINCT Elimination
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 21 / No.56 / INLIST ITERATOR と Sub Query と STATISTICS COLLECTOR
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 22 / No.57 / Subquery Unnesting
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 23 / No.58 / ANTI JOIN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 24 / No.59 / SQL MACRO (19.7〜)
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 25 / No.60 / ANSI JOIN

 

| | | コメント (0)

2022年12月25日 (日)

実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 25 / No.60 / ANSI JOIN

Previously on Mac De Oracle...
Day 24は, SQL MACROにフォーカスをあてました. SEMI JOINだろうと思ってた方々 m(_ _)m 元々今日のネタの伏線をはろうとしていたので, いずれにしても, SEMI JOINではなかったのですがw

と, いうことで Day 25!
ついに, アドベントカレンダー 実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022も千秋楽です

最終日ですので, 大人の事情に金縛りに会いながらも, 頑張って作ってしまったと思われる, 稀に, よくみるタイプのモデルを, それぞれのバージョンのOracleオプティマイザが, どう最適化しようと苦労しているのか, 実行計画というレントゲンを通し, 生暖か, いや, 熱い眼差しでワイン片手に, 観察しつつ, アドベントカレンダー 実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022を締めくくりたいと思います. (オチはないかもw)

当医院に担ぎ込まれてきたSQL文を問診してみると, こんな感じに見えました. (スーパータイプ, サブタイプテーブルを大人の事情で無理強いされて出来上がってしまったような危うい雰囲気であります. 本題はモデルの良し悪しではないので, これ以上, ツッコまないよ)

ということで, 稀によく見るタイプの患者さんを図に起こしてみました. ん〜, かなり複雑な事情がありそうですね!
参考までに, スーパータイプ, サブタイプの概念モデルの実装方法についてはいくつかのパターンがあります. サブタイプがニコイチになっている割に, 結合キーが2個というところが大人の事情を強く感じますが.
(スーパータイプ, サブタイプよくわからんという方は, 斜め読みするならスーパータイプ/サブタイプのテーブルへの実装 / hmatsu47が良いかなと思います)

Sql_20221224173301

 

他に, 外傷がないか SQL文 を診ておきましょう, SQL文はこんなでした. ANSI構文でなければ, こうはならないですよね. Oracleの方言では結合条件のORは書けないので, UNIONで書くことになるのですが, Oracleの方言でこれを書こうとすると割と大変です. UNIONで書いた方が割と無難な実行計画に最適化されやすいというのもありますが, さて, ANSI構文ではどうなりますか. .
(SQLは雰囲気が伝わるように作ってありますw)

SELECT *
FROM
supertype st
LEFT OUTER JOIN nikoichi_mitaina_subtype nmst
ON
st.pkey = nmst.col1
OR st.pkey = nmst.col2
;

 

では, 実行計画という名のレントゲンを11gR1, 11gR2, 12cR1, 12cR2, 18c, 19c, 21cで, 最適化の違いを診ていきましょう. なお, 隠しパラメータ含めパラメータはデフォルト設定です.
データの準備

SCOTT@orclpdb1> @day25-0
1* DROP TABLE supertype

表が削除されました.

経過: 00:00:00.05
1 CREATE TABLE supertype
2 (
3 pkey NUMBER PRIMARY KEY
4 , attr1 NUMBER NOT NULL
5 , attr2 NUMBER NOT NULL
6 , note VARCHAR2(500)
7* )

表が作成されました.

経過: 00:00:00.03
1* DROP TABLE nikoichi_mitaina_subtype

表が削除されました.

経過: 00:00:00.05
1 CREATE TABLE nikoichi_mitaina_subtype
2 (
3 pkey NUMBER PRIMARY KEY
4 , col1 NUMBER
5 , col2 NUMBER
6 , description VARCHAR2(1000)
7 , CONSTRAINT uk1 unique (col1) USING INDEX
8 , CONSTRAINT uk2 unique (col2) USING INDEX
9* )

表が作成されました.

経過: 00:00:00.03
1 BEGIN
2 FOR i IN 1..10000 LOOP
3 INSERT INTO supertype VALUES(i,0,0,LPAD(i,500,'*'));
4 INSERT INTO nikoichi_mitaina_subtype VALUES(
5 i
6 , CASE WHEN MOD(i,2) = 0 THEN i ELSE null END
7 , CASE WHEN MOD(i,2) = 1 THEN i ELSE null END
8 , LPAD(i,1000,'*')
9 );
10 IF MOD(i,100) = 0 THEN COMMIT; END IF;
11 END LOOP;
12 INSERT INTO supertype VALUES(10001,0,0,null);
13 COMMIT;
14 DBMS_STATS.GATHER_TABLE_STATS(ownname=>'SCOTT',tabname=>'SUPERTYPE',no_invalidate=>false,cascade=>true);
15 DBMS_STATS.GATHER_TABLE_STATS(ownname=>'SCOTT',tabname=>'NIKOICHI_MITAINA_SUBTYPE',no_invalidate=>false,cascade=>true);
16* END;

PL/SQLプロシージャが正常に完了しました.

経過: 00:00:02.83

 

現時点でリリースされている最新版, 21cから順に, 11gR2まで遡って診ていきます

やはり, 最新のオプティマイザは, なかなかやりますね.

結合条件のORId=5, VW_ORE_FDF394AEで分かるように, OR_EXPANDしているようです.
さらに, その結果を, Id=6, VW_LAT_E87C3AAFで分かるように, LATERALビューに変換し, MERGE JOIN OUTERしています. LATERALが使えるようになったリリースであることも大きく影響しているように見えます.
(実は, 昨日のネタは, LATERALして伏線にしようと思ってたのですが, SQL MACROの面白さ先にしたくなったのでしたw)

さらに, 興味深いのは, NIKOICHI_MITAINA_SUBTYPEのユニーク索引をIS NOT NULLでフィルタリングしながらアクセスしているところ. 流石です. とは言っても, INDEX UNIQUE SCANしているのでデータ量次第の危さも感じますよね. キャッシュに乗ってたら早そうですが.

SCOTT@orclpdb1> select banner from v$version;

BANNER
------------------------------------------------------------------------
Oracle Database 21c Enterprise Edition Release 21.0.0.0.0 - Production

SCOTT@orclpdb1> @day25
1 SELECT *
2 FROM
3 supertype st
4 LEFT OUTER JOIN nikoichi_mitaina_subtype nmst
5 ON
6 st.pkey = nmst.col1
7* OR st.pkey = nmst.col2

10001行が選択されました.

実行計画
----------------------------------------------------------
Plan hash value: 2133431102

-------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 20002 | 20M| 40226 (1)| 00:00:02 |
| 1 | MERGE JOIN OUTER | | 20002 | 20M| 40226 (1)| 00:00:02 |
| 2 | TABLE ACCESS FULL | SUPERTYPE | 10001 | 4971K| 204 (0)| 00:00:01 |
| 3 | BUFFER SORT | | 2 | 1082 | 40021 (1)| 00:00:02 |
| 4 | VIEW | VW_LAT_E87C3AAF | 2 | 1082 | 4 (0)| 00:00:01 |
| 5 | VIEW | VW_ORE_FDF394AE | 2 | 1082 | 4 (0)| 00:00:01 |
| 6 | UNION-ALL | | | | | |
| 7 | TABLE ACCESS BY INDEX ROWID| NIKOICHI_MITAINA_SUBTYPE | 1 | 1009 | 2 (0)| 00:00:01 |
|* 8 | INDEX UNIQUE SCAN | UK1 | 1 | | 1 (0)| 00:00:01 |
|* 9 | TABLE ACCESS BY INDEX ROWID| NIKOICHI_MITAINA_SUBTYPE | 1 | 1009 | 2 (0)| 00:00:01 |
|* 10 | INDEX UNIQUE SCAN | UK2 | 1 | | 1 (0)| 00:00:01 |
-------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

8 - access("ST"."PKEY"="NMST"."COL1")
filter("NMST"."COL1" IS NOT NULL)
9 - filter(LNNVL("ST"."PKEY"="NMST"."COL1"))
10 - access("ST"."PKEY"="NMST"."COL2")
filter("NMST"."COL2" IS NOT NULL)

統計
----------------------------------------------------------
0 recursive calls
0 db block gets
32231 consistent gets
0 physical reads
0 redo size
15493776 bytes sent via SQL*Net to client
7378 bytes received via SQL*Net from client
668 SQL*Net roundtrips to/from client
10001 sorts (memory)
0 sorts (disk)
10001 rows processed

 

冒頭で, ”Oracleの方言でこれを書こうとすると割と大変です. ”と書きましたが, 以下が理由です.
同じような表現はできないのです. 方言でこれを書こうとすると割と大変と言ったのはこの理由からなんです.

  1  SELECT *
2 FROM
3 supertype st
4 , nikoichi_mitaina_subtype nmst
5 WHERE
6 st.pkey = nmst.col1(+)
7* OR st.pkey = nmst.col2(+)
OR st.pkey = nmst.col2(+)
*
行7でエラーが発生しました. :
ORA-01719: ORまたはINオペランドの中で外部結合演算子(+)は使用できません

 

余談はこれぐらいにして, 19cではどうか見てみましょう(結果飲み)
同じ実行計画です. LATERALやOR_EXPANDが実装が利用されていることから, それらが実装されたあたりからはこのような実行計画が生成されている可能性が高いですね.

SCOTT@ORCL> select banner from v$version;

BANNER
--------------------------------------------------------------------------------
Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production

Execution Plan
----------------------------------------------------------
Plan hash value: 2133431102

-------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 20002 | 20M| 40219 (1)| 00:00:02 |
| 1 | MERGE JOIN OUTER | | 20002 | 20M| 40219 (1)| 00:00:02 |
| 2 | TABLE ACCESS FULL | SUPERTYPE | 10001 | 4971K| 204 (0)| 00:00:01 |
| 3 | BUFFER SORT | | 2 | 1082 | 40015 (1)| 00:00:02 |
| 4 | VIEW | VW_LAT_E87C3AAF | 2 | 1082 | 4 (0)| 00:00:01 |
| 5 | VIEW | VW_ORE_FDF394AE | 2 | 1082 | 4 (0)| 00:00:01 |
| 6 | UNION-ALL | | | | | |
| 7 | TABLE ACCESS BY INDEX ROWID| NIKOICHI_MITAINA_SUBTYPE | 1 | 1009 | 2 (0)| 00:00:01 |
|* 8 | INDEX UNIQUE SCAN | UK1 | 1 | | 1 (0)| 00:00:01 |
|* 9 | TABLE ACCESS BY INDEX ROWID| NIKOICHI_MITAINA_SUBTYPE | 1 | 1009 | 2 (0)| 00:00:01 |
|* 10 | INDEX UNIQUE SCAN | UK2 | 1 | | 1 (0)| 00:00:01 |
-------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

8 - access("ST"."PKEY"="NMST"."COL1")
filter("NMST"."COL1" IS NOT NULL)
9 - filter(LNNVL("ST"."PKEY"="NMST"."COL1"))
10 - access("ST"."PKEY"="NMST"."COL2")
filter("NMST"."COL2" IS NOT NULL)

 

18cではどうでしょう(結果のみ)
やはり, 同じ, Plan hash valueになっていますね. なるほどなるほど.

SCOTT> select banner from v$version;

BANNER
--------------------------------------------------------------------------------
Oracle Database 18c Enterprise Edition Release 18.0.0.0.0 - Production

Execution Plan
----------------------------------------------------------
Plan hash value: 2133431102

-------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 20002 | 20M| 40218 (1)| 00:00:02 |
| 1 | MERGE JOIN OUTER | | 20002 | 20M| 40218 (1)| 00:00:02 |
| 2 | TABLE ACCESS FULL | SUPERTYPE | 10001 | 4971K| 204 (0)| 00:00:01 |
| 3 | BUFFER SORT | | 2 | 1082 | 40014 (1)| 00:00:02 |
| 4 | VIEW | VW_LAT_E87C3AAF | 2 | 1082 | 4 (0)| 00:00:01 |
| 5 | VIEW | VW_ORE_FDF394AE | 2 | 1082 | 4 (0)| 00:00:01 |
| 6 | UNION-ALL | | | | | |
| 7 | TABLE ACCESS BY INDEX ROWID| NIKOICHI_MITAINA_SUBTYPE | 1 | 1009 | 2 (0)| 00:00:01 |
|* 8 | INDEX UNIQUE SCAN | UK1 | 1 | | 1 (0)| 00:00:01 |
|* 9 | TABLE ACCESS BY INDEX ROWID| NIKOICHI_MITAINA_SUBTYPE | 1 | 1009 | 2 (0)| 00:00:01 |
|* 10 | INDEX UNIQUE SCAN | UK2 | 1 | | 1 (0)| 00:00:01 |
-------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

8 - access("ST"."PKEY"="NMST"."COL1")
filter("NMST"."COL1" IS NOT NULL)
9 - filter(LNNVL("ST"."PKEY"="NMST"."COL1"))
10 - access("ST"."PKEY"="NMST"."COL2")
filter("NMST"."COL2" IS NOT NULL)

 

お!, 12cR2も同じ実行計画になりますね!

orcl@SCOTT> select banner from v$version;

BANNER
--------------------------------------------------------------------------------
Oracle Database 12c Enterprise Edition Release 12.2.0.1.0 - 64bit Production
PL/SQL Release 12.2.0.1.0 - Production
CORE 12.2.0.1.0 Production
TNS for Linux: Version 12.2.0.1.0 - Production
NLSRTL Version 12.2.0.1.0 - Production

Execution Plan
----------------------------------------------------------
Plan hash value: 2133431102

-------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 20002 | 20M| 40217 (1)| 00:00:02 |
| 1 | MERGE JOIN OUTER | | 20002 | 20M| 40217 (1)| 00:00:02 |
| 2 | TABLE ACCESS FULL | SUPERTYPE | 10001 | 4971K| 204 (0)| 00:00:01 |
| 3 | BUFFER SORT | | 2 | 1082 | 40013 (1)| 00:00:02 |
| 4 | VIEW | VW_LAT_E87C3AAF | 2 | 1082 | 4 (0)| 00:00:01 |
| 5 | VIEW | VW_ORE_FDF394AE | 2 | 1082 | 4 (0)| 00:00:01 |
| 6 | UNION-ALL | | | | | |
| 7 | TABLE ACCESS BY INDEX ROWID| NIKOICHI_MITAINA_SUBTYPE | 1 | 1009 | 2 (0)| 00:00:01 |
|* 8 | INDEX UNIQUE SCAN | UK1 | 1 | | 1 (0)| 00:00:01 |
|* 9 | TABLE ACCESS BY INDEX ROWID| NIKOICHI_MITAINA_SUBTYPE | 1 | 1009 | 2 (0)| 00:00:01 |
|* 10 | INDEX UNIQUE SCAN | UK2 | 1 | | 1 (0)| 00:00:01 |
-------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

8 - access("ST"."PKEY"="NMST"."COL1")
filter("NMST"."COL1" IS NOT NULL)
9 - filter(LNNVL("ST"."PKEY"="NMST"."COL1"))
10 - access("ST"."PKEY"="NMST"."COL2")
filter("NMST"."COL2" IS NOT NULL)

 

12cR1はどうでしょう. おっと, ここで差が出ました. OR_EXPANDではなく, USE_CONCATが行われています. たた, VW_LAT_E87C3AAFがあることからLATERALビューが内部的に利用されていることが見えますね.
性能に影響しそうなのは, NESTED LOOPS OUTERになっているあたりでしょうね. データ量が大きい想定見積もりに倒れている最近のリリースとは明らかに異なり. 危険な感じの実行計画ではあります.

SCOTT@pdborcl12c> select banner from v$version;

BANNER
--------------------------------------------------------------------------------
Oracle Database 12c Enterprise Edition Release 12.1.0.2.0 - 64bit Production
PL/SQL Release 12.1.0.2.0 - Production
CORE 12.1.0.2.0 Production
TNS for Linux: Version 12.1.0.2.0 - Production
NLSRTL Version 12.1.0.2.0 - Production

実行計画
----------------------------------------------------------
Plan hash value: 3799136614

-----------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 20002 | 20M| 40216 (1)| 00:00:02 |
| 1 | NESTED LOOPS OUTER | | 20002 | 20M| 40216 (1)| 00:00:02 |
| 2 | TABLE ACCESS FULL | SUPERTYPE | 10001 | 4971K| 204 (0)| 00:00:01 |
| 3 | VIEW | VW_LAT_E87C3AAF | 2 | 1082 | 4 (0)| 00:00:01 |
| 4 | CONCATENATION | | | | | |
| 5 | TABLE ACCESS BY INDEX ROWID| NIKOICHI_MITAINA_SUBTYPE | 1 | 1009 | 2 (0)| 00:00:01 |
|* 6 | INDEX UNIQUE SCAN | UK2 | 1 | | 1 (0)| 00:00:01 |
|* 7 | TABLE ACCESS BY INDEX ROWID| NIKOICHI_MITAINA_SUBTYPE | 1 | 1009 | 2 (0)| 00:00:01 |
|* 8 | INDEX UNIQUE SCAN | UK1 | 1 | | 1 (0)| 00:00:01 |
-----------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

6 - access("ST"."PKEY"="NMST"."COL2")
filter("NMST"."COL2" IS NOT NULL)
7 - filter(LNNVL("NMST"."COL2" IS NOT NULL) OR LNNVL("ST"."PKEY"="NMST"."COL2"))
8 - access("ST"."PKEY"="NMST"."COL1")
filter("NMST"."COL1" IS NOT NULL)

 

11gR2です. LATERALビューも消え, USE_CONCATが行われているだけで, さらに, NESTED LOOPS OUTERなのでデータ量が多いとやはり危険なタイプの実行計画になっているのがわかります.

orcl@SCOTT> select banner from v$version;

BANNER
--------------------------------------------------------------------------------
Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Production
PL/SQL Release 11.2.0.4.0 - Production
CORE 11.2.0.4.0 Production
TNS for Linux: Version 11.2.0.4.0 - Production
NLSRTL Version 11.2.0.4.0 - Production

orcl@SCOTT> @day25
1 SELECT *
2 FROM
3 supertype st
4 LEFT OUTER JOIN nikoichi_mitaina_subtype nmst
5 ON
6 st.pkey = nmst.col1
7* OR st.pkey = nmst.col2

Execution Plan
----------------------------------------------------------
Plan hash value: 2117741269

-----------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 20002 | 20M| 40236 (1)| 00:08:03 |
| 1 | NESTED LOOPS OUTER | | 20002 | 20M| 40236 (1)| 00:08:03 |
| 2 | TABLE ACCESS FULL | SUPERTYPE | 10001 | 4971K| 205 (1)| 00:00:03 |
| 3 | VIEW | | 2 | 1082 | 4 (0)| 00:00:01 |
| 4 | CONCATENATION | | | | | |
| 5 | TABLE ACCESS BY INDEX ROWID| NIKOICHI_MITAINA_SUBTYPE | 1 | 1009 | 2 (0)| 00:00:01 |
|* 6 | INDEX UNIQUE SCAN | UK2 | 1 | | 1 (0)| 00:00:01 |
|* 7 | TABLE ACCESS BY INDEX ROWID| NIKOICHI_MITAINA_SUBTYPE | 1 | 1009 | 2 (0)| 00:00:01 |
|* 8 | INDEX UNIQUE SCAN | UK1 | 1 | | 1 (0)| 00:00:01 |
-----------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

6 - access("ST"."PKEY"="NMST"."COL2")
filter("NMST"."COL2" IS NOT NULL)
7 - filter(LNNVL("NMST"."COL2" IS NOT NULL) OR LNNVL("ST"."PKEY"="NMST"."COL2"))
8 - access("ST"."PKEY"="NMST"."COL1")
filter("NMST"."COL1" IS NOT NULL)

 

このケース, 最新のリリースでは, LATERALビューを使い, MERGE JOINも利用するような多くの内部的な書き換えが行われ, いい感じの実行計画が生成されています.

ただ, 稀に, そうでもないケースもあります. (ググってみると結構ある. あった. ことがわかります)
そのような場合, 結合条件でORを利用する構文を書き換え, UNIONを使った構文(このケースではオプティマイザが内部的に変換していますが)へ書き換えてしまった方が良い実行計画にできる場合があります. (その方がヒントでの細かい制御もしやすい場合があります)
その辺りは, 状況に応じ臨機応変に対応すれば良いと思います.
今回のMERGE OUTER JOINで想定より遅い場合には, やはり構文変更してしまった方が処理時間は安定して, 無難な方向になるケースもありそうに思います.

ということで, 今年のアドベントカレンダーは, しゅうーーーりょう!!

参考) Internal Views / Oracle Scratchpad

 

I wish you all a Merry Christmas and a Happy New Year!

ではまた ;)

 


Related article on Mac De Oracle
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 1 / TABLE FULL SCAN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 2 / INDEX UNIQUE SCAN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 3 / INDEX RANGE SCAN, Index Only Scan
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 4 / INDEX RANGE SCAN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 5 / INDEX RANGE SCAN, INLIST ITERATOR
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 6 / INDEX FAST SCAN, Index Only Scan
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 7 / INDEX FULL SCAN,Index Only Scan
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 8 / INDEX SKIP SCAN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 9 / TABLE ACCESS INMEMORY FULL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 10 / NESTED LOOP JOIN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 11 / MERGE JOIN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 12 / HASH JOIN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 13 / HASH JOIN OUTER
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 14 / HASH JOIN FULL OUTER
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 15 / PX, TABLE ACCESS FULL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 16 / CONCATENATION
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 17 / SORT UNIQUE, UNION-ALL = UNION
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 18 / UNION-ALL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 19 / INTERSECTION
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 20 / MINUS
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 21 / WINDOW NOSORT STOPKEY
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 22 / COUNT STOPKEY
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 23 / HASH JOIN - LEFT-DEEP JOIN vs RIGHT-DEEP JOIN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 24 / CONNECT BY NO FILTERING WITH START-WITH
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 25 / UNION ALL (RECURSIVE WITH) DEPTH FIRST, RECURSIVE WITH PUMP
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - おまけ#1 / STAR TRANSFORM, VECTOR TRANSFORM (DWH向け)
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - おまけ#2 / MERGE (UPSERT)
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - おまけ#3 / RDFView
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - おまけ#4 / INDEX FULL SCAN (MIN/MAX) - Index Only Scan
・実行計画は, SQL文のレントゲン写真だ! No.30 - LOAD TABLE CONVENTIONAL vs. LOAD AS SELECT
・実行計画は, SQL文のレントゲン写真だ! No.31 - TEMP TABLE TRANSFORMATION LOAD AS SELECT (CURSOR DURATION MEMORY)
・実行計画は, SQL文のレントゲン写真だ! No.32 - EXTERNAL TABLE ACCESS FULL / INMEMORY FULL
・実行計画は, SQL文のレントゲン写真だ! No.33 - BITMAP CONVERSION TO ROWIDS
・実行計画は, SQL文のレントゲン写真だ! No.34 - 似て非なるもの USE_CONCAT と OR_EXPAND ヒント と 手書きSQLのレントゲンの見分け方
・実行計画は, SQL文のレントゲン写真だ! No.35 - 似て非なるもの USE_CONCAT と OR_EXPANDヒントとパラレルクエリー
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 1 / No.36 / INTERSECT ALL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 2 / No.37 / MINUS ALL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 3 / No.38 / EXCEPT and EXCEPT ALL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 4 / No.39 / In-Memory Hybrid Scans
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 5 / No.40 / PIVOT and UNPIVOT
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 6 / No.41 / In-Memory Vectorized Join
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 7 / No.42 / INDEX RANGE SCAN (MULTI VALUE)
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 8 / No.43 / TABLE ACCESS BY INDEX ROWID BATCHED
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 9 / No.44 / COLLECTION ITERATOR PICKLER FETCH
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 10 / No.45 / MAT_VIEW REWRITE ACCESS FULL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 11 / No.46 / GROUPING SETS, ROLLUP, CUBE
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 12 / No.47 / TEMP TABLE TRANSFORMATION
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 13 / No.48 / MULTI-TABLE INSERT
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 14 / No.49 / the DUAL Table
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 15 / No.50 / REMOTE
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 16 / No.51 / Concurrent Execution of Union All and Union
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 17 / No.52 / Order by Elimination
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 18 / No.53 / Join Elimination
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 19 / No.54 / Group by Elimination
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 20 / No.55 / DISTINCT Elimination
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 21 / No.56 / INLIST ITERATOR と Sub Query と STATISTICS COLLECTOR
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 22 / No.57 / Subquery Unnesting
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 23 / No.58 / ANTI JOIN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 24 / No.59 / SQL MACRO (19.7〜)

 

| | | コメント (0)

2022年12月24日 (土)

実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 24 / No.59 / SQL MACRO (19.7〜)


Previously on Mac De Oracle...

Day 23は, ANTI JOINにフォーカスをあてました. そうくれば, 次は, SEMI JOINだろう? と思ったあなた! ハズレですw

では, Day 24 クリスマスイブの窓を開けましょう!
実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 9 / No.44 / COLLECTION ITERATOR PICKLER FETCH
で, パイプラインテーブルファンクションだと, ファンクションが実行されていることしかExplain等で見る事はできなくて, COLLECTION ITERATOR PICKLER FETCH だけなんだよね, と言うお話をしました.

1  SELECT
2 *
3 FROM
4* day9_pkg.list_2_latest_sales(2, 20, 5745)

PROD_ID CUST_ID TIME_ID CHANNEL_ID PROMO_ID QUANTITY_SOLD AMOUNT_SOLD
---------- ---------- -------- ---------- ---------- ------------- -----------
20 5745 01-12-31 2 999 1 628.89

実行計画
----------------------------------------------------------
Plan hash value: 457385954

---------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 8168 | 16336 | 29 (0)| 00:00:01 |
| 1 | COLLECTION ITERATOR PICKLER FETCH| LIST_2_LATEST_SALES | 8168 | 16336 | 29 (0)| 00:00:01 |
---------------------------------------------------------------------------------------------------------

レントゲン屋さん的にはw 辛いよね. と. 間接的に見るしかないわけで. 少々面倒, 対応を意識していないと難しいですし.


今日は, クリスマスイブですし, Oracleさんもどんどん新機能提供してくれてて, それファンクションじゃないの? いえ, いえ. ?? 今日は, SQLマクロ(SQM)の実行計画という名のレントゲンです.

SQLマクロ(SQM)を作ります. パイプラインテーブルファンクションと似てますけども, SQL_MACROです.

SCOTT@orclpdb1> @day24
1* DROP FUNCTION sq_macro_sample

ファンクションが削除されました.

1 CREATE FUNCTION sq_macro_sample
2 (
3 p_first_rows NUMBER
4 , p_table_name DBMS_TF.TABLE_T
5 )
6 RETURN VARCHAR2
7 SQL_MACRO
8 IS
9 BEGIN
10 RETURN
11 'SELECT
12 *
13 FROM
14 p_table_name
15 FETCH FIRST sq_macro_sample.p_first_rows ROWS ONLY'
16 ;
17* END;

ファンクションが作成されました.


おおおおおおおおおお〜っと. マクロが展開されて, emp表の直接アクセスしている. (マクロだからそりゃそうだw)
レントゲンを見てみましょう.

パイプラインテーブルファンクションと外見からはあまり違いに気づかないというか, 気づけないですが. レントゲンの結果は全く違います! マクロが展開されて, 普通の SQL文の実行計画という名のレントゲンを見ることができます.

  1  SELECT
2 *
3 FROM
4* sq_macro_sample(3, emp)

EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
---------- ------------------------------ --------------------------- ---------- -------- ---------- ---------- ----------
7369 SMITH CLERK 7902 80-12-17 800 20
7499 ALLEN SALESMAN 7698 81-02-20 1600 300 30
7521 WARD SALESMAN 7698 81-02-22 1250 500 30

実行計画
----------------------------------------------------------
Plan hash value: 3611411408

-------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 3 | 300 | 2 (0)| 00:00:01 |
|* 1 | VIEW | | 3 | 300 | 2 (0)| 00:00:01 |
|* 2 | WINDOW NOSORT STOPKEY| | 3 | 117 | 2 (0)| 00:00:01 |
| 3 | TABLE ACCESS FULL | EMP | 3 | 117 | 2 (0)| 00:00:01 |
-------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

1 - filter("from$_subquery$_009"."rowlimit_$$_rownumber"<=3)
2 - filter(ROW_NUMBER() OVER ( ORDER BY NULL )<=3)

統計
----------------------------------------------------------
0 recursive calls
0 db block gets
3 consistent gets
0 physical reads
0 redo size
1262 bytes sent via SQL*Net to client
52 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
3 rows processed


おおおおおおおおおお〜っと. 2回目w  マクロが展開されて, dept表の直接アクセスしている. (マクロだからそりゃそうだw)

  1  SELECT
2 *
3 FROM
4* sq_macro_sample(2, dept)

DEPTNO DNAME LOC
---------- ------------------------------------------ ---------------------------------------
10 ACCOUNTING NEW YORK
20 RESEARCH DALLAS

実行計画
----------------------------------------------------------
Plan hash value: 3452784451

-------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 2 | 86 | 3 (0)| 00:00:01 |
|* 1 | VIEW | | 2 | 86 | 3 (0)| 00:00:01 |
|* 2 | WINDOW NOSORT STOPKEY| | 2 | 40 | 3 (0)| 00:00:01 |
| 3 | TABLE ACCESS FULL | DEPT | 2 | 40 | 3 (0)| 00:00:01 |
-------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

1 - filter("from$_subquery$_009"."rowlimit_$$_rownumber"<=2)
2 - filter(ROW_NUMBER() OVER ( ORDER BY NULL )<=2)

統計
----------------------------------------------------------
0 recursive calls
0 db block gets
3 consistent gets
0 physical reads
0 redo size
827 bytes sent via SQL*Net to client
52 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
2 rows processed


みなさん, SQL_MACRO, 実は, 物凄く, いいいやつ, っぽい感じがします. 慣れるまでは敷居高そうでもありますがw 
マニュアルを真面目に読んで, 倒れそうになりました. (斜め読みでは理解しきれない深さを感じます)


入門としては, HNakaieさんのエントリがわかりやすいですかね.
Oracle DatabaseのSQLマクロを検証する /

参考)
Oracle Database 21c Database PL/SQL Language Reference / 14.64 SQL_MACRO Clause


ということで,  Happy Holidays中の方も, Hard Wroking Now!な方も, I wish you all a Merry Christmas.

そういえば, もう1週間以上前ですがw, アメリカのOracleの中の人からのメッセージが, Happy Holidays! で締めくくられていました.
日本人の感覚だと, え, と思わなくもないわけですが, アメリカとかだとそうだよねーーー. そう言う時期だよねーーと, 思いつつ,
アドベントカレンダー全部俺のネタ作りに追われているw 俺, なんなの? みたいに思ったりw

では, アドベントカレンダー最終日の担当も, 私です.

ではまた.



Related article on Mac De Oracle

・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 1 / TABLE FULL SCAN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 2 / INDEX UNIQUE SCAN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 3 / INDEX RANGE SCAN, Index Only Scan
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 4 / INDEX RANGE SCAN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 5 / INDEX RANGE SCAN, INLIST ITERATOR
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 6 / INDEX FAST SCAN, Index Only Scan
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 7 / INDEX FULL SCAN,Index Only Scan
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 8 / INDEX SKIP SCAN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 9 / TABLE ACCESS INMEMORY FULL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 10 / NESTED LOOP JOIN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 11 / MERGE JOIN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 12 / HASH JOIN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 13 / HASH JOIN OUTER
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 14 / HASH JOIN FULL OUTER
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 15 / PX, TABLE ACCESS FULL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 16 / CONCATENATION
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 17 / SORT UNIQUE, UNION-ALL = UNION
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 18 / UNION-ALL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 19 / INTERSECTION
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 20 / MINUS
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 21 / WINDOW NOSORT STOPKEY
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 22 / COUNT STOPKEY
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 23 / HASH JOIN - LEFT-DEEP JOIN vs RIGHT-DEEP JOIN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 24 / CONNECT BY NO FILTERING WITH START-WITH
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 25 / UNION ALL (RECURSIVE WITH) DEPTH FIRST, RECURSIVE WITH PUMP
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - おまけ#1 / STAR TRANSFORM, VECTOR TRANSFORM (DWH向け)
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - おまけ#2 / MERGE (UPSERT)
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - おまけ#3 / RDFView
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - おまけ#4 / INDEX FULL SCAN (MIN/MAX) - Index Only Scan
・実行計画は, SQL文のレントゲン写真だ! No.30 - LOAD TABLE CONVENTIONAL vs. LOAD AS SELECT
・実行計画は, SQL文のレントゲン写真だ! No.31 - TEMP TABLE TRANSFORMATION LOAD AS SELECT (CURSOR DURATION MEMORY)
・実行計画は, SQL文のレントゲン写真だ! No.32 - EXTERNAL TABLE ACCESS FULL / INMEMORY FULL
・実行計画は, SQL文のレントゲン写真だ! No.33 - BITMAP CONVERSION TO ROWIDS
・実行計画は, SQL文のレントゲン写真だ! No.34 - 似て非なるもの USE_CONCAT と OR_EXPAND ヒント と 手書きSQLのレントゲンの見分け方
・実行計画は, SQL文のレントゲン写真だ! No.35 - 似て非なるもの USE_CONCAT と OR_EXPANDヒントとパラレルクエリー
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 1 / No.36 / INTERSECT ALL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 2 / No.37 / MINUS ALL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 3 / No.38 / EXCEPT and EXCEPT ALL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 4 / No.39 / In-Memory Hybrid Scans
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 5 / No.40 / PIVOT and UNPIVOT
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 6 / No.41 / In-Memory Vectorized Join
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 7 / No.42 / INDEX RANGE SCAN (MULTI VALUE)
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 8 / No.43 / TABLE ACCESS BY INDEX ROWID BATCHED
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 9 / No.44 / COLLECTION ITERATOR PICKLER FETCH
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 10 / No.45 / MAT_VIEW REWRITE ACCESS FULL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 11 / No.46 / GROUPING SETS, ROLLUP, CUBE
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 12 / No.47 / TEMP TABLE TRANSFORMATION
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 13 / No.48 / MULTI-TABLE INSERT
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 14 / No.49 / the DUAL Table
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 15 / No.50 / REMOTE
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 16 / No.51 / Concurrent Execution of Union All and Union
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 17 / No.52 / Order by Elimination
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 18 / No.53 / Join Elimination
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 19 / No.54 / Group by Elimination
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 20 / No.55 / DISTINCT Elimination
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 21 / No.56 / INLIST ITERATOR と Sub Query と STATISTICS COLLECTOR
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 22 / No.57 / Subquery Unnesting
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 23 / No.58 / ANTI JOIN

| | | コメント (0)

2022年12月23日 (金)

実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 23 / No.58 / ANTI JOIN

Day 22は, Subquery Unnestingを取り上げました. 最近は積極的にUnnestingしているように思うのですが, 皆さんはどう思いますか?

では, Day 23の窓を開けましょう!

今日は, 昨日話題にした, Subquery Unnesting の発動も必要ですが ANTI JOIN の実行計画という名のレントゲンから, いくつか特徴のある物をピックアップ(全バリエーション取れなかった言い訳w).

ANTI JOIN(結合されなかった主問い合わせの対象行を返す)もJOINのナカーマなであるわけで, Nested Loop Join, Hash Join, Merge joinがあり, さらに, NULLを考慮する必要のある結合列がないか, 一つか, それ以上かで, Null-Awareなし, NA(Null-Aware), SNA(Single Null-Aware) でOperation列に表示されるOperation名にいくつかのバリエーションがあります.
とはいえ, ANTI JOINかNULLを意識する必要があるかないか大きな分類で, JOIN方式は通常のJOINと同じ種類があるのはご存知の通り.

NOT EXISTS演算子や, NOT IN条件かつSubquery Unnestingが発動していると, 直感的にイメージできるようになってればいいかもしれないですね. かつ, NULLを意識してるなどもOperation名から見切れるとなお.
たった1文のOperationにそこまで情報が詰め込まれているんですよね.

参考)

Oracle Database 21c SQL Tuning Guide / 9.3.4 Antijoins

いつもと同じように 21c で確認します.

SCOTT@orclpdb1> select banner from v$version;

BANNER
----------------------------------------------------------------------
Oracle Database 21c Enterprise Edition Release 21.0.0.0.0 - Production


ヒントまで使ってなんとか, NESTED LOOPS ANTI が取れました(なかなか言うこと聞いてくれなかったw)
結合列でNULLを意識する必要のない場合に現れます.

HR@orclpdb1> @day23-2
1 SELECT
2 /*+
3 NO_INDEX(departments DEPT_ID_PK)
4 */
5 department_id
6 , department_name
7 FROM
8 departments
9 WHERE
10 department_id NOT IN
11 (
12 SELECT
13 /*+
14 NL_AJ
15 */
16 department_id
17 FROM
18 employees
19 WHERE
20 department_id IS NOT NULL
21* )

DEPARTMENT_ID DEPARTMENT_NAME
------------- ----------------------
120 Treasury
130 Corporate Tax
140 Control And Credit

...略...

240 Government Sales
250 Retail Sales
260 Recruiting
270 Payroll

16行が選択されました.

実行計画
----------------------------------------------------------
Plan hash value: 3082375452

----------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 17 | 323 | 3 (0)| 00:00:01 |
| 1 | NESTED LOOPS ANTI | | 17 | 323 | 3 (0)| 00:00:01 |
| 2 | TABLE ACCESS FULL| DEPARTMENTS | 27 | 432 | 3 (0)| 00:00:01 |
|* 3 | INDEX RANGE SCAN | EMP_DEPARTMENT_IX | 41 | 123 | 0 (0)| 00:00:01 |
----------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

3 - access("DEPARTMENT_ID"="DEPARTMENT_ID")
filter("DEPARTMENT_ID" IS NOT NULL)

一つ前のSQL文とほぼ同じですが, IS NOT NULL条件を取り除いてあります.
NESTED LOOPS ANTI SNAです, SNAとなっているので, NULLを意識する必要のあることがわかります.

  1  SELECT
2 /*+
3 NO_INDEX(departments DEPT_ID_PK)
4 */
5 department_id
6 , department_name
7 FROM
8 departments
9 WHERE
10 department_id NOT IN
11 (
12 SELECT
13 department_id
14 FROM
15 employees
16* )

レコードが選択されませんでした.

実行計画
----------------------------------------------------------
Plan hash value: 2953329389

--------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 19 | 6 (0)| 00:00:01 |
|* 1 | FILTER | | | | | |
| 2 | NESTED LOOPS ANTI SNA| | 17 | 323 | 6 (50)| 00:00:01 |
| 3 | TABLE ACCESS FULL | DEPARTMENTS | 27 | 432 | 3 (0)| 00:00:01 |
|* 4 | INDEX RANGE SCAN | EMP_DEPARTMENT_IX | 41 | 123 | 0 (0)| 00:00:01 |
|* 5 | TABLE ACCESS FULL | EMPLOYEES | 1 | 3 | 3 (0)| 00:00:01 |
--------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

1 - filter( NOT EXISTS (SELECT 0 FROM "EMPLOYEES" "EMPLOYEES" WHERE
"DEPARTMENT_ID" IS NULL))
4 - access("DEPARTMENT_ID"="DEPARTMENT_ID")
5 - filter("DEPARTMENT_ID" IS NULL)


MERGE JOIN ANTIが現れています. NA, SNAが現れていないことから, NULLは考慮しないANTI JOINであることがわかります.

SCOTT@orclpdb1> @day23

1 SELECT
2 deptno
3 ,dname
4 FROM
5 dept
6 WHERE
7 deptno NOT IN
8 (
9 SELECT
10 deptno
11 FROM
12 emp
13 WHERE
14 deptno IS NOT NULL
15* )

DEPTNO DNAME
---------- ------------------------------------------
40 OPERATIONS

実行計画
----------------------------------------------------------
Plan hash value: 1353548327

----------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 16 | 6 (17)| 00:00:01 |
| 1 | MERGE JOIN ANTI | | 1 | 16 | 6 (17)| 00:00:01 |
| 2 | TABLE ACCESS BY INDEX ROWID| DEPT | 4 | 52 | 2 (0)| 00:00:01 |
| 3 | INDEX FULL SCAN | PK_DEPT | 4 | | 1 (0)| 00:00:01 |
|* 4 | SORT UNIQUE | | 12 | 36 | 4 (25)| 00:00:01 |
|* 5 | TABLE ACCESS FULL | EMP | 12 | 36 | 3 (0)| 00:00:01 |
----------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

4 - access("DEPTNO"="DEPTNO")
filter("DEPTNO"="DEPTNO")
5 - filter("DEPTNO" IS NOT NULL)


MERGE JOIN ANTI NAが出ています. NAがあるので, NULLを考慮したMERGE JOIN ANTIであることがわかります. でもこれ本当は, SNAではないのか?(時間があったら10053でも追ってみようかなぁ)

  1  SELECT
2 deptno
3 ,dname
4 FROM
5 dept
6 WHERE
7 deptno NOT IN
8 (
9 SELECT
10 deptno
11 FROM
12 emp
13* )

DEPTNO DNAME
---------- ------------------------------------------
40 OPERATIONS

実行計画
----------------------------------------------------------
Plan hash value: 218628244

-------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 16 | 6 (17)| 00:00:01 |
| 1 | MERGE JOIN ANTI NA | | 1 | 16 | 6 (17)| 00:00:01 |
| 2 | SORT JOIN | | 4 | 52 | 2 (0)| 00:00:01 |
| 3 | TABLE ACCESS BY INDEX ROWID BATCHED| DEPT | 4 | 52 | 2 (0)| 00:00:01 |
| 4 | INDEX FULL SCAN | PK_DEPT | 4 | | 1 (0)| 00:00:01 |
|* 5 | SORT UNIQUE | | 12 | 36 | 4 (25)| 00:00:01 |
| 6 | TABLE ACCESS FULL | EMP | 12 | 36 | 3 (0)| 00:00:01 |
-------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

5 - access("DEPTNO"="DEPTNO")
filter("DEPTNO"="DEPTNO")


HASH JOIN ANTIが現れています. NULLを考慮させないために, IS NOT NULL条件を追加しています.

 1  SELECT
2 empno
3 ,ename
4 FROM
5 emp
6 WHERE
7 emp.deptno NOT IN
8 (
9 SELECT
10 /*+
11 HASH_AJ
12 */
13 dept.deptno
14 FROM
15 dept
16 WHERE
17 dept.deptno = 50
18 AND dept.deptno IS NOT NULL
19 )
20* AND emp.deptno IS NOT NULL

EMPNO ENAME
---------- ------------------------------
7499 ALLEN
7521 WARD

...略...

7369 SMITH
7566 JONES
7902 FORD

12行が選択されました.

実行計画
----------------------------------------------------------
Plan hash value: 4131168823

------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 11 | 176 | 3 (0)| 00:00:01 |
|* 1 | HASH JOIN ANTI | | 11 | 176 | 3 (0)| 00:00:01 |
|* 2 | TABLE ACCESS FULL| EMP | 12 | 156 | 3 (0)| 00:00:01 |
|* 3 | INDEX UNIQUE SCAN| PK_DEPT | 1 | 3 | 0 (0)| 00:00:01 |
------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

1 - access("EMP"."DEPTNO"="DEPT"."DEPTNO")
2 - filter("EMP"."DEPTNO" IS NOT NULL)
3 - access("DEPT"."DEPTNO"=50)


HASH JOIN ANTI SNAが現れています. NULLを考慮する必要のあるSNAが付いた, HASH JOIN ANTIですね.

  1  SELECT
2 empno
3 ,ename
4 FROM
5 emp
6 WHERE
7 deptno NOT IN
8 (
9 SELECT
10 deptno
11 FROM
12 dept
13 WHERE
14 deptno = 50
15* )

EMPNO ENAME
---------- ------------------------------
7499 ALLEN
7521 WARD
7654 MARTIN

...略...

7369 SMITH
7566 JONES
7902 FORD

12行が選択されました.

実行計画
----------------------------------------------------------
Plan hash value: 2782438375

------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 11 | 176 | 3 (0)| 00:00:01 |
|* 1 | HASH JOIN ANTI SNA| | 11 | 176 | 3 (0)| 00:00:01 |
| 2 | TABLE ACCESS FULL| EMP | 12 | 156 | 3 (0)| 00:00:01 |
|* 3 | INDEX UNIQUE SCAN| PK_DEPT | 1 | 3 | 0 (0)| 00:00:01 |
------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

1 - access("DEPTNO"="DEPTNO")
3 - access("DEPTNO"=50)


次は, HASH JOIN ANTI NAが出ているので, NULLを複数列で考慮してもらう必要があるので, 無理感はありますがw. 一応, 取れたw NA付きのHASH JOIN ANTIのOperationです.

SCOTT@orclpdb1> desc foo
名前 NULL? 型
----------------------------------------- -------- ----------------------------
COL1 NOT NULL NUMBER
COL2 NOT NULL NUMBER
COL3 NUMBER

SCOTT@orclpdb1> desc bar
名前 NULL? 型
----------------------------------------- -------- ----------------------------
COL0 NOT NULL NUMBER
COL1 NUMBER
COL2 NUMBER
COL4 NUMBER
 1  SELECT
2 col1
3 FROM
4 foo
5 WHERE
6 col3 NOT IN
7 (
8 SELECT
9 col2
10 FROM
11 bar
12* )

レコードが選択されませんでした.

実行計画
----------------------------------------------------------
Plan hash value: 3985729167

---------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 39 | 4 (0)| 00:00:01 |
|* 1 | HASH JOIN ANTI NA | | 1 | 39 | 4 (0)| 00:00:01 |
| 2 | TABLE ACCESS FULL| FOO | 1 | 26 | 2 (0)| 00:00:01 |
| 3 | TABLE ACCESS FULL| BAR | 1 | 13 | 2 (0)| 00:00:01 |
---------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

1 - access("COL3"="COL2")


狙った通りのOperationを行わせるのって難しいですねwwwwwwww (^^;;;;;;; NA, SNAまで考えるとw 

なかなか, これだけのバリエーション, 現場で見ることはないわけですけどもwww 今回のレントゲンシリーズで一番疲れたw
今日は, ここまで,

残り2日だ.

明日も, 頑張って, 窓を開きますよ. ここまできたらw



Related article on Mac De Oracle

・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 1 / TABLE FULL SCAN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 2 / INDEX UNIQUE SCAN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 3 / INDEX RANGE SCAN, Index Only Scan
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 4 / INDEX RANGE SCAN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 5 / INDEX RANGE SCAN, INLIST ITERATOR
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 6 / INDEX FAST SCAN, Index Only Scan
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 7 / INDEX FULL SCAN,Index Only Scan
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 8 / INDEX SKIP SCAN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 9 / TABLE ACCESS INMEMORY FULL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 10 / NESTED LOOP JOIN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 11 / MERGE JOIN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 12 / HASH JOIN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 13 / HASH JOIN OUTER
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 14 / HASH JOIN FULL OUTER
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 15 / PX, TABLE ACCESS FULL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 16 / CONCATENATION
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 17 / SORT UNIQUE, UNION-ALL = UNION
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 18 / UNION-ALL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 19 / INTERSECTION
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 20 / MINUS
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 21 / WINDOW NOSORT STOPKEY
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 22 / COUNT STOPKEY
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 23 / HASH JOIN - LEFT-DEEP JOIN vs RIGHT-DEEP JOIN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 24 / CONNECT BY NO FILTERING WITH START-WITH
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 25 / UNION ALL (RECURSIVE WITH) DEPTH FIRST, RECURSIVE WITH PUMP
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - おまけ#1 / STAR TRANSFORM, VECTOR TRANSFORM (DWH向け)
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - おまけ#2 / MERGE (UPSERT)
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - おまけ#3 / RDFView
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - おまけ#4 / INDEX FULL SCAN (MIN/MAX) - Index Only Scan
・実行計画は, SQL文のレントゲン写真だ! No.30 - LOAD TABLE CONVENTIONAL vs. LOAD AS SELECT
・実行計画は, SQL文のレントゲン写真だ! No.31 - TEMP TABLE TRANSFORMATION LOAD AS SELECT (CURSOR DURATION MEMORY)
・実行計画は, SQL文のレントゲン写真だ! No.32 - EXTERNAL TABLE ACCESS FULL / INMEMORY FULL
・実行計画は, SQL文のレントゲン写真だ! No.33 - BITMAP CONVERSION TO ROWIDS
・実行計画は, SQL文のレントゲン写真だ! No.34 - 似て非なるもの USE_CONCAT と OR_EXPAND ヒント と 手書きSQLのレントゲンの見分け方
・実行計画は, SQL文のレントゲン写真だ! No.35 - 似て非なるもの USE_CONCAT と OR_EXPANDヒントとパラレルクエリー
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 1 / No.36 / INTERSECT ALL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 2 / No.37 / MINUS ALL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 3 / No.38 / EXCEPT and EXCEPT ALL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 4 / No.39 / In-Memory Hybrid Scans
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 5 / No.40 / PIVOT and UNPIVOT
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 6 / No.41 / In-Memory Vectorized Join
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 7 / No.42 / INDEX RANGE SCAN (MULTI VALUE)
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 8 / No.43 / TABLE ACCESS BY INDEX ROWID BATCHED
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 9 / No.44 / COLLECTION ITERATOR PICKLER FETCH
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 10 / No.45 / MAT_VIEW REWRITE ACCESS FULL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 11 / No.46 / GROUPING SETS, ROLLUP, CUBE
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 12 / No.47 / TEMP TABLE TRANSFORMATION
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 13 / No.48 / MULTI-TABLE INSERT
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 14 / No.49 / the DUAL Table
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 15 / No.50 / REMOTE
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 16 / No.51 / Concurrent Execution of Union All and Union
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 17 / No.52 / Order by Elimination
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 18 / No.53 / Join Elimination
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 19 / No.54 / Group by Elimination
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 20 / No.55 / DISTINCT Elimination
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 21 / No.56 / INLIST ITERATOR と Sub Query と STATISTICS COLLECTOR
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 22 / No.57 / Subquery Unnesting

| | | コメント (0)

2022年12月22日 (木)

実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 22 / No.57 / Subquery Unnesting

Previously on Mac De Oracle...

Day 21は, INLIST ITERATOR と Sub Query と STATISTICS COLLECTORを取り上げました. 古くからあるOperationを最適化する比較的新しい機能ですね. とはいえ, 現場で見たことない! なんていうのは多そうではあります.

では, Day 22の窓を開けましょう!

昨日の記事でちょっとだけ話題にした, Subquery Unnesting なので, Subquery Unnestingの代表的な3例を診ておきましょう.

いつもと同じように 21c で確認します.

SCOTT@orclpdb1> select banner from v$version;

BANNER
----------------------------------------------------------------------
Oracle Database 21c Enterprise Edition Release 21.0.0.0.0 - Production


まず, これも通常は, SQLを書き換えないと対応タイプですが, Oracleは結合に書き換えてくれます. 大量にデータを返すのに, スカラー副問い合わせが使われていて辛かった経験って一度ぐらいはありそうですね.
(私も過去一度だけこいつのチューニングしたことがありますが, 当時はスカラー副問い合わせをUnnestingできなかったので, SQLをOUTER JOINに書き換えてもらいました!)

以下の例では, スカラー副問い合わせが, OUTER JOINかつ, このケースではMERGE JOINに書き換えられています.

SCOTT@orclpdb1> @day22
1 SELECT
2 deptno
3 ,dname
4 ,(
5 SELECT
6 MAX(sal)
7 FROM
8 emp
9 WHERE
10 emp.deptno=dept.deptno
11 ) AS max_sal
12 FROM
13 dept
14 ORDER BY
15* deptno

DEPTNO DNAME MAX_SAL
---------- ------------------------------------------ ----------
10 ACCOUNTING 5000
20 RESEARCH 3000
30 SALES 2850
40 OPERATIONS

実行計画
----------------------------------------------------------
Plan hash value: 2834279049

-----------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 4 | 116 | 7 (29)| 00:00:01 |
| 1 | MERGE JOIN OUTER | | 4 | 116 | 7 (29)| 00:00:01 |
| 2 | TABLE ACCESS BY INDEX ROWID| DEPT | 4 | 52 | 2 (0)| 00:00:01 |
| 3 | INDEX FULL SCAN | PK_DEPT | 4 | | 1 (0)| 00:00:01 |
|* 4 | SORT JOIN | | 3 | 48 | 5 (40)| 00:00:01 |
| 5 | VIEW | VW_SSQ_1 | 3 | 48 | 4 (25)| 00:00:01 |
| 6 | HASH GROUP BY | | 3 | 21 | 4 (25)| 00:00:01 |
| 7 | TABLE ACCESS FULL | EMP | 12 | 84 | 3 (0)| 00:00:01 |
-----------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

4 - access("ITEM_1"(+)="DEPT"."DEPTNO")
filter("ITEM_1"(+)="DEPT"."DEPTNO")

では, Scalar Subquery Unnestingされなかった場合はどう見えるでしょうか?(これが, SELECTリストで利用されたScalar subqueryの実行計画です. NO_UNNESTヒントで抑止します.
スカラーサブクエリーが実行計画の最初に現れるのが特徴です(Oracleの場合)

以下の例では, dept表の行数分, Nested Loop Joinのように, emp表へのアクセスが繰り返し実行されます. なので, 行数が多い場合は, HASH JOINなどに書き換えた方が効率が良いわけです. Scalar Subquery UnnestingはそれをOracleが内部的に実施してくれている便利な機能なんですよ.

  1  SELECT
2 deptno
3 ,dname
4 ,(
5 SELECT
6 /*+
7 NO_UNNEST
8 */
9 MAX(sal)
10 FROM
11 emp
12 WHERE
13 emp.deptno=dept.deptno
14 ) AS max_sal
15 FROM
16 dept
17 ORDER BY
18* deptno

DEPTNO DNAME MAX_SAL
---------- ------------------------------------------ ----------
10 ACCOUNTING 5000
20 RESEARCH 3000
30 SALES 2850
40 OPERATIONS

実行計画
----------------------------------------------------------
Plan hash value: 1283604845

------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 4 | 52 | 8 (0)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | 7 | | |
| 2 | TABLE ACCESS BY INDEX ROWID BATCHED| EMP | 4 | 28 | 2 (0)| 00:00:01 |
|* 3 | INDEX RANGE SCAN | IX_EMP | 4 | | 1 (0)| 00:00:01 |
| 4 | TABLE ACCESS BY INDEX ROWID | DEPT | 4 | 52 | 2 (0)| 00:00:01 |
| 5 | INDEX FULL SCAN | PK_DEPT | 4 | | 1 (0)| 00:00:01 |
------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

3 - access("EMP"."DEPTNO"=:B1)


次は, IN条件内のサブクエリーがUnnestingされた例です.
相関関係のないIN副問合せや, IN(集計ファンクションまたはGROUP BY句を含まない場合)に書き換えるとされています. この例は, 相関関係のない副問合せにしてあります. IN LIST ITERATION等ではなく, SubqueryがUnnestingされ, Nested Loop Joinに書き換えられています!

  1  SELECT
2 deptno
3 ,dname
4 FROM
5 dept
6 WHERE
7 deptno IN (
8 SELECT
9 deptno
10 FROM
11 emp
12 WHERE
13 sal < 1000
14 )
15 ORDER BY
16* deptno

DEPTNO DNAME
---------- ------------------------------------------
20 RESEARCH
30 SALES

実行計画
----------------------------------------------------------
Plan hash value: 35786210

------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 20 | 4 (25)| 00:00:01 |
| 1 | NESTED LOOPS | | 1 | 20 | 4 (25)| 00:00:01 |
| 2 | NESTED LOOPS | | 1 | 20 | 4 (25)| 00:00:01 |
| 3 | SORT UNIQUE | | 1 | 7 | 2 (0)| 00:00:01 |
|* 4 | TABLE ACCESS BY INDEX ROWID| EMP | 1 | 7 | 2 (0)| 00:00:01 |
| 5 | INDEX FULL SCAN | IX_EMP | 12 | | 1 (0)| 00:00:01 |
|* 6 | INDEX UNIQUE SCAN | PK_DEPT | 1 | | 0 (0)| 00:00:01 |
| 7 | TABLE ACCESS BY INDEX ROWID | DEPT | 1 | 13 | 1 (0)| 00:00:01 |
------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

4 - filter("SAL"<1000)
6 - access("DEPTNO"="DEPTNO")

IN条件のSubqueryのUnnestingをNO_UNNESTヒントで抑止すると元の実行計画という名のレントゲンが現れてきます.
Unnestingが抑止されたことで, 結合ではなくFILTER条件(EXISTS書き換えられ)になっていることがわかりますよね. どちらの実行計画が有利にかは状況次第ですが, 以前も書いたように, 最近の傾向では, 積極的にUnnestingしているように感じています.

  1  SELECT
2 deptno
3 ,dname
4 FROM
5 dept
6 WHERE
7 deptno IN (
8 SELECT
9 /*+
10 NO_UNNEST
11 */
12 deptno
13 FROM
14 emp
15 WHERE
16 sal < 1000
17 )
18 ORDER BY
19* deptno

DEPTNO DNAME
---------- ------------------------------------------
20 RESEARCH
30 SALES

実行計画
----------------------------------------------------------
Plan hash value: 3458873336

-------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 13 | 8 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID | DEPT | 4 | 52 | 2 (0)| 00:00:01 |
|* 2 | INDEX FULL SCAN | PK_DEPT | 4 | | 1 (0)| 00:00:01 |
|* 3 | TABLE ACCESS BY INDEX ROWID BATCHED| EMP | 1 | 7 | 2 (0)| 00:00:01 |
|* 4 | INDEX RANGE SCAN | IX_EMP | 4 | | 1 (0)| 00:00:01 |
-------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

2 - filter( EXISTS (SELECT /*+ NO_UNNEST */ 0 FROM "EMP" "EMP" WHERE "DEPTNO"=:B1 AND
"SAL"<1000))
3 - filter("SAL"<1000)
4 - access("DEPTNO"=:B1)

最後は, EXISTS演算子内のサブクエリーがUnnestingされた例ですよー. こちらも同じようにUnnestingは積極的に行われているように思います. 私が関わった範囲ですけども.
なお, 書き換え条件として, EXISTS相関副問合せ(集計ファンクションまたはGROUP BY句を含まない場合)となっています. 以下の例でも, 集計ファンクション, GROUP BYを含まない相関服問い合わせにしてあります.

  1  SELECT
2 deptno
3 ,dname
4 FROM
5 dept
6 WHERE
7 EXISTS (
8 SELECT
9 1
10 FROM
11 emp
12 WHERE
13 sal < 1000
14 AND emp.deptno = dept.deptno
15 )
16 ORDER BY
17* deptno

DEPTNO DNAME
---------- ------------------------------------------
20 RESEARCH
30 SALES

実行計画
----------------------------------------------------------
Plan hash value: 35786210

------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 20 | 4 (25)| 00:00:01 |
| 1 | NESTED LOOPS | | 1 | 20 | 4 (25)| 00:00:01 |
| 2 | NESTED LOOPS | | 1 | 20 | 4 (25)| 00:00:01 |
| 3 | SORT UNIQUE | | 1 | 7 | 2 (0)| 00:00:01 |
|* 4 | TABLE ACCESS BY INDEX ROWID| EMP | 1 | 7 | 2 (0)| 00:00:01 |
| 5 | INDEX FULL SCAN | IX_EMP | 12 | | 1 (0)| 00:00:01 |
|* 6 | INDEX UNIQUE SCAN | PK_DEPT | 1 | | 0 (0)| 00:00:01 |
| 7 | TABLE ACCESS BY INDEX ROWID | DEPT | 1 | 13 | 1 (0)| 00:00:01 |
------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

4 - filter("SAL"<1000)
6 - access("EMP"."DEPTNO"="DEPT"."DEPTNO")

NO_UNNESTヒントでUnnestingを抑止してもとの実行計画を覗いています!
Plan hash valueを見ると, なんと, IN条件のNO_UNNESTヒントを付加した実行計画と同じに!

  1  SELECT
2 deptno
3 ,dname
4 FROM
5 dept
6 WHERE
7 EXISTS (
8 SELECT
9 /*+
10 NO_UNNEST
11 */
12 1
13 FROM
14 emp
15 WHERE
16 sal < 1000
17 AND emp.deptno = dept.deptno
18 )
19 ORDER BY
20* deptno

DEPTNO DNAME
---------- ------------------------------------------
20 RESEARCH
30 SALES

実行計画
----------------------------------------------------------
Plan hash value: 3458873336

-------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 13 | 8 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID | DEPT | 4 | 52 | 2 (0)| 00:00:01 |
|* 2 | INDEX FULL SCAN | PK_DEPT | 4 | | 1 (0)| 00:00:01 |
|* 3 | TABLE ACCESS BY INDEX ROWID BATCHED| EMP | 1 | 7 | 2 (0)| 00:00:01 |
|* 4 | INDEX RANGE SCAN | IX_EMP | 4 | | 1 (0)| 00:00:01 |
-------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

2 - filter( EXISTS (SELECT /*+ NO_UNNEST */ 0 FROM "EMP" "EMP" WHERE
"EMP"."DEPTNO"=:B1 AND "SAL"<1000))
3 - filter("SAL"<1000)
4 - access("EMP"."DEPTNO"=:B1)

ということで, 残り3日まで窓を開けました- ;)

安心して, 寝坊しないようにしないと.

ではまた.


参考)
Oracle Database 21c SQL Language Reference / Unnesting of Nested Subqueries



Related article on Mac De Oracle

・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 1 / TABLE FULL SCAN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 2 / INDEX UNIQUE SCAN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 3 / INDEX RANGE SCAN, Index Only Scan
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 4 / INDEX RANGE SCAN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 5 / INDEX RANGE SCAN, INLIST ITERATOR
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 6 / INDEX FAST SCAN, Index Only Scan
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 7 / INDEX FULL SCAN,Index Only Scan
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 8 / INDEX SKIP SCAN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 9 / TABLE ACCESS INMEMORY FULL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 10 / NESTED LOOP JOIN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 11 / MERGE JOIN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 12 / HASH JOIN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 13 / HASH JOIN OUTER
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 14 / HASH JOIN FULL OUTER
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 15 / PX, TABLE ACCESS FULL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 16 / CONCATENATION
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 17 / SORT UNIQUE, UNION-ALL = UNION
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 18 / UNION-ALL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 19 / INTERSECTION
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 20 / MINUS
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 21 / WINDOW NOSORT STOPKEY
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 22 / COUNT STOPKEY
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 23 / HASH JOIN - LEFT-DEEP JOIN vs RIGHT-DEEP JOIN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 24 / CONNECT BY NO FILTERING WITH START-WITH
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 25 / UNION ALL (RECURSIVE WITH) DEPTH FIRST, RECURSIVE WITH PUMP
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - おまけ#1 / STAR TRANSFORM, VECTOR TRANSFORM (DWH向け)
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - おまけ#2 / MERGE (UPSERT)
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - おまけ#3 / RDFView
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - おまけ#4 / INDEX FULL SCAN (MIN/MAX) - Index Only Scan
・実行計画は, SQL文のレントゲン写真だ! No.30 - LOAD TABLE CONVENTIONAL vs. LOAD AS SELECT
・実行計画は, SQL文のレントゲン写真だ! No.31 - TEMP TABLE TRANSFORMATION LOAD AS SELECT (CURSOR DURATION MEMORY)
・実行計画は, SQL文のレントゲン写真だ! No.32 - EXTERNAL TABLE ACCESS FULL / INMEMORY FULL
・実行計画は, SQL文のレントゲン写真だ! No.33 - BITMAP CONVERSION TO ROWIDS
・実行計画は, SQL文のレントゲン写真だ! No.34 - 似て非なるもの USE_CONCAT と OR_EXPAND ヒント と 手書きSQLのレントゲンの見分け方
・実行計画は, SQL文のレントゲン写真だ! No.35 - 似て非なるもの USE_CONCAT と OR_EXPANDヒントとパラレルクエリー
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 1 / No.36 / INTERSECT ALL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 2 / No.37 / MINUS ALL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 3 / No.38 / EXCEPT and EXCEPT ALL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 4 / No.39 / In-Memory Hybrid Scans
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 5 / No.40 / PIVOT and UNPIVOT
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 6 / No.41 / In-Memory Vectorized Join
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 7 / No.42 / INDEX RANGE SCAN (MULTI VALUE)
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 8 / No.43 / TABLE ACCESS BY INDEX ROWID BATCHED
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 9 / No.44 / COLLECTION ITERATOR PICKLER FETCH
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 10 / No.45 / MAT_VIEW REWRITE ACCESS FULL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 11 / No.46 / GROUPING SETS, ROLLUP, CUBE
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 12 / No.47 / TEMP TABLE TRANSFORMATION
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 13 / No.48 / MULTI-TABLE INSERT
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 14 / No.49 / the DUAL Table
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 15 / No.50 / REMOTE
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 16 / No.51 / Concurrent Execution of Union All and Union
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 17 / No.52 / Order by Elimination
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 18 / No.53 / Join Elimination
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 19 / No.54 / Group by Elimination
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 20 / No.55 / DISTINCT Elimination
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 21 / No.56 / INLIST ITERATOR と Sub Query と STATISTICS COLLECTOR

| | | コメント (0)

2022年12月21日 (水)

実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 21 / No.56 / INLIST ITERATOR と Sub Query と STATISTICS COLLECTOR

Previously on Mac De Oracle...

Day 20は, DISTINCT Eliminationを取り上げました. 古くから実装されているElimination機能ですが, 知ってる方いましたかね?w 古すぎでしょうかw. とはいえ, この恩恵を得ている方も実は多いかもしれませんよ. クソデカクエリー追いきれてないかもしれないですし.

では, Day 21の窓を開けましょう!

久々に, 実行計画は, SQL文のレントゲン写真だ! っぽく, 実行計画に現れるOperationを楽しんで診ていきましょう!

いつもと同じように 21c で確認します.

SCOTT@orclpdb1> select banner from v$version;

BANNER
----------------------------------------------------------------------
Oracle Database 21c Enterprise Edition Release 21.0.0.0.0 - Production

今日のテーマはIN条件とサブクエリー. IN条件といえば, 昔, 悩ませ過ぎは及ばざるがごとし #1という記事を書いてました. (そのころはまだIT業界に居なかった? 方も多そうですが)
IN条件, 索引を使って少量のデータをアクセスするには, 以下の実行計画にあるように,  INLIST ITERATORで繰り返しアクセスするは問題ないわけですが, 大量にあるとかなり性能面で影響が出ます. (悩ませ過ぎは及ばざるがごとし #1などは, ハードパース時間に影響がでたケースです)

SCOTT@orclpdb1> @day21
1 SELECT *
2 FROM
3 emp
4 WHERE
5* empno IN (7369,7499)

EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
---------- ------------------------------ --------------------------- ---------- -------- ---------- ---------- ----------
7369 SMITH CLERK 7902 80-12-17 800 20
7499 ALLEN SALESMAN 7698 81-02-20 1600 300 30

実行計画
----------------------------------------------------------
Plan hash value: 2355049923

---------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 2 | 78 | 2 (0)| 00:00:01 |
| 1 | IINLIST ITERATOR | | | | | |
| 2 | TABLE ACCESS BY INDEX ROWID| EMP | 2 | 78 | 2 (0)| 00:00:01 |
|* 3 | INDEX UNIQUE SCAN | PK_EMP | 2 | | 1 (0)| 00:00:01 |
---------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

3 - access("EMPNO"=7369 OR "EMPNO"=7499)


性能問題も多かった影響なのか?!, Oracle Database 9i R2頃以降, IN条件が, 結合に書き換えられるように(私の感覚でしかないのですが, 最近は, より積極的に書き換えが行われる傾向があるように感じます)なっています.
以下のようにサブクエリーを利用しているケースが典型例ですね. IN条件だけでなく, EXISTS演算子や, スカラー副問合せなどもこの書き換えの対象です. この書き換えは, Subquery Unnestingと呼ばれています. ご存知の方も多いですよね. 今日の主役はそれでなく, INLIST ITERATOR の方ですが, これ両方話さないとOperationの向き不向きが見えないのでw

  1  SELECT
2 *
3 FROM
4 emp
5 WHERE
6 deptno IN (
7 SELECT
8 deptno
9 FROM
10 dept
11 WHERE
12 dname IN ('SALES','ACCOUNT')
13* )

EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
---------- ------------------------------ --------------------------- ---------- -------- ---------- ---------- ----------
7499 ALLEN SALESMAN 7698 81-02-20 1600 300 30
7521 WARD SALESMAN 7698 81-02-22 1250 500 30
7654 MARTIN SALESMAN 7698 81-09-28 1250 1400 30
7698 BLAKE MANAGER 7839 81-05-01 2850 30
7844 TURNER SALESMAN 7698 81-09-08 1500 0 30
7900 JAMES CLERK 7698 81-12-03 950 30

6行が選択されました.

実行計画
----------------------------------------------------------
Plan hash value: 4207756064

---------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 8 | 416 | 5 (0)| 00:00:01 |
| 1 | NESTED LOOPS | | 8 | 416 | 5 (0)| 00:00:01 |
| 2 | NESTED LOOPS | | 8 | 416 | 5 (0)| 00:00:01 |
|* 3 | TABLE ACCESS FULL | DEPT | 2 | 26 | 3 (0)| 00:00:01 |
|* 4 | INDEX RANGE SCAN | IX_EMP | 4 | | 0 (0)| 00:00:01 |
| 5 | TABLE ACCESS BY INDEX ROWID| EMP | 4 | 156 | 1 (0)| 00:00:01 |
---------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

3 - filter("DNAME"='ACCOUNT' OR "DNAME"='SALES')
4 - access("DEPTNO"="DEPTNO")

Note
-----
- this is an adaptive plan

前述した実行計画の Noteに, - this is an adaptive plan と気になる情報が出ています. これ, 実行計画上は, Subquery Unnestingされて, Nested Loop Join (NLJ) になっていますが, 駆動表のヒット件数に応じて, それ以外の結合メソッドに
へ切り替わる可能性があることを示しています. これは, adaptive planと呼ばれている機能です.
実際, NLJなのかそれ以外なのかをみる方法は, SQL Monitor, Actual Planを利用する方法と, 以下のように, Adaptive Planを表示させ, どちらで動作したのかを確認する方法があります.

ここで登場するのが, Adaptive Planの鍵になる, STATISTICS COLLECTOR というOperationです. ここで駆動表の件数をみつつ, これは! HJ向きのと判断すれば, NLJ から HJ へ切り替えることになります.
今回は, NLJ のままですね. ()

  1* SELECT * FROM TABLE(DBMS_XPLAN.display_cursor(format => 'adaptive'))

PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------
SQL_ID cuxwr51s6gs61, child number 0
-------------------------------------
SELECT * FROM emp WHERE deptno IN ( SELECT deptno
FROM dept WHERE dname IN ('SALES','ACCOUNT') )

Plan hash value: 4207756064

------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | | 5 (100)| |
|- * 1 | HASH JOIN | | 8 | 416 | 5 (0)| 00:00:01 |
| 2 | NESTED LOOPS | | 8 | 416 | 5 (0)| 00:00:01 |
| 3 | NESTED LOOPS | | 8 | 416 | 5 (0)| 00:00:01 |
|- 4 | STATISTICS COLLECTOR | | | | | |
| * 5 | TABLE ACCESS FULL | DEPT | 2 | 26 | 3 (0)| 00:00:01 |
| * 6 | INDEX RANGE SCAN | IX_EMP | 4 | | 0 (0)| |
| 7 | TABLE ACCESS BY INDEX ROWID| EMP | 4 | 156 | 1 (0)| 00:00:01 |
|- 8 | TABLE ACCESS FULL | EMP | 4 | 156 | 1 (0)| 00:00:01 |
------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

1 - access("DEPTNO"="DEPTNO")
5 - filter(("DNAME"='ACCOUNT' OR "DNAME"='SALES'))
6 - access("DEPTNO"="DEPTNO")

Note
-----
- this is an adaptive plan (rows marked '-' are inactive)

残り, 4日, 最終日はクリスマスで, 日曜日じゃないか!今年は.
大きめのネタをぶん投げて, おまけブログでまとめる感じにするか. 悩みどころだ. それとも軽めのネタで最後まで通すか.

明日も担当は, 私ですよ. (全部俺アドベントカレンダー, 来年はどうしようw なんの苦行だという感じw でも, それ楽しんでる俺は...w)

では, また :)



Related article on Mac De Oracle

・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 1 / TABLE FULL SCAN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 2 / INDEX UNIQUE SCAN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 3 / INDEX RANGE SCAN, Index Only Scan
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 4 / INDEX RANGE SCAN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 5 / INDEX RANGE SCAN, INLIST ITERATOR
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 6 / INDEX FAST SCAN, Index Only Scan
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 7 / INDEX FULL SCAN,Index Only Scan
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 8 / INDEX SKIP SCAN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 9 / TABLE ACCESS INMEMORY FULL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 10 / NESTED LOOP JOIN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 11 / MERGE JOIN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 12 / HASH JOIN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 13 / HASH JOIN OUTER
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 14 / HASH JOIN FULL OUTER
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 15 / PX, TABLE ACCESS FULL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 16 / CONCATENATION
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 17 / SORT UNIQUE, UNION-ALL = UNION
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 18 / UNION-ALL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 19 / INTERSECTION
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 20 / MINUS
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 21 / WINDOW NOSORT STOPKEY
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 22 / COUNT STOPKEY
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 23 / HASH JOIN - LEFT-DEEP JOIN vs RIGHT-DEEP JOIN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 24 / CONNECT BY NO FILTERING WITH START-WITH
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 25 / UNION ALL (RECURSIVE WITH) DEPTH FIRST, RECURSIVE WITH PUMP
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - おまけ#1 / STAR TRANSFORM, VECTOR TRANSFORM (DWH向け)
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - おまけ#2 / MERGE (UPSERT)
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - おまけ#3 / RDFView
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - おまけ#4 / INDEX FULL SCAN (MIN/MAX) - Index Only Scan
・実行計画は, SQL文のレントゲン写真だ! No.30 - LOAD TABLE CONVENTIONAL vs. LOAD AS SELECT
・実行計画は, SQL文のレントゲン写真だ! No.31 - TEMP TABLE TRANSFORMATION LOAD AS SELECT (CURSOR DURATION MEMORY)
・実行計画は, SQL文のレントゲン写真だ! No.32 - EXTERNAL TABLE ACCESS FULL / INMEMORY FULL
・実行計画は, SQL文のレントゲン写真だ! No.33 - BITMAP CONVERSION TO ROWIDS
・実行計画は, SQL文のレントゲン写真だ! No.34 - 似て非なるもの USE_CONCAT と OR_EXPAND ヒント と 手書きSQLのレントゲンの見分け方
・実行計画は, SQL文のレントゲン写真だ! No.35 - 似て非なるもの USE_CONCAT と OR_EXPANDヒントとパラレルクエリー
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 1 / No.36 / INTERSECT ALL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 2 / No.37 / MINUS ALL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 3 / No.38 / EXCEPT and EXCEPT ALL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 4 / No.39 / In-Memory Hybrid Scans
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 5 / No.40 / PIVOT and UNPIVOT
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 6 / No.41 / In-Memory Vectorized Join
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 7 / No.42 / INDEX RANGE SCAN (MULTI VALUE)
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 8 / No.43 / TABLE ACCESS BY INDEX ROWID BATCHED
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 9 / No.44 / COLLECTION ITERATOR PICKLER FETCH
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 10 / No.45 / MAT_VIEW REWRITE ACCESS FULL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 11 / No.46 / GROUPING SETS, ROLLUP, CUBE
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 12 / No.47 / TEMP TABLE TRANSFORMATION
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 13 / No.48 / MULTI-TABLE INSERT
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 14 / No.49 / the DUAL Table
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 15 / No.50 / REMOTE
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 16 / No.51 / Concurrent Execution of Union All and Union
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 17 / No.52 / Order by Elimination
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 18 / No.53 / Join Elimination
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 19 / No.54 / Group by Elimination
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 20 / No.55 / DISTINCT Elimination

| | | コメント (0)

2022年12月20日 (火)

実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 20 / No.55 / DISTINCT Elimination

Previously on Mac De Oracle... 
Day 19は, かなり地味にデビューしていた機能ですが、変なところで目立った Group by Elimination にフォーカスを当てました。この手のEliminationは、実行計画という名のレントゲンからは見えなくなってしまう。何か悪さをしているときの調査は難易度高めです。基本的に操作が行われなくなるわけですが、例としてお見せしたような単純なSQLなら別ですが、クソデカクエリーだと、キッツイですよねw 結果不正って。

と言うことで、Day 20の窓を開けましょう!

 

今日は、 DISTINCT Eliminationです。またか! と。そういうEliminationもある。ということ知っておいた方が良いと思うので、eliminationネタの最後として、ちょっと飽きてきた感じはありますが取り上げてみました。この機能の提供も古く、機能が提供されていなかった時代を知る人の方が少ないかもしれませんw

ちなみに、今回も該当機能をを局所的に無効化する例を書いていますが、ヒントが提供されていない最適化もあるので、そう言う場合は、隠しパラメータからそれらしいのを探してして、検証して効果の有無を確かめると良いと思います。MOSに書かれてないケースも多いのでBlogなどから情報を集めたりして、最終的には動作確認。もし不具合などと関連しているようであればサポートへ問い合わせても対応してくれるでしょう。コミュニティーにこれどうよ?と投げてみるのもありだと思います。Jonathanもネタもとは、コミュニティーでのやりとりだったりすることも多く、調べてみたら、そうだった!という記事も多く、本当に助かった!って経験は何度もあります!!!。

parameterはこんなあたりから見つけると楽ですよん。
Difference of Initialization Parameters between 19c (19.3.0.0.0) and 21c (21.3.0.0.0) - including hidden params
Difference of Initialization Parameters between 19c (19.3.0.0.0) and 21c (21.3.0.0.0)

 

いつもと同じように 21c で確認します.


SCOTT@orclpdb1> select banner from v$version;

BANNER
----------------------------------------------------------------------
Oracle Database 21c Enterprise Edition Release 21.0.0.0.0 - Production

 

前回と同じデータを使います。(こんな使いまわせるテストデータを作るスクリプト用意しておくと何かと便利ですよ!)


SCOTT@orclpdb1> @day20
1* DROP TABLE business_day_calendar

表が削除されました。

1 CREATE TABLE business_day_calendar AS
2 WITH
3 FUNCTION get_num_of_dates
4 RETURN NUMBER IS
5 l_dummy_date DATE;
6 --
7 eORA01839 exception;
8 pragma exception_init(eORA01839, -1839);
9 BEGIN
10 -- validate leap year
11 l_dummy_date := TO_DATE(TO_CHAR(SYSDATE, 'YYYY') || '0229', 'YYYYMMDD');
12 RETURN 366;
13 EXCEPTION
14 WHEN eORA01839 THEN
15 RETURN 365;
16 END;
17 SELECT
18 TO_DATE(TRUNC(SYSDATE,'YYYY') + level - 1) AS business_date
19 , CASE
20 WHEN TO_CHAR(
21 TO_DATE(TRUNC(SYSDATE,'YYYY') + level - 1)
22 , 'DY'
23 , 'NLS_DATE_LANGUAGE=AMERICAN'
24 ) IN ('SUN','WED')
25 THEN '1'
26 ELSE '0'
27 END AS is_holiday
28 FROM
29 dual
30 CONNECT BY
31* level <= get_num_of_dates

表が作成されました。

1 ALTER TABLE business_day_calendar
2 ADD CONSTRAINT pk_business_day_calendar PRIMARY KEY
3 (
4 business_date
5 )
6* USING INDEX

表が変更されました。

 

はい、主キー列にDISTINCTを使ってますが、無駄ですよね!(いきなり本題w)

DISTINCT操作は見事に実行計画から排除されています!(簡単ですね。とは言っても実行計画を見ただけでは、DISTINCT Eliminationが行われていることには気付けないわけですけども)


  1  SELECT
2 DISTINCT business_date
3 FROM
4* business_day_calendar

BUSINESS
--------
22-01-01
22-01-02
22-01-03

...略...

22-12-29
22-12-30
22-12-31

365行が選択されました。

実行計画
----------------------------------------------------------
Plan hash value: 1786497156

---------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 365 | 2920 | 1 (0)| 00:00:01 |
| 1 | INDEX FULL SCAN | PK_BUSINESS_DAY_CALENDAR | 365 | 2920 | 1 (0)| 00:00:01 |
---------------------------------------------------------------------------------------------

統計
----------------------------------------------------------
0 recursive calls
0 db block gets
26 consistent gets
0 physical reads
0 redo size
8855 bytes sent via SQL*Net to client
316 bytes received via SQL*Net from client
26 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
365 rows processed

 

では、元栓というか、Optimizer自体を、とーーーく昔の状態にしてみましょう(DISTINCT Eliminationがバックポートもされてない時代の10g 10.2.0.3。こういうことができるOracle面白いですよね)
このようなことを本番でやるのはかなりレアで、よっぽど新しい機能を使いたくないか、めちゃめちゃキツイ大人の事情があるんだと思います(知らんけど)

Optimizerを10g R2ぐらいに戻したことで、DISTINCT操作として、SORT UNIQUE NOSORTが合わられましたが、INDEX FULL SCANでユニークキーをアクセスしているのでNOSORTとなり、SORT UNIQUE操作はスキップされていることがわかります。ソート順に索引を全捜査する INDEX FULL SCANだからこそできる動きですね。


  1  SELECT
2 /*+
3 OPTIMIZER_FEATURES_ENABLE('10.2.0.3')
4 */
5 DISTINCT business_date
6 FROM
7* business_day_calendar

BUSINESS
--------
22-01-01
22-01-02
22-01-03

...略...

22-12-29
22-12-30
22-12-31

365行が選択されました。

実行計画
----------------------------------------------------------
Plan hash value: 311283176

-----------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 365 | 2920 | 2 (50)| 00:00:01 |
| 1 | SORT UNIQUE NOSORT| | 365 | 2920 | 2 (50)| 00:00:01 |
| 2 | INDEX FULL SCAN | PK_BUSINESS_DAY_CALENDAR | 365 | 2920 | 1 (0)| 00:00:01 |
-----------------------------------------------------------------------------------------------

統計
----------------------------------------------------------
0 recursive calls
0 db block gets
26 consistent gets
0 physical reads
0 redo size
8855 bytes sent via SQL*Net to client
316 bytes received via SQL*Net from client
26 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
365 rows processed

 

Optimizerの能力を10gに戻してしまうのも勿体ないので、よく使う局所的な方法。特定のSQLだけが影響するのであれば、この方法がおすすめです。
元々の機能に影響を受けていない。逆に恩恵を受けているものあるかもしれません。
前回の結果不正などもそうですが、どの方法で治療するというかチューニングかは、対応するエンジニア考え方や、該当する患者さん(システムや、お客様の大人の事情w)にもよりますが、私は、基本的に局所的な対処で済むのなら、そちらを選ぶ方針です。
なるべく狭い範囲、SQL、セッションあたりで無効、有効にして、経過観察、副作用有無、対処した範囲外で、同一理由による問題が発生していないか。もし狭い範囲の対処では無理なら徐々に広げる。最終系がインスタンス全体で。みたいな流れにすることで、無駄に全て止めてしまうということを避けたい(恩恵を受けているのもあるはずということを前提にしています)。この辺りは考え方次第なので、絶対、こうするのが良いとか悪いという話では無いですが。長い目で考えるとそれが良いのでは無いかと個人的には思います。
この機能、直接利用できるヒントはないので、隠しパラメータでon/offできます。冒頭で紹介したパラメータ一覧には隠しパラメータもリストしているので、こういう時はクエリ投げずに該当ページを検索すると楽ですよん:)


  1  SELECT
2 /*+
3 OPT_PARAM('_optimizer_distinct_elimination','false')
4 */
5 DISTINCT business_date
6 FROM
7* business_day_calendar

BUSINESS
--------
22-01-01
22-01-02
22-01-03

...略...

22-12-29
22-12-30
22-12-31

365行が選択されました。

実行計画
----------------------------------------------------------
Plan hash value: 311283176

-----------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 365 | 2920 | 2 (50)| 00:00:01 |
| 1 | SORT UNIQUE NOSORT| | 365 | 2920 | 2 (50)| 00:00:01 |
| 2 | INDEX FULL SCAN | PK_BUSINESS_DAY_CALENDAR | 365 | 2920 | 1 (0)| 00:00:01 |
-----------------------------------------------------------------------------------------------

統計
----------------------------------------------------------
0 recursive calls
0 db block gets
26 consistent gets
0 physical reads
0 redo size
8855 bytes sent via SQL*Net to client
316 bytes received via SQL*Net from client
26 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
365 rows processed

 

別テストケースで確認してみましょう。


  1* DROP TABLE case2

表が削除されました。

1 CREATE TABLE case2
2 (
3 id NUMBER PRIMARY KEY
4 , col2 NUMBER NOT NULL
5 , col3 NUMBER
6 , col4 VARCHAR2(10) NOT NULL
7 , CONSTRAINT uix_case2 UNIQUE (col2,col3) USING INDEX
8* )

表が作成されました。

1 BEGIN
2 FOR i IN 1..2000 LOOP
3 INSERT INTO case2 VALUES(i, i, NULL, LPAD(TO_CHAR(i),10,'*'));
4 IF MOD(i,100) = 0 THEN COMMIT; END IF;
5 END LOOP;
6* END;

PL/SQLプロシージャが正常に完了しました。

 

このテストケースでは、複合一意キーかつ、第二キーに null を許しています。
Oraleの索引は、null が含まれない!という都市伝説がありましたが、そんなことはないのは以前解説していた通りです。一部の列にnullを許可した一意キーでもDISTINCT Eliminationは発動することを確認するテストケースです)

この例では、第二キー列がnullableで、この状態では、第二キー列全てを null にしています。DISTINCT Eliminationの条件を満たすため、DISTINCT 捜査が排除されていることがわかります!


  1  SELECT
2 DISTINCT col2, col3
3 FROM
4* case2

COL2 COL3
---------- ----------
541 [null]
542 [null]
543 [null]

...略...

1998 [null]
1999 [null]
2000 [null]

2000行が選択されました。

実行計画
----------------------------------------------------------
Plan hash value: 1081843087

----------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 2000 | 52000 | 5 (0)| 00:00:01 |
| 1 | INDEX FAST FULL SCAN| UIX_CASE2 | 2000 | 52000 | 5 (0)| 00:00:01 |
----------------------------------------------------------------------------------

 

OPT_PARAM('_optimizer_distinct_elimination','false')でDISTINCT Eliminationを無効化すれば、DISTINCT 操作は現れますが、INDEX FAST FULL SCANとなっているため HASH UNIQUE操作が行われていることがわかります。
実際には、ユニーク索引なので、不要ではあるのですが:)


  1  SELECT
2 /*+
3 OPT_PARAM('_optimizer_distinct_elimination','false')
4 */
5 DISTINCT col2, col3
6 FROM
7* case2

COL2 COL3
---------- ----------
555 [null]
585 [null]
586 [null]

...略...

1986 [null]
1989 [null]
1990 [null]

2000行が選択されました。

実行計画
----------------------------------------------------------
Plan hash value: 523836292

-----------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 2000 | 52000 | 6 (17)| 00:00:01 |
| 1 | HASH UNIQUE | | 2000 | 52000 | 6 (17)| 00:00:01 |
| 2 | INDEX FAST FULL SCAN| UIX_CASE2 | 2000 | 52000 | 5 (0)| 00:00:01 |
-----------------------------------------------------------------------------------

 

では、ちょっと初歩的な確認で、1, nullというすでに存在する値をINSERTしてみましょう。当然エラーです。UIX_CASE2は一意キーなので。


  1* INSERT INTO case2 VALUES(2001,1,NULL,'test')
INSERT INTO case2 VALUES(2001,1,NULL,'test')
*
行1でエラーが発生しました。:
ORA-00001: 一意制約(SCOTT.UIX_CASE2)に反しています

 

第二キーがnullではない値を登録しておきます。


  1* INSERT INTO case2 VALUES(2002,1,1,'test')

1行が作成されました。

1* COMMIT

コミットが完了しました。

 

特にどうだということもないのですがw 正しく、DISTINCT EliminationされINDEX FAST FULL SCANだけの実行計画という名のレントゲンが現れています。ニッコリ(どちらかというと、索引に null 入らないという本当の意味を知らずにいる方もいるのではないだろうかという余計な心配をしただけのお節介なテストケース。というだけだったかもしれません)


  1  SELECT
2 DISTINCT col2, col3
3 FROM
4* case2

COL2 COL3
---------- ----------
541 [null]
542 [null]
543 [null]

...略...

1 1
1 [null]
2 [null]
3 [null]

...略...

538 [null]
539 [null]
540 [null]

2001行が選択されました。

実行計画
----------------------------------------------------------
Plan hash value: 1081843087

----------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 2000 | 52000 | 5 (0)| 00:00:01 |
| 1 | INDEX FAST FULL SCAN| UIX_CASE2 | 2000 | 52000 | 5 (0)| 00:00:01 |
----------------------------------------------------------------------------------

 

ということで、 Day 20はここまで。

 

残り5日。追い込みだーーーーっ
明日も、私が担当なので、よろしくお願いします。


Related article on Mac De Oracle
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 1 / TABLE FULL SCAN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 2 / INDEX UNIQUE SCAN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 3 / INDEX RANGE SCAN, Index Only Scan
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 4 / INDEX RANGE SCAN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 5 / INDEX RANGE SCAN, INLIST ITERATOR
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 6 / INDEX FAST SCAN, Index Only Scan
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 7 / INDEX FULL SCAN,Index Only Scan
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 8 / INDEX SKIP SCAN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 9 / TABLE ACCESS INMEMORY FULL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 10 / NESTED LOOP JOIN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 11 / MERGE JOIN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 12 / HASH JOIN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 13 / HASH JOIN OUTER
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 14 / HASH JOIN FULL OUTER
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 15 / PX, TABLE ACCESS FULL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 16 / CONCATENATION
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 17 / SORT UNIQUE, UNION-ALL = UNION
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 18 / UNION-ALL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 19 / INTERSECTION
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 20 / MINUS
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 21 / WINDOW NOSORT STOPKEY
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 22 / COUNT STOPKEY
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 23 / HASH JOIN - LEFT-DEEP JOIN vs RIGHT-DEEP JOIN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 24 / CONNECT BY NO FILTERING WITH START-WITH
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 25 / UNION ALL (RECURSIVE WITH) DEPTH FIRST, RECURSIVE WITH PUMP
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - おまけ#1 / STAR TRANSFORM, VECTOR TRANSFORM (DWH向け)
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - おまけ#2 / MERGE (UPSERT)
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - おまけ#3 / RDFView
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - おまけ#4 / INDEX FULL SCAN (MIN/MAX) - Index Only Scan
・実行計画は, SQL文のレントゲン写真だ! No.30 - LOAD TABLE CONVENTIONAL vs. LOAD AS SELECT
・実行計画は, SQL文のレントゲン写真だ! No.31 - TEMP TABLE TRANSFORMATION LOAD AS SELECT (CURSOR DURATION MEMORY)
・実行計画は, SQL文のレントゲン写真だ! No.32 - EXTERNAL TABLE ACCESS FULL / INMEMORY FULL
・実行計画は, SQL文のレントゲン写真だ! No.33 - BITMAP CONVERSION TO ROWIDS
・実行計画は, SQL文のレントゲン写真だ! No.34 - 似て非なるもの USE_CONCAT と OR_EXPAND ヒント と 手書きSQLのレントゲンの見分け方
・実行計画は, SQL文のレントゲン写真だ! No.35 - 似て非なるもの USE_CONCAT と OR_EXPANDヒントとパラレルクエリー
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 1 / No.36 / INTERSECT ALL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 2 / No.37 / MINUS ALL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 3 / No.38 / EXCEPT and EXCEPT ALL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 4 / No.39 / In-Memory Hybrid Scans
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 5 / No.40 / PIVOT and UNPIVOT
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 6 / No.41 / In-Memory Vectorized Join
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 7 / No.42 / INDEX RANGE SCAN (MULTI VALUE)
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 8 / No.43 / TABLE ACCESS BY INDEX ROWID BATCHED
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 9 / No.44 / COLLECTION ITERATOR PICKLER FETCH
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 10 / No.45 / MAT_VIEW REWRITE ACCESS FULL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 11 / No.46 / GROUPING SETS, ROLLUP, CUBE
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 12 / No.47 / TEMP TABLE TRANSFORMATION
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 13 / No.48 / MULTI-TABLE INSERT
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 14 / No.49 / the DUAL Table
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 15 / No.50 / REMOTE
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 16 / No.51 / Concurrent Execution of Union All and Union
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 17 / No.52 / Order by Elimination
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 18 / No.53 / Join Elimination
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 19 / No.54 / Group by Elimination

| | | コメント (0)

2022年12月19日 (月)

実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 19 / No.54 / Group by Elimination

このポストは, JPOUG Advent Calendar 2022 Day 19帰ってきた! 実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺) Advent Calendar 2022へクロスポストしています.

 

JPOUG Advent Calendar 2022 Day 18は, tomoさんのSPM使ってる?でした. 使ってますか?ヒント埋込派, パッケージなんでSPMっす!とか大人の事情で色々ありそうですね.

Previously on Mac De Oracle... Day 18は, Join Elimination にフォーカスをあてました. Join Eliminationも他のElimination系書き換えは, 実行計画上存在が消されてしまうので, 実際行われたかどうか気づきにくいケースが多いです. 以前も書きましたが, Explain plan等で, Elimination Informationとかリストしてくれると便利かもしれません.

ということで, 今日, Day 19は, そんなElimination InformationがExplain plan等で表示されたら嬉しいかもね, という気持ちが強くなるネタにしました.

 

では, Day 19のお題, Group by Eliminationです.
この機能, 目立たないですが, 変なところで目立ったので意外に有名かもしれません. 機能として登場したのは, 12cR2ごろでした. Jonathanも書いてるから間違いない!

変なところで目立ってしまった. そんなに目立たない存在だった, Group by Eliminationの確認
目立ってしまった理由は, 結果不正.  できれば7445の方が分かりやすくて良かったわけですが, 出会いたくないですよねー. 結果不正.
(なお, すでに修正されており, 想定する結果が返されるようになっているようです. 詳細は本ページ末の参考リンクのJonathanのエントリー参照のこと)

まず, 検証用のデータ準備から(ちょいと凝ったことやってますが, 単純に当年のカレンダーで, その日が営業日か休業日かをフラグで持たせるだけのでデータで, 2022年の一年分のデータを作りました. day18.sqlを実行していますが, こちらの都合w公開日を入れ替えた影響なので, 気にしないでくださいw

SCOTT@orclpdb1> @day18
1* DROP TABLE business_day_calendar

表が削除されました.

1 CREATE TABLE business_day_calendar AS
2 WITH
3 FUNCTION get_num_of_dates
4 RETURN NUMBER IS
5 l_dummy_date DATE;
6 --
7 eORA01839 exception;
8 pragma exception_init(eORA01839, -1839);
9 BEGIN
10 -- validate leap year
11 l_dummy_date := TO_DATE(TO_CHAR(SYSDATE, 'YYYY') || '0229', 'YYYYMMDD');
12 RETURN 366;
13 EXCEPTION
14 WHEN eORA01839 THEN
15 RETURN 365;
16 END;
17 SELECT
18 TO_DATE(TRUNC(SYSDATE,'YYYY') + level - 1) AS business_date
19 , CASE
20 WHEN TO_CHAR(
21 TO_DATE(TRUNC(SYSDATE,'YYYY') + level - 1)
22 , 'DY'
23 , 'NLS_DATE_LANGUAGE=AMERICAN'
24 ) IN ('SUN','WED')
25 THEN '1'
26 ELSE '0'
27 END AS is_holiday
28 FROM
29 dual
30 CONNECT BY
31* level <= get_num_of_dates

表が作成されました.

1 ALTER TABLE business_day_calendar
2 ADD CONSTRAINT pk_business_day_calendar PRIMARY KEY
3 (
4 business_date
5 )
6* USING INDEX

表が変更されました.

 

今回は, この Order BY Elimination をちょっと有名にしてしまった, 結果不正から. 12cR2で試してみます. CASE 2の結果が想定と異なっています.

orcl@SCOTT> select banner from v$version;

BANNER
--------------------------------------------------------------------------------
Oracle Database 12c Enterprise Edition Release 12.2.0.1.0 - 64bit Production

CASE 1特に問題は起きていません. 想定通りの結果が帰り, Group By Eliminationの発動条件にはなっていないため, Group By操作が行われています.

  1  SELECT
2 EXTRACT(MONTH from business_date)
3 , COUNT(
4 CASE
5 WHEN TO_CHAR(
6 business_date
7 , 'DY'
8 , 'NLS_DATE_LANGUAGE=AMERICAN'
9 ) IN ('SUN','WED')
10 THEN 1
11 END
12 ) AS holidays
13 FROM
14 business_day_calendar
15 GROUP BY
16* EXTRACT(MONTH from business_date)

EXTRACT(MONTHFROMBUSINESS_DATE) HOLIDAYS
------------------------------- ----------
1 9
6 9
11 9
2 8
4 8
5 9
8 9
3 9
7 9
9 8
10 9
12 8

12 rows selected.

Execution Plan
----------------------------------------------------------
Plan hash value: 100882575

---------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 365 | 2920 | 2 (50)| 00:00:01 |
| 1 | HASH GROUP BY | | 365 | 2920 | 2 (50)| 00:00:01 |
| 2 | INDEX FULL SCAN| PK_BUSINESS_DAY_CALENDAR | 365 | 2920 | 1 (0)| 00:00:01 |
---------------------------------------------------------------------------------------------

 

CASE 2 おやおやおや, おかしなことになってます. 実行計画をみると, 動作対象ではないはずなのに, GROUP BY 操作が排除されているのが分かります! 結果不正です. HASH GROUP BYが排除されています! その影響で, GROUP BYが行われていません!!!!

  1  SELECT
2 TO_CHAR(business_date, 'YYYYMM')
3 , COUNT(1)
4 FROM
5 business_day_calendar
6 GROUP BY
7* TO_CHAR(business_date, 'YYYYMM')

TO_CHA COUNT(1)
------ ----------
202201 1
202201 1
202201 1

...略...

202212 1
202212 1
202212 1

365 rows selected.

Execution Plan
----------------------------------------------------------
Plan hash value: 1786497156

---------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 365 | 2920 | 1 (0)| 00:00:01 |
| 1 | INDEX FULL SCAN | PK_BUSINESS_DAY_CALENDAR | 365 | 2920 | 1 (0)| 00:00:01 |
---------------------------------------------------------------------------------------------

 

CASE 2 の結果不正回避 では, 結果不正回避策を取ってみましょう. 何度か利用している, no_elim_groupbyヒントで回避できるか試します!
結果不正の理由は, 本来発動しない条件であるにもかかわらず発動してしまった Group By Eliminationにる影響であることが分かります.

これをみると, なおさら, Explain Plan等でどのような書き換えが動作したのかしないのか一覧できるような情報が欲しいなと思ったりするわけです. .

orcl@SCOTT> @day18-2
1 SELECT
2 /*+
3 no_elim_groupby
4 */
5 TO_CHAR(business_date, 'YYYYMM')
6 , COUNT(1)
7 FROM
8 business_day_calendar
9 GROUP BY
10* TO_CHAR(business_date, 'YYYYMM')

TO_CHA COUNT(1)
------ ----------
202205 31
202209 30
202211 30
202212 31
202202 28
202208 31
202207 31
202210 31
202201 31
202204 30
202203 31
202206 30

12 rows selected.

Execution Plan
----------------------------------------------------------
Plan hash value: 100882575

---------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 365 | 2920 | 2 (50)| 00:00:01 |
| 1 | HASH GROUP BY | | 365 | 2920 | 2 (50)| 00:00:01 |
| 2 | INDEX FULL SCAN| PK_BUSINESS_DAY_CALENDAR | 365 | 2920 | 1 (0)| 00:00:01 |
---------------------------------------------------------------------------------------------

 

CASE 3 こちらは正しく GROUP BY Eliminationが発動していますね. GROUP BYしなくても問題ないクエリですから!

  1  SELECT
2 business_date
3 , COUNT(1)
4 FROM
5 business_day_calendar
6 GROUP BY
7* business_date

BUSINESS_ COUNT(1)
--------- ----------
01-JAN-22 1
02-JAN-22 1
03-JAN-22 1

...略...

29-DEC-22 1
30-DEC-22 1
31-DEC-22 1

365 rows selected.

Execution Plan
----------------------------------------------------------
Plan hash value: 1786497156

---------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 365 | 2920 | 1 (0)| 00:00:01 |
| 1 | INDEX FULL SCAN | PK_BUSINESS_DAY_CALENDAR | 365 | 2920 | 1 (0)| 00:00:01 |
---------------------------------------------------------------------------------------------

 

CASE 4 GROUP BY Eliminationを無効化しても他のバージョンと結果同じで, 想定した結果通りです. CASE 3と結果は同じなのは当たり前.

  1  SELECT
2 /*+
3 no_elim_groupby
4 */
5 business_date
6 , COUNT(1)
7 FROM
8 business_day_calendar
9 GROUP BY
10* business_date

BUSINESS_ COUNT(1)
--------- ----------
01-JAN-22 1
02-JAN-22 1
03-JAN-22 1

...略...

29-DEC-22 1
30-DEC-22 1
31-DEC-22 1

365 rows selected.

Execution Plan
----------------------------------------------------------
Plan hash value: 3672056694

-------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 365 | 2920 | 1 (0)| 00:00:01 |
| 1 | SORT GROUP BY NOSORT| | 365 | 2920 | 1 (0)| 00:00:01 |
| 2 | INDEX FULL SCAN | PK_BUSINESS_DAY_CALENDAR | 365 | 2920 | 1 (0)| 00:00:01 |
-------------------------------------------------------------------------------------------------

 

では, 私が確認したテストケースの範囲で結果不正が起きていない, 21cは全テストケース, それ以外のバージョンでは, 結果不正の発生していた CASE 2 の実行計画という名のレントゲンを並べておきたいと思います. 頭に浮かんだイメージは, レントゲン写真を光るボードに沢山貼り付けてる感じw

Oracle Database 21cのCASE 1 - CASE 4まで全て

SCOTT@orclpdb1> select banner from v$version;

BANNER
----------------------------------------------------------------------
Oracle Database 21c Enterprise Edition Release 21.0.0.0.0 - Production

 

CASE 1:Group By Eliminationは発生しないケース

  1  SELECT
2 EXTRACT(MONTH from business_date)
3 , COUNT(
4 CASE
5 WHEN TO_CHAR(
6 business_date
7 , 'DY'
8 , 'NLS_DATE_LANGUAGE=AMERICAN'
9 ) IN ('SUN','WED')
10 THEN 1
11 END
12 ) AS holidays
13 FROM
14 business_day_calendar
15 GROUP BY
16* EXTRACT(MONTH from business_date)

EXTRACT(MONTHFROMBUSINESS_DATE) HOLIDAYS
------------------------------- ----------
1 9
2 8
3 9
4 8
5 9
6 9
7 9
8 9
9 8
10 9
11 9
12 8

12行が選択されました.

実行計画
----------------------------------------------------------
Plan hash value: 100882575

---------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 365 | 2920 | 2 (50)| 00:00:01 |
| 1 | HASH GROUP BY | | 365 | 2920 | 2 (50)| 00:00:01 |
| 2 | INDEX FULL SCAN| PK_BUSINESS_DAY_CALENDAR | 365 | 2920 | 1 (0)| 00:00:01 |
---------------------------------------------------------------------------------------------

 

CASE 2:Group By Eliminationは発生しないケース(12cR2でGroup By Eliminationの誤作動で結果不正となったテストケース)

  1  SELECT
2 TO_CHAR(business_date, 'YYYYMM')
3 , COUNT(1)
4 FROM
5 business_day_calendar
6 GROUP BY
7* TO_CHAR(business_date, 'YYYYMM')

TO_CHAR(BUSINESS_D COUNT(1)
------------------ ----------
202201 31
202202 28
202203 31
202204 30
202205 31
202206 30
202207 31
202208 31
202209 30
202210 31
202211 30
202212 31

12行が選択されました.

実行計画
----------------------------------------------------------
Plan hash value: 100882575

---------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 365 | 2920 | 2 (50)| 00:00:01 |
| 1 | HASH GROUP BY | | 365 | 2920 | 2 (50)| 00:00:01 |
| 2 | INDEX FULL SCAN| PK_BUSINESS_DAY_CALENDAR | 365 | 2920 | 1 (0)| 00:00:01 |
---------------------------------------------------------------------------------------------

 

CASE 3:Group By Eliminationが発生するケース

  1  SELECT
2 business_date
3 , COUNT(1)
4 FROM
5 business_day_calendar
6 GROUP BY
7* business_date

BUSINESS_DATE COUNT(1)
--------------- ----------
20220101 000000 1
20220102 000000 1
20220103 000000 1

...略...

20221228 000000 1
20221229 000000 1
20221230 000000 1
20221231 000000 1

365行が選択されました.

経過: 00:00:00.01

実行計画
----------------------------------------------------------
Plan hash value: 1786497156

---------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 365 | 2920 | 1 (0)| 00:00:01 |
| 1 | INDEX FULL SCAN | PK_BUSINESS_DAY_CALENDAR | 365 | 2920 | 1 (0)| 00:00:01 |
---------------------------------------------------------------------------------------------

 

CASE 4:Group By Eliminationが発生するケースで, no_elim_groupby ヒントでGroup By Eliminationを抑止したケース

  1  SELECT
2 /*+
3 no_elim_groupby
4 */
5 business_date
6 , COUNT(1)
7 FROM
8 business_day_calendar
9 GROUP BY
10* business_date

BUSINESS_DATE COUNT(1)
--------------- ----------
20220101 000000 1
20220102 000000 1
20220103 000000 1
20220104 000000 1

...略...

20221228 000000 1
20221229 000000 1
20221230 000000 1
20221231 000000 1

365行が選択されました.

実行計画
----------------------------------------------------------
Plan hash value: 3672056694

-------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 365 | 2920 | 1 (0)| 00:00:01 |
| 1 | SORT GROUP BY NOSORT| | 365 | 2920 | 1 (0)| 00:00:01 |
| 2 | INDEX FULL SCAN | PK_BUSINESS_DAY_CALENDAR | 365 | 2920 | 1 (0)| 00:00:01 |
-------------------------------------------------------------------------------------------------

 

Oracle Database 19cです. CASE 2だけ確認します.

SCOTT@orcl> select banner from v$version;

BANNER
--------------------------------------------------------------------------------
Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production

 

CASE 2:このリリースでも問題は無さそうですね

  1  SELECT
2 TO_CHAR(business_date, 'YYYYMM')
3 , COUNT(1)
4 FROM
5 business_day_calendar
6 GROUP BY
7* TO_CHAR(business_date, 'YYYYMM')

TO_CHA COUNT(1)
------ ----------
202206 30
202203 31
202210 31
202212 31
202202 28
202211 30
202204 30
202208 31
202209 30
202201 31
202205 31
202207 31

12 rows selected.

Execution Plan
----------------------------------------------------------
Plan hash value: 100882575

---------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 365 | 2920 | 2 (50)| 00:00:01 |
| 1 | HASH GROUP BY | | 365 | 2920 | 2 (50)| 00:00:01 |
| 2 | INDEX FULL SCAN| PK_BUSINESS_DAY_CALENDAR | 365 | 2920 | 1 (0)| 00:00:01 |
---------------------------------------------------------------------------------------------

 

Oracle Database 18c です. 同様に, CASE 2のみ確認しています.

SCOTT> select banner from v$version;

BANNER
--------------------------------------------------------------------------------
Oracle Database 18c Enterprise Edition Release 18.0.0.0.0 - Production

CASE 2:このリリースでも問題は無さそう

  1  SELECT
2 TO_CHAR(business_date, 'YYYYMM')
3 , COUNT(1)
4 FROM
5 business_day_calendar
6 GROUP BY
7* TO_CHAR(business_date, 'YYYYMM')

TO_CHA COUNT(1)
------ ----------
202206 30
202203 31
202210 31
202212 31
202202 28
202211 30
202204 30
202208 31
202209 30
202201 31
202205 31
202207 31

12 rows selected.

Execution Plan
----------------------------------------------------------
Plan hash value: 100882575

---------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 365 | 2920 | 2 (50)| 00:00:01 |
| 1 | HASH GROUP BY | | 365 | 2920 | 2 (50)| 00:00:01 |
| 2 | INDEX FULL SCAN| PK_BUSINESS_DAY_CALENDAR | 365 | 2920 | 1 (0)| 00:00:01 |
---------------------------------------------------------------------------------------------

 

ちょっと思ったのですが, 現状, 10053トレース等をみるしかないタイプの書き換えでも, OTHER_XML列からOUTLINEを抜き出すと比較的簡単に発動有無がわかるものもあるかもしれないですね. 今回のように固有のヒントでON/OFFできるタイプだとOUTLINEには, elim_groupby のようなヒントが含まれているだろうし. (全てではないとは思いますが)

ふ〜〜〜っ. JPOUG Advent Calendar 2022 の自分のターンも終わって, 自分の分をなんとかするだけだーーーーー.

 

ということで,
帰ってきた! 実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺) Advent Calendar 2022は, 明日も私が担当です. よろしくお願いします.
そして, JPOUG Advent Calendar 2022 Day 20は, 凌直孝さんの担当です. よろしくお願いします!

 

では, また:)

参考)

Group by Elimination / Oracle Scratchpad
A Look at the Oracle Group-by Bug / Database Journal

 


Related article on Mac De Oracle
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 1 / TABLE FULL SCAN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 2 / INDEX UNIQUE SCAN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 3 / INDEX RANGE SCAN, Index Only Scan
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 4 / INDEX RANGE SCAN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 5 / INDEX RANGE SCAN, INLIST ITERATOR
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 6 / INDEX FAST SCAN, Index Only Scan
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 7 / INDEX FULL SCAN,Index Only Scan
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 8 / INDEX SKIP SCAN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 9 / TABLE ACCESS INMEMORY FULL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 10 / NESTED LOOP JOIN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 11 / MERGE JOIN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 12 / HASH JOIN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 13 / HASH JOIN OUTER
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 14 / HASH JOIN FULL OUTER
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 15 / PX, TABLE ACCESS FULL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 16 / CONCATENATION
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 17 / SORT UNIQUE, UNION-ALL = UNION
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 18 / UNION-ALL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 19 / INTERSECTION
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 20 / MINUS
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 21 / WINDOW NOSORT STOPKEY
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 22 / COUNT STOPKEY
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 23 / HASH JOIN - LEFT-DEEP JOIN vs RIGHT-DEEP JOIN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 24 / CONNECT BY NO FILTERING WITH START-WITH
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 25 / UNION ALL (RECURSIVE WITH) DEPTH FIRST, RECURSIVE WITH PUMP
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - おまけ#1 / STAR TRANSFORM, VECTOR TRANSFORM (DWH向け)
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - おまけ#2 / MERGE (UPSERT)
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - おまけ#3 / RDFView
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - おまけ#4 / INDEX FULL SCAN (MIN/MAX) - Index Only Scan
・実行計画は, SQL文のレントゲン写真だ! No.30 - LOAD TABLE CONVENTIONAL vs. LOAD AS SELECT
・実行計画は, SQL文のレントゲン写真だ! No.31 - TEMP TABLE TRANSFORMATION LOAD AS SELECT (CURSOR DURATION MEMORY)
・実行計画は, SQL文のレントゲン写真だ! No.32 - EXTERNAL TABLE ACCESS FULL / INMEMORY FULL
・実行計画は, SQL文のレントゲン写真だ! No.33 - BITMAP CONVERSION TO ROWIDS
・実行計画は, SQL文のレントゲン写真だ! No.34 - 似て非なるもの USE_CONCAT と OR_EXPAND ヒント と 手書きSQLのレントゲンの見分け方
・実行計画は, SQL文のレントゲン写真だ! No.35 - 似て非なるもの USE_CONCAT と OR_EXPANDヒントとパラレルクエリー
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 1 / No.36 / INTERSECT ALL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 2 / No.37 / MINUS ALL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 3 / No.38 / EXCEPT and EXCEPT ALL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 4 / No.39 / In-Memory Hybrid Scans
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 5 / No.40 / PIVOT and UNPIVOT
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 6 / No.41 / In-Memory Vectorized Join
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 7 / No.42 / INDEX RANGE SCAN (MULTI VALUE)
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 8 / No.43 / TABLE ACCESS BY INDEX ROWID BATCHED
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 9 / No.44 / COLLECTION ITERATOR PICKLER FETCH
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 10 / No.45 / MAT_VIEW REWRITE ACCESS FULL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 11 / No.46 / GROUPING SETS, ROLLUP, CUBE
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 12 / No.47 / TEMP TABLE TRANSFORMATION
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 13 / No.48 / MULTI-TABLE INSERT
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 14 / No.49 / the DUAL Table
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 15 / No.50 / REMOTE
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 16 / No.51 / Concurrent Execution of Union All and Union
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 17 / No.52 / Order by Elimination
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 18 / No.53 / Join Elimination

 

| | | コメント (0)

2022年12月18日 (日)

実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 18 / No.53 / Join Elimination

Previously on Mac De Oracle...
Day 17は, order by Elimination にフォーカスをあてました. チューニングの現場で気づいたのが最初だったと思いますが, SQL文を見ていて, これ無駄なソートだなぁなんて思いながら実行計画という名のレントゲンをみていたら, おお! NOSORTとかではなく, ORDER BY自体が消されてる! 賢い! と.

では, Day 18のお題, Join Eliminationです. (登場したのは10gR2 ぐらいのはずですが, 間違ってたらツッコミ歓迎)
この排除系書き換えも, 実行計画という名のレントゲンシリーズでは, まだ紹介していなかったので, 今回は, ヒントで無効化する例も含め, 軽めの内容でw, 診ていきたいと思います. (参照整合性制約アレルギーネタを思い出すw)


いつもと同じように 21c で確認します.

SCOTT@orclpdb1> select banner from v$version;

BANNER
----------------------------------------------------------------------
Oracle Database 21c Enterprise Edition Release 21.0.0.0.0 - Production

対象となる表には外部参照整合制約があることが前提です.
20190321-144842

customers表を結合していますが, 参照整合性制約でcustomers表に存在する顧客しか注文できないという制約があります. つまり, この参照整合性制約があるため, INNER JOINやEXISTSを利用して存在チェックする必要はないということを意味しています.
Join EliminationによりSQLが書き換えられ結合が排除されていることがわかります. 実行計画には, ORDER_PKをIndex Only Scanしているだけで, customers表やcustomersの索引を結合しているOperationは含まれていない!!!
結合しないので, 結合のコスト及び, customers表やcustomersの索引へのアクセスコストが削減されています. 実行統計からは, Pysical Readや, Buffer Getsの低下という形で現れてきます.

とはいえ, 参照整合性制約アレルギーのお持ちの方も多く, 一生目にすることのない方々も, 残念ながら多いのも事実です.
参照整合性制約アレルギーが発症してしまうと, 一生付き合っていくことになちゃいますからね(大抵の場合)


Day19の内容とDay18のネタを入れ替えたので, day19.sqlを実行しているところは気にしないでくださいw

OE@orclpdb1> @day19
1 SELECT
2 order_id
3 FROM
4 orders o
5 INNER JOIN customers c
6 ON
7 o.customer_id = c.customer_id
8 WHERE
9* order_id < 2400

ORDER_ID
----------
2354
2355
2356
2357
2358

...略...

2396
2397
2398
2399

実行計画
----------------------------------------------------------
Plan hash value: 1653993310

-----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 46 | 184 | 1 (0)| 00:00:01 |
|* 1 | INDEX RANGE SCAN| ORDER_PK | 46 | 184 | 1 (0)| 00:00:01 |
-----------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

1 - access("O"."ORDER_ID"<2400)

統計
----------------------------------------------------------
0 recursive calls
0 db block gets
5 consistent gets
0 physical reads
0 redo size
1482 bytes sent via SQL*Net to client
85 bytes received via SQL*Net from client
5 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
46 rows processed
/code>


NO_ELIMINATE_JOINヒントを利用し, Join Eliminationを抑止してみましょう.
NO_ELIMINATE_JOINは, 使うことがあるのか? と思う方もいるかもしれませんが, 例えば, 不具合で7445とか, その他結果不正などに当たった時, かつ, 局所的対応で回避できそうなケースでは, 該当SQLにヒントを埋め込み, Join Eliminationの抑止で回避したりします.
どこで起きるかわからんので, インスタンスレベルで止めるケースもなくなないですが, そういう場合は, 隠しパラメータで無効化するのが一般的です. (ほぼ使わないと思いますが, ELIMINATE_JOIN でJoin Eliminationを利用できます. インスタンスレベルで無効化している状態で, 特定のSQLだけはJoin Eliminationしたいという場合に使うぐらいですね. 滅多にないと思いますが)

  1  SELECT
2 /*+
3 NO_ELIMINATE_JOIN(c)
4 */
5 order_id
6 FROM
7 orders o
8 INNER JOIN customers c
9 ON
10 o.customer_id = c.customer_id
11 WHERE
12* order_id < 2400

ORDER_ID
----------
2354
2355
2356
2357
2358

...略...

2392
2393
2394
2395
2396
2397
2398
2399

実行計画
----------------------------------------------------------
Plan hash value: 875022219

-----------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 46 | 552 | 2 (0)| 00:00:01 |
| 1 | NESTED LOOPS | | 46 | 552 | 2 (0)| 00:00:01 |
|* 2 | TABLE ACCESS BY INDEX ROWID BATCHED| ORDERS | 46 | 368 | 2 (0)| 00:00:01 |
|* 3 | INDEX RANGE SCAN | ORDER_PK | 46 | | 1 (0)| 00:00:01 |
|* 4 | INDEX UNIQUE SCAN | CUSTOMERS_PK | 1 | 4 | 0 (0)| 00:00:01 |
-----------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

2 - filter("O"."CUSTOMER_ID">0)
3 - access("O"."ORDER_ID"<2400)
4 - access("O"."CUSTOMER_ID"="C"."CUSTOMER_ID")

統計
----------------------------------------------------------
0 recursive calls
0 db block gets
15 consistent gets
0 physical reads
0 redo size
1482 bytes sent via SQL*Net to client
85 bytes received via SQL*Net from client
5 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
46 rows processed
/code>

アドベントカレンダー終わったら, もう, 今年も残りわずか....

ということで, 出口が見えつつある, アドベントカレンダー全部俺, 明日も, 俺が書きますw
では, また.


参考)
Join Elimination(結合の排除)と 参照整合性制約 / FAQ
db tech showcase Tokyo 2013 - A35 特濃JPOUG:潮溜まりでジャブジャブ, SQLチューニングの「参照整合性制約アレルギー」を参照のこと



Related article on Mac De Oracle

・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 1 / TABLE FULL SCAN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 2 / INDEX UNIQUE SCAN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 3 / INDEX RANGE SCAN, Index Only Scan
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 4 / INDEX RANGE SCAN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 5 / INDEX RANGE SCAN, INLIST ITERATOR
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 6 / INDEX FAST SCAN, Index Only Scan
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 7 / INDEX FULL SCAN,Index Only Scan
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 8 / INDEX SKIP SCAN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 9 / TABLE ACCESS INMEMORY FULL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 10 / NESTED LOOP JOIN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 11 / MERGE JOIN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 12 / HASH JOIN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 13 / HASH JOIN OUTER
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 14 / HASH JOIN FULL OUTER
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 15 / PX, TABLE ACCESS FULL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 16 / CONCATENATION
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 17 / SORT UNIQUE, UNION-ALL = UNION
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 18 / UNION-ALL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 19 / INTERSECTION
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 20 / MINUS
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 21 / WINDOW NOSORT STOPKEY
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 22 / COUNT STOPKEY
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 23 / HASH JOIN - LEFT-DEEP JOIN vs RIGHT-DEEP JOIN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 24 / CONNECT BY NO FILTERING WITH START-WITH
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 25 / UNION ALL (RECURSIVE WITH) DEPTH FIRST, RECURSIVE WITH PUMP
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - おまけ#1 / STAR TRANSFORM, VECTOR TRANSFORM (DWH向け)
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - おまけ#2 / MERGE (UPSERT)
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - おまけ#3 / RDFView
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - おまけ#4 / INDEX FULL SCAN (MIN/MAX) - Index Only Scan
・実行計画は, SQL文のレントゲン写真だ! No.30 - LOAD TABLE CONVENTIONAL vs. LOAD AS SELECT
・実行計画は, SQL文のレントゲン写真だ! No.31 - TEMP TABLE TRANSFORMATION LOAD AS SELECT (CURSOR DURATION MEMORY)
・実行計画は, SQL文のレントゲン写真だ! No.32 - EXTERNAL TABLE ACCESS FULL / INMEMORY FULL
・実行計画は, SQL文のレントゲン写真だ! No.33 - BITMAP CONVERSION TO ROWIDS
・実行計画は, SQL文のレントゲン写真だ! No.34 - 似て非なるもの USE_CONCAT と OR_EXPAND ヒント と 手書きSQLのレントゲンの見分け方
・実行計画は, SQL文のレントゲン写真だ! No.35 - 似て非なるもの USE_CONCAT と OR_EXPANDヒントとパラレルクエリー
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 1 / No.36 / INTERSECT ALL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 2 / No.37 / MINUS ALL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 3 / No.38 / EXCEPT and EXCEPT ALL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 4 / No.39 / In-Memory Hybrid Scans
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 5 / No.40 / PIVOT and UNPIVOT
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 6 / No.41 / In-Memory Vectorized Join
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 7 / No.42 / INDEX RANGE SCAN (MULTI VALUE)
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 8 / No.43 / TABLE ACCESS BY INDEX ROWID BATCHED
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 9 / No.44 / COLLECTION ITERATOR PICKLER FETCH
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 10 / No.45 / MAT_VIEW REWRITE ACCESS FULL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 11 / No.46 / GROUPING SETS, ROLLUP, CUBE
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 12 / No.47 / TEMP TABLE TRANSFORMATION
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 13 / No.48 / MULTI-TABLE INSERT
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 14 / No.49 / the DUAL Table
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 15 / No.50 / REMOTE
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 16 / No.51 / Concurrent Execution of Union All and Union
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 17 / No.52 / Order by Elimination

| | | コメント (0)

2022年12月17日 (土)

実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 17 / No.52 / Order by Elimination

Previously on Mac De Oracle... Day 16は, Concurrent Execution of Union All and Union にフォーカスをあてました. 使う機会があったら試してみてくださいね. 私は, この機能が登場した頃, Spatialな機能でRDFを使った際, Exadataでバリバリ活用してたというか, されていたという記憶があります.

では, Day 17のお題, Order by Eliminationです. 文字通り, Order byが排除される, 書き換え機能の一種です. だからと言って, 無駄なOrder by句書いても大丈夫ってことではないですから, 注意しましょうw

 

10gR2ぐらいから実装されている最適化の一つですね. 多少無駄なOrder byを書いちゃっても無駄だと判断されれば, 行われません. (だからと言って, 気にしないでOrder By書いちゃってもいいという話ではありませんがw)

いつもと同じように 21c で確認します.

SCOTT@orclpdb1> select banner from v$version;

BANNER
----------------------------------------------------------------------
Oracle Database 21c Enterprise Edition Release 21.0.0.0.0 - Production

 

emp表の索引などはいかの通り(scottのemp表を知らない方向け. いるのか?)

SCOTT@orclpdb1> desc emp
名前 NULL? 型
----------------------------------------- -------- ----------------------------
EMPNO NOT NULL NUMBER(4)
ENAME VARCHAR2(10)
JOB VARCHAR2(9)
MGR NUMBER(4)
HIREDATE DATE
SAL NUMBER(7,2)
COMM NUMBER(7,2)
DEPTNO NUMBER(2)

SCOTT@orclpdb1> select index_name,column_name from user_ind_columns where
2 table_name = 'EMP' order by index_name,column_position;

INDEX_NAME COLUMN_NAME
------------------------------ ------------------------------
IX01_EMP DEPTNO
PK_EMP EMPNO

 

SQL中に ORDER BY句がありますが, NOSORT操作もないのにソートされていません. そもそも書き換えられて, ORDER BY句が削除されているんですよーーーー.
このケースでは, empno順にソートされた結果返ってきているかのう様に見えますが, それは索引をempno順に読無ことで, ソートを排除できるからなんですよね. 索引がなければ, ソートは必要なのです. ちなみに, INDEX FULL SCAN はソートされたキー順に索引を全てスキャンするところがポイント, INDEX FAST FULL SCANはとは違うのはみなさんご存知のはずなのでコマけーことは省略.

SCOTT@orclpdb1> @day17
1 SELECT
2 *
3 FROM
4 emp
5 ORDER BY
6* empno

EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
---------- ------------------------------ --------------------------- ---------- -------- ---------- ---------- ----------
7369 SMITH CLERK 7902 80-12-17 800 20
7499 ALLEN SALESMAN 7698 81-02-20 1600 300 30
7521 WARD SALESMAN 7698 81-02-22 1250 500 30
7566 JONES MANAGER 7839 81-04-02 2975 20
7654 MARTIN SALESMAN 7698 81-09-28 1250 1400 30
7698 BLAKE MANAGER 7839 81-05-01 2850 30
7782 CLARK MANAGER 7839 81-06-09 2450 10
7839 KING PRESIDENT 81-11-17 5000 10
7844 TURNER SALESMAN 7698 81-09-08 1500 0 30
7900 JAMES CLERK 7698 81-12-03 950 30
7902 FORD ANALYST 7566 81-12-03 3000 20
7934 MILLER CLERK 7782 82-01-23 1300 10

実行計画
----------------------------------------------------------
Plan hash value: 4170700152

--------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 12 | 468 | 2 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID| EMP | 12 | 468 | 2 (0)| 00:00:01 |
| 2 | INDEX FULL SCAN | PK_EMP | 12 | | 1 (0)| 00:00:01 |
--------------------------------------------------------------------------------------

統計
----------------------------------------------------------
0 recursive calls
0 db block gets
4 consistent gets
0 physical reads
0 redo size
1669 bytes sent via SQL*Net to client
52 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
12 rows processed

 

こちらも, 無用なORDER BY句が削除されています. 賢い. オプティマイザー!
以下のORDER BYは, みるからに無駄なソートですが, オプティマイザーは気づいて排除しています.

  1  SELECT
2 COUNT(ename)
3 FROM
4 (
5 SELECT
6 *
7 FROM
8 emp
9 ORDER BY
10 ename
11* )

COUNT(ENAME)
------------
12

実行計画
----------------------------------------------------------
Plan hash value: 2083865914

---------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 6 | 3 (0)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | 6 | | |
| 2 | TABLE ACCESS FULL| EMP | 12 | 72 | 3 (0)| 00:00:01 |
---------------------------------------------------------------------------

統計
----------------------------------------------------------
0 recursive calls
0 db block gets
6 consistent gets
0 physical reads
0 redo size
595 bytes sent via SQL*Net to client
52 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed

 

EXPLAIN等改善してほしいなと思うのはこれらのElimination関連情報, 今回のように無駄なORDER BYを排除したという情報を, Elimination Informationとしてリストしたら良いのではないかと思っています. 最近, SQLヒントに関する情報をリストするようになったのでできるのではないだろうかと. ただ, 諸々内部でSQL文を書き換えたりするから, 実は面倒なのかもねw  10053トレースなら見える訳ですが, 毎回取得するわけにもいかないしね.

ついに,  Day 17 done. あと少しだ頑張れ, 俺w

 

ということで, 残念ですが, 明日も私です.
ではまた.

 


Related article on Mac De Oracle
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 1 / TABLE FULL SCAN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 2 / INDEX UNIQUE SCAN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 3 / INDEX RANGE SCAN, Index Only Scan
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 4 / INDEX RANGE SCAN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 5 / INDEX RANGE SCAN, INLIST ITERATOR
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 6 / INDEX FAST SCAN, Index Only Scan
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 7 / INDEX FULL SCAN,Index Only Scan
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 8 / INDEX SKIP SCAN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 9 / TABLE ACCESS INMEMORY FULL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 10 / NESTED LOOP JOIN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 11 / MERGE JOIN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 12 / HASH JOIN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 13 / HASH JOIN OUTER
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 14 / HASH JOIN FULL OUTER
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 15 / PX, TABLE ACCESS FULL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 16 / CONCATENATION
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 17 / SORT UNIQUE, UNION-ALL = UNION
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 18 / UNION-ALL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 19 / INTERSECTION
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 20 / MINUS
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 21 / WINDOW NOSORT STOPKEY
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 22 / COUNT STOPKEY
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 23 / HASH JOIN - LEFT-DEEP JOIN vs RIGHT-DEEP JOIN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 24 / CONNECT BY NO FILTERING WITH START-WITH
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 25 / UNION ALL (RECURSIVE WITH) DEPTH FIRST, RECURSIVE WITH PUMP
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - おまけ#1 / STAR TRANSFORM, VECTOR TRANSFORM (DWH向け)
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - おまけ#2 / MERGE (UPSERT)
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - おまけ#3 / RDFView
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - おまけ#4 / INDEX FULL SCAN (MIN/MAX) - Index Only Scan
・実行計画は, SQL文のレントゲン写真だ! No.30 - LOAD TABLE CONVENTIONAL vs. LOAD AS SELECT
・実行計画は, SQL文のレントゲン写真だ! No.31 - TEMP TABLE TRANSFORMATION LOAD AS SELECT (CURSOR DURATION MEMORY)
・実行計画は, SQL文のレントゲン写真だ! No.32 - EXTERNAL TABLE ACCESS FULL / INMEMORY FULL
・実行計画は, SQL文のレントゲン写真だ! No.33 - BITMAP CONVERSION TO ROWIDS
・実行計画は, SQL文のレントゲン写真だ! No.34 - 似て非なるもの USE_CONCAT と OR_EXPAND ヒント と 手書きSQLのレントゲンの見分け方
・実行計画は, SQL文のレントゲン写真だ! No.35 - 似て非なるもの USE_CONCAT と OR_EXPANDヒントとパラレルクエリー
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 1 / No.36 / INTERSECT ALL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 2 / No.37 / MINUS ALL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 3 / No.38 / EXCEPT and EXCEPT ALL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 4 / No.39 / In-Memory Hybrid Scans
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 5 / No.40 / PIVOT and UNPIVOT
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 6 / No.41 / In-Memory Vectorized Join
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 7 / No.42 / INDEX RANGE SCAN (MULTI VALUE)
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 8 / No.43 / TABLE ACCESS BY INDEX ROWID BATCHED
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 9 / No.44 / COLLECTION ITERATOR PICKLER FETCH
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 10 / No.45 / MAT_VIEW REWRITE ACCESS FULL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 11 / No.46 / GROUPING SETS, ROLLUP, CUBE
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 12 / No.47 / TEMP TABLE TRANSFORMATION
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 13 / No.48 / MULTI-TABLE INSERT
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 14 / No.49 / the DUAL Table
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 15 / No.50 / REMOTE
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 16 / No.51 / Concurrent Execution of Union All and Union

 

| | | コメント (0)

2022年12月16日 (金)

実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 16 / No.51 / Concurrent Execution of Union All and Union

Previously on Mac De Oracle... Day 15は, 分散, リモートクエリーにフォーカスをあてました. 好き嫌い多いネタだったかもしれませんねぇw

では, Day 16のお題, Concurrent Execution of Union All and Union

これは何かというと, 12c R1以降だったか?(定かでないw)に, UNION/UNION ALLの各分岐がパラレルで実行されるという機能です. それまではシリアルに処理されていたので, 分岐が多いほど処理時間も増加していた訳ですが, 分岐がそれぞれパラレルで実行される分処理時間は短くなるというやつですね.

Concurrent Execution of Union All and Unionが実行されている時の特徴は, PX SELECTOR があるかどうかで見分けます.

いつもと同じように 21c で確認します.


SCOTT@orclpdb1> select banner from v$version;

BANNER
----------------------------------------------------------------------
Oracle Database 21c Enterprise Edition Release 21.0.0.0.0 - Production

 

準備として, 12c R1以前ではシリアルに処理される代表格, リモート表を用意します. (昨日のネタはこの準備のためでもあったり)



SCOTT@orclpdb2> @day16
1* CREATE DATABASE LINK remote_scott CONNECT TO scott IDENTIFIED BY tiger USING 'orclpdb1'

データベース・リンクが作成されました.

1 CREATE TABLE local_emp
2 AS
3 SELECT *
4 FROM
5 emp@remote_scott
6 ORDER BY
7 empno
8* FETCH FIRST 5 ROWS ONLY

表が作成されました.

1* INSERT INTO local_emp(empno, ename) VALUES(1, 'NULL')

1行が作成されました.

 

クエリーの結果、たまたま、empno順に並んでいるように見える結果もありますが、ソートしたい場合は、必ず!!! ORDER BY句が必要ですからねw(誰となくw)

シリアルで実行してみます. よく見る実行計画という名のレントゲンです. リモート表は Operationが REMOTE として現れています. 2つある分岐は, シリアルに実行されます.

  1  SELECT
2 *
3 FROM
4 local_emp
5 UNION ALL
6 SELECT
7 *
8 FROM
9* emp@remote_scott

EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
---------- ------------------------------ --------------------------- ---------- -------- ---------- ---------- ----------
7369 SMITH CLERK 7902 80-12-17 800 20
7499 ALLEN SALESMAN 7698 81-02-20 1600 300 30
7521 WARD SALESMAN 7698 81-02-22 1250 500 30
7566 JONES MANAGER 7839 81-04-02 2975 20
7654 MARTIN SALESMAN 7698 81-09-28 1250 1400 30
1 NULL
7369 SMITH CLERK 7902 80-12-17 800 20
7499 ALLEN SALESMAN 7698 81-02-20 1600 300 30
7521 WARD SALESMAN 7698 81-02-22 1250 500 30
7566 JONES MANAGER 7839 81-04-02 2975 20
7654 MARTIN SALESMAN 7698 81-09-28 1250 1400 30
7698 BLAKE MANAGER 7839 81-05-01 2850 30
7782 CLARK MANAGER 7839 81-06-09 2450 10
7839 KING PRESIDENT 81-11-17 5000 10
7844 TURNER SALESMAN 7698 81-09-08 1500 0 30
7900 JAMES CLERK 7698 81-12-03 950 30
7902 FORD ANALYST 7566 81-12-03 3000 20
7934 MILLER CLERK 7782 82-01-23 1300 10

実行計画
----------------------------------------------------------
Plan hash value: 1607333107

------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Inst |IN-OUT|
------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 18 | 990 | 5 (0)| 00:00:01 | | |
| 1 | UNION-ALL | | | | | | | |
| 2 | TABLE ACCESS FULL| LOCAL_EMP | 6 | 522 | 2 (0)| 00:00:01 | | |
| 3 | REMOTE | EMP | 12 | 468 | 3 (0)| 00:00:01 | REMOT~ | R->S |
------------------------------------------------------------------------------------------------

Remote SQL Information (identified by operation id):
----------------------------------------------------

3 - SELECT "EMPNO","ENAME","JOB","MGR","HIREDATE","SAL","COMM","DEPTNO" FROM "EMP"
"EMP" (accessing 'REMOTE_SCOTT' )

Note
-----
- dynamic statistics used: dynamic sampling (level=2)

 

次に, パラレルクエリーにして, かつ, Concurrent Execution を抑止する NO_PQ_CONCURRENT_UNION  を付加して実行してみました.
PX SELECTOR は現れていません. パラレルクエリーではありますが, 分岐は, 順に処理されていきます.

  1  SELECT
2 /*+
3 PARALLEL(3)
4 NO_PQ_CONCURRENT_UNION
5 */
6 *
7 FROM
8 local_emp
9 UNION ALL
10 SELECT
11 *
12 FROM
13* emp@remote_scott

EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
---------- ------------------------------ --------------------------- ---------- -------- ---------- ---------- ----------
7369 SMITH CLERK 7902 80-12-17 800 20
7499 ALLEN SALESMAN 7698 81-02-20 1600 300 30
7521 WARD SALESMAN 7698 81-02-22 1250 500 30
7566 JONES MANAGER 7839 81-04-02 2975 20
7654 MARTIN SALESMAN 7698 81-09-28 1250 1400 30
1 NULL
7369 SMITH CLERK 7902 80-12-17 800 20
7499 ALLEN SALESMAN 7698 81-02-20 1600 300 30
7521 WARD SALESMAN 7698 81-02-22 1250 500 30
7566 JONES MANAGER 7839 81-04-02 2975 20
7654 MARTIN SALESMAN 7698 81-09-28 1250 1400 30
7698 BLAKE MANAGER 7839 81-05-01 2850 30
7782 CLARK MANAGER 7839 81-06-09 2450 10
7839 KING PRESIDENT 81-11-17 5000 10
7844 TURNER SALESMAN 7698 81-09-08 1500 0 30
7900 JAMES CLERK 7698 81-12-03 950 30
7902 FORD ANALYST 7566 81-12-03 3000 20
7934 MILLER CLERK 7782 82-01-23 1300 10

実行計画
----------------------------------------------------------
Plan hash value: 3305250800

----------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | TQ/Ins |IN-OUT| PQ Distrib |
----------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 18 | 990 | 5 (0)| 00:00:01 | | | |
| 1 | UNION-ALL | | | | | | | | |
| 2 | PX COORDINATOR | | | | | | | | |
| 3 | PX SEND QC (RANDOM)| :TQ10000 | 6 | 522 | 2 (0)| 00:00:01 | Q1,00 | P->S | QC (RAND) |
| 4 | PX BLOCK ITERATOR | | 6 | 522 | 2 (0)| 00:00:01 | Q1,00 | PCWC | |
| 5 | TABLE ACCESS FULL| LOCAL_EMP | 6 | 522 | 2 (0)| 00:00:01 | Q1,00 | PCWP | |
| 6 | REMOTE | EMP | 12 | 468 | 3 (0)| 00:00:01 | REMOT~ | R->S | |
----------------------------------------------------------------------------------------------------------------

Remote SQL Information (identified by operation id):
----------------------------------------------------

6 - SELECT /*+ SHARED (3) */ "EMPNO","ENAME","JOB","MGR","HIREDATE","SAL","COMM","DEPTNO" FROM "EMP"
"EMP" (accessing 'REMOTE_SCOTT' )

Note
-----
- dynamic statistics used: dynamic sampling (level=2)
- Degree of Parallelism is 3 because of hint

 

本日の主役 PX SELECTORREMOTE 操作の上に出てきました. この状態であれば, 各分岐はパラレルに処理されることになり, 分岐が順に処理されるより処理時間は短縮されることになります(REMOTE処理が重かったら, その処理時間に引きづら訳ですが, 順に処理するよりは早く終わると予想できますよね)

  1  SELECT
2 /*+
3 PARALLEL(3)
4 */
5 *
6 FROM
7 local_emp
8 UNION ALL
9 SELECT
10 *
11 FROM
12* emp@remote_scott

EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
---------- ------------------------------ --------------------------- ---------- -------- ---------- ---------- ----------
1 NULL
7369 SMITH CLERK 7902 80-12-17 800 20
7499 ALLEN SALESMAN 7698 81-02-20 1600 300 30
7521 WARD SALESMAN 7698 81-02-22 1250 500 30
7566 JONES MANAGER 7839 81-04-02 2975 20
7654 MARTIN SALESMAN 7698 81-09-28 1250 1400 30
7369 SMITH CLERK 7902 80-12-17 800 20
7499 ALLEN SALESMAN 7698 81-02-20 1600 300 30
7521 WARD SALESMAN 7698 81-02-22 1250 500 30
7566 JONES MANAGER 7839 81-04-02 2975 20
7654 MARTIN SALESMAN 7698 81-09-28 1250 1400 30
7698 BLAKE MANAGER 7839 81-05-01 2850 30
7782 CLARK MANAGER 7839 81-06-09 2450 10
7839 KING PRESIDENT 81-11-17 5000 10
7844 TURNER SALESMAN 7698 81-09-08 1500 0 30
7900 JAMES CLERK 7698 81-12-03 950 30
7902 FORD ANALYST 7566 81-12-03 3000 20
7934 MILLER CLERK 7782 82-01-23 1300 10

実行計画
----------------------------------------------------------
Plan hash value: 2359762278

----------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | TQ |IN-OUT| PQ Distrib |
----------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 18 | 990 | 5 (0)| 00:00:01 | | | |
| 1 | PX COORDINATOR | | | | | | | | |
| 2 | PX SEND QC (RANDOM) | :TQ10000 | | | | | Q1,00 | P->S | QC (RAND) |
| 3 | UNION-ALL | | | | | | Q1,00 | PCWP | |
| 4 | PX BLOCK ITERATOR | | 6 | 522 | 2 (0)| 00:00:01 | Q1,00 | PCWC | |
| 5 | TABLE ACCESS FULL| LOCAL_EMP | 6 | 522 | 2 (0)| 00:00:01 | Q1,00 | PCWP | |
| 6 | PX SELECTOR | | | | | | Q1,00 | PCWP | |
| 7 | REMOTE | EMP | 12 | 468 | 3 (0)| 00:00:01 | Q1,00 | PCWP | |
----------------------------------------------------------------------------------------------------------------

Remote SQL Information (identified by operation id):
----------------------------------------------------

7 - SELECT /*+ SHARED (3) */ "EMPNO","ENAME","JOB","MGR","HIREDATE","SAL","COMM","DEPTNO" FROM "EMP"
"EMP" (accessing ':Q1000' )

Note
-----
- dynamic statistics used: dynamic sampling (level=2)
- Degree of Parallelism is 3 because of hint

 

以下, UNIONでも同様に, 実行計画というレントゲンを確認しておきましょう. まずはシリアル.


  1  SELECT
2 *
3 FROM
4 local_emp
5 UNION
6 SELECT
7 *
8 FROM
9* emp@remote_scott

EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
---------- ------------------------------ --------------------------- ---------- -------- ---------- ---------- ----------
7369 SMITH CLERK 7902 80-12-17 800 20
7499 ALLEN SALESMAN 7698 81-02-20 1600 300 30
7521 WARD SALESMAN 7698 81-02-22 1250 500 30
7566 JONES MANAGER 7839 81-04-02 2975 20
7654 MARTIN SALESMAN 7698 81-09-28 1250 1400 30
1 NULL
7698 BLAKE MANAGER 7839 81-05-01 2850 30
7782 CLARK MANAGER 7839 81-06-09 2450 10
7839 KING PRESIDENT 81-11-17 5000 10
7844 TURNER SALESMAN 7698 81-09-08 1500 0 30
7900 JAMES CLERK 7698 81-12-03 950 30
7902 FORD ANALYST 7566 81-12-03 3000 20
7934 MILLER CLERK 7782 82-01-23 1300 10

実行計画
----------------------------------------------------------
Plan hash value: 2189749816

-------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Inst |IN-OUT|
-------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 18 | 990 | 7 (29)| 00:00:01 | | |
| 1 | HASH UNIQUE | | 18 | 990 | 7 (29)| 00:00:01 | | |
| 2 | UNION-ALL | | | | | | | |
| 3 | TABLE ACCESS FULL| LOCAL_EMP | 6 | 522 | 2 (0)| 00:00:01 | | |
| 4 | REMOTE | EMP | 12 | 468 | 3 (0)| 00:00:01 | REMOT~ | R->S |
-------------------------------------------------------------------------------------------------

Remote SQL Information (identified by operation id):
----------------------------------------------------

4 - SELECT "EMPNO","ENAME","JOB","MGR","HIREDATE","SAL","COMM","DEPTNO" FROM "EMP"
"EMP" (accessing 'REMOTE_SCOTT' )

Note
-----
- dynamic statistics used: dynamic sampling (level=2)

 

NO_PQ_CONCURRENT_UNIONでConcurrent Execution を抑止してみると, 順に処理されていることがわかります.

  1  SELECT
2 /*+
3 PARALLEL(3)
4 NO_PQ_CONCURRENT_UNION 5 */
6 *
7 FROM
8 local_emp
9 UNION
10 SELECT
11 *
12 FROM
13* emp@remote_scott

EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
---------- ------------------------------ --------------------------- ---------- -------- ---------- ---------- ----------
7902 FORD ANALYST 7566 81-12-03 3000 20
7566 JONES MANAGER 7839 81-04-02 2975 20
7654 MARTIN SALESMAN 7698 81-09-28 1250 1400 30
7369 SMITH CLERK 7902 80-12-17 800 20
1 NULL
7900 JAMES CLERK 7698 81-12-03 950 30
7934 MILLER CLERK 7782 82-01-23 1300 10
7839 KING PRESIDENT 81-11-17 5000 10
7782 CLARK MANAGER 7839 81-06-09 2450 10
7499 ALLEN SALESMAN 7698 81-02-20 1600 300 30
7844 TURNER SALESMAN 7698 81-09-08 1500 0 30
7521 WARD SALESMAN 7698 81-02-22 1250 500 30
7698 BLAKE MANAGER 7839 81-05-01 2850 30

実行計画
----------------------------------------------------------
Plan hash value: 622056383

-----------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | TQ/Ins |IN-OUT| PQ Distrib |
-----------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 18 | 990 | 7 (29)| 00:00:01 | | | |
| 1 | PX COORDINATOR | | | | | | | | |
| 2 | PX SEND QC (RANDOM) | :TQ10002 | 18 | 990 | 7 (29)| 00:00:01 | Q1,02 | P->S | QC (RAND) |
| 3 | HASH UNIQUE | | 18 | 990 | 7 (29)| 00:00:01 | Q1,02 | PCWP | |
| 4 | PX RECEIVE | | 18 | 990 | 7 (29)| 00:00:01 | Q1,02 | PCWP | |
| 5 | PX SEND HASH | :TQ10001 | 18 | 990 | 7 (29)| 00:00:01 | Q1,01 | P->P | HASH |
| 6 | HASH UNIQUE | | 18 | 990 | 7 (29)| 00:00:01 | Q1,01 | PCWP | |
| 7 | UNION-ALL | | | | | | Q1,01 | PCWP | |
| 8 | PX BLOCK ITERATOR | | 6 | 522 | 2 (0)| 00:00:01 | Q1,01 | PCWC | |
| 9 | TABLE ACCESS FULL | LOCAL_EMP | 6 | 522 | 2 (0)| 00:00:01 | Q1,01 | PCWP | |
| 10 | BUFFER SORT | | | | | | Q1,01 | PCWC | |
| 11 | PX RECEIVE | | 12 | 468 | 3 (0)| 00:00:01 | Q1,01 | PCWP | |
| 12 | PX SEND ROUND-ROBIN| :TQ10000 | 12 | 468 | 3 (0)| 00:00:01 | | S->P | RND-ROBIN |
| 13 | REMOTE | EMP | 12 | 468 | 3 (0)| 00:00:01 | REMOT~ | R->S | |
-----------------------------------------------------------------------------------------------------------------------

Remote SQL Information (identified by operation id):
----------------------------------------------------

13 - SELECT /*+ SHARED (3) */ "EMPNO","ENAME","JOB","MGR","HIREDATE","SAL","COMM","DEPTNO" FROM "EMP" "EMP"
(accessing 'REMOTE_SCOTT' )

Note
-----
- dynamic statistics used: dynamic sampling (level=2)
- Degree of Parallelism is 3 because of hint

 

UNIONでもPX SELECTORが現れ, 分岐がパラレルに処理されていることが見えます. :)

  1  SELECT
2 /*+
3 PARALLEL(3)
4 */
5 *
6 FROM
7 local_emp
8 UNION
9 SELECT
10 *
11 FROM
12* emp@remote_scott

EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
---------- ------------------------------ --------------------------- ---------- -------- ---------- ---------- ----------
7499 ALLEN SALESMAN 7698 81-02-20 1600 300 30
7844 TURNER SALESMAN 7698 81-09-08 1500 0 30
7521 WARD SALESMAN 7698 81-02-22 1250 500 30
7698 BLAKE MANAGER 7839 81-05-01 2850 30
7902 FORD ANALYST 7566 81-12-03 3000 20
7566 JONES MANAGER 7839 81-04-02 2975 20
7654 MARTIN SALESMAN 7698 81-09-28 1250 1400 30
7369 SMITH CLERK 7902 80-12-17 800 20
1 NULL
7900 JAMES CLERK 7698 81-12-03 950 30
7934 MILLER CLERK 7782 82-01-23 1300 10
7839 KING PRESIDENT 81-11-17 5000 10
7782 CLARK MANAGER 7839 81-06-09 2450 10

実行計画
----------------------------------------------------------
Plan hash value: 3647789528

--------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | TQ |IN-OUT| PQ Distrib |
--------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 18 | 990 | 7 (29)| 00:00:01 | | | |
| 1 | PX COORDINATOR | | | | | | | | |
| 2 | PX SEND QC (RANDOM) | :TQ10001 | 18 | 990 | 7 (29)| 00:00:01 | Q1,01 | P->S | QC (RAND) |
| 3 | HASH UNIQUE | | 18 | 990 | 7 (29)| 00:00:01 | Q1,01 | PCWP | |
| 4 | PX RECEIVE | | 18 | 990 | 7 (29)| 00:00:01 | Q1,01 | PCWP | |
| 5 | PX SEND HASH | :TQ10000 | 18 | 990 | 7 (29)| 00:00:01 | Q1,00 | P->P | HASH |
| 6 | HASH UNIQUE | | 18 | 990 | 7 (29)| 00:00:01 | Q1,00 | PCWP | |
| 7 | UNION-ALL | | | | | | Q1,00 | PCWP | |
| 8 | PX BLOCK ITERATOR | | 6 | 522 | 2 (0)| 00:00:01 | Q1,00 | PCWC | |
| 9 | TABLE ACCESS FULL| LOCAL_EMP | 6 | 522 | 2 (0)| 00:00:01 | Q1,00 | PCWP | |
| 10 | PX SELECTOR | | | | | | Q1,00 | PCWP | |
| 11 | REMOTE | EMP | 12 | 468 | 3 (0)| 00:00:01 | Q1,00 | PCWP | |
--------------------------------------------------------------------------------------------------------------------

Remote SQL Information (identified by operation id):
----------------------------------------------------

11 - SELECT /*+ SHARED (3) */ "EMPNO","ENAME","JOB","MGR","HIREDATE","SAL","COMM","DEPTNO" FROM "EMP"
"EMP" (accessing ':Q1000' )

Note
-----
- dynamic statistics used: dynamic sampling (level=2)
- Degree of Parallelism is 3 because of hint

 

ちなみに, Concurrent Execution of Union All and Union と書いている通り, MINUS/EXCEPT/INTERSECTでは今まで通りです.  EXCEPTとINTERSECTの実行計画で見てみます. PX SELECTOR は現れていません. (MINUSとEXCEPTはどちらもMINUSとして扱われているので片方だけで十分です)

  1  SELECT
2 /*+
3 PARALLEL(3)
4 */
5 *
6 FROM
7 local_emp
8 EXCEPT
9 SELECT
10 *
11 FROM
12* emp@remote_scott

EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
---------- ------------------------------ --------------------------- ---------- -------- ---------- ---------- ----------
1 NULL

実行計画
----------------------------------------------------------
Plan hash value: 331225933

-------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | TQ/Ins |IN-OUT| PQ Distrib |
-------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 6 | 990 | 7 (29)| 00:00:01 | | | |
| 1 | PX COORDINATOR | | | | | | | | |
| 2 | PX SEND QC (RANDOM) | :TQ10002 | | | | | Q1,02 | P->S | QC (RAND) |
| 3 | MINUS HASH | | | | | | Q1,02 | PCWP | |
| 4 | PX RECEIVE | | | | | | Q1,02 | PCWP | |
| 5 | PX SEND HASH | :TQ10001 | | | | | Q1,01 | P->P | HASH |
| 6 | HASH UNIQUE | | 6 | 522 | 3 (34)| 00:00:01 | Q1,01 | PCWP | |
| 7 | PX BLOCK ITERATOR | | 6 | 522 | 2 (0)| 00:00:01 | Q1,01 | PCWC | |
| 8 | TABLE ACCESS FULL| LOCAL_EMP | 6 | 522 | 2 (0)| 00:00:01 | Q1,01 | PCWP | |
| 9 | BUFFER SORT | | | | | | Q1,02 | PCWC | |
| 10 | PX RECEIVE | | 12 | 468 | 3 (0)| 00:00:01 | Q1,02 | PCWP | |
| 11 | PX SEND HASH | :TQ10000 | 12 | 468 | 3 (0)| 00:00:01 | | S->P | HASH |
| 12 | REMOTE | EMP | 12 | 468 | 3 (0)| 00:00:01 | REMOT~ | R->S | |
-------------------------------------------------------------------------------------------------------------------

Remote SQL Information (identified by operation id):
----------------------------------------------------

12 - SELECT /*+ SHARED (3) */ "EMPNO","ENAME","JOB","MGR","HIREDATE","SAL","COMM","DEPTNO" FROM "EMP"
"EMP" (accessing 'REMOTE_SCOTT' )

Note
-----
- dynamic statistics used: dynamic sampling (level=2)
- Degree of Parallelism is 3 because of hint

  1  SELECT
2 /*+
3 PARALLEL(3)
4 */
5 *
6 FROM
7 local_emp
8 INTERSECT
9 SELECT
10 *
11 FROM
12* emp@remote_scott

EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
---------- ------------------------------ --------------------------- ---------- -------- ---------- ---------- ----------
7369 SMITH CLERK 7902 80-12-17 800 20
7566 JONES MANAGER 7839 81-04-02 2975 20
7654 MARTIN SALESMAN 7698 81-09-28 1250 1400 30
7499 ALLEN SALESMAN 7698 81-02-20 1600 300 30
7521 WARD SALESMAN 7698 81-02-22 1250 500 30

実行計画
----------------------------------------------------------
Plan hash value: 1417135745

-------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | TQ/Ins |IN-OUT| PQ Distrib |
-------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 6 | 990 | 7 (29)| 00:00:01 | | | |
| 1 | PX COORDINATOR | | | | | | | | |
| 2 | PX SEND QC (RANDOM) | :TQ10002 | | | | | Q1,02 | P->S | QC (RAND) |
| 3 | INTERSECTION HASH | | | | | | Q1,02 | PCWP | |
| 4 | PX RECEIVE | | | | | | Q1,02 | PCWP | |
| 5 | PX SEND HASH | :TQ10001 | | | | | Q1,01 | P->P | HASH |
| 6 | HASH UNIQUE | | 6 | 522 | 3 (34)| 00:00:01 | Q1,01 | PCWP | |
| 7 | PX BLOCK ITERATOR | | 6 | 522 | 2 (0)| 00:00:01 | Q1,01 | PCWC | |
| 8 | TABLE ACCESS FULL| LOCAL_EMP | 6 | 522 | 2 (0)| 00:00:01 | Q1,01 | PCWP | |
| 9 | BUFFER SORT | | | | | | Q1,02 | PCWC | |
| 10 | PX RECEIVE | | 12 | 468 | 3 (0)| 00:00:01 | Q1,02 | PCWP | |
| 11 | PX SEND HASH | :TQ10000 | 12 | 468 | 3 (0)| 00:00:01 | | S->P | HASH |
| 12 | REMOTE | EMP | 12 | 468 | 3 (0)| 00:00:01 | REMOT~ | R->S | |
-------------------------------------------------------------------------------------------------------------------

Remote SQL Information (identified by operation id):
----------------------------------------------------

12 - SELECT /*+ SHARED (3) */ "EMPNO","ENAME","JOB","MGR","HIREDATE","SAL","COMM","DEPTNO" FROM "EMP"
"EMP" (accessing 'REMOTE_SCOTT' )

Note
-----
- dynamic statistics used: dynamic sampling (level=2)
- Degree of Parallelism is 3 because of hint

 

ということで, Day 16 done

残り9日だ. ふ〜〜〜〜っ. 明日も絶対, 担当は私です.

ではまた.

 

参考) Oracle Database 21c - VLDB and Partitioning Guide / 8.5.3.14 Concurrent Execution of Union All


Related article on Mac De Oracle
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 1 / TABLE FULL SCAN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 2 / INDEX UNIQUE SCAN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 3 / INDEX RANGE SCAN, Index Only Scan
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 4 / INDEX RANGE SCAN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 5 / INDEX RANGE SCAN, INLIST ITERATOR
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 6 / INDEX FAST SCAN, Index Only Scan
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 7 / INDEX FULL SCAN,Index Only Scan
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 8 / INDEX SKIP SCAN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 9 / TABLE ACCESS INMEMORY FULL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 10 / NESTED LOOP JOIN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 11 / MERGE JOIN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 12 / HASH JOIN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 13 / HASH JOIN OUTER
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 14 / HASH JOIN FULL OUTER
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 15 / PX, TABLE ACCESS FULL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 16 / CONCATENATION
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 17 / SORT UNIQUE, UNION-ALL = UNION
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 18 / UNION-ALL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 19 / INTERSECTION
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 20 / MINUS
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 21 / WINDOW NOSORT STOPKEY
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 22 / COUNT STOPKEY
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 23 / HASH JOIN - LEFT-DEEP JOIN vs RIGHT-DEEP JOIN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 24 / CONNECT BY NO FILTERING WITH START-WITH
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 25 / UNION ALL (RECURSIVE WITH) DEPTH FIRST, RECURSIVE WITH PUMP
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - おまけ#1 / STAR TRANSFORM, VECTOR TRANSFORM (DWH向け)
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - おまけ#2 / MERGE (UPSERT)
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - おまけ#3 / RDFView
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - おまけ#4 / INDEX FULL SCAN (MIN/MAX) - Index Only Scan
・実行計画は, SQL文のレントゲン写真だ! No.30 - LOAD TABLE CONVENTIONAL vs. LOAD AS SELECT
・実行計画は, SQL文のレントゲン写真だ! No.31 - TEMP TABLE TRANSFORMATION LOAD AS SELECT (CURSOR DURATION MEMORY)
・実行計画は, SQL文のレントゲン写真だ! No.32 - EXTERNAL TABLE ACCESS FULL / INMEMORY FULL
・実行計画は, SQL文のレントゲン写真だ! No.33 - BITMAP CONVERSION TO ROWIDS
・実行計画は, SQL文のレントゲン写真だ! No.34 - 似て非なるもの USE_CONCAT と OR_EXPAND ヒント と 手書きSQLのレントゲンの見分け方
・実行計画は, SQL文のレントゲン写真だ! No.35 - 似て非なるもの USE_CONCAT と OR_EXPANDヒントとパラレルクエリー
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 1 / No.36 / INTERSECT ALL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 2 / No.37 / MINUS ALL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 3 / No.38 / EXCEPT and EXCEPT ALL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 4 / No.39 / In-Memory Hybrid Scans
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 5 / No.40 / PIVOT and UNPIVOT
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 6 / No.41 / In-Memory Vectorized Join
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 7 / No.42 / INDEX RANGE SCAN (MULTI VALUE)
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 8 / No.43 / TABLE ACCESS BY INDEX ROWID BATCHED
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 9 / No.44 / COLLECTION ITERATOR PICKLER FETCH
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 10 / No.45 / MAT_VIEW REWRITE ACCESS FULL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 11 / No.46 / GROUPING SETS, ROLLUP, CUBE
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 12 / No.47 / TEMP TABLE TRANSFORMATION
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 13 / No.48 / MULTI-TABLE INSERT
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 14 / No.49 / the DUAL Table
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 15 / No.50 / REMOTE

 

| | | コメント (0)

2022年12月15日 (木)

実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 15 / No.50 / REMOTE

Previously on Mac De Oracle...
Day 14は, the DUAL Table にフォーカスをあてました. 23cでは省略できるようになる. やっと, と言う感じもしなくないですが. やっとと言う言葉しかないわけです. はいw

帰ってきた! 実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺) Advent Calendar 2022も遂に, 残り10回. 頑張ってネタ考えようw
それでは, Day 15 の窓を開けましょう!.

REMOTE と聞いて, ピンと来た方w 多いと思いますが, そうです, 変なおじ, いや, 変なSQL, 違うw,  リモートクエリーか, 分散クエリーのどちらかで現れるOperationです.  リモートクエリーと分散クエリーの違いは, この辺り, とかググっていただくとして.

リモートクエリーとか分散クエリー嫌いな方も多いとは思いますがw とにかく簡単な例で診てみましょう.


いつもと同じように 21c で確認します.

SCOTT@orclpdb1> select banner from v$version;

BANNER
----------------------------------------------------------------------
Oracle Database 21c Enterprise Edition Release 21.0.0.0.0 - Production

検証を簡単に行うため, 2つのPDBを用意し, 一方のPDBのSCOTTへDatabase Linkを作成しています.

SCOTT@orclpdb2> @day15
1* CREATE DATABASE LINK remote_scott CONNECT TO scott IDENTIFIED BY tiger USING 'orclpdb1'

データベース・リンクが作成されました.

経過: 00:00:00.01
1 CREATE TABLE local_emp
2 AS
3 SELECT *
4 FROM
5 emp@remote_scott
6 ORDER BY
7 empno
8* FETCH FIRST 5 ROWS ONLY

表が作成されました.

経過: 00:00:00.09


今回の例は分散クエリーです(複数のデータベースを問い合わせてるので). Database Linkを介してアクセスされる表へのOperationは, REMOTE となり, REMOTEデータベースへSQL文の実行がリクエストされることになります.
リクエストされるSQLは, 最近では, AUTO TRACEのRemote SQL Informationセクションでも確認できるようになっています(便利ですよね). 該当SQLをリモートデータベースで実行して実行計画を確認することができます.

  1  SELECT
2 *
3 FROM
4 local_emp
5 INTERSECT
6 SELECT
7 *
8 FROM
9* emp@remote_scott

EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
---------- ------------------------------ --------------------------- ---------- -------- ---------- ---------- ----------
7369 SMITH CLERK 7902 80-12-17 800 20
7499 ALLEN SALESMAN 7698 81-02-20 1600 300 30
7521 WARD SALESMAN 7698 81-02-22 1250 500 30
7566 JONES MANAGER 7839 81-04-02 2975 20
7654 MARTIN SALESMAN 7698 81-09-28 1250 1400 30

実行計画
----------------------------------------------------------
Plan hash value: 63876577

------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Inst |IN-OUT|
------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 5 | 903 | 7 (29)| 00:00:01 | | |
| 1 | INTERSECTION HASH | | | | | | | |
| 2 | TABLE ACCESS FULL| LOCAL_EMP | 5 | 435 | 2 (0)| 00:00:01 | | |
| 3 | REMOTE | EMP | 12 | 468 | 3 (0)| 00:00:01 | REMOT~ | R->S |
------------------------------------------------------------------------------------------------

Remote SQL Information (identified by operation id):
----------------------------------------------------

3 - SELECT "EMPNO","ENAME","JOB","MGR","HIREDATE","SAL","COMM","DEPTNO" FROM "EMP"
"EMP" (accessing 'REMOTE_SCOTT' )

Note
-----
- dynamic statistics used: dynamic sampling (level=2)

統計
----------------------------------------------------------
0 recursive calls
0 db block gets
3 consistent gets
0 physical reads
0 redo size
1352 bytes sent via SQL*Net to client
52 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
5 rows processed

9年ほど前, クエリー分裂症の治療の様子を見たい方はこちらのスライド見てね. :)


ということで, 明日も私です:)




Related article on Mac De Oracle

・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 1 / TABLE FULL SCAN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 2 / INDEX UNIQUE SCAN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 3 / INDEX RANGE SCAN, Index Only Scan
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 4 / INDEX RANGE SCAN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 5 / INDEX RANGE SCAN, INLIST ITERATOR
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 6 / INDEX FAST SCAN, Index Only Scan
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 7 / INDEX FULL SCAN,Index Only Scan
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 8 / INDEX SKIP SCAN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 9 / TABLE ACCESS INMEMORY FULL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 10 / NESTED LOOP JOIN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 11 / MERGE JOIN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 12 / HASH JOIN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 13 / HASH JOIN OUTER
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 14 / HASH JOIN FULL OUTER
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 15 / PX, TABLE ACCESS FULL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 16 / CONCATENATION
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 17 / SORT UNIQUE, UNION-ALL = UNION
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 18 / UNION-ALL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 19 / INTERSECTION
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 20 / MINUS
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 21 / WINDOW NOSORT STOPKEY
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 22 / COUNT STOPKEY
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 23 / HASH JOIN - LEFT-DEEP JOIN vs RIGHT-DEEP JOIN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 24 / CONNECT BY NO FILTERING WITH START-WITH
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 25 / UNION ALL (RECURSIVE WITH) DEPTH FIRST, RECURSIVE WITH PUMP
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - おまけ#1 / STAR TRANSFORM, VECTOR TRANSFORM (DWH向け)
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - おまけ#2 / MERGE (UPSERT)
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - おまけ#3 / RDFView
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - おまけ#4 / INDEX FULL SCAN (MIN/MAX) - Index Only Scan
・実行計画は, SQL文のレントゲン写真だ! No.30 - LOAD TABLE CONVENTIONAL vs. LOAD AS SELECT
・実行計画は, SQL文のレントゲン写真だ! No.31 - TEMP TABLE TRANSFORMATION LOAD AS SELECT (CURSOR DURATION MEMORY)
・実行計画は, SQL文のレントゲン写真だ! No.32 - EXTERNAL TABLE ACCESS FULL / INMEMORY FULL
・実行計画は, SQL文のレントゲン写真だ! No.33 - BITMAP CONVERSION TO ROWIDS
・実行計画は, SQL文のレントゲン写真だ! No.34 - 似て非なるもの USE_CONCAT と OR_EXPAND ヒント と 手書きSQLのレントゲンの見分け方
・実行計画は, SQL文のレントゲン写真だ! No.35 - 似て非なるもの USE_CONCAT と OR_EXPANDヒントとパラレルクエリー
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 1 / No.36 / INTERSECT ALL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 2 / No.37 / MINUS ALL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 3 / No.38 / EXCEPT and EXCEPT ALL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 4 / No.39 / In-Memory Hybrid Scans
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 5 / No.40 / PIVOT and UNPIVOT
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 6 / No.41 / In-Memory Vectorized Join
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 7 / No.42 / INDEX RANGE SCAN (MULTI VALUE)
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 8 / No.43 / TABLE ACCESS BY INDEX ROWID BATCHED
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 9 / No.44 / COLLECTION ITERATOR PICKLER FETCH
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 10 / No.45 / MAT_VIEW REWRITE ACCESS FULL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 11 / No.46 / GROUPING SETS, ROLLUP, CUBE
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 12 / No.47 / TEMP TABLE TRANSFORMATION
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 13 / No.48 / MULTI-TABLE INSERT
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 14 / No.49 / the DUAL Table

| | | コメント (0)

2022年12月14日 (水)

実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 14 / No.49 / the DUAL Table

Previously on Mac De Oracle... Day 13は, MULTI-TABLE INESRT にフォーカスをあてました. 癖は多いですけども, 便利ですよねーと思っている文の一つでした.

 

それでは, Day 14 の窓を開けましょう!.

Oracle Databaseでは有名すぎる, Selecting from the DUAL Tableですが, 遂に, 21c23cで省略できるようになる!!らしい. まだ, 23cは触ったことはないですが, リリースされたら試してみたいですよね. というか, 多分, みんな, 間違いなく, ブログに書くネタだろうと思いますw

今日は, そんな消えゆく, dual 表, ありがとう. という意味も込めて, 魚拓として, 実行計画という名のレントゲンを残しておこうと思います. (23cリリースされた時の引用にもなるのでw)

 

いつもと同じように 21c で確認します.


SCOTT@orclpdb1> select banner from v$version;

BANNER
----------------------------------------------------------------------
Oracle Database 21c Enterprise Edition Release 21.0.0.0.0 - Production

dual表って実在する表なんですよねw.
昔, 誰かが, dual表へ行をINSERTして, dual表が複数行返すようにしたらどうなるか? なんていう, おイタをしていたような...誰だろうなぁ, あれやってたのw 



SCOTT@orclpdb1> @day14
1* SELECT * FROM dual

DUM
---
X

経過: 00:00:00.01

経過: 00:00:00.01

実行計画
----------------------------------------------------------
Plan hash value: 272002086

--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 2 | 2 (0)| 00:00:01 |
| 1 | TABLE ACCESS FULL| DUAL | 1 | 2 | 2 (0)| 00:00:01 |
--------------------------------------------------------------------------

統計
----------------------------------------------------------
0 recursive calls
0 db block gets
2 consistent gets
0 physical reads
0 redo size
587 bytes sent via SQL*Net to client
52 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed

Oracle Database 10g R1以降では, DUMMY列にアクセスしない場合には, dual表へのconsistent getsの発生が抑止されるようになりました. その場合 FAST DUAL としてOperationに現れます


  1* SELECT null FROM dual

N
-

経過: 00:00:00.00

経過: 00:00:00.01

実行計画
----------------------------------------------------------
Plan hash value: 1388734953

-----------------------------------------------------------------
| Id | Operation | Name | Rows | Cost (%CPU)| Time |
-----------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 2 (0)| 00:00:01 |
| 1 | FAST DUAL | | 1 | 2 (0)| 00:00:01 |
-----------------------------------------------------------------

統計
----------------------------------------------------------
0 recursive calls
0 db block gets
0 consistent gets
0 physical reads
0 redo size
584 bytes sent via SQL*Net to client
52 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed

SELECT * FROM dual の動きで面白いところの一つは, 前回のエントリーで, Multi Table Insertのような構文では, SELECT * FROM dual を使っていますが, SELECT * FROM dual 単体で使う時とは異なり, 実行計画中では, しっかり, コストの低い FAST DUAL が現れている点です. 21cまでは, 文法上必須なわけですが, SELECT * FROM dual と書いた場合でも, ただのお約束上の話なので, よしなに FAST DUAL してくれていると言うことになります. ただ、23cになったら記述不要になるようなので, SQL文には書かなくなりそうな気がします(下位互換で残るのはあるでしょうけども).

と, 言うことで, 本日はここまで.

 

はぁ. アドベントカレンダー全部俺も折り返しましたが, まだ, 先は長いw
バテ気味な感じが, しつつも, 明日も私が担当します!
では, また.

 


Related article on Mac De Oracle
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 1 / TABLE FULL SCAN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 2 / INDEX UNIQUE SCAN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 3 / INDEX RANGE SCAN, Index Only Scan
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 4 / INDEX RANGE SCAN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 5 / INDEX RANGE SCAN, INLIST ITERATOR
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 6 / INDEX FAST SCAN, Index Only Scan
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 7 / INDEX FULL SCAN,Index Only Scan
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 8 / INDEX SKIP SCAN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 9 / TABLE ACCESS INMEMORY FULL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 10 / NESTED LOOP JOIN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 11 / MERGE JOIN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 12 / HASH JOIN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 13 / HASH JOIN OUTER
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 14 / HASH JOIN FULL OUTER
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 15 / PX, TABLE ACCESS FULL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 16 / CONCATENATION
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 17 / SORT UNIQUE, UNION-ALL = UNION
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 18 / UNION-ALL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 19 / INTERSECTION
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 20 / MINUS
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 21 / WINDOW NOSORT STOPKEY
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 22 / COUNT STOPKEY
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 23 / HASH JOIN - LEFT-DEEP JOIN vs RIGHT-DEEP JOIN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 24 / CONNECT BY NO FILTERING WITH START-WITH
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 25 / UNION ALL (RECURSIVE WITH) DEPTH FIRST, RECURSIVE WITH PUMP
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - おまけ#1 / STAR TRANSFORM, VECTOR TRANSFORM (DWH向け)
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - おまけ#2 / MERGE (UPSERT)
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - おまけ#3 / RDFView
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - おまけ#4 / INDEX FULL SCAN (MIN/MAX) - Index Only Scan
・実行計画は, SQL文のレントゲン写真だ! No.30 - LOAD TABLE CONVENTIONAL vs. LOAD AS SELECT
・実行計画は, SQL文のレントゲン写真だ! No.31 - TEMP TABLE TRANSFORMATION LOAD AS SELECT (CURSOR DURATION MEMORY)
・実行計画は, SQL文のレントゲン写真だ! No.32 - EXTERNAL TABLE ACCESS FULL / INMEMORY FULL
・実行計画は, SQL文のレントゲン写真だ! No.33 - BITMAP CONVERSION TO ROWIDS
・実行計画は, SQL文のレントゲン写真だ! No.34 - 似て非なるもの USE_CONCAT と OR_EXPAND ヒント と 手書きSQLのレントゲンの見分け方
・実行計画は, SQL文のレントゲン写真だ! No.35 - 似て非なるもの USE_CONCAT と OR_EXPANDヒントとパラレルクエリー
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 1 / No.36 / INTERSECT ALL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 2 / No.37 / MINUS ALL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 3 / No.38 / EXCEPT and EXCEPT ALL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 4 / No.39 / In-Memory Hybrid Scans
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 5 / No.40 / PIVOT and UNPIVOT
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 6 / No.41 / In-Memory Vectorized Join
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 7 / No.42 / INDEX RANGE SCAN (MULTI VALUE)
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 8 / No.43 / TABLE ACCESS BY INDEX ROWID BATCHED
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 9 / No.44 / COLLECTION ITERATOR PICKLER FETCH
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 10 / No.45 / MAT_VIEW REWRITE ACCESS FULL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 11 / No.46 / GROUPING SETS, ROLLUP, CUBE
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 12 / No.47 / TEMP TABLE TRANSFORMATION
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 13 / No.48 / MULTI-TABLE INSERT

 

| | | コメント (0)

2022年12月13日 (火)

実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 13 / No.48 / MULTI-TABLE INSERT

Previously on Mac De Oracle... Day 12は, TEMP TABLE TRANSFORMATIONにフォーカスをあてました. WITH句以外でも内部的に行われますが, 一時表へのマテリアライズを意図した話ではありますが, クソでかSQLの可読性向上のために利用されることも少なくなく, そのようなケースではインラインビューとして展開されるとうお話しでした. オプティマイザが間違えなければ:)

それでは, Day 13 の窓を開けましょう!.

今日は, MULTI-TABLE INSERT です. え!, INSERT文なのに? みたいに思った方もいるかもしれませんが, MULTI-TABLE INSERTは特徴的なOperationgが現れるので, 知っていた方が良いですよ. ただ, この構文自体はOracleの方言なので, なかなかお目にかからない(マルチテーブルインサート自体は他のRDBMSにもありますが, 癖の多い部分の一つなので)のですがねw 良い機能だと思いますけどね!
では, 診ていこうと思います.

いつもと同じように 21c で確認します.


SCOTT@orclpdb1> select banner from v$version;

BANNER
----------------------------------------------------------------------
Oracle Database 21c Enterprise Edition Release 21.0.0.0.0 - Production

Oracle Database 23cからdualを省略できるようになるらしいですが! 21cまでは, MULTI TABLE INSERTを利用する場合, SELECT * FROM dual が必須です. 不要になるとかなり便利ですよね.
以下では, 文字通り複数表へINSERTしていますが, a href="https://discus-hamburg.cocolog-nifty.com/mac_de_oracle/2020/12/post-10aa61.html">同一表へ複数行INSERTすることもできます. 何気に便利でしょこれ.


SCOTT@orclpdb1> @day13
1 INSERT ALL
2 INTO emp(empno, ename) VALUES(7788, 'Lucky')
3 INTO dept(deptno, dname) VALUES(88, 'QA')
4* SELECT * FROM dual

2行が作成されました.

 

さて, 実行計画は, どうでしょうか. MULTI-TABLE INSERTに加えて, INTOが複数現れます. 現状, FAST DUALも出ますけど:)


実行計画
----------------------------------------------------------
Plan hash value: 2939908344

--------------------------------------------------------------------
| Id | Operation | Name | Rows | Cost (%CPU)| Time |
--------------------------------------------------------------------
| 0 | INSERT STATEMENT | | 1 | 2 (0)| 00:00:01 |
| 1 | MULTI-TABLE INSERT | | | | |
| 2 | FAST DUAL | | 1 | 2 (0)| 00:00:01 |
| 3 | INTO | EMP | | | |
| 4 | INTO | DEPT | | | |
--------------------------------------------------------------------

統計
----------------------------------------------------------
6 recursive calls
11 db block gets
10 consistent gets
4 physical reads
1288 redo size
188 bytes sent via SQL*Net to client
41 bytes received via SQL*Net from client
1 SQL*Net roundtrips to/from client
2 sorts (memory)
0 sorts (disk)
2 rows processed

この手の方言って, SQL標準で使用禁止みたいに書かれてたりすることが多くて, なんで?という気はします. 方言でも性能面で有利に働くのであれば例外は設けておくべきだと, 個人的は思うんですよね.
昔. 階層問合せ使わずに(典型的なSQLアンチパターンで)ヒーヒー言ってた現場を思い出したり. かなり昔ですけどね ー> その現場へ有用性説明し階層問い合わせに書き換えたことで, 皆さん幸せな感じになってましたよーと:)

 

調子が出てきたので, また明日も, 担当は, 私です!

ではでは.

 


Related article on Mac De Oracle

・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 1 / TABLE FULL SCAN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 2 / INDEX UNIQUE SCAN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 3 / INDEX RANGE SCAN, Index Only Scan
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 4 / INDEX RANGE SCAN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 5 / INDEX RANGE SCAN, INLIST ITERATOR
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 6 / INDEX FAST SCAN, Index Only Scan
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 7 / INDEX FULL SCAN,Index Only Scan
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 8 / INDEX SKIP SCAN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 9 / TABLE ACCESS INMEMORY FULL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 10 / NESTED LOOP JOIN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 11 / MERGE JOIN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 12 / HASH JOIN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 13 / HASH JOIN OUTER
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 14 / HASH JOIN FULL OUTER
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 15 / PX, TABLE ACCESS FULL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 16 / CONCATENATION
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 17 / SORT UNIQUE, UNION-ALL = UNION
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 18 / UNION-ALL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 19 / INTERSECTION
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 20 / MINUS
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 21 / WINDOW NOSORT STOPKEY
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 22 / COUNT STOPKEY
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 23 / HASH JOIN - LEFT-DEEP JOIN vs RIGHT-DEEP JOIN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 24 / CONNECT BY NO FILTERING WITH START-WITH
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 25 / UNION ALL (RECURSIVE WITH) DEPTH FIRST, RECURSIVE WITH PUMP
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - おまけ#1 / STAR TRANSFORM, VECTOR TRANSFORM (DWH向け)
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - おまけ#2 / MERGE (UPSERT)
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - おまけ#3 / RDFView
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - おまけ#4 / INDEX FULL SCAN (MIN/MAX) - Index Only Scan
・実行計画は, SQL文のレントゲン写真だ! No.30 - LOAD TABLE CONVENTIONAL vs. LOAD AS SELECT
・実行計画は, SQL文のレントゲン写真だ! No.31 - TEMP TABLE TRANSFORMATION LOAD AS SELECT (CURSOR DURATION MEMORY)
・実行計画は, SQL文のレントゲン写真だ! No.32 - EXTERNAL TABLE ACCESS FULL / INMEMORY FULL
・実行計画は, SQL文のレントゲン写真だ! No.33 - BITMAP CONVERSION TO ROWIDS
・実行計画は, SQL文のレントゲン写真だ! No.34 - 似て非なるもの USE_CONCAT と OR_EXPAND ヒント と 手書きSQLのレントゲンの見分け方
・実行計画は, SQL文のレントゲン写真だ! No.35 - 似て非なるもの USE_CONCAT と OR_EXPANDヒントとパラレルクエリー
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 1 / No.36 / INTERSECT ALL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 2 / No.37 / MINUS ALL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 3 / No.38 / EXCEPT and EXCEPT ALL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 4 / No.39 / In-Memory Hybrid Scans
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 5 / No.40 / PIVOT and UNPIVOT
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 6 / No.41 / In-Memory Vectorized Join
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 7 / No.42 / INDEX RANGE SCAN (MULTI VALUE)
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 8 / No.43 / TABLE ACCESS BY INDEX ROWID BATCHED
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 9 / No.44 / COLLECTION ITERATOR PICKLER FETCH
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 10 / No.45 / MAT_VIEW REWRITE ACCESS FULL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 11 / No.46 / GROUPING SETS, ROLLUP, CUBE
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 12 / No.47 / TEMP TABLE TRANSFORMATION

| | | コメント (0)

2022年12月12日 (月)

実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 12 / No.47 / TEMP TABLE TRANSFORMATION

Previously on Mac De Oracle... Day 11は, GROUPING SETS, ROLLUP, CUBEでした. ROLLUP, CUBEが登場したのは, Oracle Database 8i なので, 1999年あたりだったと思います. それまでUNIONを使ったクソ重, クソクエリーが多かった記憶はありますw ROLLUP, CUBEが神様に見えましたものw 

それでは, Day 12 の窓を開けましょう!.

今日の実行計画という名のレントゲンは, TEMP TABLE TRANSFORMATION です. 内部的に変換されて行われて現れることもあるこのOperationですが, 意図的にTEMP TABLE TRANSFORMATIONに行う場合で有名なのはCTEではないでしょうか?
類似する話題LOAD AS SELECT (CURSOR DURATION MEMORY)を取り上げていました, 内容としては11g,12c,18c,19cの差異の話。今回はその元となるTEMP TABLE TRANSFORMATIONにフォーカスをあてます。

では診ていこうと思います.

いつもと同じように 21c で確認します.


SCOTT@orclpdb1> select banner from v$version;

BANNER
----------------------------------------------------------------------
Oracle Database 21c Enterprise Edition Release 21.0.0.0.0 - Production

ちなみに, WITH句でCTEを使ったら必ず, TEMP TABLE TRANSFORMATION でマテリアライズされるということでもなく, マテリアライズするよ理, インラインビューのままでいいよねとオプティマイザが判断してインラインビューとして展開する場合もあります. それを強制する INLINE というヒントもあります.
WITH句が利用されるケースの1つとして, 可読性向上だけを目的としている場合WITH句で定義されたクエリーが一度しか参照されていないようなケースでは, マテリアライズして一時表作るよりインラインビューで十分という判断でそのような最適化が行われます:)
逆に, マテリアライズして, 一時表に変換してほいしケースもあります. (複数回参照しているのに....みたいな場合ですね. 場合は, MATERIALIZE ヒントでオプティマイザヒントに教えてあげましょう. 最近ミスらなくなった気がしないでもない. オプティマイザも進化してますからね)

 

以下, オプティマイザはCTEと認識して, 一時表へマテリアライズした上で, 一時表を再利用しています.


SCOTT@orclpdb1> @day12
1 WITH temp_emp AS
2 (
3 SELECT
4 emp.*
5 ,dept.dname
6 FROM
7 emp
8 INNER JOIN dept
9 ON
10 emp.deptno = dept.deptno
11 )
12 SELECT
13 *
14 FROM
15 temp_emp
16 WHERE
17 temp_emp.empno = 7369
18 UNION
19 SELECT
20 *
21 FROM
22 temp_emp
23 WHERE
24* temp_emp.deptno = 20

EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO DNAME
---------- ------------------------------ --------------------------- ---------- -------- ---------- ---------- ---------- ------------------------------------------
7369 SMITH CLERK 7902 80-12-17 800 20 RESEARCH
7902 FORD ANALYST 7566 81-12-03 3000 20 RESEARCH
7566 JONES MANAGER 7839 81-04-02 2975 20 RESEARCH

実行計画
----------------------------------------------------------
Plan hash value: 1235767800

----------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 8 | 768 | 6 (34)| 00:00:01 |
| 1 | TEMP TABLE TRANSFORMATION | | | | | |
| 2 | LOAD AS SELECT (CURSOR DURATION MEMORY)| SYS_TEMP_0FD9D665A_DDA815 | | | | |
| 3 | MERGE JOIN | | 4 | 208 | 6 (17)| 00:00:01 |
| 4 | TABLE ACCESS BY INDEX ROWID | DEPT | 4 | 52 | 2 (0)| 00:00:01 |
| 5 | INDEX FULL SCAN | PK_DEPT | 4 | | 1 (0)| 00:00:01 |
|* 6 | SORT JOIN | | 4 | 156 | 4 (25)| 00:00:01 |
|* 7 | TABLE ACCESS FULL | EMP | 4 | 156 | 3 (0)| 00:00:01 |
| 8 | HASH UNIQUE | | 8 | 768 | 6 (34)| 00:00:01 |
| 9 | UNION-ALL | | | | | |
|* 10 | VIEW | | 4 | 384 | 2 (0)| 00:00:01 |
| 11 | TABLE ACCESS FULL | SYS_TEMP_0FD9D665A_DDA815 | 4 | 196 | 2 (0)| 00:00:01 |
|* 12 | VIEW | | 4 | 384 | 2 (0)| 00:00:01 |
| 13 | TABLE ACCESS FULL | SYS_TEMP_0FD9D665A_DDA815 | 4 | 196 | 2 (0)| 00:00:01 |
----------------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

6 - access("EMP"."DEPTNO"="DEPT"."DEPTNO")
filter("EMP"."DEPTNO"="DEPT"."DEPTNO")
7 - filter("EMP"."DEPTNO"=20 OR "EMP"."EMPNO"=7369)
10 - filter("TEMP_EMP"."EMPNO"=7369)
12 - filter("TEMP_EMP"."DEPTNO"=20)

統計
----------------------------------------------------------
0 recursive calls
0 db block gets
8 consistent gets
0 physical reads
0 redo size
1362 bytes sent via SQL*Net to client
52 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
1 sorts (memory)
0 sorts (disk)
3 rows processed

 

CTEの一時表へのマテリアライズを INLINE ヒントでインラインに展開するようにした例です. 一時表へのマテリアライズが抑止され, SQL本文に同一クエリーが展開されている様子が見えます.
WITH句がサポートされていなかった頃は, 事前に一時表を作成して使ったり苦労していたことを思うと, これも非常に便利な機能ですよね.


  1  WITH temp_emp AS
2 (
3 SELECT
4 /*+
5 inline
6 */
7 emp.*
8 ,dept.dname
9 FROM
10 emp
11 INNER JOIN dept
12 ON
13 emp.deptno = dept.deptno
14 )
15 SELECT
16 *
17 FROM
18 temp_emp
19 WHERE
20 temp_emp.empno = 7369
21 UNION
22 SELECT
23 *
24 FROM
25 temp_emp
26 WHERE
27* temp_emp.deptno = 20

EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO DNAME
---------- ------------------------------ --------------------------- ---------- -------- ---------- ---------- ---------- ------------------------------------------
7369 SMITH CLERK 7902 80-12-17 800 20 RESEARCH
7566 JONES MANAGER 7839 81-04-02 2975 20 RESEARCH
7902 FORD ANALYST 7566 81-12-03 3000 20 RESEARCH

実行計画
----------------------------------------------------------
Plan hash value: 119758422

---------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 4 | 208 | 5 (20)| 00:00:01 |
| 1 | HASH UNIQUE | | 4 | 208 | 5 (20)| 00:00:01 |
| 2 | UNION-ALL | | | | | |
| 3 | NESTED LOOPS | | 1 | 52 | 2 (0)| 00:00:01 |
| 4 | TABLE ACCESS BY INDEX ROWID | EMP | 1 | 39 | 1 (0)| 00:00:01 |
|* 5 | INDEX UNIQUE SCAN | PK_EMP | 1 | | 0 (0)| 00:00:01 |
| 6 | TABLE ACCESS BY INDEX ROWID | DEPT | 1 | 13 | 1 (0)| 00:00:01 |
|* 7 | INDEX UNIQUE SCAN | PK_DEPT | 1 | | 0 (0)| 00:00:01 |
| 8 | NESTED LOOPS | | 3 | 156 | 2 (0)| 00:00:01 |
| 9 | TABLE ACCESS BY INDEX ROWID | DEPT | 1 | 13 | 1 (0)| 00:00:01 |
|* 10 | INDEX UNIQUE SCAN | PK_DEPT | 1 | | 0 (0)| 00:00:01 |
| 11 | TABLE ACCESS BY INDEX ROWID BATCHED| EMP | 3 | 117 | 1 (0)| 00:00:01 |
|* 12 | INDEX RANGE SCAN | IX01_EMP | 3 | | 0 (0)| 00:00:01 |
---------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

5 - access("EMP"."EMPNO"=7369)
7 - access("EMP"."DEPTNO"="DEPT"."DEPTNO")
10 - access("DEPT"."DEPTNO"=20)
12 - access("EMP"."DEPTNO"=20)

統計
----------------------------------------------------------
0 recursive calls
0 db block gets
8 consistent gets
0 physical reads
0 redo size
1362 bytes sent via SQL*Net to client
52 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
3 rows processed

 

サッカーの判定に利用されているVAR(Video Assistant Referee)ですが, 人の判断だと微妙なところとは人それぞれのブレが現れるので, テニスでもそうですがわかりやすいので良いんじゃないかと思いますが. ね. (ここ数日そういうブレによる判定へ意義申し立てしたりしてるw しかも見落としだし原因は. )

 

でちょいと, めんどくせーなーとなっていたりしているわけですけども.

それはさておき.

 

明日も, アドベントの担当は私ですw

ではまた.

 

参考)


SCOTT@orclpdb1> select name,inverse, sql_feature from v$sql_hint where name in ('INLINE');

NAME INVERSE SQL_FEATURE
-------------------- -------------------- ------------------------------
INLINE MATERIALIZE QKSFM_TRANSFORMATION

 

 


Related article on Mac De Oracle

・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 1 / TABLE FULL SCAN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 2 / INDEX UNIQUE SCAN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 3 / INDEX RANGE SCAN, Index Only Scan
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 4 / INDEX RANGE SCAN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 5 / INDEX RANGE SCAN, INLIST ITERATOR
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 6 / INDEX FAST SCAN, Index Only Scan
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 7 / INDEX FULL SCAN,Index Only Scan
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 8 / INDEX SKIP SCAN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 9 / TABLE ACCESS INMEMORY FULL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 10 / NESTED LOOP JOIN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 11 / MERGE JOIN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 12 / HASH JOIN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 13 / HASH JOIN OUTER
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 14 / HASH JOIN FULL OUTER
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 15 / PX, TABLE ACCESS FULL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 16 / CONCATENATION
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 17 / SORT UNIQUE, UNION-ALL = UNION
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 18 / UNION-ALL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 19 / INTERSECTION
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 20 / MINUS
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 21 / WINDOW NOSORT STOPKEY
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 22 / COUNT STOPKEY
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 23 / HASH JOIN - LEFT-DEEP JOIN vs RIGHT-DEEP JOIN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 24 / CONNECT BY NO FILTERING WITH START-WITH
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 25 / UNION ALL (RECURSIVE WITH) DEPTH FIRST, RECURSIVE WITH PUMP
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - おまけ#1 / STAR TRANSFORM, VECTOR TRANSFORM (DWH向け)
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - おまけ#2 / MERGE (UPSERT)
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - おまけ#3 / RDFView
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - おまけ#4 / INDEX FULL SCAN (MIN/MAX) - Index Only Scan
・実行計画は, SQL文のレントゲン写真だ! No.30 - LOAD TABLE CONVENTIONAL vs. LOAD AS SELECT
・実行計画は, SQL文のレントゲン写真だ! No.31 - TEMP TABLE TRANSFORMATION LOAD AS SELECT (CURSOR DURATION MEMORY)
・実行計画は, SQL文のレントゲン写真だ! No.32 - EXTERNAL TABLE ACCESS FULL / INMEMORY FULL
・実行計画は, SQL文のレントゲン写真だ! No.33 - BITMAP CONVERSION TO ROWIDS
・実行計画は, SQL文のレントゲン写真だ! No.34 - 似て非なるもの USE_CONCAT と OR_EXPAND ヒント と 手書きSQLのレントゲンの見分け方
・実行計画は, SQL文のレントゲン写真だ! No.35 - 似て非なるもの USE_CONCAT と OR_EXPANDヒントとパラレルクエリー
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 1 / No.36 / INTERSECT ALL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 2 / No.37 / MINUS ALL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 3 / No.38 / EXCEPT and EXCEPT ALL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 4 / No.39 / In-Memory Hybrid Scans
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 5 / No.40 / PIVOT and UNPIVOT
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 6 / No.41 / In-Memory Vectorized Join
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 7 / No.42 / INDEX RANGE SCAN (MULTI VALUE)
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 8 / No.43 / TABLE ACCESS BY INDEX ROWID BATCHED
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 9 / No.44 / COLLECTION ITERATOR PICKLER FETCH
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 10 / No.45 / MAT_VIEW REWRITE ACCESS FULL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 11 / No.46 / GROUPING SETS, ROLLUP, CUBE

 

| | | コメント (0)

2022年12月11日 (日)

実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 11 / No.46 / GROUPING SETS, ROLLUP, CUBE

Previously on Mac De Oracle... Day 10は, MAT_VIEW REWRITE ACCESS FULLでした. Materialized Viewアクセスへ内部でRewriteする機能は随分前からありますが, Oracle Databaseらしい機能の一つだなぁ. と思います. 6.7 Using Real-time Materialized Viewsのように既存機能のブラッシュアップなど継続的に細かい改善が行われていたりします.

それでは, Day 11 の窓を開けましょう!.

まだ紹介していない既存の実行計画多いんですよね. SQLもそうですが, 実行計画になるとますます奥が深いですといいますか, このシリーズ, ネタは沢山あるので当分持ちそうですw

まず, 2011年の面倒くさい大人の事情縛りシリーズのネタですが, 考え方は今でも同じなので, 一度, 軽く眺めておいてください. その間に準備しますのでw.. (違
なお, SQLヒントの書き方で, 最近, ヒントが利用されたかどうかレポートされるようになったことで, USE_HASH, USE_NLのヒントの書き方が云々とかいう話をたまに聞きますが, エラーではなくて無視されるというのが仕様なので, それをうまく利用した使い方を, 面倒くさい大人の事情だらけの現場で考えて今に至った結果であるということは, いずれどこかで説明したいとは思います. (ポイントはチューニングする際の手間削減だったり, どこまで固定するべきか, しないほうが良いかという判断だったりします. 経年で変化もしますからね. ただ, それが手癖になっているという点は否めないわけですけども)
・いろいろと面倒くさい大人の事情縛りのOracleパフォーマンスチューニング #1
・いろいろと面倒くさい大人の事情縛りのOracleパフォーマンスチューニング #2
・いろいろと面倒くさい大人の事情縛りのOracleパフォーマンスチューニング #3
・いろいろと面倒くさい大人の事情縛りのOracleパフォーマンスチューニング #4
・いろいろと面倒くさい大人の事情縛りのOracleパフォーマンスチューニング #5
・いろいろと面倒くさい大人の事情縛りのOracleパフォーマンスチューニング #6
・いろいろと面倒くさい大人の事情縛りのOracleパフォーマンスチューニング #7 おまけ
・いろいろと面倒くさい大人の事情縛りのOracleパフォーマンスチューニング8 おまけのおまけ
・いろいろと面倒くさい大人の事情縛りのOracleパフォーマンスチューニング番外編

 

昔の2011年ぐらいの頃の Oracle Database の実行計画を見たことない年齢のエンジニア多くなってきているとは思いますが, どうでしたか? 上記の過去エントリー. 今でも考え方の基本のキです.

ということで, やっと, 今日の本題です.

データはなくても想定した実行計画のキーワードは取得できるので, 表(データなし)と索引だけ作っておきます. (データ登録するのが面倒だったということでもありますが, 影響はないのでw)
なお, 以下表は, ・いろいろと面倒くさい大人の事情縛りのOracleパフォーマンスチューニング #1で利用したものと同一です.

SCOTT@orclpdb1> @day11
1* drop table test1

表が削除されました.

経過: 00:00:00.04
1 create table test1
2 (
3 starting_date char(8) not null,
4 shop_code char(4) not null,
5 sales_figure number not null,
6 item_code char(10) not null,
7 constraint pk_test1 primary key (starting_date,item_code,shop_code) using index nologging
8 )
9* nologging

表が作成されました.

経過: 00:00:00.02
1* drop table test2

表が削除されました.

経過: 00:00:00.05
1 create table test2
2 (
3 starting_date char(8) not null,
4 shop_code char(4) not null,
5 sales_figure number not null,
6 item_code char(10) not null,
7 constraint pk_test2 primary key (starting_date,item_code,shop_code) using index global nologging
8 )
9 partition by hash(starting_date)
10 (
11 partition test201,
12 partition test202,
13 partition test203,
14 partition test204
15 )
16* nologging

表が作成されました.

経過: 00:00:00.02
1* drop table test3

表が削除されました.

経過: 00:00:00.07
1 create table test3
2 (
3 starting_date char(8) not null,
4 shop_code char(4) not null,
5 sales_figure number not null,
6 item_code char(10) not null,
7 constraint pk_test3 primary key (starting_date,item_code,shop_code) using index local
8 (
9 partition test301idx,
10 partition test302idx,
11 partition test303idx,
12 partition test304idx,
13 partition test305idx,
14 partition test306idx,
15 partition test307idx,
16 partition test308idx,
17 partition test309idx,
18 partition test310idx,
19 partition test311idx,
20 partition test312idx,
21 partition testmaxidx
22 )
23 nologging
24 )
25 partition by range(starting_date) (
26 partition test301 values less than ('20110201') ,
27 partition test302 values less than ('20110301') ,
28 partition test303 values less than ('20110401') ,
29 partition test304 values less than ('20110501') ,
30 partition test305 values less than ('20110601') ,
31 partition test306 values less than ('20110701') ,
32 partition test307 values less than ('20110801') ,
33 partition test308 values less than ('20110901') ,
34 partition test309 values less than ('20111001') ,
35 partition test310 values less than ('20111101') ,
36 partition test311 values less than ('20111201') ,
37 partition test312 values less than ('20120101') ,
38 partition testmax values less than (maxvalue)
39 )
40* nologging

表が作成されました.

経過: 00:00:00.05

GROUPING SETSから.
GROUPING SETSというキーワードは実行計画には現れまん. 内部で後半で説明するROLLUPが含まれる一時表が生成されるように書き換えられる挙動が特徴です. 2011の頃の実行計画と大きく違うのは, CURSOR DURATION MEMORYなんて操作が行われてるあたりですね.
GROUPING SETSというキーワードはないですが, 内部的には, CTEが利用されてROLLUP等と併用されている挙動なので, CTEによる一時表の生成コストがポイントになります. 最近はSSDがほとんどだろうと思うので, HDDだった頃ほど, 一時表の生成コストは気にならないケースも多いかもしれないですけども, 状況次第, どこまでチューニングするか次第というところはありますよね.

  1  SELECT
2 CASE
3 WHEN quarter IS NULL THEN month
4 ELSE quarter
5 END AS month
6 ,CASE
7 WHEN grouping_id = 1 THEN 'ALL'
8 ELSE shop_code
9 END AS shop_code
10 ,sales_figure
11 FROM (
12 SELECT
13 grouping_id(shop_code) as grouping_id
14 ,quarter
15 ,month
16 ,shop_code
17 ,SUM(sales_figure) AS sales_figure
18 FROM
19 (
20 SELECT
21 CASE
22 WHEN SUBSTR(starting_date,5,2) BETWEEN '04' AND '06' THEN 'Q1'
23 WHEN SUBSTR(starting_date,5,2) BETWEEN '07' AND '09' THEN 'Q2'
24 WHEN SUBSTR(starting_date,5,2) BETWEEN '10' AND '12' THEN 'Q3'
25 WHEN SUBSTR(starting_date,5,2) BETWEEN '01' AND '03' THEN 'Q4'
26 END AS quarter
27 ,SUBSTR(starting_date,1,6) AS month
28 ,shop_code
29 ,sales_figure
30 FROM
31 test2
32 WHERE
33 SUBSTR(starting_date,1,6) BETWEEN '201101' AND '201103'
34 )
35 GROUP BY GROUPING SETS (
36 (month, shop_code),
37 (quarter, shop_code),
38 (month),
39 (quarter)
40 )
41 )
42 WHERE
43 shop_code = '1000'
44 OR grouping_id = 1
45 ORDER BY
46 month
47* ,shop_code

レコードが選択されませんでした.

経過: 00:00:00.03

レコードが選択されませんでした.

経過: 00:00:00.01

実行計画
----------------------------------------------------------
Plan hash value: 2567395266

----------------------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Pstart| Pstop |
----------------------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 50 | 11 (28)| 00:00:01 | | |
| 1 | SORT ORDER BY | | 1 | 50 | 11 (28)| 00:00:01 | | |
| 2 | VIEW | | 1 | 50 | 10 (20)| 00:00:01 | | |
| 3 | TEMP TABLE TRANSFORMATION | | | | | | | |
| 4 | LOAD AS SELECT (CURSOR DURATION MEMORY)| SYS_TEMP_0FD9D6620_DD3617 | | | | | | |
| 5 | PARTITION HASH ALL | | 1 | 29 | 2 (0)| 00:00:01 | 1 | 4 |
|* 6 | TABLE ACCESS FULL | TEST2 | 1 | 29 | 2 (0)| 00:00:01 | 1 | 4 |
| 7 | LOAD AS SELECT (CURSOR DURATION MEMORY)| SYS_TEMP_0FD9D6621_DD3617 | | | | | | |
| 8 | HASH GROUP BY ROLLUP | | 1 | 29 | 3 (34)| 00:00:01 | | |
| 9 | TABLE ACCESS FULL | SYS_TEMP_0FD9D6620_DD3617 | 1 | 29 | 2 (0)| 00:00:01 | | |
| 10 | LOAD AS SELECT (CURSOR DURATION MEMORY)| SYS_TEMP_0FD9D6621_DD3617 | | | | | | |
| 11 | HASH GROUP BY ROLLUP | | 1 | 23 | 3 (34)| 00:00:01 | | |
| 12 | TABLE ACCESS FULL | SYS_TEMP_0FD9D6620_DD3617 | 1 | 23 | 2 (0)| 00:00:01 | | |
| 13 | VIEW | | 1 | 50 | 2 (0)| 00:00:01 | | |
|* 14 | TABLE ACCESS FULL | SYS_TEMP_0FD9D6621_DD3617 | 1 | 29 | 2 (0)| 00:00:01 | | |
----------------------------------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

6 - filter(SUBSTR("SYS_TBL_$1$"."STARTING_DATE",1,6)>='201101' AND SUBSTR("SYS_TBL_$1$"."STARTING_DATE",1,6)<='201103')
14 - filter("SYS_TEMP_0FD9D6621_DD3617"."C1"='1000' OR BIN_TO_NUM(SYS_OP_VECBIT(SYS_OP_NUMTORAW("SYS_TEMP_0FD9D6621_DD3617"."D
0"),1))=1)

Hint Report (identified by operation id / Query Block Name / Object Alias):
Total hints for statement: 1 (U - Unused (1))
---------------------------------------------------------------------------

13 - SEL$80FD2AB9
U - NO_MERGE

Note
-----
- dynamic statistics used: dynamic sampling (level=2)

統計
----------------------------------------------------------
0 recursive calls
2 db block gets
0 consistent gets
0 physical reads
384 redo size
542 bytes sent via SQL*Net to client
41 bytes received via SQL*Net from client
1 SQL*Net roundtrips to/from client
1 sorts (memory)
0 sorts (disk)
0 rows processed

次に, ROLLUP. GROUPPING SETSで内部的に行われていますが, 実際にROLLUPを実行するとこうなります. (最初のSQL分とは集計内容が異なるので結果は同一ではないことはお気づきだと思います. データが無い状態で実行しているのでわかりづらいですが, ご注意くさだい)

  1  SELECT
2 CASE
3 WHEN grouping_id(month) = 1 THEN
4 CASE
5 WHEN SUBSTR(MIN(month),5,2)||SUBSTR(MAX(month),5,2) = '0406' THEN 'Q1'
6 WHEN SUBSTR(MIN(month),5,2)||SUBSTR(MAX(month),5,2) = '0709' THEN 'Q2'
7 WHEN SUBSTR(MIN(month),5,2)||SUBSTR(MAX(month),5,2) = '1012' THEN 'Q3'
8 WHEN SUBSTR(MIN(month),5,2)||SUBSTR(MAX(month),5,2) = '0103' THEN 'Q4'
9 END
10 ELSE month
11 END AS month
12 ,CASE
13 WHEN grouping_id(shop_code) = 1 THEN 'ALL'
14 ELSE shop_code
15 END AS shop_code
16 ,SUM(sales_figure) AS sales_figure
17 FROM
18 (
19 SELECT
20 SUBSTR(starting_date,1,6) AS month
21 ,shop_code
22 ,SUM(sales_figure) AS sales_figure
23 FROM
24 test2
25 WHERE
26 starting_date BETWEEN '20110101' AND '20110331'
27 GROUP BY
28 SUBSTR(starting_date,1,6)
29 ,shop_code
30 )
31 GROUP BY
32 ROLLUP(month,shop_code)
33 HAVING
34 shop_code = '1000'
35 OR grouping_id(shop_code) = 1
36 ORDER BY
37 month
38* ,shop_code

レコードが選択されませんでした.

経過: 00:00:00.02

レコードが選択されませんでした.

経過: 00:00:00.01

実行計画
----------------------------------------------------------
Plan hash value: 3343531542

----------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Pstart| Pstop |
----------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 33 | 4 (75)| 00:00:01 | | |
| 1 | SORT ORDER BY | | 1 | 33 | 4 (75)| 00:00:01 | | |
|* 2 | FILTER | | | | | | | |
| 3 | HASH GROUP BY ROLLUP | | 1 | 33 | 4 (75)| 00:00:01 | | |
| 4 | VIEW | | 1 | 33 | 2 (50)| 00:00:01 | | |
| 5 | HASH GROUP BY | | 1 | 29 | 2 (50)| 00:00:01 | | |
| 6 | TABLE ACCESS BY GLOBAL INDEX ROWID BATCHED| TEST2 | 1 | 29 | 1 (0)| 00:00:01 | ROWID | ROWID |
|* 7 | INDEX RANGE SCAN | PK_TEST2 | 1 | | 1 (0)| 00:00:01 | | |
----------------------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

2 - filter("SHOP_CODE"='1000' OR GROUPING_ID(BIN_TO_NUM(SYS_OP_GROUPING("SHOP_CODE",1,0,SYS_OP_BITVEC)))=1)
7 - access("STARTING_DATE">='20110101' AND "STARTING_DATE"<='20110331')

Note
-----
- dynamic statistics used: dynamic sampling (level=2)

統計
----------------------------------------------------------
0 recursive calls
0 db block gets
0 consistent gets
0 physical reads
0 redo size
542 bytes sent via SQL*Net to client
41 bytes received via SQL*Net from client
1 SQL*Net roundtrips to/from client
1 sorts (memory)
0 sorts (disk)
0 rows processed

最後は, CUBEです. これは, GROUPING SETSで行っていたことと同じことをCUBEを使って実現しています. 同じ結果を得るのであれば, CUBEの方が有利そうだ, という点に気づいた方は多いだろう思います:)

  1  SELECT
2 CASE
3 WHEN grouping_id(month) = 1 THEN
4 CASE
5 WHEN SUBSTR(MIN(month),5,2)||SUBSTR(MAX(month),5,2) = '0406' THEN 'Q1'
6 WHEN SUBSTR(MIN(month),5,2)||SUBSTR(MAX(month),5,2) = '0709' THEN 'Q2'
7 WHEN SUBSTR(MIN(month),5,2)||SUBSTR(MAX(month),5,2) = '1012' THEN 'Q3'
8 WHEN SUBSTR(MIN(month),5,2)||SUBSTR(MAX(month),5,2) = '0103' THEN 'Q4'
9 END
10 ELSE month
11 END AS month
12 ,CASE
13 WHEN grouping_id(shop_code) = 1 THEN 'ALL'
14 ELSE shop_code
15 END AS shop_code
16 ,SUM(sales_figure) AS sales_figure
17 FROM
18 (
19 SELECT
20 SUBSTR(starting_date,1,6) AS month
21 ,shop_code
22 ,SUM(sales_figure) AS sales_figure
23 FROM
24 test2
25 WHERE
26 starting_date BETWEEN '20110101' AND '20110331'
27 GROUP BY
28 SUBSTR(starting_date,1,6)
29 ,shop_code
30 )
31 GROUP BY
32 CUBE(month,shop_code)
33 HAVING
34 shop_code = '1000'
35 OR grouping_id(shop_code) = 1
36 ORDER BY
37 month
38* ,shop_code

レコードが選択されませんでした.

経過: 00:00:00.01

レコードが選択されませんでした.

経過: 00:00:00.00

実行計画
----------------------------------------------------------
Plan hash value: 2588666537

------------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Pstart| Pstop |
------------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 33 | 4 (75)| 00:00:01 | | |
| 1 | SORT ORDER BY | | 1 | 33 | 4 (75)| 00:00:01 | | |
|* 2 | FILTER | | | | | | | |
| 3 | SORT GROUP BY | | 1 | 33 | 4 (75)| 00:00:01 | | |
| 4 | GENERATE CUBE | | 1 | 33 | 4 (75)| 00:00:01 | | |
| 5 | SORT GROUP BY | | 1 | 33 | 4 (75)| 00:00:01 | | |
| 6 | VIEW | | 1 | 33 | 2 (50)| 00:00:01 | | |
| 7 | HASH GROUP BY | | 1 | 29 | 2 (50)| 00:00:01 | | |
| 8 | TABLE ACCESS BY GLOBAL INDEX ROWID BATCHED| TEST2 | 1 | 29 | 1 (0)| 00:00:01 | ROWID | ROWID |
|* 9 | INDEX RANGE SCAN | PK_TEST2 | 1 | | 1 (0)| 00:00:01 | | |
------------------------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

2 - filter("SHOP_CODE"='1000' OR GROUPING_ID(BIN_TO_NUM(SYS_OP_GROUPING("SHOP_CODE",1,0,SYS_OP_BITVEC)))=1)
9 - access("STARTING_DATE">='20110101' AND "STARTING_DATE"<='20110331')

Note
-----
- dynamic statistics used: dynamic sampling (level=2)

統計
----------------------------------------------------------
0 recursive calls
0 db block gets
0 consistent gets
0 physical reads
0 redo size
542 bytes sent via SQL*Net to client
41 bytes received via SQL*Net from client
1 SQL*Net roundtrips to/from client
3 sorts (memory)
0 sorts (disk)
0 rows processed

 

アドベントカレンダー書いているだけで, 12月が終わってしまう気がするw

ということを, 言っても, やはり, 明日も担当は, 私ですw

では, また.

 

参考) Oracle Database 21c - Data Warehousing Guide / 21 SQL for Aggregation in Data Warehouses


Related article on Mac De Oracle ・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 1 / TABLE FULL SCAN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 2 / INDEX UNIQUE SCAN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 3 / INDEX RANGE SCAN, Index Only Scan
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 4 / INDEX RANGE SCAN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 5 / INDEX RANGE SCAN, INLIST ITERATOR
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 6 / INDEX FAST SCAN, Index Only Scan
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 7 / INDEX FULL SCAN,Index Only Scan
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 8 / INDEX SKIP SCAN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 9 / TABLE ACCESS INMEMORY FULL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 10 / NESTED LOOP JOIN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 11 / MERGE JOIN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 12 / HASH JOIN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 13 / HASH JOIN OUTER
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 14 / HASH JOIN FULL OUTER
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 15 / PX, TABLE ACCESS FULL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 16 / CONCATENATION
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 17 / SORT UNIQUE, UNION-ALL = UNION
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 18 / UNION-ALL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 19 / INTERSECTION
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 20 / MINUS
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 21 / WINDOW NOSORT STOPKEY
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 22 / COUNT STOPKEY
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 23 / HASH JOIN - LEFT-DEEP JOIN vs RIGHT-DEEP JOIN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 24 / CONNECT BY NO FILTERING WITH START-WITH
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 25 / UNION ALL (RECURSIVE WITH) DEPTH FIRST, RECURSIVE WITH PUMP
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - おまけ#1 / STAR TRANSFORM, VECTOR TRANSFORM (DWH向け)
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - おまけ#2 / MERGE (UPSERT)
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - おまけ#3 / RDFView
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - おまけ#4 / INDEX FULL SCAN (MIN/MAX) - Index Only Scan
・実行計画は, SQL文のレントゲン写真だ! No.30 - LOAD TABLE CONVENTIONAL vs. LOAD AS SELECT
・実行計画は, SQL文のレントゲン写真だ! No.31 - TEMP TABLE TRANSFORMATION LOAD AS SELECT (CURSOR DURATION MEMORY)
・実行計画は, SQL文のレントゲン写真だ! No.32 - EXTERNAL TABLE ACCESS FULL / INMEMORY FULL
・実行計画は, SQL文のレントゲン写真だ! No.33 - BITMAP CONVERSION TO ROWIDS
・実行計画は, SQL文のレントゲン写真だ! No.34 - 似て非なるもの USE_CONCAT と OR_EXPAND ヒント と 手書きSQLのレントゲンの見分け方
・実行計画は, SQL文のレントゲン写真だ! No.35 - 似て非なるもの USE_CONCAT と OR_EXPANDヒントとパラレルクエリー
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 1 / No.36 / INTERSECT ALL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 2 / No.37 / MINUS ALL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 3 / No.38 / EXCEPT and EXCEPT ALL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 4 / No.39 / In-Memory Hybrid Scans
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 5 / No.40 / PIVOT and UNPIVOT
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 6 / No.41 / In-Memory Vectorized Join
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 7 / No.42 / INDEX RANGE SCAN (MULTI VALUE)
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 8 / No.43 / TABLE ACCESS BY INDEX ROWID BATCHED
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 9 / No.44 / COLLECTION ITERATOR PICKLER FETCH
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 10 / No.45 / MAT_VIEW REWRITE ACCESS FULL

| | | コメント (0)

2022年12月10日 (土)

実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 10 / No.45 / MAT_VIEW REWRITE ACCESS FULL

Previously on Mac De Oracle...
Day 9は, COLLECTION ITERATOR PICKLER FETCHでした. パイプラインテーブルファンクションだけに限りませんが, 利用者定義プロシージャやファンクション内から実行されるSQL文の有無, そして, 実行計画の把握という一手間多くなるタイプです. 特にパイプラインテーブルファンクションについては, 実行計画に特殊な操作として現れるのが特徴というお話しでした.

では, Day 10 の窓を開けましょう.

今日も, 紹介済みだと勘違いして忘れていた, MAT_VIEW REWRITE ACCESS FULL です!

いつもと同じように 21c で確認します.

SCOTT@orclpdb1> select banner from v$version;

BANNER
----------------------------------------------------------------------
Oracle Database 21c Enterprise Edition Release 21.0.0.0.0 - Production

データ作りが面倒なので, 再びサンプルスキーマのSHの力を借りましょうw (アドベントカレンダー, 全部俺は, ある意味体力, 気力の勝負w でもあるので, 楽できるところは楽に行きましょう :)


SH@orclpdb1> @day10
1 CREATE MATERIALIZED VIEW LOG ON sales
2 WITH
3 SEQUENCE
4 , ROWID
5 (
6 prod_id
7 , quantity_sold
8 , amount_sold
9 )
10* INCLUDING NEW VALUES

マテリアライズド・ビュー・ログが作成されました.

1 CREATE MATERIALIZED VIEW LOG ON products
2 WITH
3 ROWID
4 (
5 prod_id
6 , prod_name
7 , prod_category
8 , prod_subcategory)
9* INCLUDING NEW VALUES

マテリアライズド・ビュー・ログが作成されました.

1 CREATE MATERIALIZED VIEW mv_sales_4_day10
2 REFRESH FAST ON DEMAND
3 ENABLE QUERY REWRITE
4 AS
5 SELECT
6 prod_name
7 , SUM(quantity_sold) AS sum_quantity
8 , SUM(amount_sold) AS sum_amount
9 FROM
10 sales
11 INNER JOIN products
12 ON
13 sales.prod_id = products.prod_id
14 GROUP BY
15* prod_name

マテリアライズド・ビューが作成されました.


マテビューの準備ができたので, 本日の主役. Query Rewriteが働いで, sales, products表ではなく, materialize viewが full scan されるように書き換えられ, MAT_VIEW REWRITE ACCESS FULLが現れています!
処理時間もいい感じですよね.  経過: 00:00:00.02 となっています.

  1  SELECT
2 prod_name
3 , SUM(quantity_sold)
4 , SUM(amount_sold)
5 FROM
6 sales
7 INNER JOIN products
8 ON
9 sales.prod_id = products.prod_id
10 GROUP BY
11* prod_name

PROD_NAME SUM(QUANTITY_SOLD) SUM(AMOUNT_SOLD)
-------------------------------------------------- ------------------ ----------------
5MP Telephoto Digital Camera 6002 6312268.4
17" LCD w/built-in HDTV Tuner 6010 7189171.77
Envoy 256MB - 40GB 5766 5635963.08
Y Box 6929 2082330.3
Mini DV Camcorder with 3.5" Swivel LCD 6160 8314815.4
Envoy Ambassador 9591 15011642.5

...略...

Smash up Boxing 7844 260436.75
Martial Arts Champions 6711 148558.92
Comic Book Heroes 4572 101214.6
Fly Fishing 4091 34547.82
Finding Fido 6168 78881.08
Adventures with Numbers 12742 175563.92
Extension Cable 7576 60713.47
Xtend Memory 15191 366858.31

71行が選択されました.

経過: 00:00:00.02

71行が選択されました.

実行計画
----------------------------------------------------------
Plan hash value: 3048942819

-------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 71 | 2627 | 3 (0)| 00:00:01 |
| 1 | MAT_VIEW REWRITE ACCESS FULL| MV_SALES_4_DAY10 | 71 | 2627 | 3 (0)| 00:00:01 |
-------------------------------------------------------------------------------------------------

統計
----------------------------------------------------------
0 recursive calls
0 db block gets
7 consistent gets
0 physical reads
0 redo size
4356 bytes sent via SQL*Net to client
96 bytes received via SQL*Net from client
6 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
71 rows processed

ついでなの, Query Rewirteを無効にしてみるとどうなるでしょうか? 当然, オリジナルのsales, products表が結合されます! 
処理時間も大幅に増加して,  経過: 00:00:00.28 ですね! かなりの差ですよねこれ. このあたりもうまく使いたい, Oracleの便利な機能の一つではありますね.

  1  SELECT
2 /*+
3 NO_REWRITE
4 */
5 prod_name
6 , SUM(quantity_sold)
7 , SUM(amount_sold)
8 FROM
9 sales
10 INNER JOIN products
11 ON
12 sales.prod_id = products.prod_id
13 GROUP BY
14* prod_name

PROD_NAME SUM(QUANTITY_SOLD) SUM(AMOUNT_SOLD)
-------------------------------------------------- ------------------ ----------------
5MP Telephoto Digital Camera 6002 6312268.4
17" LCD w/built-in HDTV Tuner 6010 7189171.77
Envoy 256MB - 40GB 5766 5635963.08
Y Box 6929 2082330.3
Mini DV Camcorder with 3.5" Swivel LCD 6160 8314815.4

...略...

Martial Arts Champions 6711 148558.92
Comic Book Heroes 4572 101214.6
Fly Fishing 4091 34547.82
Finding Fido 6168 78881.08
Adventures with Numbers 12742 175563.92
Extension Cable 7576 60713.47
Xtend Memory 15191 366858.31

71行が選択されました.

経過: 00:00:00.28

71行が選択されました.

実行計画
----------------------------------------------------------
Plan hash value: 504757596

----------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Pstart| Pstop |
----------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 71 | 4260 | 574 (11)| 00:00:01 | | |
| 1 | HASH GROUP BY | | 71 | 4260 | 574 (11)| 00:00:01 | | |
|* 2 | HASH JOIN | | 72 | 4320 | 573 (11)| 00:00:01 | | |
| 3 | VIEW | VW_GBC_5 | 72 | 2160 | 570 (11)| 00:00:01 | | |
| 4 | HASH GROUP BY | | 72 | 864 | 570 (11)| 00:00:01 | | |
| 5 | PARTITION RANGE ALL| | 918K| 10M| 523 (3)| 00:00:01 | 1 | 28 |
| 6 | TABLE ACCESS FULL | SALES | 918K| 10M| 523 (3)| 00:00:01 | 1 | 28 |
| 7 | TABLE ACCESS FULL | PRODUCTS | 72 | 2160 | 3 (0)| 00:00:01 | | |
----------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

2 - access("ITEM_1"="PRODUCTS"."PROD_ID")

Note
-----
- this is an adaptive plan

統計
----------------------------------------------------------
0 recursive calls
0 db block gets
1641 consistent gets
0 physical reads
0 redo size
4356 bytes sent via SQL*Net to client
96 bytes received via SQL*Net from client
6 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
71 rows processed

1* DROP MATERIALIZED VIEW LOG ON sales

マテリアライズド・ビュー・ログが削除されました.

1* DROP MATERIALIZED VIEW LOG ON products

マテリアライズド・ビュー・ログが削除されました.

1* DROP MATERIALIZED VIEW mv_sales_4_day10

マテリアライズド・ビューが削除されました.


さてさて, やっと, Day 10です. まだ半分も終わってないのかと, 遠ーーーーーーーーーーくをみるなど.

そんなこと, してても, 明日も私が担当なので, 何か考えますw

参考)
Oracle Database 21c / Data Warehousing Guide - 6 Advanced Materialized Views



Related article on Mac De Oracle
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 1 / TABLE FULL SCAN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 2 / INDEX UNIQUE SCAN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 3 / INDEX RANGE SCAN, Index Only Scan
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 4 / INDEX RANGE SCAN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 5 / INDEX RANGE SCAN, INLIST ITERATOR
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 6 / INDEX FAST SCAN, Index Only Scan
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 7 / INDEX FULL SCAN,Index Only Scan
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 8 / INDEX SKIP SCAN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 9 / TABLE ACCESS INMEMORY FULL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 10 / NESTED LOOP JOIN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 11 / MERGE JOIN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 12 / HASH JOIN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 13 / HASH JOIN OUTER
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 14 / HASH JOIN FULL OUTER
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 15 / PX, TABLE ACCESS FULL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 16 / CONCATENATION
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 17 / SORT UNIQUE, UNION-ALL = UNION
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 18 / UNION-ALL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 19 / INTERSECTION
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 20 / MINUS
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 21 / WINDOW NOSORT STOPKEY
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 22 / COUNT STOPKEY
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 23 / HASH JOIN - LEFT-DEEP JOIN vs RIGHT-DEEP JOIN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 24 / CONNECT BY NO FILTERING WITH START-WITH
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 25 / UNION ALL (RECURSIVE WITH) DEPTH FIRST, RECURSIVE WITH PUMP
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - おまけ#1 / STAR TRANSFORM, VECTOR TRANSFORM (DWH向け)
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - おまけ#2 / MERGE (UPSERT)
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - おまけ#3 / RDFView
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - おまけ#4 / INDEX FULL SCAN (MIN/MAX) - Index Only Scan
・実行計画は, SQL文のレントゲン写真だ! No.30 - LOAD TABLE CONVENTIONAL vs. LOAD AS SELECT
・実行計画は, SQL文のレントゲン写真だ! No.31 - TEMP TABLE TRANSFORMATION LOAD AS SELECT (CURSOR DURATION MEMORY)
・実行計画は, SQL文のレントゲン写真だ! No.32 - EXTERNAL TABLE ACCESS FULL / INMEMORY FULL
・実行計画は, SQL文のレントゲン写真だ! No.33 - BITMAP CONVERSION TO ROWIDS
・実行計画は, SQL文のレントゲン写真だ! No.34 - 似て非なるもの USE_CONCAT と OR_EXPAND ヒント と 手書きSQLのレントゲンの見分け方
・実行計画は, SQL文のレントゲン写真だ! No.35 - 似て非なるもの USE_CONCAT と OR_EXPANDヒントとパラレルクエリー
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 1 / No.36 / INTERSECT ALL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 2 / No.37 / MINUS ALL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 3 / No.38 / EXCEPT and EXCEPT ALL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 4 / No.39 / In-Memory Hybrid Scans
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 5 / No.40 / PIVOT and UNPIVOT
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 6 / No.41 / In-Memory Vectorized Join
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 7 / No.42 / INDEX RANGE SCAN (MULTI VALUE)
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 8 / No.43 / TABLE ACCESS BY INDEX ROWID BATCHED
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 9 / No.44 / COLLECTION ITERATOR PICKLER FETCH

| | | コメント (0)

2022年12月 9日 (金)

実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 9 / No.44 / COLLECTION ITERATOR PICKLER FETCH

Previously on Mac De Oracle...
Day 8は, レントゲンで紹介済みだと, すっかり勘違いして紹介し忘れていた TABLE ACCESS BY INDEX ROWID BATCHED でした. 索引スキャンはしているけど, 実行回数が多かったり, 実行回数は少ないが, 一回あたりのBuffer gets, Physical Readsが多いケースでは, ボディーブローのような感じで結構影響出るタイプであるケースも少なくないので, もし必要があれば, Index Only ScanなどでIO数削減して(重箱の隅を突くような)治療に繋がることも多い身近なOperationでもあるので知っておくと何かの時には助けになりますよ. きっと.

ということで, Day 9 の窓を開けましょう.

今日の主役は, COLLECTION ITERATOR PICKLER FETCHです.
どのような時に現れるOperationか, 既にググってる方はお気づきだと思いますがw パイプラインテーブルファンクションを利用してコレクションを返している場合です. これ意外に多くなってきているようにも思いますが, PJ次第なのかなとは思います. 上手く使えば味方になったり. .

いつもと同じように 21c で確認します.

SCOTT@orclpdb1> select banner from v$version;

BANNER
----------------------------------------------------------------------
Oracle Database 21c Enterprise Edition Release 21.0.0.0.0 - Production


Pipelined table function で ascii artで使ったパイプラインテーブルファンクションで実行計画を見てみましょう. (ちなみに, ASCII ARTのYouTube動画には無音です:)


前述のパイプラインテーブルファンクションでは, 表データをアクセスしていませんが, 表をアクセスしている場合でも, パイプラインテーブルファンクション内部から実行されているSQLは表面上現れません.

SCOTT@orclpdb1> set autot trace exp stat
SCOTT@orclpdb1> select * from tree(50, 0.2);

4651行が選択されました.

実行計画
----------------------------------------------------------
Plan hash value: 1806254315

------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 8168 | 16336 | 29 (0)| 00:00:01 |
| 1 | COLLECTION ITERATOR PICKLER FETCH| TREE | 8168 | 16336 | 29 (0)| 00:00:01 |
------------------------------------------------------------------------------------------

統計
----------------------------------------------------------
23 recursive calls
0 db block gets
26 consistent gets
0 physical reads
0 redo size
311383 bytes sent via SQL*Net to client
3462 bytes received via SQL*Net from client
312 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
4651 rows processed


以下, サンプルスキーマであるshのsales表をアクセスするパイプラインテーブルファンクションですが, 実行計画には, COLLECTION ITERATOR PICKLER FETCHが現れるだけであることが分かります.
通常このように, PL/SQLなどのUDFやプロシージャ内部から実行されるSQL文はAWR等で別途確認していく必要があるという点は, 21cでも同様です. この辺りは, 仕方ないかなという感じはしますが, もう少し楽に該当SQL文の実行計画が確認できたら楽になるかな. という気はします.

データを確認し, 引数に利用する値を選んでいるようす.

SH@orclpdb1> desc sales
名前 NULL? 型
----------------------------------------- -------- ----------------------------
PROD_ID NOT NULL NUMBER
CUST_ID NOT NULL NUMBER
TIME_ID NOT NULL DATE
CHANNEL_ID NOT NULL NUMBER
PROMO_ID NOT NULL NUMBER
QUANTITY_SOLD NOT NULL NUMBER(10,2)
AMOUNT_SOLD NOT NULL NUMBER(10,2)

SH@orclpdb1>
SH@orclpdb1> select * from sales order by time_id desc fetch first 10 rows only;

PROD_ID CUST_ID TIME_ID CHANNEL_ID PROMO_ID QUANTITY_SOLD AMOUNT_SOLD
---------- ---------- -------- ---------- ---------- ------------- -----------
14 1472 01-12-31 3 351 1 1193.02
20 3042 01-12-31 3 351 1 628.89
20 8182 01-12-31 2 999 1 628.89
20 7231 01-12-31 2 999 1 628.89
20 5745 01-12-31 2 999 1 628.89
20 3973 01-12-31 2 999 1 628.89
20 1978 01-12-31 3 999 1 628.89
20 118 01-12-31 3 999 1 628.89
20 1978 01-12-31 2 999 1 628.89
16 4958 01-12-31 3 999 1 298.11


パイプラインテーブルファンクションの作成中

SH@orclpdb1> @day9
1 CREATE OR REPLACE PACKAGE day9_pkg AS
2 CURSOR cur_2_latest_sales (
3 in_channel_id sales.channel_id%TYPE
4 ,in_prod_id sales.prod_id%TYPE
5 ,in_cust_id sales.cust_id%TYPE
6 ) IS
7 SELECT
8 *
9 FROM
10 sales
11 WHERE
12 channel_id = in_channel_id
13 AND prod_id = in_prod_id
14 AND cust_id = in_cust_id
15 ORDER BY
16 time_id DESC
17 FETCH FIRST 2 ROWS ONLY;
18
19 TYPE outtable_type IS TABLE OF sales%ROWTYPE;
20
21 FUNCTION list_2_latest_sales (
22 in_channel_id IN sales.channel_id%TYPE
23 ,in_prod_id IN sales.prod_id%TYPE
24 ,in_cust_id IN sales.cust_id%TYPE
25 )
26 RETURN outtable_type PIPELINED;
27* END day9_pkg;

パッケージが作成されました.

経過: 00:00:00.00
エラーはありません.


1 CREATE OR REPLACE PACKAGE BODY day9_pkg AS
2 FUNCTION list_2_latest_sales (
3 in_channel_id IN sales.channel_id%TYPE
4 ,in_prod_id IN sales.prod_id%TYPE
5 ,in_cust_id IN sales.cust_id%TYPE
6 )
7 RETURN outtable_type PIPELINED IS
8 sales_rec outtable_type;
9 BEGIN
10 FOR sales_rec IN cur_2_latest_sales(in_channel_id, in_prod_id, in_cust_id) LOOP
11 PIPE ROW(sales_rec);
12 END LOOP;
13 RETURN;
14 END list_2_latest_sales;
15* END day9_pkg;

パッケージ本体が作成されました.

経過: 00:00:00.00
エラーはありません.

以下, テーブルファンクションでsales表をアクセスしていますが, 見える範囲は21cになっても同じで, テーブルファンクションの場合は, COLLECTION ITERATOR PICKLER FETCHという形で表に見える状態なんですよ.
内部で, SQLが実行されているかどうかは, 実行計画からだけでは判断できない例の一つでもあります. このOperationを見つけたら, ファンクション内部で利用されているSQL文を特定しておくと後々役に立つこともあります.

  1  SELECT
2 *
3 FROM
4* day9_pkg.list_2_latest_sales(2, 20, 5745)

PROD_ID CUST_ID TIME_ID CHANNEL_ID PROMO_ID QUANTITY_SOLD AMOUNT_SOLD
---------- ---------- -------- ---------- ---------- ------------- -----------
20 5745 01-12-31 2 999 1 628.89

経過: 00:00:00.00

経過: 00:00:00.01

実行計画
----------------------------------------------------------
Plan hash value: 457385954

---------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 8168 | 16336 | 29 (0)| 00:00:01 |
| 1 | COLLECTION ITERATOR PICKLER FETCH| LIST_2_LATEST_SALES | 8168 | 16336 | 29 (0)| 00:00:01 |
---------------------------------------------------------------------------------------------------------

統計
----------------------------------------------------------
2 recursive calls
0 db block gets
49 consistent gets
0 physical reads
0 redo size
1093 bytes sent via SQL*Net to client
52 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
1 sorts (memory)
0 sorts (disk)
1 rows processed

テーブルファンクションから実行されるSQLは以下のような感じです. 実際にはバインド変数が利用されるため, バインドピークによる影響も合わせて見る必要もあります(バインドピーク無効にしているところって, まだありそうですしね. 昔からの大人の事情に縛られまくっているところとか)

  1  SELECT
2 *
3 FROM
4 sales
5 WHERE
6 channel_id = 2
7 AND prod_id = 20
8 AND cust_id = 5745
9 ORDER BY
10 time_id DESC
11* FETCH FIRST 2 ROWS ONLY

PROD_ID CUST_ID TIME_ID CHANNEL_ID PROMO_ID QUANTITY_SOLD AMOUNT_SOLD
---------- ---------- -------- ---------- ---------- ------------- -----------
20 5745 01-12-31 2 999 1 628.89

実行計画
----------------------------------------------------------
Plan hash value: 3545264548

-------------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Pstart| Pstop |
-------------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 2 | 218 | 59 (2)| 00:00:01 | | |
|* 1 | VIEW | | 2 | 218 | 59 (2)| 00:00:01 | | |
|* 2 | WINDOW SORT PUSHED RANK | | 1 | 29 | 59 (2)| 00:00:01 | | |
| 3 | PARTITION RANGE ALL | | 1 | 29 | 58 (0)| 00:00:01 | 1 | 28 |
|* 4 | TABLE ACCESS BY LOCAL INDEX ROWID BATCHED| SALES | 1 | 29 | 58 (0)| 00:00:01 | 1 | 28 |
| 5 | BITMAP CONVERSION TO ROWIDS | | | | | | | |
| 6 | BITMAP AND | | | | | | | |
|* 7 | BITMAP INDEX SINGLE VALUE | SALES_CUST_BIX | | | | | 1 | 28 |
|* 8 | BITMAP INDEX SINGLE VALUE | SALES_PROD_BIX | | | | | 1 | 28 |
-------------------------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

1 - filter("from$_subquery$_002"."rowlimit_$$_rownumber"<=2)
2 - filter(ROW_NUMBER() OVER ( ORDER BY INTERNAL_FUNCTION("SALES"."TIME_ID") DESC )<=2)
4 - filter("CHANNEL_ID"=2)
7 - access("CUST_ID"=5745)
8 - access("PROD_ID"=20)


統計
----------------------------------------------------------
0 recursive calls
0 db block gets
49 consistent gets
0 physical reads
0 redo size
1093 bytes sent via SQL*Net to client
52 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
1 sorts (memory)
0 sorts (disk)
1 rows processed

v$sqlareaビューからはこんな感じでSQL_IDが取得できるので, AWRなどから問題になっていそうならば. こいつの実行計画をおっていく感じ. まあ, ファンクションやプロシージャで実装されている場合だと一手間増える感じなのは21cでも変わらんですね. (この例ではplan_hash_valueを指定していますが、バインド変数が利用されているケースでは同一とは限らないのでご注意ください)
SH@orclpdb1> select sql_id,plan_hash_value,sql_text from v$sqlarea where sql_text like '%SALES%' and plan_hash_value = 3545264548;

SQL_ID                                  PLAN_HASH_VALUE SQL_TEXT
--------------------------------------- --------------- ----------------------------------------------------------------------------------------------------
5ang5upk282ga 3545264548 SELECT * FROM SALES WHERE CHANNEL_ID = :B3 AND PROD_ID = :B2 AND CUST_ID = :B1 ORDER BY TIME_ID DESC
FETCH FIRST 2 ROWS ONLY


さて, さて, 続きのネタ考えてると, 睡眠不足になりそうな週にw突入してきたぞw

参考)
Oracle Database 21c / 13.5 Chaining Pipelined Table Functions for Multiple Transformations


眠くても, 明日の担当は, 私しかいませんので, やりますw はい.



Related article on Mac De Oracle
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 1 / TABLE FULL SCAN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 2 / INDEX UNIQUE SCAN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 3 / INDEX RANGE SCAN, Index Only Scan
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 4 / INDEX RANGE SCAN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 5 / INDEX RANGE SCAN, INLIST ITERATOR
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 6 / INDEX FAST SCAN, Index Only Scan
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 7 / INDEX FULL SCAN,Index Only Scan
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 8 / INDEX SKIP SCAN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 9 / TABLE ACCESS INMEMORY FULL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 10 / NESTED LOOP JOIN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 11 / MERGE JOIN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 12 / HASH JOIN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 13 / HASH JOIN OUTER
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 14 / HASH JOIN FULL OUTER
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 15 / PX, TABLE ACCESS FULL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 16 / CONCATENATION
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 17 / SORT UNIQUE, UNION-ALL = UNION
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 18 / UNION-ALL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 19 / INTERSECTION
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 20 / MINUS
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 21 / WINDOW NOSORT STOPKEY
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 22 / COUNT STOPKEY
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 23 / HASH JOIN - LEFT-DEEP JOIN vs RIGHT-DEEP JOIN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 24 / CONNECT BY NO FILTERING WITH START-WITH
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 25 / UNION ALL (RECURSIVE WITH) DEPTH FIRST, RECURSIVE WITH PUMP
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - おまけ#1 / STAR TRANSFORM, VECTOR TRANSFORM (DWH向け)
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - おまけ#2 / MERGE (UPSERT)
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - おまけ#3 / RDFView
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - おまけ#4 / INDEX FULL SCAN (MIN/MAX) - Index Only Scan
・実行計画は, SQL文のレントゲン写真だ! No.30 - LOAD TABLE CONVENTIONAL vs. LOAD AS SELECT
・実行計画は, SQL文のレントゲン写真だ! No.31 - TEMP TABLE TRANSFORMATION LOAD AS SELECT (CURSOR DURATION MEMORY)
・実行計画は, SQL文のレントゲン写真だ! No.32 - EXTERNAL TABLE ACCESS FULL / INMEMORY FULL
・実行計画は, SQL文のレントゲン写真だ! No.33 - BITMAP CONVERSION TO ROWIDS
・実行計画は, SQL文のレントゲン写真だ! No.34 - 似て非なるもの USE_CONCAT と OR_EXPAND ヒント と 手書きSQLのレントゲンの見分け方
・実行計画は, SQL文のレントゲン写真だ! No.35 - 似て非なるもの USE_CONCAT と OR_EXPANDヒントとパラレルクエリー
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 1 / No.36 / INTERSECT ALL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 2 / No.37 / MINUS ALL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 3 / No.38 / EXCEPT and EXCEPT ALL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 4 / No.39 / In-Memory Hybrid Scans
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 5 / No.40 / PIVOT and UNPIVOT
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 6 / No.41 / In-Memory Vectorized Join
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 7 / No.42 / INDEX RANGE SCAN (MULTI VALUE)
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 8 / No.43 / TABLE ACCESS BY INDEX ROWID BATCHED

| | | コメント (0)

2022年12月 8日 (木)

実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 8 / No.43 / TABLE ACCESS BY INDEX ROWID BATCHED

Previously on Mac De Oracle...
Day 7は, 実行計画という名のレントゲンにもしっかり現れる安心感のあるJINDEX RANGE SCAN (MULTI VALUE)という操作というJSON絡みの機能のお話でした. やはり, レントゲンだけで診れた方が楽ですねw
帰ってきた! 実行計画は、SQL文のレントゲン写真だ! Oracle Database (全部俺) Advent Calendar 2022もやっと1/3ぐらいw 毎年思うけど, 大変. 全部俺だとw

ということで, Day 8 の窓を開けましょう.

今日は, すでに紹介済みと勘違いして, すっかり忘れていた TABLE ACCESS BY INDEX ROWID BATCHED について診ていきたいというか, 改めて確認しておきましょう.

TABLE ACCESS BY INDEX ROWID BATCHEDが登場したのは12cの頃です. 2014年に本ブログでも扱っていました. その時の解説で復習しておきましょう.

実は, この, TABLE ACCESS BY INDEX ROWID BATCHED, 実行計画のOperationに現れるようになったのは, 12cからですが, 内部的には, 11gでも同様の挙動を示していました.
11gの頃は, Operation上は, TABLE ACCESS BY INDEX ROWIDとして現れていましたが, 内部的には, 待機イベント, db file parallel readとして起きている、ということが分かる程度でした. そう, 実行計画という名のレントゲンだけでは判別できない部類の動きでした. その後, 12cになってからOperationとして簡易に判断できるようになりました.

以下, 2014年の記事ですが, SQLトレースを取得して待機イベントも含め調べてた思い出.
TABLE ACCESS BY INDEX ROWID BATCHED (Oracle Database 12c R1) ってなに! #1
TABLE ACCESS BY INDEX ROWID BATCHED (Oracle Database 12c R1) ってなに! #2
TABLE ACCESS BY INDEX ROWID BATCHED (Oracle Database 12c R1) ってなに! #3


では, レントゲンを見てみましょう. (索引レンジスキャンするケースでは, TABLE ACCESS BY INDEX ROWID BATCHEDになる場合が圧倒的に多くなったようにも感じるので, 比較的よく見るOperationだと思います)
INDEX RANGE SCAN + TABLE ACCESS BY INDEX ROWID BATCHEDが行われており, かつ、索引のクラスタリングファクターが大きめ(行数に近い)である場合, Index Only Scanによって, ギリギリまでチューニングできる可能性が高いケースが多いのも, このタイプのOperationあ現れた時の特徴だったりします.

いつもと同じように 21c で確認します.

SCOTT@orclpdb1> select banner from v$version;

BANNER
----------------------------------------------------------------------
Oracle Database 21c Enterprise Edition Release 21.0.0.0.0 - Production

データの準備は以下.

SCOTT@orclpdb1> @day8
1* DROP TABLE day8

表が削除されました.

1 CREATE TABLE day8
2 (
3 id NUMBER PRIMARY KEY
4 ,string_data VARCHAR2(500)
5* )

表が作成されました.

1 DECLARE
2 i NUMBER(4) := 0;
3 num_of_rows CONSTANT NUMBER(4) := 1000;
4 done BOOLEAN := false;
5 BEGIN
6 WHILE NOT done LOOP
7 BEGIN
8 INSERT INTO day8 VALUES(TRUNC(DBMS_RANDOM.VALUE(1,3001)), LPAD(TO_CHAR(i),500,'*'));
9 i := i + 1;
10 IF i >= num_of_rows THEN EXIT; END IF;
11 EXCEPTION
12 WHEN DUP_VAL_ON_INDEX THEN
13 NULL;
14 END;
15 IF MOD(i,100) = 0 THEN COMMIT; END IF;
16 END LOOP;
17* END;

PL/SQLプロシージャが正常に完了しました.

1 BEGIN
2 DBMS_STATS.GATHER_TABLE_STATS(ownname=>'SCOTT',tabname=>UPPER('day8'),no_invalidate=>false,cascade=>true);
3* END;

PL/SQLプロシージャが正常に完了しました.

1 SELECT id
2 FROM
3 day8
4 ORDER BY id
5* FETCH FIRST 5 ROWS ONLY

ID
----------
4
8
10
12
15

良かったw 綺麗に, TABLE ACCESS BY INDEX ROWID BATCHEDが出てますね.

SCOTT@orclpdb1> @day8-2 4 15
1 SELECT
2 id
3 ,substr(string_data,1,10)
4 FROM
5 day8
6 WHERE
7* id BETWEEN &1 AND &2
旧 7: id BETWEEN &1 AND &2
新 7: id BETWEEN 4 AND 15

ID SUBSTR(STRING_DATA,1,10)
---------- -----------------------------------
4 **********
8 **********
10 **********
12 **********
15 **********

旧 7: id BETWEEN &1 AND &2
新 7: id BETWEEN 4 AND 15


実行計画
----------------------------------------------------------
Plan hash value: 145644201

---------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 5 | 2525 | 7 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID BATCHED| DAY8 | 5 | 2525 | 7 (0)| 00:00:01 |
|* 2 | INDEX RANGE SCAN | SYS_C008604 | 5 | | 2 (0)| 00:00:01 |
---------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

2 - access("ID">=4 AND "ID"<=15)

統計
----------------------------------------------------------
0 recursive calls
0 db block gets
8 consistent gets
0 physical reads
0 redo size
779 bytes sent via SQL*Net to client
52 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
5 rows processed

やっと, 実行計画は, SQL文のレントゲン写真だ!というタイトルっぽいネタになったような気がしたところで, 本日はこれまで.

明日の担当は, 私しかいないので, 私が書きますw (全部俺)



Related article on Mac De Oracle
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 1 / TABLE FULL SCAN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 2 / INDEX UNIQUE SCAN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 3 / INDEX RANGE SCAN, Index Only Scan
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 4 / INDEX RANGE SCAN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 5 / INDEX RANGE SCAN, INLIST ITERATOR
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 6 / INDEX FAST SCAN, Index Only Scan
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 7 / INDEX FULL SCAN,Index Only Scan
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 8 / INDEX SKIP SCAN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 9 / TABLE ACCESS INMEMORY FULL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 10 / NESTED LOOP JOIN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 11 / MERGE JOIN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 12 / HASH JOIN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 13 / HASH JOIN OUTER
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 14 / HASH JOIN FULL OUTER
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 15 / PX, TABLE ACCESS FULL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 16 / CONCATENATION
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 17 / SORT UNIQUE, UNION-ALL = UNION
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 18 / UNION-ALL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 19 / INTERSECTION
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 20 / MINUS
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 21 / WINDOW NOSORT STOPKEY
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 22 / COUNT STOPKEY
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 23 / HASH JOIN - LEFT-DEEP JOIN vs RIGHT-DEEP JOIN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 24 / CONNECT BY NO FILTERING WITH START-WITH
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 25 / UNION ALL (RECURSIVE WITH) DEPTH FIRST, RECURSIVE WITH PUMP
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - おまけ#1 / STAR TRANSFORM, VECTOR TRANSFORM (DWH向け)
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - おまけ#2 / MERGE (UPSERT)
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - おまけ#3 / RDFView
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - おまけ#4 / INDEX FULL SCAN (MIN/MAX) - Index Only Scan
・実行計画は, SQL文のレントゲン写真だ! No.30 - LOAD TABLE CONVENTIONAL vs. LOAD AS SELECT
・実行計画は, SQL文のレントゲン写真だ! No.31 - TEMP TABLE TRANSFORMATION LOAD AS SELECT (CURSOR DURATION MEMORY)
・実行計画は, SQL文のレントゲン写真だ! No.32 - EXTERNAL TABLE ACCESS FULL / INMEMORY FULL
・実行計画は, SQL文のレントゲン写真だ! No.33 - BITMAP CONVERSION TO ROWIDS
・実行計画は, SQL文のレントゲン写真だ! No.34 - 似て非なるもの USE_CONCAT と OR_EXPAND ヒント と 手書きSQLのレントゲンの見分け方
・実行計画は, SQL文のレントゲン写真だ! No.35 - 似て非なるもの USE_CONCAT と OR_EXPANDヒントとパラレルクエリー
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 1 / No.36 / INTERSECT ALL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 2 / No.37 / MINUS ALL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 3 / No.38 / EXCEPT and EXCEPT ALL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 4 / No.39 / In-Memory Hybrid Scans
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 5 / No.40 / PIVOT and UNPIVOT
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 6 / No.41 / In-Memory Vectorized Join
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 7 / No.42 / INDEX RANGE SCAN (MULTI VALUE)

| | | コメント (0)

2022年12月 7日 (水)

実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 7 / No.42 / INDEX RANGE SCAN (MULTI VALUE)

Previously on Mac De Oracle...
Day 6は, 実行計画という名のレントゲンにも現れないタイプ。SQLモニターアクティブレポート(html)という名の内視鏡を利用してなんとか見ることができました。また、v$sysstatからシステム統計という名の血液検査を利用してもある判断できることを確認しました。最近、レントゲンだけで確定できないタイプの多くなってきて遠ーくを見ることが多くなってきたかもねーw

さて、帰ってきた! 実行計画は、SQL文のレントゲン写真だ! Oracle Database (全部俺) Advent Calendar 2022もなんとか1/3ほどです。持つのかネタというより、検証するのツレーのが多すぎて、記事アップが間に合うのか? これw(レントゲンに映したいだけのシリーズのはずなのにw)

ということで、 Day 7の窓を開けましょう。今日は、レントゲンで分かるタイプです(一安心w)

Multi-Value Functional Indexです。21cより前は、JSON_VALUE()を利用する関数索引は、Single-Valueだけが利用できました。Single-Valueだけだと辛い場面は多いわけで、その課題への答えが、Multi-Value Functional Indexですね。
JSONへの対応を追っていると、XMLへの対応が始まった頃のOracle Databaseを思い出すお年頃の私なので、色々当時のことを思い出してしまいます(ところで、XML Masterっていう資格知ってます?w みなさん?)

余談はこれぐらいにして、本題へ。

いつもと同じように 21c で確認します.


SCOTT@orclpdb1> select banner from v$version;

BANNER
----------------------------------------------------------------------
Oracle Database 21c Enterprise Edition Release 21.0.0.0.0 - Production

table、データを用意します。


SCOTT@orclpdb1> @day7
1* DROP TABLE groups

表が削除されました。

経過: 00:00:00.04
1* CREATE TABLE groups (group_list_json JSON)

表が作成されました。

経過: 00:00:00.02
1 INSERT INTO
2 groups(group_list_json)
3 SELECT
4 JSON_OBJECT
5 (
6 'group_id' VALUE deptno
7 ,'object_type' VALUE JSON_ARRAYAGG
8 (
9 JSON_OBJECT
10 (
11 'member_id' VALUE empno
12 ,'member_name' VALUE ename
13 ) RETURNING CLOB
14 ) RETURNING CLOB
15 )
16 FROM
17 emp
18 GROUP BY
19* deptno

3行が作成されました。

経過: 00:00:00.01
1* COMMIT

コミットが完了しました。

経過: 00:00:00.01

multi-value functional indexを作成! group_id毎に配列を持っており、配列に含まれている member_idに対して、MULTIVALUE INDEXを作成しています!


  1* CREATE MULTIVALUE INDEX groups_mvix ON groups t1( t1.group_list_json.object_type.member_id.number() )

索引が作成されました。

経過: 00:00:00.01

 

本日の主役はこれです。
JSON_EXISTS()でMULTIVALUE INDEXを作成した、 member_id で指定したメンバーが含まれているメンバー全員の名前を取得しています。(その元となっている、JSONも)

想定通り、MULTIVALUE INDEXをアクセスしており、実行計画にも分かりやすく現れています:)
ついでに、Predicate Information には興味深い情報も現れていますね。これもアドベントカレンダー以外でネタになりそうです。

JSONTABLE EVALUATIONというオペレーションは、SQL/JSON Function である、JSON_TABLE() の操作を示しています。(なぜ、PIVOTが実行計画のOperationに現れないのか、ますます、謎ですなw)


  1  SELECT
2 member_name
3 , group_list_json
4 FROM
5 groups
6 ,JSON_TABLE
7 (
8 group_list_json, '$.object_type[*]'
9 COLUMNS
10 (
11 member_name VARCHAR2(10) PATH '$.member_name'
12 )
13 )
14 WHERE
15 JSON_EXISTS
16 (
17 group_list_json
18 ,'$.object_type?(@.member_id == 7499)'
19* )

MEMBER_NAME GROUP_LIST_JSON
------------------------------ ----------------------------------------------------------------------------------------------------
ALLEN {"group_id":30,"object_type":[{"member_id":7499,"member_name":"ALLEN"},{"member_id":7900,"member_nam
e":"JAMES"},{"member_id":7844,"member_name":"TURNER"},{"member_id":7698,"member_name":"BLAKE"},{"mem
ber_id":7654,"member_name":"MARTIN"},{"member_id":7521,"member_name":"WARD"}]}

JAMES
TURNER
BLAKE
MARTIN
WARD

6行が選択されました。

経過: 00:00:00.02

6行が選択されました。

経過: 00:00:00.01

実行計画
----------------------------------------------------------
Plan hash value: 1011849735

----------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 8168 | 32M| 31 (0)| 00:00:01 |
| 1 | NESTED LOOPS | | 8168 | 32M| 31 (0)| 00:00:01 |
| 2 | TABLE ACCESS BY INDEX ROWID BATCHED| GROUPS | 1 | 4115 | 2 (0)| 00:00:01 |
| 3 | HASH UNIQUE | | 8168 | 32M| | |
|* 4 | INDEX RANGE SCAN (MULTI VALUE) | GROUPS_MVIX | 1 | | 1 (0)| 00:00:01 |
| 5 | JSONTABLE EVALUATION | | | | | |
----------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

4 - access(JSON_QUERY("GROUP_LIST_JSON" /*+ LOB_BY_VALUE */ FORMAT OSON ,
'$.object_type.member_id.number()' RETURNING NUMBER ASIS WITHOUT ARRAY WRAPPER ERROR ON
ERROR NULL ON EMPTY NULL ON MISMATCH MULTIVALUE)=7499)

Note
-----
- dynamic statistics used: dynamic sampling (level=2)

統計
----------------------------------------------------------
0 recursive calls
0 db block gets
2 consistent gets
0 physical reads
0 redo size
3446 bytes sent via SQL*Net to client
532 bytes received via SQL*Net from client
8 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
6 rows processed

 


久々に、実行計画という名のレントゲンだけで完結した記事で、ホットしたw (なんだこの気持ちはw
ということで、スッキリしたわけですが、 JSONの構文に、XMLの構文と同じような、思い出を思い出しつつw  明日は、やっぱり、私が担当です:)

 

参考) Oracle Database 21c / 28.8 Creating Multivalue Function-Based Indexes for JSON_EXISTS


Related article on Mac De Oracle
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 1 / TABLE FULL SCAN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 2 / INDEX UNIQUE SCAN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 3 / INDEX RANGE SCAN, Index Only Scan
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 4 / INDEX RANGE SCAN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 5 / INDEX RANGE SCAN, INLIST ITERATOR
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 6 / INDEX FAST SCAN, Index Only Scan
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 7 / INDEX FULL SCAN,Index Only Scan
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 8 / INDEX SKIP SCAN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 9 / TABLE ACCESS INMEMORY FULL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 10 / NESTED LOOP JOIN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 11 / MERGE JOIN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 12 / HASH JOIN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 13 / HASH JOIN OUTER
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 14 / HASH JOIN FULL OUTER
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 15 / PX, TABLE ACCESS FULL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 16 / CONCATENATION
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 17 / SORT UNIQUE, UNION-ALL = UNION
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 18 / UNION-ALL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 19 / INTERSECTION
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 20 / MINUS
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 21 / WINDOW NOSORT STOPKEY
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 22 / COUNT STOPKEY
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 23 / HASH JOIN - LEFT-DEEP JOIN vs RIGHT-DEEP JOIN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 24 / CONNECT BY NO FILTERING WITH START-WITH
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 25 / UNION ALL (RECURSIVE WITH) DEPTH FIRST, RECURSIVE WITH PUMP
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - おまけ#1 / STAR TRANSFORM, VECTOR TRANSFORM (DWH向け)
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - おまけ#2 / MERGE (UPSERT)
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - おまけ#3 / RDFView
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - おまけ#4 / INDEX FULL SCAN (MIN/MAX) - Index Only Scan
・実行計画は, SQL文のレントゲン写真だ! No.30 - LOAD TABLE CONVENTIONAL vs. LOAD AS SELECT
・実行計画は, SQL文のレントゲン写真だ! No.31 - TEMP TABLE TRANSFORMATION LOAD AS SELECT (CURSOR DURATION MEMORY)
・実行計画は, SQL文のレントゲン写真だ! No.32 - EXTERNAL TABLE ACCESS FULL / INMEMORY FULL
・実行計画は, SQL文のレントゲン写真だ! No.33 - BITMAP CONVERSION TO ROWIDS
・実行計画は, SQL文のレントゲン写真だ! No.34 - 似て非なるもの USE_CONCAT と OR_EXPAND ヒント と 手書きSQLのレントゲンの見分け方
・実行計画は, SQL文のレントゲン写真だ! No.35 - 似て非なるもの USE_CONCAT と OR_EXPANDヒントとパラレルクエリー
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 1 / No.36 / INTERSECT ALL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 2 / No.37 / MINUS ALL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 3 / No.38 / EXCEPT and EXCEPT ALL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 4 / No.39 / In-Memory Hybrid Scans
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 5 / No.40 / PIVOT and UNPIVOT
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 6 / No.41 / In-Memory Vectorized Join

 

| | | コメント (0)

2022年12月 6日 (火)

実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 6 / No.41 / In-Memory Vectorized Join

Previously on Mac De Oracle...
Day 5は, 実行計画というレントゲンにも現れない PIVOT の謎。みたいなオチですが、UNPIVOTは現れるんだよねー。ということでした。

今日は、さらに、このタイトルでいいのか! という結末になっております (乞うご期待w

ということで、 Day 6の窓を開けましょう。

今回、データを準備するのは、面倒だな、と思ったので、 サンプルスキーマである SH スキーマの sales表とcustomer表を利用します。ただ、少しだけ準備は必要ですが.
(なお、INMEMORY_DEEP_VECTORIZATION パラメータのデフォルト値は、TRUEなので, INMEMORY_SIZE パラメータが設定されているのであれば、追加の設定は不要です)

SH@orclpdb1> show parameter INMEMORY_DEEP_VECTORIZATION

NAME TYPE VALUE
------------------------------------ --------------------------------- ------------------------------
inmemory_deep_vectorization boolean TRUE


では、準備を。
各表をIn-Memory化してポピュレーションする必要があります。v$im_segmentsビューからすべて載ったことを確認します。

SH@orclpdb1> alter table customers inmemory priority high memcompress for capacity low;

表が変更されました。

SH@orclpdb1> alter table sales inmemory priority high memcompress for capacity low;

表が変更されました。

SH@orclpdb1> select /*+ full(s) no_parallel(s) */ count(*) from sales s;

count(*)
----------
918843

SH@orclpdb1> select /*+ full(c) no_parallel(c) */ count(*) from customers c;

count(*)
----------
55500

SH@orclpdb1> select segment_name,inmemory_size,bytes_not_populated from v$im_segments;

SEGMENT_NAME INMEMORY_SIZE BYTES_NOT_POPULATED
------------------------------ ------------- -------------------
SALES 1310720 0
SALES 1310720 0
SALES 1310720 0
DAY4 15990784 0
SALES 1310720 0
SALES 1310720 0
SALES 1310720 0
SALES 1310720 0
SALES 1310720 0
SALES 1310720 0
SALES 1310720 0
SALES 1310720 0
SALES 1310720 0
CUSTOMERS 2359296 0
SALES 1310720 0
SALES 1310720 0
SALES 1310720 0
SALES 1310720 0

18行が選択されました。

実行計画という名のレントゲンがテーマのシリーズですがw 実行計画を見ただけでは、はっきりわからないというPIVOTに続き、2つ目の事例が!!!!!
実行時に実施するかどうかを判断しているとのことで、実行計画を立てている時点では判断できず、実行後または、実行中にのみ確認できるということらしい(なんとかならんのか。ん〜〜〜〜)

ということで、SQLモニターアクティブレポート(html)という名の内視鏡を利用して診る必要のある事例であることがわかりました!!!!!!!
(各表はin-memory fullでアクセスされてます。前提はクリアしているHASH JOINになっています)

SH@orclpdb1> @day6

1 SELECT
2 /*+
3 NO_STAR_TRANSFORMATION
4 NO_VECTOR_TRANSFORM
5 FULL(c)
6 FULL(s)
7 MONITOR
8 */
9 count(*)
10 FROM
11 sales s
12 INNER JOIN customers c
13 ON
14* s.cust_id = c.cust_id


実行計画
----------------------------------------------------------
Plan hash value: 3219640484

-----------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Pstart| Pstop |
-----------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 10 | 56 (24)| 00:00:01 | | |
| 1 | SORT AGGREGATE | | 1 | 10 | | | | |
|* 2 | HASH JOIN | | 918K| 8973K| 56 (24)| 00:00:01 | | |
| 3 | TABLE ACCESS INMEMORY FULL | CUSTOMERS | 55500 | 270K| 17 (6)| 00:00:01 | | |
| 4 | PARTITION RANGE ALL | | 918K| 4486K| 34 (21)| 00:00:01 | 1 | 28 |
| 5 | TABLE ACCESS INMEMORY FULL| SALES | 918K| 4486K| 34 (21)| 00:00:01 | 1 | 28 |
-----------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

2 - access("S"."CUST_ID"="C"."CUST_ID")


統計
----------------------------------------------------------
4 recursive calls
0 db block gets
36 consistent gets
0 physical reads
0 redo size
593 bytes sent via SQL*Net to client
52 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed

...略...

内視鏡で撮影したスナップショットにもメモしてありますが、HASH JOIN操作の行のInfo列の双眼鏡アイコンをクリックすることで、In-Memory Vectorized Joinが行われたか否かを確認することができます。
DeepVec Hash Joins が重要なキーワードです。見逃さないようにしてくださいね。

今の所、この方法が最も確実で分かりやすい方法です。
Vectorized-join1
Vectorized-join11

次に、通常のHASH JOINとどう違うのかも見ておきましょう。
sales表と、customers表を非インメモリー化します。

SH@orclpdb1> alter table customers no inmemory;

表が変更されました。

SH@orclpdb1> alter table sales no inmemory;

表が変更されました。

SH@orclpdb1> select segment_name,inmemory_size,bytes_not_populated from v$im_segments;

SEGMENT_NAME INMEMORY_SIZE BYTES_NOT_POPULATED
------------------------------ ------------- -------------------
DAY4 15990784 0


1  SELECT
2 /*+
3 NO_STAR_TRANSFORMATION
4 NO_VECTOR_TRANSFORM
5 FULL(c)
6 FULL(s)
7 MONITOR
8 */
9 count(*)
10 FROM
11 sales s
12 INNER JOIN customers c
13 ON
14* s.cust_id = c.cust_id

実行計画
----------------------------------------------------------
Plan hash value: 3219640484

---------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Pstart| Pstop |
---------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 10 | 947 (2)| 00:00:01 | | |
| 1 | SORT AGGREGATE | | 1 | 10 | | | | |
|* 2 | HASH JOIN | | 918K| 8973K| 947 (2)| 00:00:01 | | |
| 3 | TABLE ACCESS FULL | CUSTOMERS | 55500 | 270K| 423 (1)| 00:00:01 | | |
| 4 | PARTITION RANGE ALL| | 918K| 4486K| 518 (2)| 00:00:01 | 1 | 28 |
| 5 | TABLE ACCESS FULL | SALES | 918K| 4486K| 518 (2)| 00:00:01 | 1 | 28 |
---------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

2 - access("S"."CUST_ID"="C"."CUST_ID")

統計
----------------------------------------------------------
178 recursive calls
0 db block gets
3444 consistent gets
1586 physical reads
220 redo size
593 bytes sent via SQL*Net to client
52 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
21 sorts (memory)
0 sorts (disk)
1 rows processed

...略...


SQLモニターアクティブレポート(html)というなの内視鏡のスナップショット画像から、例の双眼鏡アイコンをクリックして結果をみると、In-Memory Vectorized Joinが行われていないことが分かります。また、In-memory table full も抑止したのでその差は物凄い差になって現れますね。
In-Memory Vectorized Join 19.39 ms
Hash Join / In-Memory Off 0.13 s


20221205-85808
20221205-85820

....

SQLモニターアクティブレポート(html)以外に、システム統計からも確認できるようですね。慣れないと読みにくいかも知れないですが、特定のSQL実行前後の変化を見る必要があります。ちょっと面倒ですね。セッション統計でも拾えるのだろうか。。。。(要追跡調査)

SOURCE     NAME                                     Before                After
---------- ---------------------------------------- -------------------- --------------------
sysstat IM simd KV add rows 610500 666000
sysstat IM simd KV probe calls 176 192
sysstat IM simd KV probe keys 393888 429696
sysstat IM simd KV probe rows 393888 429696
sysstat IM simd decode symbol calls 352 384
sysstat IM simd decode unpack calls 176 192
sysstat IM simd decode unpack selective calls 176 192

最後に、インメモリーにポピュレートされた状態で、In-Memory Vectorized Joinを無効化して差分をみてみましょう。

SH@orclpdb1> alter session set INMEMORY_DEEP_VECTORIZATION = false;

セッションが変更されました。

SH@orclpdb1> show parameter INMEMORY_DEEP_VECTORIZATION

NAME TYPE VALUE
------------------------------------ --------------------------------- ------------------------------
inmemory_deep_vectorization boolean FALSE


該当表はポピュレートされている状態です

SH@orclpdb1> select segment_name,inmemory_size,bytes_not_populated from v$im_segments;

SEGMENT_NAME INMEMORY_SIZE BYTES_NOT_POPULATED
------------------------------ ------------- -------------------
SALES 1310720 0
SALES 1310720 0
SALES 1310720 0
DAY4 15990784 0
SALES 1310720 0
SALES 1310720 0
SALES 1310720 0
SALES 1310720 0
SALES 1310720 0
SALES 1310720 0
SALES 1310720 0
SALES 1310720 0
SALES 1310720 0
CUSTOMERS 2359296 0
SALES 1310720 0
SALES 1310720 0
SALES 1310720 0
SALES 1310720 0


実行計画は、In-Memory Vectorized Joinが行われたものと同じ(Plan hash valueが同一)ですが、前後で取得したシステム統計値で、In-Memory Vectorized Joinに関連するsimd関連の数値に変化がみられません!!!!
システム統計をみるとIn-Memory Vectorized Joinは動作してないことが分かります。とはいえ、SQLモニターレポート(アクティブレポート)が明らかに見やすいとは思います。

  1  SELECT
2 /*+
3 NO_STAR_TRANSFORMATION
4 NO_VECTOR_TRANSFORM
5 FULL(c)
6 FULL(s)
7 MONITOR
8 */
9 count(*)
10 FROM
11 sales s
12 INNER JOIN customers c
13 ON
14* s.cust_id = c.cust_id

経過: 00:00:00.03

実行計画
----------------------------------------------------------
Plan hash value: 3219640484

-----------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Pstart| Pstop |
-----------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 10 | 56 (24)| 00:00:01 | | |
| 1 | SORT AGGREGATE | | 1 | 10 | | | | |
|* 2 | HASH JOIN | | 918K| 8973K| 56 (24)| 00:00:01 | | |
| 3 | TABLE ACCESS INMEMORY FULL | CUSTOMERS | 55500 | 270K| 17 (6)| 00:00:01 | | |
| 4 | PARTITION RANGE ALL | | 918K| 4486K| 34 (21)| 00:00:01 | 1 | 28 |
| 5 | TABLE ACCESS INMEMORY FULL| SALES | 918K| 4486K| 34 (21)| 00:00:01 | 1 | 28 |
-----------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

2 - access("S"."CUST_ID"="C"."CUST_ID")

統計
----------------------------------------------------------
33 recursive calls
0 db block gets
67 consistent gets
0 physical reads
0 redo size
593 bytes sent via SQL*Net to client
52 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
8 sorts (memory)
0 sorts (disk)
1 rows processed

...略...

SOURCE NAME Before After
---------- -------------------------------------------------- ---------- ----------
sysstat IM simd KV add rows 0 0
sysstat IM simd KV probe calls 0 0
sysstat IM simd KV probe keys 0 0
sysstat IM simd KV probe rows 0 0
sysstat IM simd decode symbol calls 0 0
sysstat IM simd decode unpack calls 0 0
sysstat IM simd decode unpack selective calls 0 0


In-Memory Vectorized Joinが、利用されたかどうかを判断しやすいというわけではないですが、システム統計の差分で判断するのも、ありといえばアリですかね。この結果をみると。
In-Memory Vectorized Joinを無効化すると、IM simd ***という複数の統計値が変化しなくなりました!
ただ、血液検査みたいなものなので、これは、一般的には、判断の敷居が上がる気がします。

もう少し簡易に動作有無が判断できるようになると良いのではないかと思います。

例えば、実行後の NOTE) 等のテキストで、実行されたことが判断できる情報を付加してもらうとか。auto explainでもいいし、AWR SQLレポートや実行計画をリストするときに、追加で特定のビューを問い合わせると分かるとか、とか。

実行時間の差にも注目してみてください。

どちらもIn-Memory table full scanが行われた場合、このケースでIn-Memory Vectorized Joinを利用した場合、10%ほど改善しています、より効果的な場面で利用すれば大きな改善につながりそうではありますね。
In-Memory Vectorized Join 有効化 19.39 ms
In-Memory Vectorized Join 無効化 22.54 ms
20221205-82613
20221205-82624

明日も、やはり、担当は、私ですw



参考)
Oracle Database 21c / 8.3 Optimizing Joins Using In-Memory Deep Vectorization




Related article on Mac De Oracle
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 1 / TABLE FULL SCAN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 2 / INDEX UNIQUE SCAN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 3 / INDEX RANGE SCAN, Index Only Scan
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 4 / INDEX RANGE SCAN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 5 / INDEX RANGE SCAN, INLIST ITERATOR
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 6 / INDEX FAST SCAN, Index Only Scan
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 7 / INDEX FULL SCAN,Index Only Scan
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 8 / INDEX SKIP SCAN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 9 / TABLE ACCESS INMEMORY FULL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 10 / NESTED LOOP JOIN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 11 / MERGE JOIN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 12 / HASH JOIN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 13 / HASH JOIN OUTER
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 14 / HASH JOIN FULL OUTER
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 15 / PX, TABLE ACCESS FULL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 16 / CONCATENATION
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 17 / SORT UNIQUE, UNION-ALL = UNION
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 18 / UNION-ALL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 19 / INTERSECTION
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 20 / MINUS
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 21 / WINDOW NOSORT STOPKEY
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 22 / COUNT STOPKEY
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 23 / HASH JOIN - LEFT-DEEP JOIN vs RIGHT-DEEP JOIN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 24 / CONNECT BY NO FILTERING WITH START-WITH
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 25 / UNION ALL (RECURSIVE WITH) DEPTH FIRST, RECURSIVE WITH PUMP
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - おまけ#1 / STAR TRANSFORM, VECTOR TRANSFORM (DWH向け)
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - おまけ#2 / MERGE (UPSERT)
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - おまけ#3 / RDFView
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - おまけ#4 / INDEX FULL SCAN (MIN/MAX) - Index Only Scan
・実行計画は, SQL文のレントゲン写真だ! No.30 - LOAD TABLE CONVENTIONAL vs. LOAD AS SELECT
・実行計画は, SQL文のレントゲン写真だ! No.31 - TEMP TABLE TRANSFORMATION LOAD AS SELECT (CURSOR DURATION MEMORY)
・実行計画は, SQL文のレントゲン写真だ! No.32 - EXTERNAL TABLE ACCESS FULL / INMEMORY FULL
・実行計画は, SQL文のレントゲン写真だ! No.33 - BITMAP CONVERSION TO ROWIDS
・実行計画は, SQL文のレントゲン写真だ! No.34 - 似て非なるもの USE_CONCAT と OR_EXPAND ヒント と 手書きSQLのレントゲンの見分け方
・実行計画は, SQL文のレントゲン写真だ! No.35 - 似て非なるもの USE_CONCAT と OR_EXPANDヒントとパラレルクエリー
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 1 / No.36 / INTERSECT ALL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 2 / No.37 / MINUS ALL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 3 / No.38 / EXCEPT and EXCEPT ALL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 4 / No.39 / In-Memory Hybrid Scans
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 5 / No.40 / PIVOT and UNPIVOT

| | | コメント (0)

2022年12月 5日 (月)

実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 5 / No.40 / PIVOT and UNPIVOT

Previously on Mac De Oracle...
Day 4は, SQLというより, in-memory operationに追加された, In-Memory Hybrid Scans の実行計画という名のレントゲンをみながら, どのような状況で発動するのかを簡単に確認しましたー.

 

なかな面白い動きでしたね. 別途時間を取って深掘りしないとね, と. :)

 

 

ということで, Day 5 の窓を開けましょう. 今日は, 新機能というより以前からあったのにレントゲン取ってなかったよね? ということで PIVOT and UNPIVOT を診てみたいと思います.

 

いつもと同じように 21c で確認します.


SCOTT@orclpdb1> select banner from v$version;

BANNER
----------------------------------------------------------------------
Oracle Database 21c Enterprise Edition Release 21.0.0.0.0 - Production

 

 

最初は, pivot 向けデータの準備から


SCOTT@orclpdb1> @day5

表が削除されました.

1 CREATE TABLE for_pivot
2 AS
3 SELECT
4 stat_name
5 , value
6 FROM
7 v$sys_time_model
8 WHERE
9 stat_name IN (
10 'DB time'
11 , 'DB CPU'
12 , 'background elapsed time'
13 , 'background cpu time'
14* )

表が作成されました.

1* CREATE INDEX ix_for_pivot ON for_pivot(stat_name)

索引が作成されました.

1 SELECT
2 *
3 FROM
4* for_pivot

STAT_NAME VALUE
------------------------------ ----------
DB time 143415979
DB CPU 127540525
background elapsed time 7381483
background cpu time 6340262
/code>

 

 

 

PIVOTで行持ちを列持ちに変換してみます.

 

おお, 実行計画には, PIVOT とか出ないのですよーーーー!! (知ってましたか!
こいつも実行計画を見ただけでは, PIVOTが行われているかは読み取れないですねw アクセスパス以外は注意する箇所はあまりないわけですけども:)


  1  SELECT
2 db_time
3 ,db_cpu
4 FROM
5 (
6 SELECT
7 stat_name
8 , value
9 FROM
10 for_pivot
11 WHERE
12 stat_name IN ('DB time', 'DB CPU')
13 )
14 PIVOT
15 (
16 MAX(value)
17 FOR stat_name IN
18 (
19 'DB time' AS db_time
20 ,'DB CPU' AS db_cpu
21 )
22* )

DB_TIME DB_CPU
---------- ----------
143415979 127540525


実行計画
----------------------------------------------------------
Plan hash value: 1690715989

-------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 26 | 2 (0)| 00:00:01 |
| 1 | VIEW | | 1 | 26 | 2 (0)| 00:00:01 |
| 2 | SORT AGGREGATE | | 1 | 22 | | |
| 3 | INLIST ITERATOR | | | | | |
| 4 | TABLE ACCESS BY INDEX ROWID BATCHED| FOR_PIVOT | 2 | 44 | 2 (0)| 00:00:01 |
|* 5 | INDEX RANGE SCAN | IX_FOR_PIVOT | 2 | | 1 (0)| 00:00:01 |
-------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

5 - access("STAT_NAME"='DB CPU' OR "STAT_NAME"='DB time')

統計
----------------------------------------------------------
0 recursive calls
0 db block gets
3 consistent gets
0 physical reads
0 redo size
677 bytes sent via SQL*Net to client
52 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed
/code>

 

次に, UNPIVOT 向けデータの準備


表が削除されました. 

1 CREATE TABLE for_unpivot
2 AS
3 SELECT
4 db_time
5 ,db_cpu
6 ,bg_time
7 ,bg_cpu
8 FROM
9 (
10 SELECT
11 stat_name
12 ,value
13 FROM
14 v$sys_time_model
15 )
16 PIVOT
17 (
18 MAX(value)
19 FOR stat_name IN
20 (
21 'DB time' AS db_time
22 ,'DB CPU' AS db_cpu
23 ,'background elapsed time' AS bg_time
24 ,'background cpu time' AS bg_cpu
25 )
26* )

表が作成されました.

1* COMMIT

コミットが完了しました.

1 SELECT
2 *
3 FROM
4* for_unpivot

DB_TIME DB_CPU BG_TIME BG_CPU
---------- ---------- ---------- ----------
143522885 127634777 7381483 6340262
/code>

 

 

UNPIVOT では, PIVOT とは異なり, 実行計画上 UNPIVOT であることが読み取れます!!! ここ試験に出ますよ!(嘘w


  1  SELECT
2 stat_name
3 , value
4 FROM
5 for_unpivot
6 UNPIVOT
7 (
8 value FOR stat_name IN
9 (
10 db_time
11 , db_cpu
12 , bg_time
13 , bg_cpu
14 )
15 )
16* ORDER BY stat_name

STAT_NAME VALUE
------------------------------ ----------
BG_CPU 6340262
BG_TIME 7381483
DB_CPU 127634777
DB_TIME 143522885

実行計画
----------------------------------------------------------
Plan hash value: 3659757171

------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 4 | 72 | 6 (17)| 00:00:01 |
| 1 | SORT ORDER BY | | 4 | 72 | 6 (17)| 00:00:01 |
|* 2 | VIEW | | 4 | 72 | 5 (0)| 00:00:01 |
| 3 | UNPIVOT | | | | | |
| 4 | TABLE ACCESS FULL| FOR_UNPIVOT | 1 | 26 | 3 (0)| 00:00:01 |
------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

2 - filter("unpivot_view_005"."VALUE" IS NOT NULL)

統計
----------------------------------------------------------
0 recursive calls
0 db block gets
2 consistent gets
0 physical reads
0 redo size
781 bytes sent via SQL*Net to client
52 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
1 sorts (memory)
0 sorts (disk)
4 rows processed
/code>

 

ということで,  Operation には, なぜ, UNPIVOT は現れるのに, PIVOT が現れないのだろう. . . その謎を求め, 一向は洞窟の奥深くへ進んでいくのであった. . . .

 

昔からサポートされている PIVOT / UNPIVOT ですが, 改めて実行計画というレントゲンを診てみると, 新しい気づきとかあって良いですね.

 

参考 SQL Language Reference / PIVOT and UNPIVOT

 

 

Oracle Database 11g:Oracle ACEディレクター, Arup Nanda - PIVOT and UNPIVOT

 

 

ということで, 明日の担当は, またまた私ですw

 

 

 


Related article on Mac De Oracle ・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 1 / TABLE FULL SCAN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 2 / INDEX UNIQUE SCAN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 3 / INDEX RANGE SCAN, Index Only Scan
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 4 / INDEX RANGE SCAN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 5 / INDEX RANGE SCAN, INLIST ITERATOR
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 6 / INDEX FAST SCAN, Index Only Scan
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 7 / INDEX FULL SCAN,Index Only Scan
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 8 / INDEX SKIP SCAN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 9 / TABLE ACCESS INMEMORY FULL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 10 / NESTED LOOP JOIN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 11 / MERGE JOIN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 12 / HASH JOIN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 13 / HASH JOIN OUTER
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 14 / HASH JOIN FULL OUTER
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 15 / PX, TABLE ACCESS FULL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 16 / CONCATENATION
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 17 / SORT UNIQUE, UNION-ALL = UNION
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 18 / UNION-ALL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 19 / INTERSECTION
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 20 / MINUS
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 21 / WINDOW NOSORT STOPKEY
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 22 / COUNT STOPKEY
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 23 / HASH JOIN - LEFT-DEEP JOIN vs RIGHT-DEEP JOIN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 24 / CONNECT BY NO FILTERING WITH START-WITH
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 25 / UNION ALL (RECURSIVE WITH) DEPTH FIRST, RECURSIVE WITH PUMP
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - おまけ#1 / STAR TRANSFORM, VECTOR TRANSFORM (DWH向け)
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - おまけ#2 / MERGE (UPSERT)
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - おまけ#3 / RDFView
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - おまけ#4 / INDEX FULL SCAN (MIN/MAX) - Index Only Scan
・実行計画は, SQL文のレントゲン写真だ! No.30 - LOAD TABLE CONVENTIONAL vs. LOAD AS SELECT
・実行計画は, SQL文のレントゲン写真だ! No.31 - TEMP TABLE TRANSFORMATION LOAD AS SELECT (CURSOR DURATION MEMORY)
・実行計画は, SQL文のレントゲン写真だ! No.32 - EXTERNAL TABLE ACCESS FULL / INMEMORY FULL
・実行計画は, SQL文のレントゲン写真だ! No.33 - BITMAP CONVERSION TO ROWIDS
・実行計画は, SQL文のレントゲン写真だ! No.34 - 似て非なるもの USE_CONCAT と OR_EXPAND ヒント と 手書きSQLのレントゲンの見分け方
・実行計画は, SQL文のレントゲン写真だ! No.35 - 似て非なるもの USE_CONCAT と OR_EXPANDヒントとパラレルクエリー
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 1 / No.36 / INTERSECT ALL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 2 / No.37 / MINUS ALL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 3 / No.38 / EXCEPT and EXCEPT ALL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 4 / No.39 / In-Memory Hybrid Scans

 

| | | コメント (0)

2022年12月 4日 (日)

実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 4 / No.39 / In-Memory Hybrid Scans

reviously on Mac De Oracle...
Day3は, Oracleの場合の EXCEPT/EXCEPT ALLは, 内部で MINUS/MINUS ALLになってるね. やってること同じだし. SQLのキーワードが違うだけなので, まあ, そりゃそうだという感じの実装になっているようだ.
というところを, 実行計画という名のレントゲンで確認しましたw

 

それでは, Day 4 の窓を開けましょう!

タイトルの通り, SQL単体ではなく, 実行計画上の新機能を診てみたいと思います. 狙い通りのレントゲンが取れるでしょうか. . . .

 

いつもと同じように 21c で確認します.


SCOTT@orclpdb1> select banner from v$version;

BANNER
----------------------------------------------------------------------
Oracle Database 21c Enterprise Edition Release 21.0.0.0.0 - Production

 

なお, 今回は, in-memory機能を利用するのでお約束の inmemory_size パラメータを確認しておきますよ.
以前, 何度かセットし忘れで in-memory 発動せず!
みたいなこと何度かやらかしてたのことを思い出しますw
ちなみに, この inmemory_size パラメータのデフォルトは 0


SYS@ORCLCDB> show parameter inmemory_size

NAME TYPE VALUE
------------------------------------ --------------------------------- ------------------------------
inmemory_size big integer 112M

 

まず, 準備から. データサイズが大したことないのと, データのカーディナリティもあまり深く考えてなかったのでイマイチかも知れません.

in-memory columnsと no in-memory columnsを持つ表を作成します. In-Memory Hybrid Scansは, 同一表の列がインメモリーだったり非インメモリーだったという状況で効果のある操作なので. :)


SCOTT@orclpdb1> @day4

表が削除されました.

経過: 00:00:04.17

1 CREATE TABLE day4
2 (
3 no_im_id NUMBER
4 , im_subid NUMBER
5 , no_im_str VARCHAR2(1000)
6 , im_str VARCHAR2(1000)
7 )
8 INMEMORY PRIORITY HIGH
9 MEMCOMPRESS FOR CAPACITY LOW
10 NO INMEMORY (
11 no_im_id
12 , no_im_str
13* )

表が作成されました.

経過: 00:00:00.02


1 BEGIN
2 FOR i IN 1..100000 LOOP
3 INSERT
4 INTO day4
5 VALUES(i, i+1000, LPAD(TO_CHAR(i),1000,'*'), LPAD(TO_CHAR(i+1000),1000.,'*'));
6 IF MOD(i,100) = 0
7 THEN
8 COMMIT;
9 END IF;
10 END LOOP;
11* END;

PL/SQLプロシージャが正常に完了しました.

経過: 00:00:16.88

 

定義を確認しておきましょうね.


  1  SELECT
2 table_name
3 , inmemory_compression "compression"
4 , inmemory_priority "priority"
5 FROM
6 user_tables
7 WHERE
8* table_name = 'DAY4'

TABLE_NAME compression priority
---------- --------------------------------------------------- ------------------------
DAY4 FOR CAPACITY LOW HIGH

経過: 00:00:00.00


1 SELECT
2 obj_num
3 , segment_column_id
4 , inmemory_compression
5 FROM
6 v$im_column_level im
7 INNER JOIN dba_objects do
8 ON
9 im.obj_num = do.object_id
10 WHERE
11* do.object_name = 'DAY4'

OBJ_NUM SEGMENT_COLUMN_ID INMEMORY_COM
---------- ----------------- ------------
77251 1 NO INMEMORY
77251 2 DEFAULT
77251 3 NO INMEMORY
77251 4 DEFAULT

経過: 00:00:00.01

 

データのPOPULATEを行います. 必要な列はすべてインメモリーにPOPULATEされたようです:)


  1  SELECT
2 /*+
3 FULL(day4)
4 NO_PARALLEL(day4)
5 */
6 COUNT(*)
7 FROM
8* day4

COUNT(*)
----------
100000

経過: 00:00:00.08


1 SELECT
2 segment_name
3 , inmemory_size
4 , bytes_not_populated
5 FROM
6* v$im_segments

SEGMENT_NAME INMEMORY_SIZE BYTES_NOT_POPULATED
------------ ------------- -------------------
DAY4 15990784 0

経過: 00:00:00.01

 

準備運動からw SELECT LISTにある2列は, どちらも非インメモリー列なので, 結果としてはよく見る table full scanになります. 当然の結果ですね.


  1  SELECT
2 MAX(no_im_id)
3 , COUNT(no_im_str)
4 FROM
5* day4

MAX(NO_IM_ID) COUNT(NO_IM_STR)
------------- ----------------
100000 100000

経過: 00:00:00.09

実行計画
----------------------------------------------------------
Plan hash value: 2217228964

---------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 515 | 9104 (1)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | 515 | | |
| 2 | TABLE ACCESS FULL| DAY4 | 87887 | 43M| 9104 (1)| 00:00:01 |
---------------------------------------------------------------------------

Note
-----
- dynamic statistics used: dynamic sampling (level=2)

統計
----------------------------------------------------------
0 recursive calls
0 db block gets
33544 consistent gets
0 physical reads
0 redo size
685 bytes sent via SQL*Net to client
52 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed

 

ベタな検証その2. 今度は, SELECT LISTの2列はどちらもインメモリー列です. 結果はみなさんの想像の通り, TABLE ACCESS INMEMORY FULLです.
consistent getsが非常に少なくなっています. (処理時間的なところはまあ, データ量次第なので大きな差にはなってないですね. 深く分析していないので, 別の機会にデータ量などを変えつつ検証しておきたいですよね, この辺り)


  1  SELECT
2 MAX(im_subid)
3 , COUNT(im_str)
4 FROM
5* day4

MAX(IM_SUBID) COUNT(IM_STR)
------------- -------------
101000 100000

経過: 00:00:00.10

実行計画
----------------------------------------------------------
Plan hash value: 2217228964

------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 515 | 382 (13)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | 515 | | |
| 2 | TABLE ACCESS INMEMORY FULL| DAY4 | 87887 | 43M| 382 (13)| 00:00:01 |
------------------------------------------------------------------------------------

Note
-----
- dynamic statistics used: dynamic sampling (level=2)

統計
----------------------------------------------------------
0 recursive calls
0 db block gets
11 consistent gets
0 physical reads
0 redo size
683 bytes sent via SQL*Net to client
52 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed

 

次に, in-memory hybrid scan発動の条件に該当しない例をみてみましょう.
このクエリーでは, SELECT LISTにインメモリー列のみ. WHERE句に非インメモリー列のみがありますが, これは, in-memory hybrid scan発動条件に一致しません.

結果として, 通常のTABLE ACCESS FULLとなってしまいますので注意しましょうね.


  1  SELECT
2 MAX(im_subid)
3 , COUNT(im_str)
4 FROM
5 day4
6 WHERE
7* no_im_id < 5000

MAX(IM_SUBID) COUNT(IM_STR)
------------- -------------
5999 4999

経過: 00:00:00.08

実行計画
----------------------------------------------------------
Plan hash value: 2217228964

---------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 528 | 9104 (1)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | 528 | | |
|* 2 | TABLE ACCESS FULL| DAY4 | 4794 | 2471K| 9104 (1)| 00:00:01 |
---------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

2 - filter("NO_IM_ID"<5000)

Note
-----
- dynamic statistics used: dynamic sampling (level=2)

統計
----------------------------------------------------------
0 recursive calls
0 db block gets
33544 consistent gets
0 physical reads
0 redo size
684 bytes sent via SQL*Net to client
52 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed

 

最後に, 本日の主役の登場です!

SELECT LISTには, 非インメモリー列のみ. WHERE句には, インメモリー列のみが利用されています. これが発動条件です.
結果として, これまで, みたことのないOperationである,  TABLE ACCESS INMEMORY FULL (HYBRID) が現れています. ふむふむ.
consistent getsもかなり少ないですし, このケースでは, 処理時間も早くなっていますね. ますます別途詳しく調査したくなりまし:)

なんとなくですが, この in-memory hybrid scan を見て, MySQL Heatwaveが浮かんできますよね. 諸々応用しているのでしょうかね...


  1  SELECT
2 MAX(no_im_id)
3 , COUNT(no_im_str)
4 FROM
5 day4
6 WHERE
7* im_subid < 5000

MAX(NO_IM_ID) COUNT(NO_IM_STR)
------------- ----------------
3999 3999

経過: 00:00:00.02

実行計画
----------------------------------------------------------
Plan hash value: 2217228964

---------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 528 | 9104 (1)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | 528 | | |
|* 2 | TABLE ACCESS INMEMORY FULL (HYBRID)| DAY4 | 1598 | 823K| 9104 (1)| 00:00:01 |
---------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

2 - filter("IM_SUBID"<5000)

Note
-----
- dynamic statistics used: dynamic sampling (level=2)

統計
----------------------------------------------------------
0 recursive calls
0 db block gets
1342 consistent gets
0 physical reads
0 redo size
687 bytes sent via SQL*Net to client
52 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed

 


アドベントカレンダー, 全部俺をやらなきゃ, 師走は走り回るほど忙しいわけではないはずだったのになぁw と, 遠ーーーくを見てるw

では, また,

明日の担当も! 私です.


参考 Database In-Memory Office Hours / In-Memory Hybrid Scans

 

そして, Ask Tomがこんな感じになるとは:) いい感じですよね.
Database In-Memory Office Hours / ASK TOM

Database In-Memory Guide / 21c


Related article on Mac De Oracle
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 1 / TABLE FULL SCAN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 2 / INDEX UNIQUE SCAN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 3 / INDEX RANGE SCAN, Index Only Scan
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 4 / INDEX RANGE SCAN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 5 / INDEX RANGE SCAN, INLIST ITERATOR
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 6 / INDEX FAST SCAN, Index Only Scan
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 7 / INDEX FULL SCAN,Index Only Scan
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 8 / INDEX SKIP SCAN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 9 / TABLE ACCESS INMEMORY FULL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 10 / NESTED LOOP JOIN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 11 / MERGE JOIN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 12 / HASH JOIN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 13 / HASH JOIN OUTER
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 14 / HASH JOIN FULL OUTER
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 15 / PX, TABLE ACCESS FULL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 16 / CONCATENATION
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 17 / SORT UNIQUE, UNION-ALL = UNION
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 18 / UNION-ALL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 19 / INTERSECTION
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 20 / MINUS
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 21 / WINDOW NOSORT STOPKEY
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 22 / COUNT STOPKEY
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 23 / HASH JOIN - LEFT-DEEP JOIN vs RIGHT-DEEP JOIN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 24 / CONNECT BY NO FILTERING WITH START-WITH
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 25 / UNION ALL (RECURSIVE WITH) DEPTH FIRST, RECURSIVE WITH PUMP
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - おまけ#1 / STAR TRANSFORM, VECTOR TRANSFORM (DWH向け)
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - おまけ#2 / MERGE (UPSERT)
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - おまけ#3 / RDFView
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - おまけ#4 / INDEX FULL SCAN (MIN/MAX) - Index Only Scan
・実行計画は, SQL文のレントゲン写真だ! No.30 - LOAD TABLE CONVENTIONAL vs. LOAD AS SELECT
・実行計画は, SQL文のレントゲン写真だ! No.31 - TEMP TABLE TRANSFORMATION LOAD AS SELECT (CURSOR DURATION MEMORY)
・実行計画は, SQL文のレントゲン写真だ! No.32 - EXTERNAL TABLE ACCESS FULL / INMEMORY FULL
・実行計画は, SQL文のレントゲン写真だ! No.33 - BITMAP CONVERSION TO ROWIDS
・実行計画は, SQL文のレントゲン写真だ! No.34 - 似て非なるもの USE_CONCAT と OR_EXPAND ヒント と 手書きSQLのレントゲンの見分け方
・実行計画は, SQL文のレントゲン写真だ! No.35 - 似て非なるもの USE_CONCAT と OR_EXPANDヒントとパラレルクエリー
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 1 / No.36 / INTERSECT ALL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 2 / No.37 / MINUS ALL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 3 / No.38 / EXCEPT and EXCEPT ALL

| | | コメント (0)

2022年12月 3日 (土)

実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 3 / No.38 / EXCEPT and EXCEPT ALL

Day 2は, Oracleの方言である集合演算 MINUS ALL の実行計画というレントゲンを確認しました. MINUSでも19cまでは, ALLはサポートされていませんでした. サポートされるようになった理由は, 今日レントゲンを見ていくEXCEPT/EXCEPT ALLのサポートが影響してそうですね. やることは同じですので:)

では, お約束のw
なお, 今回のSQL文の結果セットはソートされているように並んでいますが, たまたま昇順に並んでいるだけなので, ソートが必要な場合は. 必ず. ORDER BY句を付けてくださいね.

ということで, Day 3の窓を開けましょう!

MINUSは方言ですが, 標準SQLに合わせた形で同様の機能を持つEXCEPTがサポートされました. また, 方言であるMINUSも同様にサポートは継続されています. 下位互換の意味もあると思いますが, MINUS/MINUS ALLの実行計画というレントゲンと比較しながら見ると良いと思います.

 

いつもと同じように 21c で確認します.

SCOTT@orclpdb1> select banner from v$version;

BANNER
----------------------------------------------------------------------
Oracle Database 21c Enterprise Edition Release 21.0.0.0.0 - Production

 

Day 1と同じ表とデータを利用します(再掲). 意図的に, 該当表には索引を作成していません.

SCOTT@orclpdb1> @day3
1 SELECT
2 num
3 FROM
4* groupa

NUM
----------
1
2
2
3
4
4
5

7行が選択されました.

1 SELECT
2 num
3 FROM
4* groupb

NUM
----------
0
2
3
3
4
4
4
7

8行が選択されました.

 

最初は, EXCEPT ALL から診てみます 実行計画を見て〜〜〜〜〜〜くださ〜〜〜〜い, 驚きますよ!!!! 

 

内部では, MINUS ALL に書き換えられている!! これが MINUS ALLをサポートした理由ですねw やってることが同じなので, まあ無駄が無いのは確かだw

EXCEPT ALLが内部で, MINUS ALLに書き換えられているのでしょうか. 今回はトレースを取得して追いかける余力はないので, その辺りは別の機会にでも.
また, このケースでもHASH操作が現れています.

  1  SELECT
2 num
3 FROM
4 groupa
5 EXCEPT ALL
6 SELECT
7 num
8 FROM
9* groupb

NUM
----------
1
2
5

実行計画
----------------------------------------------------------
Plan hash value: 895579533

-----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 7 | 45 | 8 (25)| 00:00:01 |
| 1 | MINUS ALL HASH | | | | | |
| 2 | TABLE ACCESS FULL| GROUPA | 7 | 21 | 3 (0)| 00:00:01 |
| 3 | TABLE ACCESS FULL| GROUPB | 8 | 24 | 3 (0)| 00:00:01 |
-----------------------------------------------------------------------------

統計
----------------------------------------------------------
0 recursive calls
0 db block gets
12 consistent gets
0 physical reads
0 redo size
648 bytes sent via SQL*Net to client
52 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
3 rows processed

 

次は, EXCEPT 同様に, HASH操作を伴うMINUSとして現れています. やっている集合演算も同じですから, 実行計画だけ見せられたら, EXCEPTなのかMINUSなのかは区別できないでしょうね. 区別する必要もないわけですけども.
プロジェクトのSQL標準がどちらを使うか定めていれば, どちらかなのかは想像できるかも知れませんがw

  1  SELECT
2 num
3 FROM
4 groupa
5 EXCEPT
6 SELECT
7 num
8 FROM
9* groupb

NUM
----------
1
5

実行計画
----------------------------------------------------------
Plan hash value: 2352437695

-----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 7 | 45 | 8 (25)| 00:00:01 |
| 1 | MINUS HASH | | | | | |
| 2 | TABLE ACCESS FULL| GROUPA | 7 | 21 | 3 (0)| 00:00:01 |
| 3 | TABLE ACCESS FULL| GROUPB | 8 | 24 | 3 (0)| 00:00:01 |
-----------------------------------------------------------------------------

統計
----------------------------------------------------------
0 recursive calls
0 db block gets
12 consistent gets
0 physical reads
0 redo size
640 bytes sent via SQL*Net to client
52 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
2 rows processed

 

次に, 索引アクセスがある場合はどうなるかを確認します. 利用するデータや表はDay1と同じです.(再掲) なお, 索引等の情報は前回のエントリーをご覧ください

  1  SELECT
2 unique_id
3 FROM
4 tab311
5 WHERE
6* unique_id BETWEEN 1 AND 50

UNIQUE_ID
----------
1
1
1
2
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50

53行が選択されました.

1 SELECT
2 unique_id
3 FROM
4 tab312
5 WHERE
6* unique_id BETWEEN 25 AND 75

UNIQUE_ID
----------
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75

51行が選択されました.

まずは, EXCEPT ALLから Table Full Scanであろうが, Index Range Scanであろうが, HASH操作になる点も含め, MINUS ALLそのものですね:)

  1  SELECT
2 unique_id
3 FROM
4 tab311
5 WHERE
6 unique_id BETWEEN 1 AND 50
7 EXCEPT ALL
8 SELECT
9 unique_id
10 FROM
11 tab312
12 WHERE
13* unique_id BETWEEN 25 AND 75

UNIQUE_ID
----------
1
1
1
2
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

27行が選択されました.

実行計画
----------------------------------------------------------
Plan hash value: 381125746

---------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 50 | 612 | 8 (25)| 00:00:01 |
| 1 | MINUS ALL HASH | | | | | |
|* 2 | INDEX RANGE SCAN| TAB311_PK | 50 | 300 | 3 (0)| 00:00:01 |
|* 3 | INDEX RANGE SCAN| IX01_TAB312 | 52 | 312 | 3 (0)| 00:00:01 |
---------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

2 - access("UNIQUE_ID">=1 AND "UNIQUE_ID"<=50)
3 - access("UNIQUE_ID">=25 AND "UNIQUE_ID"<=75)v
統計
----------------------------------------------------------
0 recursive calls
0 db block gets
6 consistent gets
0 physical reads
0 redo size
1040 bytes sent via SQL*Net to client
63 bytes received via SQL*Net from client
3 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
27 rows processed

 

EXCEPTの実行計画という名のレントゲンはどうでしょう?

 

思った通り MINUS と同じ実行計画が現れています

  1  SELECT
2 unique_id
3 FROM
4 tab311
5 WHERE
6 unique_id BETWEEN 1 AND 50
7 EXCEPT
8 SELECT
9 unique_id
10 FROM
11 tab312
12 WHERE
13* unique_id BETWEEN 25 AND 75

UNIQUE_ID
----------
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

24行が選択されました.

実行計画
----------------------------------------------------------
Plan hash value: 2829086308

-----------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 50 | 612 | 8 (25)| 00:00:01 |
| 1 | MINUS | | | | | |
| 2 | SORT UNIQUE NOSORT| | | | | |
|* 3 | INDEX RANGE SCAN | TAB311_PK | 50 | 300 | 3 (0)| 00:00:01 |
| 4 | SORT UNIQUE NOSORT| | | | | |
|* 5 | INDEX RANGE SCAN | IX01_TAB312 | 52 | 312 | 3 (0)| 00:00:01 |
-----------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

3 - access("UNIQUE_ID">=1 AND "UNIQUE_ID"<=50)
5 - access("UNIQUE_ID">=25 AND "UNIQUE_ID"<=75)

統計
----------------------------------------------------------
0 recursive calls
0 db block gets
9 consistent gets
0 physical reads
0 redo size
993 bytes sent via SQL*Net to client
63 bytes received via SQL*Net from client
3 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
24 rows processed

 

19cでは, EXCEPT/EXCEPT ALLともに未サポートなので, どちらもシンタックスエラーです. 当然と言えば当然の結果です:)

SCOTT@orcl> select banner from v$version;

BANNER
--------------------------------------------------------------------------------
Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production

 

1  SELECT
2 unique_id
3 FROM
4 tab311
5 WHERE
6 unique_id BETWEEN 1 AND 50
7 EXCEPT ALL
8 SELECT
9 unique_id
10 FROM
11 tab312
12 WHERE
13* unique_id BETWEEN 25 AND 75
EXCEPT ALL
*
ERROR at line 7:
ORA-00933: SQL command not properly ended

 

1  SELECT
2 unique_id
3 FROM
4 tab311
5 WHERE
6 unique_id BETWEEN 1 AND 50
7 EXCEPT
8 SELECT
9 unique_id
10 FROM
11 tab312
12 WHERE
13* unique_id BETWEEN 25 AND 75
EXCEPT
*
ERROR at line 7:
ORA-00933: SQL command not properly ended

 


まだまだ, Day 3 ですねーーーーw

 

意外に多くの, ITアドベントカレンダー全部俺, または, 準全部俺(タイトルに全部俺って書いてないだけで, 多分, 全部俺になっちゃうでしょうーーっなカレンダー立てた方含め,
楽しんでやってきましょう.  w

 

明日の Day 4の担当は, なんとーーーっ, 私ですw

 

では, また.


参考)

19c UNION [ALL], INTERSECTおよびMINUS演算子

21c The Set Operators


Related article on Mac De Oracle
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 1 / TABLE FULL SCAN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 2 / INDEX UNIQUE SCAN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 3 / INDEX RANGE SCAN, Index Only Scan
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 4 / INDEX RANGE SCAN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 5 / INDEX RANGE SCAN, INLIST ITERATOR
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 6 / INDEX FAST SCAN, Index Only Scan
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 7 / INDEX FULL SCAN,Index Only Scan
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 8 / INDEX SKIP SCAN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 9 / TABLE ACCESS INMEMORY FULL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 10 / NESTED LOOP JOIN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 11 / MERGE JOIN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 12 / HASH JOIN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 13 / HASH JOIN OUTER
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 14 / HASH JOIN FULL OUTER
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 15 / PX, TABLE ACCESS FULL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 16 / CONCATENATION
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 17 / SORT UNIQUE, UNION-ALL = UNION
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 18 / UNION-ALL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 19 / INTERSECTION
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 20 / MINUS
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 21 / WINDOW NOSORT STOPKEY
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 22 / COUNT STOPKEY
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 23 / HASH JOIN - LEFT-DEEP JOIN vs RIGHT-DEEP JOIN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 24 / CONNECT BY NO FILTERING WITH START-WITH
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 25 / UNION ALL (RECURSIVE WITH) DEPTH FIRST, RECURSIVE WITH PUMP
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - おまけ#1 / STAR TRANSFORM, VECTOR TRANSFORM (DWH向け)
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - おまけ#2 / MERGE (UPSERT)
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - おまけ#3 / RDFView
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - おまけ#4 / INDEX FULL SCAN (MIN/MAX) - Index Only Scan
・実行計画は, SQL文のレントゲン写真だ! No.30 - LOAD TABLE CONVENTIONAL vs. LOAD AS SELECT
・実行計画は, SQL文のレントゲン写真だ! No.31 - TEMP TABLE TRANSFORMATION LOAD AS SELECT (CURSOR DURATION MEMORY)
・実行計画は, SQL文のレントゲン写真だ! No.32 - EXTERNAL TABLE ACCESS FULL / INMEMORY FULL
・実行計画は, SQL文のレントゲン写真だ! No.33 - BITMAP CONVERSION TO ROWIDS
・実行計画は, SQL文のレントゲン写真だ! No.34 - 似て非なるもの USE_CONCAT と OR_EXPAND ヒント と 手書きSQLのレントゲンの見分け方
・実行計画は, SQL文のレントゲン写真だ! No.35 - 似て非なるもの USE_CONCAT と OR_EXPANDヒントとパラレルクエリー
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 1 / No.36 / INTERSECT ALL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 2 / No.37 / MINUS ALL

 

| | | コメント (0)

2022年12月 2日 (金)

実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 2 / No.37 / MINUS ALL

Previously on Mac De Oracle...
帰ってきた! 実行計画は、SQL文のレントゲン写真だ! Oracle Database (全部俺) Advent Calendar 2022始まっちゃいましたw

Day 1は, 19cまでのINTERSECTに加え, 21c(正確には20c)からサポートされたINTRESECT ALLの実行計画というレントゲンはどう見えるのか?を確認しました.
21cからはHASH操作が加わっているとことは興味深いので, HASH操作について観点を変えて実行計画というレントゲンを見ておかねば, という気がしていますね. 今のところ, おまけとして考えているところですw(ネタがキツくなったら普通にやるかもw)


ということで, Day 2の窓を開けましょう!

なお, 今回のSQL文の結果セットはソートされているように並んでいますが, たまたま昇順に並んでいるだけなので, ソートが必要な場合は, 必ず, ORDER BY句を付けてくださいね.


INTERSECTと同様に, 19cまでは, ALLがサポートされていなかったOracleの方言である集合演算 MINUS にも MINUS ALLがサポートされました.
21c以降で利用できます. 実際には20cですが世に出てくることは無かったわけで, 事実上21c以降といってもいいですよね
(おそらく)

21cでみてみましょう.

SCOTT@orclpdb1> select banner from v$version;

BANNER
----------------------------------------------------------------------
Oracle Database 21c Enterprise Edition Release 21.0.0.0.0 - Production


Day 1と同じ表とデータを利用します(再掲). 意図的に, 該当表には索引を作成していません.

SCOTT@orclpdb1> @day2
1 SELECT
2 num
3 FROM
4* groupa

NUM
----------
1
2
2
3
4
4
5

7行が選択されました.

1 SELECT
2 num
3 FROM
4* groupb

NUM
----------
0
2
3
3
4
4
4
7

8行が選択されました.


今回の主役, MINUS ALLの実行計画という名のレントゲンから診てみます.

OperationにMINUS ALLと現れています. わかりやすいですね. また, ここでもHASH操作が現れています. 21cの特徴でもあるので頭の片隅に置いといた方が良さそうです.

  1  SELECT
2 num
3 FROM
4 groupa
5 MINUS ALL
6 SELECT
7 num
8 FROM
9* groupb

NUM
----------
1
2
5

実行計画
----------------------------------------------------------
Plan hash value: 895579533

-----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 7 | 45 | 8 (25)| 00:00:01 |
| 1 | MINUS ALL HASH | | | | | |
| 2 | TABLE ACCESS FULL| GROUPA | 7 | 21 | 3 (0)| 00:00:01 |
| 3 | TABLE ACCESS FULL| GROUPB | 8 | 24 | 3 (0)| 00:00:01 |
-----------------------------------------------------------------------------


統計
----------------------------------------------------------
0 recursive calls
0 db block gets
12 consistent gets
0 physical reads
0 redo size
648 bytes sent via SQL*Net to client
52 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
3 rows processed


次にこれまでもサポートされていた, MINUSの実行計画という名のレントゲンから診てみます.

これも判断しやすいですね. キーワードとなるMINUSが, Operationに現れています. 同様に, HASHも.

  1  SELECT
2 num
3 FROM
4 groupa
5 MINUS
6 SELECT
7 num
8 FROM
9* groupb

NUM
----------
1
5


実行計画
----------------------------------------------------------
Plan hash value: 2352437695

-----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 7 | 45 | 8 (25)| 00:00:01 |
| 1 | MINUS HASH | | | | | |
| 2 | TABLE ACCESS FULL| GROUPA | 7 | 21 | 3 (0)| 00:00:01 |
| 3 | TABLE ACCESS FULL| GROUPB | 8 | 24 | 3 (0)| 00:00:01 |
-----------------------------------------------------------------------------


統計
----------------------------------------------------------
0 recursive calls
0 db block gets
12 consistent gets
0 physical reads
0 redo size
640 bytes sent via SQL*Net to client
52 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
2 rows processed


次に, 索引アクセスがある場合はどうなるかを確認します. 利用するデータや表はDay1と同じです.(再掲)
なお, 索引等の情報は前回のエントリーをご覧ください

  1  SELECT
2 unique_id
3 FROM
4 tab311
5 WHERE
6* unique_id BETWEEN 1 AND 50

UNIQUE_ID
----------
1
1
1
2
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50

53行が選択されました.

1 SELECT
2 unique_id
3 FROM
4 tab312
5 WHERE
6* unique_id BETWEEN 25 AND 75

UNIQUE_ID
----------
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75

51行が選択されました.


まずは, MINUS ALLから

Table Full Scanであろうが, Index Range Scanであろうが, HASH操作になるというのも特徴のようですね. 興味深いです.

  1  SELECT
2 unique_id
3 FROM
4 tab311
5 WHERE
6 unique_id BETWEEN 1 AND 50
7 MINUS ALL
8 SELECT
9 unique_id
10 FROM
11 tab312
12 WHERE
13* unique_id BETWEEN 25 AND 75

UNIQUE_ID
----------
1
1
1
2
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

27行が選択されました.


実行計画
----------------------------------------------------------
Plan hash value: 381125746

---------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 50 | 612 | 8 (25)| 00:00:01 |
| 1 | MINUS ALL HASH | | | | | |
|* 2 | INDEX RANGE SCAN| TAB311_PK | 50 | 300 | 3 (0)| 00:00:01 |
|* 3 | INDEX RANGE SCAN| IX01_TAB312 | 52 | 312 | 3 (0)| 00:00:01 |
---------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

2 - access("UNIQUE_ID">=1 AND "UNIQUE_ID"<=50)
3 - access("UNIQUE_ID">=25 AND "UNIQUE_ID"<=75)


統計
----------------------------------------------------------
0 recursive calls
0 db block gets
6 consistent gets
0 physical reads
0 redo size
1040 bytes sent via SQL*Net to client
63 bytes received via SQL*Net from client
3 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
27 rows processed

MINUSはどうでしょう?

お! やはり, 挙動が変わりますね. これは, 索引を利用することを重要視した結果と言えそうです. SORT UNIQUE NOSORTなので, ソートなしでUNIQUE操作を行っています. ソートのバイバスを重要視したということになりますね.
ここも非常に興味深い動きですね.

  1  SELECT
2 unique_id
3 FROM
4 tab311
5 WHERE
6 unique_id BETWEEN 1 AND 50
7 MINUS
8 SELECT
9 unique_id
10 FROM
11 tab312
12 WHERE
13* unique_id BETWEEN 25 AND 75

UNIQUE_ID
----------
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

24行が選択されました.


実行計画
----------------------------------------------------------
Plan hash value: 2829086308

-----------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 50 | 612 | 8 (25)| 00:00:01 |
| 1 | MINUS | | | | | |
| 2 | SORT UNIQUE NOSORT| | | | | |
|* 3 | INDEX RANGE SCAN | TAB311_PK | 50 | 300 | 3 (0)| 00:00:01 |
| 4 | SORT UNIQUE NOSORT| | | | | |
|* 5 | INDEX RANGE SCAN | IX01_TAB312 | 52 | 312 | 3 (0)| 00:00:01 |
-----------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

3 - access("UNIQUE_ID">=1 AND "UNIQUE_ID"<=50)
5 - access("UNIQUE_ID">=25 AND "UNIQUE_ID"<=75)


統計
----------------------------------------------------------
0 recursive calls
0 db block gets
9 consistent gets
0 physical reads
0 redo size
993 bytes sent via SQL*Net to client
63 bytes received via SQL*Net from client
3 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
24 rows processed


では, 最後に, 19cでも実行計画という名のレントゲンを診ておきたいと思います.

SYS@orclcdb> select banner from v$version;

BANNER
--------------------------------------------------------------------------------
Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production


MINUS ALLは未サポートなので, シンタックスエラーになります.

SCOTT@orcl> @day2
1 SELECT
2 num
3 FROM
4 groupa
5 MINUS ALL
6 SELECT
7 num
8 FROM
9* groupb
MINUS ALL
*
ERROR at line 5:
ORA-00928: missing SELECT keyword


以前からサポートされているMINUS, やはり, SORT UNIQUE操作が利用されています. 21cのMINUSとは異なる動きのあることが見えてきます.

1  SELECT
2 num
3 FROM
4 groupa
5 MINUS
6 SELECT
7 num
8 FROM
9* groupb

NUM
----------
1
5

Execution Plan
----------------------------------------------------------
Plan hash value: 2070324559

------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 7 | 45 | 8 (25)| 00:00:01 |
| 1 | MINUS | | | | | |
| 2 | SORT UNIQUE | | 7 | 21 | 4 (25)| 00:00:01 |
| 3 | TABLE ACCESS FULL| GROUPA | 7 | 21 | 3 (0)| 00:00:01 |
| 4 | SORT UNIQUE | | 8 | 24 | 4 (25)| 00:00:01 |
| 5 | TABLE ACCESS FULL| GROUPB | 8 | 24 | 3 (0)| 00:00:01 |
------------------------------------------------------------------------------


Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
12 consistent gets
0 physical reads
0 redo size
599 bytes sent via SQL*Net to client
421 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
2 sorts (memory)
0 sorts (disk)
2 rows processed

アドベントカレンダー, 今のところ順調だが, 25回分全てのネタを書き終わったわけではないので, 先はナゲーーーーーーーなーーーと, 遠ーーーくを見てるw

Day3の担当は, 私です. よろしくお願いしますw

では, また, 明日.



参考)

19c
UNION [ALL], INTERSECTおよびMINUS演算子

21c
The Set Operators



Related article on Mac De Oracle
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 1 / TABLE FULL SCAN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 2 / INDEX UNIQUE SCAN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 3 / INDEX RANGE SCAN, Index Only Scan
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 4 / INDEX RANGE SCAN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 5 / INDEX RANGE SCAN, INLIST ITERATOR
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 6 / INDEX FAST SCAN, Index Only Scan
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 7 / INDEX FULL SCAN,Index Only Scan
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 8 / INDEX SKIP SCAN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 9 / TABLE ACCESS INMEMORY FULL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 10 / NESTED LOOP JOIN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 11 / MERGE JOIN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 12 / HASH JOIN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 13 / HASH JOIN OUTER
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 14 / HASH JOIN FULL OUTER
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 15 / PX, TABLE ACCESS FULL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 16 / CONCATENATION
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 17 / SORT UNIQUE, UNION-ALL = UNION
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 18 / UNION-ALL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 19 / INTERSECTION
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 20 / MINUS
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 21 / WINDOW NOSORT STOPKEY