« 2024年12月 | トップページ | 2025年2月 »

2025年1月30日 (木)

実行計画は, SQL文のレントゲン写真だ! No.65 / 忘れ去られたオプティマイザーヒントとTABLE ACCESS BY USER ROWID

2025年最初のレントゲン写真ネタです。今日は、みなさん(私も忘れてましたw)、忘れちゃってると思う(あまり使うこともないので)ROWIDの話題で、2025年最初のSQLネタエントリーにしたいと思います。(他のネタを考えていたのですが、軽めのネタにしてみましたw)



ROWIDヒント、今現存公開されている最古のオンラインマニュアルでは、Oracle 7 Server 7.3.3 以降から9iのマニュアルに記載されています。(もっと前からあるよね〜。7.0のマニュアルとか流石に見つからないので確認できないですがw)
で、主役ではなくなりほぼ使われなくなったヒントとして、忘れ去られてしまうきっかけは、Oracle Database 10g以降のマニュアルに記載されなくなったことが大きいでしょうね。使うこともほぼ無いと言って良いヒントだからかなぁ
昔すぎて覚えてないですねw

他にも、使ってもらっては困る黒魔術的なヒントもマニュアルから隠されたりしたこともありました。v$sql_hintには残ってますが11g以降サポートされなくなりヒントを指定しても無視されるようになった有名なヒントですね。。。。w (まだ利用できたバージョンで、某氏が使おうとした黒魔術を必死で止めた思い出が蘇るw)
余談はこれぐらいで、本題へ。

現在確認できるオンラインマニュアルだと9iまで記載されていることが確認できます。
Oracle7 Server 7.3.3
Oracle7 Tuning, release 7.3.3 / Optimization Modes and Hints / Hints for Access Methods / ROWID

Oracle Database 8i 8.1.7
Oracle8i SQL リファレンス Vol.1 リリース 8.1 P.92 / ヒント / アクセス方法のヒント / ROWID

Oracle Database 9iR2
Oracle9i Database Performance Tuning Guide and Reference Release 2 (9.2) / ROWID


10g以降のマニュアルからは表記が消えています。ただし、v$sql_planには残っており、これまで通りに使えます(もそもそのアクセスパスを利用すること自体、かなりレアな状況ですよね :)
Oracle Database 10gR2
Oracle Database Online Documentation, 10g Release 2 (10.2) / Administration Database Performance Tuning Guide / 16 Using Optimizer Hints / 16.1.2.2 Hints for Access Paths

Oracle Database 11gR2
Oracle Database SQL言語リファレンス 11gリリース2 (11.2) / コメント / 表3-21 機能のカテゴリに分類したヒント


21cで確かめてみましょう。

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

SCOTT@orclpdb1> select * from v$sql_hint where name = 'ROWID';

NAME SQL_FEATUR CLASS INVERSE TARGET_LEVEL PROPERTY VERSION VERSION_OU CON_ID
---------- ---------- ---------- ---------- ------------ ---------- ---------- ---------- ----------
ROWID QKSFM_CBO ACCESS 4 272 8.0.0 8.1.7 0

ROWID擬似列でそれぞれのROWIDを取り出してみますね。むかーし、ROWIDを使って、データブロック番号順にソートして性能問題を回避したことありましたっけw ( db tech showcase Tokyo 2013 - A35 特濃JPOUG:潮溜まりでジャブジャブ、SQLチューニング / バッファキャッシュ欠乏症 )

SCOTT@orclpdb1> select rowid,empno,ename from emp;

