« 2025年11月 | トップページ | 2026年1月 »

2025年12月26日 (金)

帰ってきた! 標準はあるにはあるが癖の多いSQL #21 - Table Value Constructer(TVC)- ハードパース時間とメモリ消費量 / BONUS TRACK

https://discus-hamburg.cocolog-nifty.com/mac_de_oracle/2025/12/post-d04e78.htmlのおまけです!

前回は、マニュアルでは言及されたりしていますが、TVCで多くの行を生成するのは複数の問題を引き起こしそう。。。
Oracle Databaseでは生成行数上限があるのですが、なにか異様に時間がかかってました。どのあたりだろう?。とか
MySQL/PostgreSQLは行数こそ制限されてないようですが、メモリ消費には影響しそうだよなぁ。
というあたり気になりますよね。今日はその辺りをざっくりと確認しておこうという。


マニュアルでも言及されてるし、TVCで大量行生成しねーーーだろーーーっ。
とも思うわけですが、世の中広いので、油断禁物ww
それやっちゃうと、実際にどうなりそうかって、肌感覚で知ってたほうが良いだろうという意図もあり。

まずは、
前回利用したSQLをCOUNT(1)に書き換えたものを利用します

Oracle Databaseの例(MySQLではRVCを利用する点以外違いはありません)
e.g.
sql_oracle_65534.sql

SELECT COUNT(1) FROM ( VALUES
(1)
,(2)
,(3)
,(4)

...略...

,(65530)
,(65531)
,(65532)
,(65533)
,(65534)
) t1 ( id )
/


環境はいつものとおり、arm64向け Oracle Database/MySQL/PostgreSQL環境をVirtualBox for macOS / Apple Siliconにて

oracle@Mac ~ % ./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: 26.2
BuildVersion: 25C56

*** VirtualBox ver. ***
7.2.4r170995

[master@arm64-oraclelinux8u10 ~]$ cat /etc/oracle-release
Oracle Linux Server release 8.10
[master@arm64-oraclelinux8u10 ~]$ uname -r
5.15.0-313.189.5.3.el8uek.aarch64

以降, 変化確認のために実行時間も記録しておきます
PostgreSQL 17.6だと、29ms程度。

[postgres@Oracle-Linux-8u10-arm64-2 ~]$ psql -U scott -d perftestdb -h localhost
Password for user scott:
psql (17.6)
Type "help" for help.

perftestdb=> \timing
Timing is on.
perftestdb=> select version();
version
---------------------------------------------------------------------------------------------------------------
PostgreSQL 17.6 on aarch64-unknown-linux-gnu, compiled by gcc (GCC) 8.5.0 20210514 (Red Hat 8.5.0-26), 64-bit
(1 row)

Time: 1.848 ms
perftestdb=>
perftestdb=> \i sql_postgresql_65534.sql
count
-------
65534
(1 row)

Time: 28.617 ms


MySQL 8.4.7 だと 60ms程度のようですね。

[master@Oracle-Linux-8u10-arm64-2 ~]$ mysql -u root -D perftestdb -p -h localhost 
Enter password:

...略...

mysql> select version();
+-----------+
| version() |
+-----------+
| 8.4.7 |
+-----------+
1 row in set (0.00 sec)

mysql>
mysql> \. sql_mysql_65534.sql
+----------+
| COUNT(1) |
+----------+
| 65534 |
+----------+
1 row in set (0.06 sec)


さて、今日の真打w Oracle Database、
前回のエントリで気づいたかもしれませんが、Oracle DatabaseのTVCどうやらハードパースにものすごく時間がかかっている雰囲気。
かといってソフトパースでも17秒ぐらいなので決して速くはないのですが、ハードパース時間がすごいですね。

[oracle@arm64-oraclelinux8u10 ~]$ sqlplus scott@localhost:1521/freepdb1 

...略...

SCOTT@localhost:1521/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.8.0.25.04


-- ハードパースだと..
SCOTT@localhost:1521/freepdb1> @sql_oracle_65534.sql

COUNT(1)
----------
65534

経過: 00:50:43.88

-- ソフトパースだと...
SCOTT@localhost:1521/freepdb1> @sql_oracle_65534.sql

COUNT(1)
----------
65534

経過: 00:00:17.99


ということで、Oracle Database。ハードハース時間が長いのですが、もう少し掘り下げて覗いてみようと思います。
10046トレース(久々w)でログをとって追ってみます。

SCOTT@localhost:1521/freepdb1> alter session set tracefile_identifier='10046_tvc';
セッションが変更されました。

SCOTT@localhost:1521/freepdb1> alter session set statistics_level=all;
セッションが変更されました。

SCOTT@localhost:1521/freepdb1> alter session set max_dump_file_size = unlimited;
セッションが変更されました。

SCOTT@localhost:1521/freepdb1> alter system flush shared_pool;
システムが変更されました。

SCOTT@localhost:1521/freepdb1> alter session set events '10046 trace name context forever,level 12';
セッションが変更されました。

SCOTT@localhost:1521/freepdb1> @sql_oracle_65534

COUNT(1)
----------
65534

経過: 00:43:01.31
SCOTT@localhost:1521/freepdb1> alter session set events '10046 trace name context off';
セッションが変更されました。

[oracle@arm64-oraclelinux8u10 trace]$ ls -l *10046_tvc*
-rw-r-----. 1 oracle oinstall 1289063 Dec 25 20:36 FREE_ora_5169_10046_tvc.trc
-rw-r-----. 1 oracle oinstall 18615 Dec 25 20:36 FREE_ora_5169_10046_tvc.trm

[oracle@arm64-oraclelinux8u10 trace]$ tkprof FREE_ora_5169_10046_tvc.trc FREE_ora_5169_10046_tvc.trc.txt explain=scott/tiger@localhost:1521/freepdb1 sys=yes waits=yes aggregate=no

...略...

該当箇所を見ると、やはり!
ハードパース時間がほとんどですね。 時間の単位は秒なので、43分ほどであることと、ほぼCPU時間に等しいことも見えますね。

call     count       cpu    elapsed       disk      query    current        rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 1 2524.81 2551.05 0 60 0 0
Execute 1 0.01 0.01 0 0 0 0
Fetch 2 0.03 0.03 0 0 0 1
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 4 2524.86 2551.10 0 60 0 1


実行計画は以前みたものと同じで、VALUES SCANになっています。

Misses in library cache during parse: 1
Optimizer mode: ALL_ROWS
Parsing user id: 134 (SCOTT)
Number of plan statistics captured: 1

