実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 9 / No.44 / COLLECTION ITERATOR PICKLER FETCH Tweet
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
コメント