ROWID EMPNO ENAME
------------------ ---------- ------------------------------
AAASguAAMAAAACTAAA 7369 SMITH
AAASguAAMAAAACTAAB 7499 ALLEN
AAASguAAMAAAACTAAC 7521 WARD
AAASguAAMAAAACTAAD 7566 JONES
AAASguAAMAAAACTAAE 7654 MARTIN
AAASguAAMAAAACTAAF 7698 BLAKE
AAASguAAMAAAACTAAG 7782 CLARK
AAASguAAMAAAACTAAH 7839 KING
AAASguAAMAAAACTAAI 7844 TURNER
AAASguAAMAAAACTAAJ 7900 JAMES
AAASguAAMAAAACTAAK 7902 FORD
AAASguAAMAAAACTAAL 7934 MILLER

12行が選択されました。


まずROWIDヒントを使わず、単純に、ROWID疑義列を使って一本引きw

すごいですよね。ピンポイントでアクセスするので1blockだけしか読みこんんでないですよね。
ROWID関する注意などはマニュアルを見てくさだい。特にROWIDのリスキーな使い方などがわかると思うので。むかーーーーし、むかーーーし、ROWIDに仕様変更がありそういう使い方をしていたシステムの移行はかなり大変だったらしい。私は幸いなことにそういつ使い方をしていたシステムに出会わなかったのでラッキーではありましたが。。)

SCOTT@orclpdb1> set autot trace exp stat
SCOTT@orclpdb1> select * from emp where rowid = 'AAASguAAMAAAACTAAA';

経過: 00:00:00.05

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

-----------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 39 | 1 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY USER ROWID| EMP | 1 | 39 | 1 (0)| 00:00:01 |
-----------------------------------------------------------------------------------


統計
----------------------------------------------------------
0 recursive calls
0 db block gets
1 consistent gets
0 physical reads
0 redo size
1142 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 TABLE ACCESS BY USER ROWIDとなるところをですが、INDEXヒントやFULLヒントで抑止してみるととうなるか見ておきましょう。(想像通りだと思いますけども)

SCOTT@orclpdb1> select /*+ FULL(emp) */ * from emp where rowid = 'AAASguAAMAAAACTAAA';

経過: 00:00:00.01

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

--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 39 | 6 (0)| 00:00:01 |
|* 1 | TABLE ACCESS FULL| EMP | 1 | 39 | 6 (0)| 00:00:01 |
--------------------------------------------------------------------------

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

1 - filter(ROWID='AAASguAAMAAAACTAAA')


統計
----------------------------------------------------------
1 recursive calls
0 db block gets
7 consistent gets
0 physical reads
0 redo size
1142 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

SCOTT@orclpdb1> select /*+ INDEX(emp) */ * from emp where rowid = 'AAASguAAMAAAACTAAA';

経過: 00:00:00.07

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

----------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 39 | 2 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID BATCHED| EMP | 1 | 39 | 2 (0)| 00:00:01 |
|* 2 | INDEX FULL SCAN | PK_EMP | 1 | | 1 (0)| 00:00:01 |
----------------------------------------------------------------------------------------------

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

2 - filter(ROWID='AAASguAAMAAAACTAAA')


統計
----------------------------------------------------------
144 recursive calls
2 db block gets
134 consistent gets
1 physical reads
0 redo size
1146 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

最後に、ROWIDヒントが使えることをSQL Hint Reportも含めて確認してみましょう。

SCOTT@orclpdb1> set autot off
SCOTT@orclpdb1> select /*+ gather_plan_statistics rowid(emp) */ * from emp where rowid = 'AAASguAAMAAAACTAAA';

EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
---------- ------------------------------ --------------------------- ---------- -------- ---------- ---------- ----------
7369 SMITH CLERK 7902 80-12-17 800 20

経過: 00:00:00.00
SCOTT@orclpdb1> @show_actualplan

PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------------
SQL_ID 69yuykdp7c1za, child number 0
-------------------------------------
select /*+ gather_plan_statistics rowid(emp) */ * from emp where rowid
= 'AAASguAAMAAAACTAAA'

Plan hash value: 1116584662