Rows (1st) Rows (avg) Rows (max) Row Source Operation
---------- ---------- ---------- ---------------------------------------------------
1 1 1 SORT AGGREGATE (cr=0 pr=0 pw=0 time=36096 us starts=1 direct read=0 direct write=0)
65534 65534 65534 VIEW (cr=0 pr=0 pw=0 time=34577 us starts=1 direct read=0 direct write=0 cost=131076 size=0 card=65534)
65534 65534 65534 VALUES SCAN (cr=0 pr=0 pw=0 time=30701 us starts=1 direct read=0 direct write=0 cost=131076 size=0 card=65534)
待機イベントをみると、前回topコマンドで気になっていたメモリー関連の待機イベントでの待機回数が非常に多くなっています。しかも、PGA内のCGA/UGA使っているようにみえますね。CGAなんて久々に見ました。(2007年のネタを思い出しますw - Mac De Oracle なんですが、Windows(32bit)でのOracleな話 #3)TVCで行を生成すると、PGA、CGAが拡大しその影響でUGAも増加、専用サーバーなのでその流れでPGAも拡大している様子が想像できますよね。23ai FREEだとメモリ制限もきついので、もう少しメモリを消費させれば、PGAのLIMITや23ai FREEのメモリ制限などに抵触する可能性はありますよね。。。それは後ほど試します!
Elapsed times include waiting on following events:
Event waited on Times Max. Wait Total Waited
---------------------------------------- Waited ---------- ------------
Allocate CGA memory from OS 488 0.00 0.00
Allocate PGA memory from OS 6 0.00 0.00
Free private memory to OS 22 0.02 0.03
Allocate UGA memory from OS 216 0.00 0.00
SQL*Net message to client 2 0.00 0.00
SQL*Net message from client 2 9.11 9.11
********************************************************************************


比較のためにソフトパースの場合は以下のとおり。

call     count       cpu    elapsed       disk      query    current        rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 1 0.00 0.00 0 0 0 0
Execute 1 0.00 0.00 0 0 0 0
Fetch 2 0.03 0.03 0 0 0 1
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 4 0.03 0.03 0 0 0 1

Misses in library cache during parse: 0
Optimizer mode: ALL_ROWS
Parsing user id: 134 (SCOTT)
Number of plan statistics captured: 1

Rows (1st) Rows (avg) Rows (max) Row Source Operation
---------- ---------- ---------- ---------------------------------------------------
1 1 1 SORT AGGREGATE (cr=0 pr=0 pw=0 time=36156 us starts=1 direct read=0 direct write=0)
65534 65534 65534 VIEW (cr=0 pr=0 pw=0 time=34656 us starts=1 direct read=0 direct write=0 cost=131076 size=0 card=65534)
65534 65534 65534 VALUES SCAN (cr=0 pr=0 pw=0 time=30708 us starts=1 direct read=0 direct write=0 cost=131076 size=0 card=65534)

Elapsed times include waiting on following events:
Event waited on Times Max. Wait Total Waited
---------------------------------------- Waited ---------- ------------
Allocate UGA memory from OS 38 0.00 0.00
SQL*Net message to client 2 0.00 0.00
SQL*Net message from client 2 26.66 26.66
********************************************************************************

おまけ。PGA/UGA/CGAに関する懐かしいエントリ。(知ってる方いるかなw)
ソートに関する検証 その2 / InsightTechnology 旧ブログ

PGA/UGAサイズの変化 / 23ai FREEのメモリー制限は2GBである前提は頭の片隅に置いておく必要はあるが、
いまのところ制限内に収まっているようなのでこのながれのまま、サイズの変化を見ておきましょう。

ハードパースさせつつ試しています。

SCOTT@localhost:1521/freepdb1> alter system flush shared_pool;
システムが変更されました。

SCOTT@localhost:1521/freepdb1> @show_mystats.sql

SID NAME VALUE
---------- ---------------------------------------------------------------- ----------
40 CPU used by this session 1
40 logical read bytes from cache 4243456
40 no work - consistent read gets 281
40 physical read IO requests 9
40 physical read bytes 106496
40 physical read total IO requests 9
40 physical read total bytes 106496
40 physical reads 13
40 physical reads cache 13
40 redo synch writes 1
40 redo write info find 1
40 session logical reads 518
40 session pga memory 2764448
40 session pga memory max 2829984
40 session uga memory 791336
40 session uga memory max 791384
40 sorts (memory) 41

17行が選択されました。

経過: 00:00:00.02
SCOTT@localhost:1521/freepdb1> @sql_oracle_65534

COUNT(1)
----------
65534

経過: 00:49:53.83
SCOTT@localhost:1521/freepdb1> @show_mystats.sql

SID NAME VALUE
---------- ---------------------------------------------------------------- ----------
40 CPU used by this session 273602
40 CPU used when call started 273602
40 logical read bytes from cache 4243456
40 no work - consistent read gets 281
40 physical read IO requests 9
40 physical read bytes 106496
40 physical read total IO requests 9
40 physical read total bytes 106496
40 physical reads 13
40 physical reads cache 13
40 redo synch writes 1
40 redo write info find 1
40 session logical reads 518
40 session pga memory 12053496
40 session pga memory max 1600383992
40 session uga memory 10680464
40 session uga memory max 40035216
40 sorts (memory) 42

18行が選択されました。


統計値差を確認!

PGAが1.5Gほど!!!!!!!に拡張!この辺りは 10046とレースの待機イベントにも現れていたCGAが占めていそうですね。UGAよりも。。。
(統計情報の詳細は、Database Reference E.2 Statistics Descriptions参照のこと)

単純な数値型1列で、65534行をTVCで生成しましたが、こんなにPGAを消費しちゃうんんですね。驚き!
PGAも無制限に利用できるわけではないので、TVCで大量に行データを生成するとPGAの制限にあたってエラーになるだろうなぁ。というのは容易に想像できます。

SCOTT@localhost:1521/freepdb1> @list_diff 2

STAT_NAME STAT_VALUE UNIT
---------------------------------------- ---------- -----
CPU used by this session 2736.01 sec
CPU used when call started 2736.02 sec
physical read total IO requests 9 times
session pga memory 8.86 MB
session pga memory max 1523.55 MB
session uga memory 9.43 MB
session uga memory max 37.43 MB
sorts (memory) 1 times


ついでなので、
数値型1行で65534行から半減させつつ16行まで、どの程度のPGAが消費されるか計測してグラフにしてみました。
TVCによる大量の行生成はやめた方が良いですよね。まじで。
PGAサイズの増加に合わせハードパース時間もとんでもないことになりますし。。。ご利用は計画的に! という感じです。
Tvc_pga_size

1列の行数だけ仕様上限だと発生まだ余裕は多少あるので、列数を多くし、1行で1ブロック(8K)程度になるようなイメージで作ってみました。PGA_AGGREGATE_LIMITでエラーになるか、
もしくは、23ai FREEのメモリ制限に先に当たってエラーになるか。。。どちらかでエラーになるはず!!!

ということで、8列かつ1行/ブロックになるような行サイズで、65534行をTVCで生成してCOUNT()するSQLを生成。(@make_tvc_sql.sql は後半に載せてあります)

SCOTT@localhost:1521/freepdb1> @make_tvc_sql.sql 65534 oracle

SELECT count(1) FROM ( VALUES
(1,
'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx1',

...略...

'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx1')

...略...

) t1 ( id, col1, col2, col3, col4, col5, col6, col7, col8 );


では実行!!!、コケると思いますよw 絶対!!!!!

Oracle Database 23ai Free Release 23.0.0.0.0 - Develop, Learn, and Run for Free
Version 23.8.0.25.04
に接続されました。
SCOTT@localhost:1521/freepdb1> @show_mystats.sql

SID NAME VALUE
---------- ---------------------------------------------------------------- ----------
203 CPU used by this session 1
203 CPU used when call started 1
203 logical read bytes from cache 3334144
203 no work - consistent read gets 215
203 physical read IO requests 16
203 physical read bytes 131072
203 physical read total IO requests 16
203 physical read total bytes 131072
203 physical reads 16
203 physical reads cache 16
203 redo synch writes 1
203 redo write info find 1
203 session logical reads 407
203 session pga memory 2698912
203 session pga memory max 2698912
203 session uga memory 791312
203 session uga memory max 791312
203 sorts (memory) 37

18行が選択されました。

経過: 00:00:00.02
SCOTT@localhost:1521/freepdb1> @sql_oracle_65534
SELECT count(1) FROM ( VALUES
*
行1でエラーが発生しました。:
ORA-00028: セッションは終了しました ヘルプ:
https://docs.oracle.com/error-help/db/ora-00028/


経過: 00:05:51.08


ね! 狙い通りにエラー発生!!!!!w
ORA-00028エラーは、副産物なので根本原因をログから確認してみましょう!

以下トレースファイルより。

$ORACLE_BASE/diag/rdbms/free/FREE/incident/incdir_134953/FREE_ora_4958_i134953.trc

...略...

23ai FREEなのでそもそも利用可能なメモリサイズ上限はあるのですが、この例では、PGA_AGGREGATE_LIMITに抵触してエラーとなったようですね。まあ、想像通りの結果なのですがw
...略...

=======================================
PRIVATE MEMORY SUMMARY FOR THIS PROCESS
---------------------------------------

******************************************************
PRIVATE HEAP SUMMARY DUMP
1842 MB total:
1795 MB commented, 523 KB permanent
47 MB free (0 KB in empty extents),
877 MB, 2 heaps: "callheap " 14 MB free held
480 MB, 1 heap: "Alloc environm " 16 MB free held
480 MB, 2 chunks: "kgh stack " 16 MB free held

...略...

Summary of subheaps at depth 2
1326 MB total:
40 MB commented, 1286 MB permanent
408 KB free (0 KB in empty extents),
signalling ORA-4036 interrupt

...略...

Incident 134953 created, dump file: /opt/oracle/diag/rdbms/free/FREE/incident/incdir_134953/FREE_ora_4958_i134953.trc
ORA-04036: インスタンスまたはPDBにより使用されるPGAメモリーがPGA_AGGREGATE_LIMITを超えています。

TVCで生成した行数のみだけではなく、列数や列サイズもPGA消費に影響するすることを意味しています!!!
とにかく、マニュアルに記載されているように、大量の行を生成するのは避けるのが吉という癖の強い機能なので、ご利用は計画的にw

ついでなので、行数上限の制約は無いPostgreSQLとMySQLのメモリ消費量をざっくりみておきました。
これらもメモリ消費は大きくなるので、TVCによる大量の行生成はさけたほうがよいでしょうね。(ほかの方法はあるわけですし)

PostgreSQLでOracle Databaseで実行したSQLと同じ文を実行してみると。。。

[postgres@Oracle-Linux-8u10-arm64-2 ~]$ psql -U scott -d perftestdb -h localhost
Password for user scott:
psql (17.6)
Type "help" for help.

perftestdb=> \i sql_postgresql_65534.sql
QUERY PLAN
------------------------------------------------------------------------------------------------------------------------
Aggregate (cost=983.01..983.02 rows=1 width=8) (actual time=34.131..34.132 rows=1 loops=1)
Output: count(1)
-> Values Scan on "*VALUES*" (cost=0.00..819.18 rows=65534 width=0) (actual time=0.003..31.264 rows=65534 loops=1)
Output: "*VALUES*".column1, "*VALUES*".column2, "*VALUES*".column3, "*VALUES*".column4, "*VALUES*".column5,
"*VALUES*".column6, "*VALUES*".column7, "*VALUES*".column8, "*VALUES*".column9
Planning:
Buffers: shared hit=3
Memory: used=602113kB allocated=607745kB
Planning Time: 2697.696 ms
Execution Time: 34.330 ms
(9 rows)


Tvc_65534rows_postgresql

以下のパラメータを設定、再起動してログ出力にてざっくりとと、max resident sizeを見てみた。
EXECUTOR STATISTICSは、2.9GBぐらいまで増加してますね。
log_statement_stats = off
log_parser_stats = on
log_planner_stats = on
log_executor_stats = on

にして再起動!

2025-12-25 20:10:25.291 JST [8356] LOG:  PARSER STATISTICS
2025-12-25 20:10:25.291 JST [8356] DETAIL: ! system usage stats:
! 1.042480 s user, 0.067788 s system, 1.112459 s elapsed
! [1.105611 s user, 0.125358 s system total]
! 1505652 kB max resident size
! 2416/0 [2416/376] filesystem blocks in/out
! 2/35500 [176/36935] page faults/reclaims, 0 [0] swaps
! 0 [0] signals rcvd, 0/0 [0/0] messages rcvd/sent
! 1/1 [10/1] voluntary/involuntary context switches
2025-12-25 20:10:25.291 JST [8356] STATEMENT: SELECT count(1) FROM ( VALUES

...略...

) t1 ( id, col1, col2, col3, col4, col5, col6, col7, col8 );
2025-12-25 20:10:27.072 JST [8356] LOG: PARSE ANALYSIS STATISTICS
2025-12-25 20:10:27.072 JST [8356] DETAIL: ! system usage stats:
! 0.271937 s user, 0.031995 s system, 0.309900 s elapsed
! [2.689273 s user, 0.260475 s system total]
! 1621520 kB max resident size
! 608/0 [3024/376] filesystem blocks in/out
! 44/38352 [220/79769] page faults/reclaims, 0 [0] swaps
! 0 [0] signals rcvd, 0/0 [0/0] messages rcvd/sent
! 19/0 [936/3] voluntary/involuntary context switches
2025-12-25 20:10:27.072 JST [8356] STATEMENT: SELECT count(1) FROM ( VALUES

...略...

) t1 ( id, col1, col2, col3, col4, col5, col6, col7, col8 );
2025-12-25 20:10:28.571 JST [8356] LOG: REWRITER STATISTICS
2025-12-25 20:10:28.571 JST [8356] DETAIL: ! system usage stats:
! 0.000005 s user, 0.000001 s system, 0.000003 s elapsed
! [4.003534 s user, 0.396938 s system total]
! 2098660 kB max resident size
! 0/0 [3024/376] filesystem blocks in/out
! 0/0 [220/84364] page faults/reclaims, 0 [0] swaps
! 0 [0] signals rcvd, 0/0 [0/0] messages rcvd/sent
! 0/0 [1781/6] voluntary/involuntary context switches
2025-12-25 20:10:28.571 JST [8356] STATEMENT: SELECT count(1) FROM ( VALUES

...略...

) t1 ( id, col1, col2, col3, col4, col5, col6, col7, col8 );
2025-12-25 20:10:32.469 JST [8356] LOG: PLANNER STATISTICS
2025-12-25 20:10:32.469 JST [8356] DETAIL: ! system usage stats:
! 2.298387 s user, 0.046537 s system, 2.349685 s elapsed
! [7.677502 s user, 0.547417 s system total]
! 2220484 kB max resident size
! 80/0 [3104/376] filesystem blocks in/out
! 4/38971 [224/127833] page faults/reclaims, 0 [0] swaps
! 0 [0] signals rcvd, 0/0 [0/0] messages rcvd/sent
! 2/4 [3274/11] voluntary/involuntary context switches
2025-12-25 20:10:32.469 JST [8356] STATEMENT: SELECT count(1) FROM ( VALUES

...略...

) t1 ( id, col1, col2, col3, col4, col5, col6, col7, col8 );
2025-12-25 20:10:34.034 JST [8356] LOG: EXECUTOR STATISTICS
2025-12-25 20:10:34.034 JST [8356] DETAIL: ! system usage stats:
! 0.040565 s user, 0.000000 s system, 0.040742 s elapsed
! [9.047784 s user, 0.654338 s system total]
! 2699340 kB max resident size
! 0/0 [3136/376] filesystem blocks in/out
! 0/9 [228/132686] page faults/reclaims, 0 [0] swaps
! 0 [0] signals rcvd, 0/0 [0/0] messages rcvd/sent
! 0/0 [5130/13] voluntary/involuntary context switches
2025-12-25 20:10:34.034 JST [8356] STATEMENT: SELECT count(1) FROM ( VALUES

...略...

) t1 ( id, col1, col2, col3, col4, col5, col6, col7, col8 );

最後は、MySQL
ERROR 1153 (08S01): Got a packet bigger than 'max_allowed_packet' bytesってエラーになったので
max_allowed_packetパラメータを64MBから768MBへ大きく設定しなおして無理やりエラーを回避して確認!

MySQLでもかなりメモリ消費しちゃってますね。。

[master@Oracle-Linux-8u10-arm64-2 ~]$ mysql -u root -D perftestdb -p -h localhost 
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.4.7 MySQL Community Server - GPL

Copyright (c) 2000, 2025, 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> \. sql_mysql_65534.sql
ERROR 1153 (08S01): Got a packet bigger than 'max_allowed_packet' bytes
No connection. Trying to reconnect...
Connection id: 9
Current database: perftestdb

...略...

Current database: perftestdb

+--------------------+----------+
| Variable_name | Value |
+--------------------+----------+
| max_allowed_packet | 67108864 |
+--------------------+----------+
1 row in set (0.01 sec)

...略...

[master@Oracle-Linux-8u10-arm64-2 ~]$ sudo vi /etc/my.cnf
[master@Oracle-Linux-8u10-arm64-2 ~]$ sudo service mysqld restart
Redirecting to /bin/systemctl restart mysqld.service
[master@Oracle-Linux-8u10-arm64-2 ~]$ mysql -u scott -D perftestdb -p -h localhost
Enter password:

...略...

-- 768MBに
mysql> show variables like 'max_allowed_packet';
+--------------------+-----------+
| Variable_name | Value |
+--------------------+-----------+
| max_allowed_packet | 805306368 |
+--------------------+-----------+
1 row in set (0.00 sec)

mysql>


Tvc_65534rows_mysql

3GBぐらいまで消費しちゃってますね。

mysql> SELECT * from performance_schema.users WHERE USER='scott';
+-------+---------------------+-------------------+-------------------------------+--------------------------+
| USER | CURRENT_CONNECTIONS | TOTAL_CONNECTIONS | MAX_SESSION_CONTROLLED_MEMORY | MAX_SESSION_TOTAL_MEMORY |
+-------+---------------------+-------------------+-------------------------------+--------------------------+
| scott | 1 | 1 | 647288 | 1398335 |
+-------+---------------------+-------------------+-------------------------------+--------------------------+
1 row in set (0.00 sec)

mysql> \. sql_mysql_65534.sql
+----------+
| COUNT(*) |
+----------+
| 65534 |
+----------+
1 row in set (3.68 sec)

mysql> SELECT * from performance_schema.users WHERE USER='scott';
+-------+---------------------+-------------------+-------------------------------+--------------------------+
| USER | CURRENT_CONNECTIONS | TOTAL_CONNECTIONS | MAX_SESSION_CONTROLLED_MEMORY | MAX_SESSION_TOTAL_MEMORY |
+-------+---------------------+-------------------+-------------------------------+--------------------------+
| scott | 1 | 1 | 2404782200 | 2893645114 |
+-------+---------------------+-------------------+-------------------------------+--------------------------+
1 row in set (0.00 sec)

mysql> SELECT MAX_TOTAL_MEMORY from performance_schema.events_statements_history WHERE SQL_TEXT LIKE 'SELECT COUNT(*)%';
Empty set (0.00 sec)

mysql> \. sql_mysql_65534.sql
+----------+
| COUNT(*) |
+----------+
| 65534 |
+----------+
1 row in set (3.93 sec)

mysql> SELECT MAX_TOTAL_MEMORY from performance_schema.events_statements_history WHERE SQL_TEXT LIKE 'SELECT COUNT(*)%';
+------------------+
| MAX_TOTAL_MEMORY |
+------------------+
| 2893680900 |
+------------------+
1 row in set (0.00 sec)


では、Advent Calendarも終わり、今年の残すところあとわずか。

みなさま、よいお年をお迎えください。






make_tvc_sql.sql
1行に複数列を持たせかつ、1行1ブロック程度になるような行サイズとなるTVCクエリを生成するスクリプト
set feed off
set timi off
set head off
set termout off
set veri off
set trimspool on

col col1 for a20
col col2 for a20
col col3 for a20
col col4 for a20
col col5 for a20
col col6 for a20
col col7 for a20
col col8 for a20
set linesize 400
set pagesize 1000
SET SERVEROUTPUT ON
spool sql_&2._&1..sql
DECLARE
c_max_rows CONSTANT NUMBER := &1;
c_rvc_text_mysql CONSTANT CHAR(3) := 'ROW';
c_type_mysql CONSTANT CHAR(5) := 'MYSQL';
c_type CONSTANT VARCHAR2(10) := UPPER('&2');
BEGIN
DBMS_OUTPUT.PUT_LINE('SELECT COUNT(*) FROM ( VALUES');
FOR i IN 1..c_max_rows LOOP
DBMS_OUTPUT.PUT_LINE(
CASE WHEN i > 1 THEN ',' END
|| CASE WHEN c_type = c_type_mysql THEN c_rvc_text_mysql END
|| '(' || TO_CHAR(i)
|| ', ''' || LPAD(TO_CHAR(i),1000,'x') || ''''
|| ', ''' || LPAD(TO_CHAR(i),1000,'x') || ''''
|| ', ''' || LPAD(TO_CHAR(i),1000,'x') || ''''
|| ', ''' || LPAD(TO_CHAR(i),1000,'x') || ''''
|| ', ''' || LPAD(TO_CHAR(i),1000,'x') || ''''
|| ', ''' || LPAD(TO_CHAR(i),1000,'x') || ''''
|| ', ''' || LPAD(TO_CHAR(i),1000,'x') || ''''
|| ', ''' || LPAD(TO_CHAR(i),373,'x') || ''')'
);
END LOOP;
DBMS_OUTPUT.PUT_LINE(') t1 ( id, col1, col2, col3, col4, col5, col6, col7, col8 );');
END;
/
spool off
SET SERVEROUTPUT OFF
UNDEFINE 1
UNDEFINE 2


set head on
set termout on
set feed on
set veri on
set timi on
set trimspool off






関連エントリー
標準はあるにはあるが癖の多い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にも癖がある)
帰ってきた! 標準はあるにはあるが癖の多いSQL #15 - 実行計画でスカラー副問合せの見せ方にも癖がでる
帰ってきた! 標準はあるにはあるが癖の多いSQL #16 - FROM句のインラインビューのエイリアスにもクセがある(必須だったり、任意だったり)
帰ってきた! 標準はあるにはあるが癖の多いSQL #17 - ANY_VALUE() ってなかなかいいじゃん、癖無さそう!
帰ってきた! 標準はあるにはあるが癖の多いSQL #18 - t_alias と c_alias にも癖が出る
帰ってきた! 標準はあるにはあるが癖の多いSQL #19 - c_alias の癖(おまけ)
帰ってきた! 標準はあるにはあるが癖の多いSQL #20 - Table Value Constructer (TVC)


| | | コメント (0)

2025年12月25日 (木)

ミックさんからクリスマスプレゼントが届いた:) / New SQL徹底入門

ミックさんからクリスマスプレゼントが届いた:) ありがとうございます! / New SQL徹底入門

正月休み読もうと思ってます。 楽しみ。

G862fsdbsaa1tfx

| | | コメント (0)

2025年12月12日 (金)

帰ってきた! 標準はあるにはあるが癖の多いSQL #20 - Table Value Constructer (TVC)


やってまいりました。年末恒例のアドベントカレンダー。

本エントリーは、以下アドベントカレンダーの12日目のクロスポストとなっています。
JPOUG Advent Calendar 2025 - Oracle Database
PostgreSQL Advent Calendar 2025
MySQL Advent Calendar 2025


11日目の窓は、それぞれ、
Oracle Databaseでマルチレイアウトのテーブルを作る方法その1 - HiroyukiNakaie さん / JPOUG Advent Calendar 2025 - Oracle Database
セキュリティ対策としての PostgreSQL マイナーバージョンアップ (PGCON2025 発表資料) - jri_narita さん / PostgreSQL Advent Calendar 2025
今年勉強会などで MySQL / HeatWave に関して話したことの振り返り+α - hmatsu47 さん / MySQL Advent Calendar 2025
でした。


今回のお題は、
帰ってきた! 標準はあるにはあるが癖の多いSQL #19 - c_alias の癖(おまけ)
ネタフリしていた、TVC です。と言っても、この曲じゃありません!!!!(この曲、知ってる人どれぐらいいるだろうw)
TVC15 / David Bowie


TVC = Table Value Constructor / 表値コンストラクタには、どのような癖があるのか、否か、、、確認しておきたいと思います。




ということで本題。

PostgreSQLではかなり前から実装されていた表値コンストラクタですが、MySQLではMySQL 8.0.19以降、Oracle Databaseでも、その流れで?!(どういう流れだw)、サポートされた感じがしますw(個人の感想です)

この表値コンストラクタ、注意点としては複数のマニュアルに記載されているので気づきやすいと思いますが、大量の行を生成することを意図したものではないという点のようですね。
メモリ消費量や最適化によっては、内部的に一時表などが利用されそうなの記述もありますね。
ということで、表値コンストラクタの癖探しの旅へw


まず、Oracle Database/MySQL/PostgreSQL、それぞれのマニュアルに目を通しておきましょう。
Oracle Database / Release 23 / values_clause::=
https://docs.oracle.com/cd/G11854_01/sqlrf/SELECT.html#GUID-CFA006CA-6FF1-4972-821E-6996142A51C6__GUID-27159C8E-617B-4ECE-AA4C-1800287F0C9D

Oracle Database / Release 23 / values_clause
https://docs.oracle.com/cd/G11854_01/sqlrf/SELECT.html#GUID-CFA006CA-6FF1-4972-821E-6996142A51C6__SECTION_UMB_QGC_FWB

values_clause::= 、および、expression_list::=
Oracle Databaseの場合、シンタックスを見る限り、value_clauseに含めることができる Expression_listの制限が、TVCで指定できる最大行数になりそうですよね。わかりにくいですが。。この点は今回確認しておきましょう。
https://docs.oracle.com/en/database/oracle/oracle-database/26/sqlrf/IN-Condition.html#SQLRF-GUID-C7961CB3-8F60-47E0-96EB-BDCF5DB1317C


MySQL 8.0 リファレンスマニュアル / SQL ステートメント / データ操作ステートメント / VALUES ステートメント
https://dev.mysql.com/doc/refman/8.0/ja/values.html


PostgreSQL 17.5文書 / SQLコマンド / VALUES
https://www.postgresql.jp/document/17/html/sql-values.html

いきなり癖、発見!www 癖多そう!!!!
これらのマニュアルを斜め読みしただけも癖のあることに気づきます。
Oracle Databaseは、VALUES句のみサポートされています、MySQL/PostgreSQLはVALUESコマンドとしても使える!。それ使う場面あるのか?! と思ったり。MySQLでは、ROW() 行値コンストラクタが必要であることなどがあります。(MySQLのINSERT文では行値コンストラクタは必須ではなさそうなので、SELECT文でも同様に扱って欲しいきがします

その他、TVCは少量のデータを想定していると記載されているものの、最大行数制限となりそうな記述は、Oracle Databaseぐらいですし、メモリ消費もそれなりに高めなので、やりたい放題って状況は避けるべきでしょうね。
なお、今回準備した環境制限ですが、Oracle Database 23ai FREE on VirtualBOXはメモリサイズが2GBに制限されているため、メモリサイズ(PGA含め)に依存しそうな上限確認のテストでは少々厳しめでした。



ログが多めなので、最初にTVCの癖の数々をサマっておきます!

  • TVCで生成できる行数の上限
    • Oracle Database : 65534行。マニュアル上は、65535行に読めるのだが、ここまで使うこともないはずw
    • MySQL/PostgreSQL : 明示的な制限なし

    • なお、少量データを想定した機能と記載されているので、大量のデータを生成するのは避けた方が無難。他の方法があるので。

  • TVCの表エイリアス記述
    • Oracle Database : 必須
    • MySQL : 必須
    • PostgreSQL : 任意

  • TVCの列エイリアス記述
    • Oracle Database : 必須。ただし、列値の個数と列エイリアスの個数は同一であること。
    • MySQL : 任意。ただし、列エイリアスを記述する場合は、列値の個数と列エイリアスの個数は同一であること。
      • e.g. SELECT * FROM (VALUES ROW(1,2)) t01; の場合、column_0 , column_1 という列エイリアスが付与される

    • PostgreSQL : 任意。列値の個数と列エイリアスの個数は一致する必要はない。列エイリアスのない列値には、デフォルトの列エイリアスが付与される。
      • e.g. SELECT * FROM (VALUES ROW(1,2)) t01; の場合、column1 , column2 という列エイリアスが付与される
      • e.g. SELECT * FROM (VALUES ROW(1,2)) t01 (c1); の場合、c1 , column2 という列エイリアスが付与される

    • 通常はコーディング規約で縛って、表エイリアスと列エイリアスの記述を必須にることがほとんどだと思われる。PostgreSQLはかなり緩め。MySQLは少々トリッキー、書き漏らした場合、気づくのが遅れることが多そうなので要注意。

  • 行値コンストラクが必要
    • Oracle Database : 行値コンストラクタ不要
    • MySQL : 行値コンストラクタ ROW() 必須
    • PostgreSQL : 行値コンストラクタ不要

  • VALUESコマンドのサポート
    • Oracle Database : サポートしていない
    • MySQL : サポートしている
    • PostgreSQL : サポートしている

    • コマンドとし単体で使えるのって嬉しいのかよくわからないのだが、どうなんだろう。


  • 実行計画
    • Oracle Database : VALUES SCAN として現れる。
    • MySQL : TREE形式の実行計画を見る限り、TVCが利用されていることを識別することはできない(8.4.7より後ではどうなるか、わからないが。)
    • PostgreSQL : Values Scan on "*VALUES*" として現れる(Oracle Databaseが後発なので、PostgreSQLの表示に近い表現にしたのかもしれない)







では、いろいろ動かして前述した癖の挙動を見ていきましょう。

後半で、大量生成しないことが推奨されているTVCで大量の値を生成したらどうなっちゃうのか。。。というあたりまで見ておきますw
そういうことやっちゃう方々は出てくるかもなーと予想しつつw。。。

e.g. IN句に仕様の限界まで値を詰めて、さらに OR条件でさらに繰り返しちゃう。。。とか、稀によく見ますし。w 
   TVCも無邪気に大量の行を生成させちゃうと。。。いろいろ副作用が強そうな部分もありw(今回はそこまで試しませんが。。。)

PostgreSQL (17.6)
マニュアルのバージョンを遡るとサポートされ始めたのは3種の中では最も古く、PostgreSQL 8.2.6文書 VALUESにあるように Ver. 8.2(2006年リリース)のころにはあったようですね。
Mac De OracleでPostgreSQL/MySQLも含めたネタが2005年12月のMac De Oracle Heterogeneous! #1で、PostgreSQL7.4.9/MySQL4.1.13a/MySQL4.0.25なので、そんな前だったか〜と、遠い目をしているところw。。。。。。

                                                    version                    
-------------------------------------------------------------------------------
PostgreSQL 17.6 on aarch64-unknown-linux-gnu,
compiled by gcc (GCC) 8.5.0 20210514 (Red Hat 8.5.0-26), 64-bit
perftestdb=> VALUES (1, 'one'), (2, 'two'), (3, 'three');
column1 | column2
---------+---------
1 | one
2 | two
3 | three

TVCの行数が増加するとExecution Timeもそうですが、Plannningで消費するメモリサイズが増加しそうなのでExplain時にmemoryオプションも付加しています。

perftestdb=> explain (memory, buffers, analyze, verbose) VALUES (1, 'one'), (2, 'two'), (3, 'three');
QUERY PLAN
--------------------------------------------------------------------------------------------------------
Values Scan on "*VALUES*" (cost=0.00..0.04 rows=3 width=36) (actual time=0.002..0.003 rows=3 loops=1)
Output: column1, column2
Planning:
Memory: used=7kB allocated=8kB
Planning Time: 0.023 ms
Execution Time: 0.008 ms

MySQL (8.4.7)
(PostgreSQL同様、ARM版です)

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

PostgreSQLに似ているようで似てない癖もあるようです。少々脱線してますが、INSERT文と組み合わせる場合は、全列で列値コンストラクタROW()を使うか、全く使わないかのどちらか、というトリッキーな仕様もあるようです。

mysql> VALUES (1, 'one'), (2, 'two'), (3, 'three');
ERROR 1064 (42000): You have an error in your SQL syntax;
check the manual that corresponds to your MySQL server version for the right syntax to use near '(1, 'one'), (2, 'two'), (3, 'three')' at line 1
mysql>
mysql>
mysql> VALUES ROW(1, 'one'), ROW(2, 'two'), ROW(3, 'three');
+----------+----------+
| column_0 | column_1 |
+----------+----------+
| 1 | one |
| 2 | two |
| 3 | three |
+----------+----------+
3 rows in set (0.00 sec)

mysql> create table hoge (id integer);
Query OK, 0 rows affected (0.02 sec)

mysql> insert into hoge(id) values (1),(2),(3),(4);
Query OK, 4 rows affected (0.00 sec)
Records: 4 Duplicates: 0 Warnings: 0

mysql> insert into hoge(id) values ROW(5),ROW(6),ROW(7),ROW(8);
Query OK, 4 rows affected (0.00 sec)
Records: 4 Duplicates: 0 Warnings: 0

mysql> insert into hoge(id) values ROW(9),ROW(10),(11),(12);
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '(11),(12)' at line 1


PostgreSQLとは異なり、実行計画上(TREEフォーマット)、TVCを利用しているということは読み取れないですね。実行計画からTVCを利用していると読み取れると判別しやすくて良いのではないだろうか。。。どう思います?

mysql> explain analyze format=tree VALUES ROW(1, 'one'), ROW(2, 'two'), ROW(3, 'three');
+---------------------------------------------------------------------------------------------------+
| EXPLAIN |
+---------------------------------------------------------------------------------------------------+
| -> Rows fetched before execution (cost=0..0 rows=3) (actual time=167e-6..209e-6 rows=3 loops=1)
|
+---------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

Oracle Database (23.8)

SCOTT@localhost:1521/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.8.0.25.04


試すまでもないわけですがw、Oracle Databaseでは、PostgreSQL/MySQLのVALUESステートメントはどちらもエラー。

SCOTT@localhost:1521/freepdb1> VALUES (1, 'one'), (2, 'two'), (3, 'three');
SP2-0734: "VALUES (1,..."で開始するコマンドが不明です - 残りの行は無視されました。
ヘルプ: https://docs.oracle.com/error-help/db/sp2-0734/

SCOTT@localhost:1521/freepdb1> VALUES ROW(1, 'one'), ROW(2, 'two'), ROW(3, 'three');
SP2-0734: "VALUES ROW..."で開始するコマンドが不明です - 残りの行は無視されました。
ヘルプ: https://docs.oracle.com/error-help/db/sp2-0734/


つづいて、Oracle DatabaseでもサポートされているTVCの癖。SELECT文やWITH句で利用するケースです。

インラインビューの形で書いて、表エイリアスと列エイリアスも合わせて記述しています。
表エイリアスと列エイリアスの指定が必須か否か、など癖が多い(後述)

PostgreSQL (17.6)

perftestdb=> SELECT * 
perftestdb-> FROM
perftestdb-> (
perftestdb(> VALUES
perftestdb(> (1, 'SCOTT')
perftestdb(> ,(2, 'SMITH')
perftestdb(> ,(3, 'JOHN' )
perftestdb(> ) t1 (
perftestdb(> employee_id
perftestdb(> , first_name
perftestdb(> );
employee_id | first_name
-------------+------------
1 | SCOTT
2 | SMITH
3 | JOHN
(3 rows)

perftestdb=> explain (memory, buffers, analyze, verbose)
perftestdb-> SELECT *
perftestdb-> FROM
perftestdb-> (
perftestdb(> VALUES
perftestdb(> (1, 'SCOTT')
perftestdb(> ,(2, 'SMITH')
perftestdb(> ,(3, 'JOHN' )
perftestdb(> ) t1 (
perftestdb(> employee_id
perftestdb(> , first_name
perftestdb(> );
QUERY PLAN
--------------------------------------------------------------------------------------------------------
Values Scan on "*VALUES*" (cost=0.00..0.04 rows=3 width=36) (actual time=0.010..0.013 rows=3 loops=1)
Output: "*VALUES*".column1, "*VALUES*".column2
Planning:
Memory: used=11kB allocated=16kB
Planning Time: 0.174 ms
Execution Time: 0.050 ms
(6 rows)

Oracle Database (23.8)
PostgreSQLと同一シンタックスでOKです。

SCOTT@localhost:1521/freepdb1> l
1 SELECT /*+ MONITOR */ *
2 FROM
3 (
4 VALUES
5 (1, 'SCOTT')
6 ,(2, 'SMITH')
7 ,(3, 'JOHN' )
8 ) t1 (
9 employee_id
10 , first_name
11* )
SCOTT@localhost:1521/freepdb1> /

EMPLOYEE_ID FIRST
----------- -----
1 SCOTT
2 SMITH
3 JOHN

経過: 00:00:00.00


実行計画もPostgreSQLのようにVALUES SCANとして現れます。VIEWとあるようにインラインビューとして認識されている点も読み取れますよね

SCOTT@localhost:1521/freepdb1> @show_sqlmonitor

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

SQL Text
------------------------------
SELECT /*+ MONITOR */ * FROM ( VALUES (1, 'SCOTT') ,(2, 'SMITH') ,(3, 'JOHN' ) ) t1 ( employee_id , first_name )

...略...

Global Stats
=============================
| Elapsed | Cpu | Fetch |
| Time(s) | Time(s) | Calls |
=============================
| 0.00 | 0.00 | 2 |
=============================

SQL Plan Monitoring Details (Plan Hash Value=1233125608)
======================================================================================================================
| Id | Operation | Name | Rows | Cost | Time | Start | Execs | Rows | Activity | Activity Detail |
| | | | (Estim) | | Active(s) | Active | | (Actual) | (%) | (# samples) |
======================================================================================================================
| 0 | SELECT STATEMENT | | | | 1 | +0 | 1 | 3 | | |
| 1 | VIEW | | 3 | 6 | 1 | +0 | 1 | 3 | | |
| 2 | VALUES SCAN | | 3 | 6 | 1 | +0 | 1 | 3 | | |
======================================================================================================================

MySQL (8.4)
MySQLはすでに癖があることは解説済みですが、SELECT文で使う場合も行値コンストラクタが必要です。

mysql> SELECT  * 
-> FROM
-> (
-> VALUES
-> (1, 'SCOTT')
-> ,(2, 'SMITH')
-> ,(3, 'JOHN' )
-> ) t1 (
-> employee_id
-> , first_name
-> );
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds
to your MySQL server version for the right syntax to use near '(1, 'SCOTT')

,(2, 'SMITH')
,(3, 'JOHN' )
) t1 (
employee_id
, first' at line 5
mysql>
mysql> SELECT *
-> FROM
-> (
-> VALUES
-> ROW(1, 'SCOTT')
-> ,ROW(2, 'SMITH')
-> ,ROW(3, 'JOHN' )
-> ) t1 (
-> employee_id
-> , first_name
-> );
+-------------+------------+
| employee_id | first_name |
+-------------+------------+
| 1 | SCOTT |
| 2 | SMITH |
| 3 | JOHN |
+-------------+------------+
3 rows in set (0.00 sec)

MySQLの場合、実行計画だけでTVCが利用されているということは判断できないのはVALUESコマンドと同様。
(小さい癖ですが。SQL文を合わせて見るようにしないと見落としてしまう可能性はありますね。実行計画だけ見るってこと自体があまり無いとは思いますが、そういう方も中にはいるので。)

mysql> explain analyze format=tree
-> SELECT *
-> FROM
-> (
-> VALUES
-> ROW(1, 'SCOTT')
-> ,ROW(2, 'SMITH')
-> ,ROW(3, 'JOHN' )
-> ) t1 (
-> employee_id
-> , first_name
-> );
+---------------------------------------------------------------------------------------------------------+
| EXPLAIN |
+---------------------------------------------------------------------------------------------------------+
| -> Table scan on t1 (cost=1.15..2.84 rows=3) (actual time=0.078..0.0795 rows=3 loops=1)
-> Materialize (cost=0.3..0.3 rows=3) (actual time=0.0713..0.0713 rows=3 loops=1)
-> Rows fetched before execution (cost=0..0 rows=3) (actual time=993e-6..0.00162 rows=3 loops=1)
|
+---------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)


すでに特徴的な癖がいくつかありますが、次は、TVCに関わる表エイリアスと列エイリアスの指定に有無に関わる癖の違いの確認。
三者三様の癖があります。試験に出るので覚えておきましょう!(ないないw

1) TVCインラインビューで、表エイリアスと列エイリアスを記述しなかった場合
Oracle DatabaseとMySQLでは表エイリアスは必須なのでエラーなのですが、PostgreSQLは許容範囲広いっすね!

PostgreSQL (17.6)

perftestdb=> select * from (values (1),(2));
column1
---------
1
2
(2 rows)

MySQL (8.4.7)

mysql> select * from (values row(1),row(2));
ERROR 1248 (42000): Every derived table must have its own alias

Oracle Database (23.8)

SCOTT@localhost:1521/freepdb1> select * from (values (1),(2));
select * from (values (1),(2))
*
行1でエラーが発生しました。:
ORA-00931: 識別子がありません。
ヘルプ:
https://docs.oracle.com/error-help/db/ora-00931/


2) TVCインラインビューで、表エイリアス記述した場合
1)でエラーとなったMySQLはシンタックスエラーなし=表エイリアスの記述は必須!。列エイリアスは任意?!っぽい。
しかし、Oracle Databaseはエラーのままです、列エイリアスも必要!!!!!。

PostgreSQL (17.6)

perftestdb=> select * from (values (1),(2)) t01;
column1
---------
1
2
(2 rows)

MySQL (8.4.7)

mysql> select * from (values row(1),row(2)) t01;
+----------+
| column_0 |
+----------+
| 1 |
| 2 |
+----------+
2 rows in set (0.01 sec)

Oracle Database (23.8)

SCOTT@localhost:1521/freepdb1>  select * from (values (1),(2)) t01;
select * from (values (1),(2)) t01
*
行1でエラーが発生しました。:
ORA-63814: 表値コンストラクタの別名に列名を指定する必要があります。
ヘルプ:
https://docs.oracle.com/error-help/db/ora-63814/


3) TVCインラインビューで、表エイリアスと列エイリアスを記述した場合
やっと、全て正常に実行された!!!

MySQL/PostgreSQLでは任意とは言え、実際に利用する場合にはSQLコーディングルールで縛るでしょうね。絶対。
そういう意味では、Oracle Databaseのように必須にしちゃったほうがSQL各側にとっては楽なのではないだろうか。ミスるとエラーにしてくれし。

PostgreSQL (17.6)

perftestdb=> select * from (values (1),(2)) t01(id);
id
----
1
2
(2 rows)

MySQL (8.4.7)

mysql> select * from (values row(1),row(2)) t01(id);
+----+
| id |
+----+
| 1 |
| 2 |
+----+
2 rows in set (0.00 sec)

Oracle Database (23.8)

SCOTT@localhost:1521/freepdb1> select * from (values (1),(2)) t01(id);

ID
----------
1
2

4) TVCインラインビューで、表エイリアスと列エイリアスを記述したが、記述した列エイリアス数と列数不一致の場合
PostgreSQLとOracle Databaseは予想通りの挙動でしたが、MySQLは想定の斜め上の挙動!

PostgreSQLは列エイリアスは任意だし、列値の個数と一致しなくても、Whatever!
Oracle Database、列エイリアスは必須だし、列値の個数と一致してないと、ダメ、絶対!
MySQL、列エイリアスは任意だけど、指定するなら列値の個数と一致してないと、ダメ!

個性派揃いですね!!!!w

ところで、PostgreSQL付与の列エイリアスって、列順なのね。2列目の列エイリアスを記述しないと、column2 が付与される。

PostgreSQL (17.6)

perftestdb=> select * from (values (1,1),(2,2)) t01(id);
id | column2
----+---------
1 | 1
2 | 2
(2 rows)

MySQL (8.4.7)

mysql> select * from (values row(1,1),row(2,2)) t01(id);
ERROR 1353 (HY000): In definition of view, derived table or common table expression,
SELECT list and column names list have different column counts

Oracle Database (23.8)

SCOTT@localhost:1521/freepdb1> select * from (values (1,1),(2,2)) t01(id);
select * from (values (1,1),(2,2)) t01(id)
*
行1でエラーが発生しました。:
ORA-63815: 列名の数は、表値コンストラクタの値の数と一致する必要があります。
ヘルプ:
https://docs.oracle.com/error-help/db/ora-63815/

5) TVCインラインビューで、表エイリアスと列値の数と同数の列エイリアスを指定した場合
こう書けば何も問題ないよーっ。

PostgreSQL (17.6)

perftestdb=> select * from (values (1,1),(2,2)) t01(id,seq1);
id | seq1
----+------
1 | 1
2 | 2
(2 rows)

MySQL (8.4.7)

mysql> select * from (values row(1,1),row(2,2)) t01(id,seq1);
+----+------+
| id | seq1 |
+----+------+
| 1 | 1 |
| 2 | 2 |
+----+------+
2 rows in set (0.00 sec)

Oracle Database (23.8)

SCOTT@localhost:1521/freepdb1> select * from (values (1,1),(2,2)) t01(id,seq1);

ID SEQ1
---------- ----------
1 1
2 2

WITH句で使うこともできます!(細かい挙動までは追わないが)

PostgreSQL (17.6)

perftestdb=> WITH 
perftestdb-> t01 AS
perftestdb-> (
perftestdb(> SELECT *
perftestdb(> FROM
perftestdb(> (
perftestdb(> VALUES
perftestdb(> (1, 'SCOTT')
perftestdb(> ,(2, 'SMITH')
perftestdb(> ,(3, 'JOHN' )
perftestdb(> ) x01 (
perftestdb(> employee_id
perftestdb(> , first_name
perftestdb(> )
perftestdb(> )
perftestdb-> SELECT * FROM t01;
employee_id | first_name
-------------+------------
1 | SCOTT
2 | SMITH
3 | JOHN
(3 rows)

perftestdb=> explain (memory, buffers, analyze, verbose)
perftestdb-> WITH
perftestdb-> t01 AS
perftestdb-> (
perftestdb(> SELECT *
perftestdb(> FROM
perftestdb(> (
perftestdb(> VALUES
perftestdb(> (1, 'SCOTT')
perftestdb(> ,(2, 'SMITH')
perftestdb(> ,(3, 'JOHN' )
perftestdb(> ) x01 (
perftestdb(> employee_id
perftestdb(> , first_name
perftestdb(> )
perftestdb(> )
perftestdb-> SELECT * FROM t01;
QUERY PLAN
--------------------------------------------------------------------------------------------------------
Values Scan on "*VALUES*" (cost=0.00..0.04 rows=3 width=36) (actual time=0.002..0.003 rows=3 loops=1)
Output: "*VALUES*".column1, "*VALUES*".column2
Planning:
Memory: used=22kB allocated=32kB
Planning Time: 0.039 ms
Execution Time: 0.011 ms
(6 rows)

Oracle Database (23.8)

SCOTT@localhost:1521/freepdb1> l
1 WITH
2 t01 AS
3 (
4 SELECT *
5 FROM
6 (
7 VALUES
8 (1, 'SCOTT')
9 ,(2, 'SMITH')
10 ,(3, 'JOHN' )
11 ) x01 (
12 employee_id
13 , first_name
14 )
15 )
16* SELECT /*+ MONITOR */ * FROM t01
SCOTT@localhost:1521/freepdb1> /

EMPLOYEE_ID FIRST
----------- -----
1 SCOTT
2 SMITH
3 JOHN

SCOTT@localhost:1521/freepdb1> @show_sqlmonitor

...略...

Global Stats
========================================
| Elapsed | Cpu | Other | Fetch |
| Time(s) | Time(s) | Waits(s) | Calls |
========================================
| 0.00 | 0.00 | 0.00 | 2 |
========================================

SQL Plan Monitoring Details (Plan Hash Value=1233125608)
======================================================================================================================
| Id | Operation | Name | Rows | Cost | Time | Start | Execs | Rows | Activity | Activity Detail |
| | | | (Estim) | | Active(s) | Active | | (Actual) | (%) | (# samples) |
======================================================================================================================
| 0 | SELECT STATEMENT | | | | 1 | +0 | 1 | 3 | | |
| 1 | VIEW | | 3 | 6 | 1 | +0 | 1 | 3 | | |
| 2 | VALUES SCAN | | 3 | 6 | 1 | +0 | 1 | 3 | | |
======================================================================================================================


Oracle Databaseの場合、通常はインラインビューへリライトされるケースでも、マテリアライズすることができるので、実行計画がどう変化するかも見ておきましょう!
一時表としてマテリアライズされ、CURSOR DURATION MEMORYによりPGA上に一時的に保持されています。すべてPGAに乗る程度のサイズなら繰り返し参照されるケースでは有利なのは自明です。このケースでは無駄ですがw

SCOTT@localhost:1521/freepdb1> l
1 WITH
2 t01 AS
3 (
4 SELECT /*+ MATERIALIZE */ *
5 FROM
6 (
7 VALUES
8 (1, 'SCOTT')
9 ,(2, 'SMITH')
10 ,(3, 'JOHN' )
11 ) x01 (
12 employee_id
13 , first_name
14 )
15 )
16* SELECT /*+ MONITOR */ * FROM t01
SCOTT@localhost:1521/freepdb1> /

EMPLOYEE_ID FIRST
----------- -----
1 SCOTT
2 SMITH
3 JOHN

経過: 00:00:00.00
SCOTT@localhost:1521/freepdb1> @show_sqlmonitor

...略...

Global Stats
=================================================
| Elapsed | Cpu | Other | Fetch | Buffer |
| Time(s) | Time(s) | Waits(s) | Calls | Gets |
=================================================
| 0.00 | 0.00 | 0.00 | 2 | 2 |
=================================================

SQL Plan Monitoring Details (Plan Hash Value=1856684117)
=============================================================================================================================================================================
| Id | Operation | Name | Rows | Cost | Time | Start | Execs | Rows | Mem | Activity | Activity Detail |
| | | | (Estim) | | Active(s) | Active | | (Actual) | (Max) | (%) | (# samples) |
=============================================================================================================================================================================
| 0 | SELECT STATEMENT | | | | 1 | +0 | 1 | 3 | . | | |
| 1 | TEMP TABLE TRANSFORMATION | | | | 1 | +0 | 1 | 3 | . | | |
| 2 | LOAD AS SELECT (CURSOR DURATION MEMORY) | SYS_TEMP_0FD9D660A_6FD25E | | | 1 | +0 | 1 | 1 | 1024 | | |
| 3 | VIEW | | 3 | 6 | 1 | +0 | 1 | 3 | . | | |
| 4 | VALUES SCAN | | 3 | | 1 | +0 | 1 | 3 | . | | |
| 5 | VIEW | | 3 | 2 | 1 | +0 | 1 | 3 | . | | |
| 6 | TABLE ACCESS FULL | SYS_TEMP_0FD9D660A_6FD25E | 3 | 2 | 1 | +0 | 1 | 3 | . | | |
=============================================================================================================================================================================

MySQL (8.4.7)

mysql> WITH 
-> t01 AS
-> (
-> SELECT *
-> FROM
-> (
-> VALUES
-> ROW(1, 'SCOTT')
-> ,ROW(2, 'SMITH')
-> ,ROW(3, 'JOHN' )
-> ) x01 (
-> employee_id
-> , first_name
-> )
-> )
-> SELECT * FROM t01;
+-------------+------------+
| employee_id | first_name |
+-------------+------------+
| 1 | SCOTT |
| 2 | SMITH |
| 3 | JOHN |
+-------------+------------+
3 rows in set, 0 warning (0.00 sec)

mysql> explain analyze format=tree
-> WITH
-> t01 AS
-> (
-> SELECT *
-> FROM
-> (
-> VALUES
-> ROW(1, 'SCOTT')
-> ,ROW(2, 'SMITH')
-> ,ROW(3, 'JOHN' )
-> ) x01 (
-> employee_id
-> , first_name
-> )
-> )
-> SELECT * FROM t01;
+-------------------------------------------------------------------------------------------------------+
| EXPLAIN |
+-------------------------------------------------------------------------------------------------------+
| -> Table scan on x01 (cost=1.15..2.84 rows=3) (actual time=0.0102..0.0105 rows=3 loops=1)
-> Materialize (cost=0.3..0.3 rows=3) (actual time=0.00871..0.00871 rows=3 loops=1)
-> Rows fetched before execution (cost=0..0 rows=3) (actual time=208e-6..417e-6 rows=3 loops=1)
|
+-------------------------------------------------------------------------------------------------------+
1 row in set, 0 warning (0.00 sec)

では、最後に、もう一つだけ確認。

再掲
Oracle Database / Release 23 / values_clause
https://docs.oracle.com/cd/G11854_01/sqlrf/SELECT.html#GUID-CFA006CA-6FF1-4972-821E-6996142A51C6__SECTION_UMB_QGC_FWB

values_clause::= 、および、expression_list::=
Oracle Databaseの場合、シンタックスを見る限り、value_clauseに含めることができる Expression_listの制限が、TVCで指定できる最大行数になりそうですよね。わかりにくいですが。。この点は今回確認しておきましょう。
https://docs.oracle.com/en/database/oracle/oracle-database/26/sqlrf/IN-Condition.html#SQLRF-GUID-C7961CB3-8F60-47E0-96EB-BDCF5DB1317C


Oracle Database (23.8)のTVCでは、マニュアルのシンタックス等から推測するに、生成できる行数に制限があるように読み取れるのだが、MySQL/PostgreSQLともにそれに類する記載は見つけられなかった。
ただ、いずれもメモリはそれなりに消費するようなので、メモリ消費量はそれなりの影響はありそうではある。。。
(明示されている箇所があればマニュアルのURLを教えていただけるとありがたい)


Oracle Database (23.8)
ということで、Oracle Database (23.8)の上限と思われる。 65535行前後程度までTVCで生成し挙動だけ(上限でエラーになるのか?)を確認しておく。
なお、Oracle Database 23ai FREEはインスタンスが利用できるメモリサイズ上限自体が2GBなので、検証する前にメモリ関連エラーになる可能性はある。。どうなりますか。。。

コード生成 Oracle 無名PL/SQL (Oracle DatabaseでMySQL向けSQLも生成しちゃいますw)。コードは後述。


マニュアルだと、65535行まではできそうだったが、65534行までがただしいようだ。いずれにしても実際に使うとなると1000行以下だとおもうけど。

65535行を生成するTVCはORA-63805: 表値コンストラクタのタプルの最大数を超えました となりました。あれ?

SCOTT@localhost:1521/freepdb1> @make_tvc_sql0.sql 65535 oracle
SCOTT@localhost:1521/freepdb1> set autot traceonly
SCOTT@localhost:1521/freepdb1> @sql_oracle_65535
SELECT * FROM ( VALUES
*
行1でエラーが発生しました。:
ORA-63805: 表値コンストラクタのタプルの最大数を超えました
ヘルプ:
https://docs.oracle.com/error-help/db/ora-63805/

経過: 00:00:00.05


ということで、65534行生成するTVCにすると実行できました。とは言ってもtopで眺めてみるとメモリ消費は激しいなという状況。。。その辺り別の機会に。

ちなみに、Oracle Database 23ai FREEって2GBっていうメモリの制限があったりするので、このケースだと explain plan for や autotrace expとかで実行計画も取得しようとするとメモリがらみのエラーが発生した(FREEのメモリサイズ制限2GBまでなので増やせない罠)ので、実行統計だけにしてあります。:)
この手の限界テストしようとするとFREEのメモリ制限ってキツいですよねw

SCOTT@localhost:1521/freepdb1> @make_tvc_sql0 65534 oracle
SCOTT@localhost:1521/freepdb1> set autot on stat
SCOTT@localhost:1521/freepdb1> @sql_oracle_65534

ID
----------
1
2
3

...略...

65532
65533
65534

65534行が選択されました。

経過: 00:53:31.31

統計
----------------------------------------------------------
1 recursive calls
0 db block gets
0 consistent gets
0 physical reads
0 redo size
1269854 bytes sent via SQL*Net to client
680591 bytes received via SQL*Net from client
4370 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
65534 rows processed

Tvc_for_adventcalendar


PostgreSQL (17.6)

TVCで生成する行数制限はなさそうですが、Planningのメモリサイズは1行生成の単純なものと比べるとかなり増えてますね。

perftestdb=> \i /var/lib/pgsql/sql_postgresql_65534.sql
QUERY PLAN
-----------------------------------------------------------------------------------------------------------------
Values Scan on "*VALUES*" (cost=0.00..819.18 rows=65534 width=4) (actual time=0.009..5.500 rows=65534 loops=1)
Output: "*VALUES*".column1
Planning:
Buffers: shared hit=3
Memory: used=19977kB allocated=26113kB
Planning Time: 10.755 ms
Execution Time: 7.745 ms
(7 rows)

perftestdb=> \i /var/lib/pgsql/sql_postgresql_65535.sql
QUERY PLAN
-----------------------------------------------------------------------------------------------------------------
Values Scan on "*VALUES*" (cost=0.00..819.19 rows=65535 width=4) (actual time=0.008..5.561 rows=65535 loops=1)
Output: "*VALUES*".column1
Planning:
Buffers: shared hit=3
Memory: used=19977kB allocated=26113kB
Planning Time: 10.969 ms
Execution Time: 7.825 ms
(7 rows)

MySQL (8.4.7)
MySQLも何事もなく実行できちゃいますね。マニュアルにはTVCの行数制限はないですが、多分、でかくするとメモリ消費は激しくなるんだろなぁ。と、想像しています。PostgreSQLもPlannerのメモリ使用量がかなり大きくなっていたので。。

mysql> \. sql_mysql_65535.sql
+-------------------------------------------------------------------------------------------------------------+
| EXPLAIN |
+-------------------------------------------------------------------------------------------------------------+
| -> Table scan on t1 (cost=6554..7375 rows=65535) (actual time=15.9..20.9 rows=65535 loops=1)
-> Materialize (cost=6554..6554 rows=65535) (actual time=15.9..15.9 rows=65535 loops=1)
-> Rows fetched before execution (cost=0..0 rows=65535) (actual time=360e-6..11.2 rows=65535 loops=1)
|
+-------------------------------------------------------------------------------------------------------------+
1 row in set (0.09 sec)

mysql> \. sql_mysql_65534.sql
+-------------------------------------------------------------------------------------------------------------+
| EXPLAIN |
+-------------------------------------------------------------------------------------------------------------+
| -> Table scan on t1 (cost=6553..7375 rows=65534) (actual time=13.4..18.5 rows=65534 loops=1)
-> Materialize (cost=6553..6553 rows=65534) (actual time=13.4..13.4 rows=65534 loops=1)
-> Rows fetched before execution (cost=0..0 rows=65534) (actual time=452e-6..9.02 rows=65534 loops=1)
|
+-------------------------------------------------------------------------------------------------------------+
1 row in set (0.08 sec)


ということで、今年のアドベントカレンダーネタ、TVCの癖! はここまで。


あす、13番目の窓は、それぞれ。
Kenji Hirano さんのターン / JPOUG Advent Calendar 2025
yuya_yoshida_forcia さんのターン / PostgreSQL Advent Calendar 2025
mita2 さんのターン / MySQL Advent Calendar 2025
です。おたのしみに〜。


私のターンdone. では、また。

Enjoy SQLs and SQLの癖!





テスト用SQL生成スクリプト(Oracle Database 23ai)
このスクリプトでMySQL、PostgreSQL、Oracle Databaseそれぞれのテストスクリプトを出力する無名PL/SQLブロック

Oracle向けtvc確認SELECT文生成(65534行を生成する例)
e.g.

SQL> @make_tvc_sql0 65534 oracle
SQL> @sql_oracle_65534

make_tvc_sql0.sql

set feed off
set timi off
set head off
set termout off
set veri off
set trimspool on

set linesize 400
set pagesize 1000
SET SERVEROUTPUT ON
spool sql_&2._&1..sql
DECLARE
c_max_rows CONSTANT NUMBER := &1;
c_rvc_text_mysql CONSTANT CHAR(3) := 'ROW';
c_type_mysql CONSTANT CHAR(5) := 'MYSQL';
c_type CONSTANT VARCHAR2(10) := UPPER('&2');
BEGIN
DBMS_OUTPUT.PUT_LINE('SELECT * FROM ( VALUES');
FOR i IN 1..c_max_rows LOOP
DBMS_OUTPUT.PUT_LINE(
CASE WHEN i > 1 THEN ',' END
|| CASE WHEN c_type = c_type_mysql THEN c_rvc_text_mysql END
|| '(' || TO_CHAR(i)
|| ')'
);
END LOOP;
DBMS_OUTPUT.PUT_LINE(') t1 ( id );');
END;
/
spool off
SET SERVEROUTPUT OFF
UNDEFINE 1
UNDEFINE 2


set head on
set termout on
set feed on
set veri on
set timi on
set trimspool off






関連エントリー
標準はあるにはあるが癖の多い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にも癖がある)
帰ってきた! 標準はあるにはあるが癖の多いSQL #15 - 実行計画でスカラー副問合せの見せ方にも癖がでる
帰ってきた! 標準はあるにはあるが癖の多いSQL #16 - FROM句のインラインビューのエイリアスにもクセがある(必須だったり、任意だったり)
帰ってきた! 標準はあるにはあるが癖の多いSQL #17 - ANY_VALUE() ってなかなかいいじゃん、癖無さそう!
帰ってきた! 標準はあるにはあるが癖の多いSQL #18 - t_alias と c_alias にも癖が出る
帰ってきた! 標準はあるにはあるが癖の多いSQL #19 - c_alias の癖(おまけ)

| | | コメント (0)

2025年12月 3日 (水)

2025年11月にリリースした曲 / DTM / GarageBand

Apple Loopとチョップで頑張るDTM 
11月は次の2曲でした:)


∞ Loops / N + 1 Loops
粛々と仕事をやっつける時のw BGM用、無限ループさせるループw

Risky Loops / N + 1 Loops
Inspired by 坂本龍一 feat. Iggy Pop / Risky Extended Mixのドラム音w なのですが、まあ、こんなもんです。


では、また。

Enjoy DTM and GarageBand!

| | | コメント (0)