-----------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows |E-Bytes| Cost (%CPU)| E-Time | A-Rows | A-Time | Buffers |
-----------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | | 1 (100)| | 1 |00:00:00.01 | 1 |
| 1 | TABLE ACCESS BY USER ROWID| EMP | 1 | 1 | 39 | 1 (0)| 00:00:01 | 1 |00:00:00.01 | 1 |
-----------------------------------------------------------------------------------------------------------------------------

Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------

1 - SEL$1 / "EMP"@"SEL$1"

Outline Data
-------------

/*+
BEGIN_OUTLINE_DATA
IGNORE_OPTIM_EMBEDDED_HINTS
OPTIMIZER_FEATURES_ENABLE('21.1.0')
DB_VERSION('21.1.0')
ALL_ROWS
OUTLINE_LEAF(@"SEL$1")
ROWID(@"SEL$1" "EMP"@"SEL$1")
END_OUTLINE_DATA
*/

Column Projection Information (identified by operation id):
-----------------------------------------------------------

1 - "EMP"."EMPNO"[NUMBER,22], "EMP"."ENAME"[VARCHAR2,10], "EMP"."JOB"[VARCHAR2,9], "EMP"."MGR"[NUMBER,22],
"EMP"."HIREDATE"[DATE,7], "EMP"."SAL"[NUMBER,22], "EMP"."COMM"[NUMBER,22], "EMP"."DEPTNO"[NUMBER,22]

Hint Report (identified by operation id / Query Block Name / Object Alias):
Total hints for statement: 1

---------------------------------------------------------------------------

1 - SEL$1 / "EMP"@"SEL$1"
- rowid(emp)

Enjoy 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
・実行計画は, 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のおまけ
実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 / No.61 / ANSI JOINのおまけのおまけ
実行計画は, SQL文のレントゲン写真だ! No.62 / ORDBMS機能であるコレクション型の列をアクセスする実行計画ってどうなるの?
実行計画は, SQL文のレントゲン写真だ! No.63 / Join Elimination (再び)その1
実行計画は, SQL文のレントゲン写真だ! No.63 / Join Elimination (再び)その2
実行計画は, SQL文のレントゲン写真だ! No.63 / Join Elimination (再び)その3
実行計画は, SQL文のレントゲン写真だ! No.64 / 先生、私のLEFT OUTER JOINが無いんです!!(Join Elimination番外編)

| | | コメント (0)

2025年1月17日 (金)

ミックさんの「センスの良いSQLを書く技術 達人エンジニアが実践している35の原則 」を査読でお手伝いした話

書店に並ぶ前ですがミックさんから献本いただきました。 ありがとうございました→ ミックさん:)

査読で一足先に読んでいるのですが、完成した書籍をまた読み返してみたいと思います。


Img_2891

Xでポストした通りの内容なのですが、ミックさんもコメントしていましたが、好き嫌いはハッキリ出そう気はしますよね。
ちなみに、私は非常に面白く読ませてもらいました:)

20250117-120511

 

ちなみに、

注釈に記載されている書籍(初版)を求めて図書館まで散歩したり、それをFBへコメントしたら木村明治さんから、「俺、持ってるよー!」とリプライがあったり、本文以外でも楽しませてもらいました!

 

では、また。

| | | コメント (0)

2025年1月 2日 (木)

2024年12月に公開した曲

先月は、Apple Loopとチョップだけで頑張るGarageBand DTMアドベントカレンダー全部俺で作ったこのループ

Neko Mimi Loops 2024 / N + 1 Loops
これは2023年に思いつきで作ったVer.1をメジャーアップデートしたやつ。


Nested Loops II / N + 1 Loops
アドベントカレンダー全部俺で疲れたのでもう一つは、2024年公開分のまとめたもの

ということで今年のDTMもガレバンとApple Loopとチョップだけ?で頑張る予定でございます m(_ _)m

| | | コメント (0)

あけましておめてとうございます。

A_happy_new_year
いつものルーティーン画像でw。

本年もよろしくおねがいいたいします。

| | | コメント (0)