2026年7月 4日 (土)

2026年6月に作ったLoop


Quest Loop / N + 1 Loops
ぼやーーんと、作ってたら、なんとなく、 RPGでQuestへ出発するみたいな雰囲気になってしまったw

Chill Time Loops / N + 1 Loops
なんとなーく、ドラムトラック作ってたらいい感じのグルーブ感でてきたので、その勢いで作ってみたw


いつになったら、GarageBandをメジャーアップデートするつもりなんだろう。Appleさん。

ではまた。

Enjoy DTM and GarageBand!

| | | コメント (0)

2026年6月13日 (土)

帰ってきた! 標準はあるにはあるが癖の多いSQL #23 - 直近データの結合方法。オールドファッションな構文 vs. モダンな構文。

新しい期間に切り替わり2026.6-2027.5期も Oracle ACE Pro となりました。:) で、新シーズン最初のエントリー。



今日のテーマは、
直近データの結合方法、オールドファッションな構文 vs. モダンな構文。そして、今回の癖はSQL文というよりも、その実行計画や挙動にあります!!!! お楽しみに!
(そういえば、モダンな って表現、外資系方面の会社でよく使われますよね。RDBMS界隈でも。むかーーし、そこが気になり過ぎて眠れなくなったことがありましたw モダンとは、、、みたいなw)

ところで、みなさん、
表にバージョン、タイムスタンプやらで履歴データを含があり、直近のデータとだけ結合したいなんてことないですかね。。。。意外と多いのかなぁ。履歴は履歴だから分離するとうのもあるわけですけども。
データ量にしても、少量データ(OLTP)から大量データ(BATCH、DWH etc)までいろいろです。

と、いろいろなケースはあるのですが、OLTP向けには、どのような構文で行うのがよいだろうというところにフォーカスしたいと思います。
(少量でもそこそこいけるし、大量データでもパラレル化しちゃっていい感じになる方法もあれば、そうでもない方法まであるわけですけども)

今回も面白い癖というか特徴を見ることができますよ。 ;)



データの準備(各データベースに同じ表、索引、データを用意します。以下、PostgreSQLの定義)
perftestdb=> \d+ master
Table "scott.master"
Column | Type | Collation | Nullable | Default | Storage | Compression | Stats target | Description
--------+---------+-----------+----------+---------+---------+-------------+--------------+-------------
id | integer | | not null | | plain | | |
Indexes:
"master_pkey" PRIMARY KEY, btree (id)
Access method: heap

perftestdb=> \d+ detail
Table "scott.detail"
Column | Type | Collation | Nullable | Default | Storage | Compression | Stats target | Description
--------+----------------------+-----------+----------+---------+----------+-------------+--------------+-------------
id | integer | | not null | | plain | | |
vnum | integer | | not null | | plain | | |
col1 | character varying(1) | | | | extended | | |
Indexes:
"pk_detail" PRIMARY KEY, btree (id, vnum)
"ix2_detail" btree (vnum)
Access method: heap


id=200に該当するdetail表のデータは存在しない状態にしてあります。

perftestdb=> SELECT id FROM master ORDER BY id;
id
----
1
2
3
4
5
200
(6 rows)


各id毎のvnumの個数は以下のとおり. id=300は100,000個あります。また直近データは、最もvnumが大きいものという設定です。
OLTPを想定しているので、履歴データがどう影響するかしないのかも見るために多めにしてあります。

perftestdb=> SELECT id,COUNT(vnum)  vnum_cout FROM detail GROUP BY id ORDER BY id;
id | vnum_cout
-----+-----------
1 | 3
2 | 1
3 | 100
4 | 98
5 | 98

...略...

97 | 98
98 | 98
99 | 98
100 | 98
300 | 100000
(101 rows)

perftestdb=> SELECT id,vnum,col1 FROM detail WHERE id = 300 ORDER BY vnum DESC FETCH FIRST 10 ROWS ONLY;
id | vnum | col1
-----+--------+------
300 | 100000 | 1
300 | 99999 | 1
300 | 99998 | 1
300 | 99997 | 1
300 | 99996 | 1
300 | 99995 | 1
300 | 99994 | 1
300 | 99993 | 1
300 | 99992 | 1
300 | 99991 | 1
(10 rows)



トップバッターは、Oracle Database、直近データだけ結合する方法は複数ありますが、オールドファッションな書き方から、比較的新しい構文(モダンな構文としておきますw)の順で試していきます。


1) 不等価結合 + 自己結合による方式
(以下はOracle Database向けにUNNEST最適化を抑止する目的でヒントを利用していますが、
他のRDBMSでは取り除いてください)

この方法、稀ですが、OLTPで見かけることがあります。(危険な香りw)
履歴データが少量であることが確実なら、あまり痛い目にあうことはないとは思います、け、ど、も。
どの辺がやばそうかは、いいませんので、考えてみてください。
(考えるまでもねぇ、脊髄反応してるあなた、さすがですね。(最近のAI風w 褒めるとこから入るw)

SELECT 
t1.id AS t1id
,t2.id AS t2id
,t2.vnum AS vnum
FROM
master t1
LEFT OUTER JOIN (
SELECT
t2_latest.id
, t2_latest.vnum
FROM
detail t2_latest
WHERE
NOT EXISTS (
SELECT /*+ UNNEST NL_AJ */
1
FROM
detail t2_all
WHERE
t2_latest.id = t2_all.id
AND t2_latest.vnum < t2_all.vnum
)
) t2
ON
t1.id = t2.id
WHERE
t1.id = 300
;


2) MAX()関数 + 自己結合 + スカラー副問合せ方式
この方法もむかーしからよく見ます。王道な方法だと思います。
最適な索引は必須ですが、非常に安定した性能を得られる方法です。
デメリットとして、自己結合が避けられないのと、ぱっと見なにやっているか理解しにくいところかなと。(経験の浅い方は特に!)

SELECT 
t1.id AS t1id
,t2.id AS t2id
,t2.vnum AS vnum
FROM
master t1
LEFT OUTER JOIN DETAIL t2
ON
t1.id = t2.id
AND t2.vnum = (
SELECT
MAX(t3.vnum)
FROM
detail t3
WHERE
t3.id = t1.id
)
WHERE
t1.id = 300
;


3) ROW_NUMBER()ウィンドウ関数方式
(分析系クエリではもうお馴染みのROW_NUMBERウインドウ関数)

この方法、OLTPでも比較的多く、履歴データが多くないのが確実ならリスクは少ない方法ではあります。
自己結合も排除できますし、可読性も良いですよね。
しかし、履歴データ多くないのが確実なら、と書いたように一癖あるので、OLTP で利用する場合少々注意が必要です。
(とことが、PostgreSQLとMySQLそれぞれに、想像してなかった癖がありましたw 良い癖と悪い癖w)
履歴データ量が予測できないのなら避けたほうが良い方法だと思います。(癖の良し悪し次第でもありますがw)
逆にバッチ処理や分析系で大量データを処理するなら得意分野だと思いますよね。
この方法の癖とは何か? も考えてみてください。:)
なお、この方法は、オプティマイザやプランナの述語プッシュダウン最適化等に依存してます。(ヒントw

SELECT 
t1.id AS t1id
, t2.id AS t2id
, t2.vnum
FROM
master t1
LEFT OUTER JOIN (
SELECT
id
, vnum
, ROW_NUMBER() OVER (
PARTITION BY
detail.id
ORDER BY
detail.id DESC
, detail.vnum DESC
) AS latest
FROM
detail
) t2
ON
t1.id = t2.id
AND t2.latest = 1
WHERE
t1.id = 300
;


4)LATERAL JOIN + Top 1 Query方式
(なお、PostgreSQL/MySQLでも fetch first n rows only 構文は利用できますが、limit nでも同様、Oracle Database では rownum を使っても同じですが、おすすめは、fetch first n rows only かな。長いけどw)

この方法 OLTP のためにあるようなものなので、うまく活用するといいと思うのですよね。
少量データ返すケースで SELECT リストないで利用するスカラー副問合せのような使い方をイメージしてもらうと良いかなと思います。NLJにしかならないので。
自己結合も排除できることに加え、適切な索引によるソートバイパス、そして、Top 1 Query の活用で無駄のない直近データ取得を可能にしています。

SELECT 
t1.id AS t1id
, t2.id AS t2id
, t2.vnum
FROM
master t1
LEFT OUTER JOIN LATERAL (
SELECT
t2l.id
, t2l.vnum
FROM
detail t2l
WHERE
t2l.id = t1.id
ORDER BY
t2l.id DESC
, t2l.vnum DESC
FETCH FIRST 1 ROWS ONLY
) t2
ON TRUE
WHERE
t1.id = 300
;




当初、ログ見てもらいつつまとめは後半で、ほう!
みたいな構成で書こうと考えていたのですが、ログがめちゃめちゃ長いので最初にまとめを書いちゃいますねw
(ログを見て、あーだーこーだ考えてもらいつつ、あれがいいよねー、という流れがおもしろいかなーとは思っていたのですけども。。。w 流石に長すぎて疲れるかなとw)




OLTPに適している直近データの結合方法はこれだ!!!!!!

結果としては、各構文の解説でも気づかれたのではないかと思いますが、

LATERAL JOIN + Top 1 Query方式が、OLTPで直近データだけ結合したいという場合には、ベストな選択だろうな。と。
2013年ごろに登場した(内部的にはもっと前から最適化として含まれていたRDBMSもあります)LATERAL JOIN なので、新しいというほどでもないですが、ひとまず、モダンな方法としておきますねw

一方、オールドファッションな方法であるMAX()関数+自己結合+スカラー副問合せ方式もかなり良いわけでが、自己結合だけは避けられません。
ここがポイントです。それなりに安定していて良い結果は得られるのですが。

また、どちらの方法も履歴データが大量だったとしても、必要最小限のデータだけを安定してアクセスします。
自己結合を回避できないMAX()関数+自己結合+スカラー副問合せ方式では、それが弱点ではあるのですが。

なお、実装の違からMySQLだけは、MAX()関数+自己結合+スカラー副問合せ方式のほうが早かったというのは面白い発見でした。(後述)





まとめ
OLTP前提で、直近データを結合するためのおすすめの構文
Oracle Database
モダンな方式である LATERAL JOIN + Top 1 Query 方式

PostgerSQL
モダンな方式である LATERAL JOIN + Top 1 Query 方式
面白い挙動は、 ROW_NUMBER()ウィンドウ関数方式の索引降順スキャンを行い最初の2行目、つまり、直近データを読み終えたところでスキャンを止めること。Oracleには見られない挙動。
MySQLでは、そもそも述語プッシュダウンすらできなかった(不具合?)

MySQL
オールドファッションな方式である MAX()関数 + 自己結合 + スカラー副問合せ方式.
なお、LATERAL JOIN + Top 1 Queryも非常に安定しているが、MAX()関数 + 自己結合 + スカラー副問合せ方式 の実行計画はMySQLの実行計画で最強のRows fetched before executionなので勝ち目なしw

続きを読む "帰ってきた! 標準はあるにはあるが癖の多いSQL #23 - 直近データの結合方法。オールドファッションな構文 vs. モダンな構文。"

| | | コメント (0)

2026年6月 9日 (火)

2026年5月に作ったLoop

To Sigh Loops v1.1 - Dub version of Too many Loops - / N + 1 Loops
80'sのなにかの曲を思い出してもらえればw


A certain Loops / N + 1 Loops
ぼやーーんとしたいときむけw


以上、2曲でした。

Enjoy DTM and GarageBand.

GarageBandにもAIきたりするのだろうか。。。

| | | コメント (0)

2026年5月 9日 (土)

2026年4月に作ったLoop


Too many Loops / N + 1 Loops
これ作ってる時にイントロ部分のシンセ使ったダブバージョンが浮かんで即作ったのだが、その後v1.1リリースしたので、こいつだけ。ということにしておくw


| | | コメント (0)

2026年4月10日 (金)

2026年3月に作ったLoop


Stare blankly Loops / N + 1 Loops
これも粛々と仕事をこなすときの無限ループBGMとして思いつきでつくったやつの一つ。


Cherry Blossom Loops 2026 / N + 1 Loops
ちょうど桜が咲いてたので今年バージョン(昨年も作ってたけどねw)。前述のループのドラム部分だけ気に入ってたので、他にも再利用したいなー思いつつ。他にも思いついたので今月は別のを作ってるわけですけどもねw。

| | | コメント (0)

2026年3月22日 (日)

2026年2月に作ったLoop

Loops and Loops! / N + 1 Loops
先月作ったループのドラムトラックが気に入りw再利用してなにかを作るということだけが目的で作ってみた一つ目。

Heavy Query Blues Loops / N + 1 Loops
ブルース風になったが、それなりに雰囲気でたかもw これもドラムトラックの一部は先月作ったループのを再利用してます。

| | | コメント (0)

2026年3月10日 (火)

x86/64 VMs on VirtualBox for macOS - Apple Silicon / Oracle Database , PostgreSQL, MySQL rebooted! :)

さてさて、半年振りぐらいの、VirtualBox for macOS / Apple Silicon ネタです。
前々回のVirtualBoxエントリーで、VirtualBox 7.2でもフラグを立てれば x86/64 VMsを起動できるところまでは確認できました。ただし、Oracle Databaseは起動できませんでしたよね。

20260310-192000

しばらく、忙しくて忘れてたので、久々に試してみたら、なんと!!!!!!! 起動するじゃあーーーーーーーーーりませんか。;)
これで、x86/64版の古いOracle Databaseとの比較ネタなんてのみできちゃうので、遅くても嬉しい。VirtualBox Teamのみなさん、ありがとう!


では、その記録です。

ホスト環境

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

*** mac info. ***
ProductName: macOS
ProductVersion: 26.3.1
BuildVersion: 25D2128

*** 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.2.7r173034

oracle@Mac-Studio ~ % VBoxManage getextradata global "VBoxInternal2/EnableX86OnArm"
Value: 1


起動していいるVirtualBox VMsとArchitectureの確認

oracle@Mac-Studio ~ % VBoxManage list --long runningvms | grep -E 'Platform Architecture|Name'
Name: Oracle Linux 8 21c and postgresql13
Platform Architecture: x86
Name: Oracle Linux 8 mysql8 postgrsql13
Platform Architecture: x86

続きを読む "x86/64 VMs on VirtualBox for macOS - Apple Silicon / Oracle Database , PostgreSQL, MySQL rebooted! :)"

| | | コメント (0)

2026年2月18日 (水)

ミックの楽しいSQLパズル / 書籍

ミックさん、インプレス様から恵贈いただきました。 :)

馴染みやすいタイトル。

SQLパズル本!
ぶ、ぶ厚いw
1日、1SQLパズルにチャレンジするか

 

ありがとうございました

Hbbfdbdbqae8e5h

Hbbfdbcbsaq0_xs

| | | コメント (0)

2026年2月 8日 (日)

2026年1月に作ったLoop


Winter Loops 2026 / N + 1 Loops
2022年にGarageBandをrebootしたときに作ったWinter Loopsを新たに作ろうとおもったが、今聞くと最初のやつのニュアンスに近いほうがよかったのかもねとかw


Winter Sunny Loops / N + 1 Loops
で、Winterでもいい天気の日はぼーっとできたりしていいかなとおもいつつ、先のLoopのドラムトラックをほぼ流用しつつ載せるものをかえてみたやつ。


WOW Loops! / N + 1 Loops
作ってて面白かなと思うのはFUNK系の路線であることを再認識w
前の2つのLoopでも使っていたドラムセットをさらに流用しつつテンポとリズムを少々かえて、さらにFUNKなループをチョップしたりまんまつかったり、VOXで遊びつつできたのがこれ。



Logic ProにAI来るって話もありますが、GarageBandのメジャーアップデートはどうなるんだろうね。。。。
20260208-65619

ではまた。

Enjoy DTM, GarageBand!

| | | コメント (0)

2026年2月 5日 (木)

Oracle Database - Multi Row INSERT、バインド変数を使うとリテラル値を使う場合では見える景色が変わるんだよね #最終回 - ぐるぐるしちゃう影響

Previously on Mac De Oracle
Oracle Database - Multi Row INSERT、バインド変数を使うとリテラル値を使う場合では見える景色が変わるんだよね #4 - The SQL was transformed!

前回は、Multi row Insertをリモート表へインサートするとSQL transformの影響で、
DUAL表アクセスがオーバーヘッドとなり Multi row Insertのメリットが削がれてしまう(現時点の仕様では)ということを確認しました!
偶々リモート表に実行したから気づけたわけですがw。あの仕様に気付けたのはラッキーというべきかw


ということで、脇道にそれまくったこのシリーズも、やっと最終回です!


リモート表を使ってぐるぐるしてネットワークラウンドトリップを乗せる必要はなくて、
それが自然に乗るAPサーバーとDBサーバー間の状況を作ればよいだけなので、
最終回は素直にw
JavaからOracle Databaseへアクセスしローカル表に対してぐるぐるしちゃいながら、
Single row insert を繰り返すぐるぐる系と、
Multi row insert を利用して、ゆるやかに、ぐーるぐーるするタイプで 100,000 行を登録してみようと思いますw

N+1問題の類とネットワークラウンドトリップとネットワークレイテンシーと、コミット間隔などパラメータは多いですが、だいたい 100 - 1000 行程度付近前後にリーズナブルなポイントが現れていますよね。。。
(ちなにみSQL*Netのパラメータ等はデフォのままです。また、リモート表ではないので、OPEN_CURSORSもデフォルトのままの 300 で問題ありません。参考まで) 

バインド変数利用と、どの程度の単位でまとめてインサートするか、コミットの間隔など沢山のパラメータがあるので、そららの様子をみながら表を見てもらうと面白いと思います。
なお、いつものように後半にログと利用したコードなどをまとめて載せています。
(今回は、生成AIのGeminiくんにサクッと書いてもらいましたw)

Multi Row Insertで、100 - 1000行程度まとめるとメモリにもCPUにも優しくなりますね。単純に、1行毎ぐるぐるすると無駄が多くなるのは一目瞭然だと思います。

Oracle-database-multi-row-insert-5-1

続きを読む "Oracle Database - Multi Row INSERT、バインド変数を使うとリテラル値を使う場合では見える景色が変わるんだよね #最終回 - ぐるぐるしちゃう影響"

| | | コメント (0)

2026年2月 4日 (水)

Oracle Database - Multi Row INSERT、バインド変数を使うとリテラル値を使う場合では見える景色が変わるんだよね #4 - The SQL was transformed!

Previously on Mac De Oracle
前回は、Oracle Database - Multi Row INSERT、バインド変数を使うとリテラル値を使う場合では見える景色が変わるんだよね #3 - ローカル表とリモート表での挙動の差異?! でした。

復習を兼ねて、前回の表(再掲)をみつつ。23aiでサポートされたMulti row Insert文をローカル表とリモート表(via DB Link)へ実行してみると。。なんと。想定外の結果に。。。

Oracle-database-multi-row-inser_20260204210701

v$mystatから得られた統計値をみると、execution countやparse count (total) - parse count (hard) それに伴うパースタイムなどなど、一体何が起きてるの。。。。。(ニヤニヤ
という感じでした。

さらに、リモート表に対して、1,000 rows / INSERT で Multi row Insert すると、OPEN_CURSORS = 300(default)では足らず、 1,300まで増やすと不足しないという、状況。

なにか引っかかりますよね。単純にSQLをまるっとリモートDB (インスタンスは同じだけど、DB Linkでパススルーして投げているだけでは??。。。と思っていたが) へ投げているだけではなさそうな様子。

ということで、その謎を追い Oracle Database の奥へ進んでいきましょう ;)

続きを読む "Oracle Database - Multi Row INSERT、バインド変数を使うとリテラル値を使う場合では見える景色が変わるんだよね #4 - The SQL was transformed!"

| | | コメント (0)

2026年2月 3日 (火)

Oracle Database - Multi Row INSERT、バインド変数を使うとリテラル値を使う場合では見える景色が変わるんだよね #3 - ローカル表とリモート表での挙動の差異?!

Previously on Mac De Oracle
前回は、
Oracle Database - Multi Row INSERT、バインド変数を使うとリテラル値を使う場合では見える景色が変わるんだよね #2
このシリーズものの本題でした。(それ書くまでの寄り道が長かったわけですがw)

ということで今日は、その続編!!

前回で完結じゃないの?!

はいw 、というか再び、脱線していきます! www

前回使った無名PL/SQLブロックのスクリプト(バインド変数を使っている方だけですが)を使って、ローカル表とリモート表(via Database Link)へMulti row Insertするとどうなるのか?
覚えていますか? 前々回、いろいろなバグやら未実装やらのエラーにハマりまくり、なんとかリモート表へMulti row Insert文を投げることに成功した話を。。。。

ローカル表とリモート表だとどのような景色の違いがあるか、絶対、Network Round Trips(dblinkの)が増加するよね!!! 

だとすると、差分(処理時間など含め)の多くは、そのDatabase Linkを介して発生するNetwork Round Trips部分だけのはず。。。ネットワークレイテンシーの影響が見えやすくなる? だろう。。。。。か。
(PL/SQLだからリモート表にするしかなかったのですが、本来なら、JavaやらPythonやらアプリケーションから実行するだけでその部分は見えるわけですけどもね。一応、PL/SQLでやってた流れで、やってみようかなと。。。。w 数々のバグやら仕様やらにハマりましたが。。。w)

ログが長いので、まとめから!w
ポイントになりそうなところだけv$mystatからまとめた表ですが、一目瞭然で、妙な箇所があります。
私が、事前に想定していたのは、execute countはローカル表と同じ値ですし、当然ですが、parse count (total) - parse count (hard) の数もローカル表と同じ想定でした。100rows付近がもっとも結果が良いのはどちらでも同じではあるのですが。。
また、それらに加えて、1,000rows/INSERTにしたケースでは、リモート表へのINSERTで、OPEN_CURSORS(デフォルト 300)が枯渇し、+1,000の 1,300に増加すると枯渇しかなった点です。1,000rowsの時に+1,000したOPEN_CURSORSで枯渇回避になるというのも、気になりますよね。。。。。

SQL*Net roundtrips to/from dblinkが乗ってくるのは、想定通りですが、なんとなく数も多めですしね。。。なんだろうこの違和感w。。。。
想定していた挙動と随分違いそう。。。。DB Linkをつかっちゃったからからもしれないですけども。。。。。。。。

Oracle-database-multi-row-insert-3-1

続きを読む "Oracle Database - Multi Row INSERT、バインド変数を使うとリテラル値を使う場合では見える景色が変わるんだよね #3 - ローカル表とリモート表での挙動の差異?!"

| | | コメント (0)

2026年2月 2日 (月)

Oracle Database - Multi Row INSERT、バインド変数を使うとリテラル値を使う場合では見える景色が変わるんだよね #2

Previously on Mac De Oracle
前回は、
Oracle Database - Multi Row INSERT、バインド変数を使うと、リテラル値を使う場合では見える景色が変わるんだよね #1 - バグなのか現時点の仕様なのか?
でした。本題からちょっと脱線気味でしたがw、今日は、Multi Row INSERT、バインド変数を使うとリテラル値を使う場合では見える景色が変わるんだよね。の本題。(やっとw)


前々回、帰ってきた! 標準はあるにはあるが癖の多いSQL #22 - Multi Row INSERTのようにリテラル値のままでMulti row Insertしちゃうと言う無茶なことやっていると、いくらメモリ(メモリだけでもないけども)があったも足らなくなるよなーーー。というのはイメージできたと思うので、今日はバインド変数化すると景色がどう変わるか(良い方に)見てみましょう。


Use The Bind Variable, Luke!

メモリ消費も抑えられますし。ハードパースコストも下げられますし。:)
特にOracle Databaseのようにハードパースなど比較的重量級かつカーソルシェアリングなど含むキャッシュ機能満載のRDBMSでは絶大な効果を発揮します。はい。

リテラル値のままのmulti row insertとバインド変数化した場合のPGA周り含めた景色、どうかわるでしょうねぇ。。。。(そんなことわかっとる! と言う方は見なくて良いです ;)


前回色々ハマりながら作ってたw 無名PL/SQLブロックを含むスクリプトを利用(Geminiくんにもお手伝いしてもらいw)して、ローカル表(リモート表の話は別ネタにてw)へアクセスして、バインド変数有無でそのような景色の違いがでるかを見てみましょう。

23aiでサポートされたMulti row Insert構文で、10行、100行、1000行まとめてインサートする文のPGA/UGAの最大サイズを比較。


バインド変数を利用せず、1000行まとめたMulti row Insertでは、SQL文をCLOBで保持した影響で、PGAから溢れて、一時LOBを利用した影響で、log write/readが発生。PGA/UGAは多少減り、変わり一時表領域へのIO増加ということからパース時間が随分伸びたことがわかります!
バインド変数を利用した場合とのPGA/UGA消費サイズ、および、パースタイムは大幅に軽減されていて、各種リソースにも優しくなっているのが見えますよね!(ハードパース回数でも一目瞭然)
あと、傾向として、100行毎ぐらいにまとめるのが全体的にリーズナブルな傾向はありますよね。(この前後がリーズナブルって肌感覚とも一致してるんですよね。何行ぐらいにしようかなー。と探る時もだいだいこれぐらいの前後一桁ずらしてってことは多いかな)

パース時間とPGA/UGAの最大サイズ比較
Oracle-database-multi-row-insert-2-pga1

続きを読む "Oracle Database - Multi Row INSERT、バインド変数を使うとリテラル値を使う場合では見える景色が変わるんだよね #2"

| | | コメント (0)

2026年1月27日 (火)

Oracle Database - Multi Row INSERT、バインド変数を使うと、リテラル値を使う場合では見える景色が変わるんだよね #1 - バグなのか現時点の仕様なのか?

Previously on Mac De Oracle
前回は、
帰ってきた! 標準はあるにはあるが癖の多いSQL #22 - Multi Row INSERT でした。
TVC(Table Value Constractor)の流れではあったのですが、通常やるとは思えないリテラルを使ったMulti row insertで大量の行を詰め込んでみました!
TVCはともかく、Multi row insertをリテラル値で、かつ、大量の行を詰め込むのはリーズナブルな方法ではないですよね。特にOracle Databaseでは。というあたりに気づければそれで良いと思います:)

PostgreSQL/MySQLは幾分マイルドなw 結果でしたが、Oracle Databaseは、らしい特徴がでていましたよね。
ハードパースコストがめちゃめちゃ高くて。 

 

そういえば、
以前、
パースが重いぞーというネタをやってたことありましたが、取り上げたハードパースがキツくなるネタは、Oracle Databaseで索引のある列に対してIN句を使い大量の値をセットするネタでした。(これ意外と見かけます)
それ以外のケースだと、MySQLで結合する表が多くて考え過ぎてるケース。
どちらも実行計画を立てるためにオプティマイザが考え過ぎてしまう(得られる実行計画は良いのですが)ことでパース時間が異常に長くなる症状でしたよね!
悩ませ過ぎは及ばざるがごとし #3
悩ませ過ぎは及ばざるがごとし #4
悩ませ過ぎは及ばざるがごとし #7 - おまけ
悩ませ過ぎは及ばざるがごとし (MySQL 8.0.32編)

ただ、今回取り上げたOracle DatabaseのINSERT(Multi row insert)は、どちらかというとメモリリソース確保の影響が色濃い状況でした。(パース時の帯域イベントもほぼそれだけ)
リテラル値を使い、大量の行を詰め込んだ巨大なmulti row insert文を実行するのは考えものですよね。まじでw


前置きはそれぐらいにして、
前回、そんなことやる人いないでしょーっ、というノリで、リテラル値を使い巨大なMulti row insertを行いましたが、
通常なら、バインド変数使いますよね! 絶対!w

ということで、バインド変数を利用したMulti row insertの準備をしていた際に気づいたバグというか現時点の仕様というかなんというかw にハマった記録です! が今回のネタ。
(Oracle Database 23ai FREEのPL/SQLからの実行だと、現時点では、EXECUTE IMMEDIATEを利用してバインド変数化することぐらいしかできなそう!)
まじで?! という状況なので、細かい確認は次のリリース以降で再度試してみようかなと。

 

続きを読む "Oracle Database - Multi Row INSERT、バインド変数を使うと、リテラル値を使う場合では見える景色が変わるんだよね #1 - バグなのか現時点の仕様なのか?"

| | | コメント (0)

2026年1月 8日 (木)

帰ってきた! 標準はあるにはあるが癖の多いSQL #22 - Multi Row INSERT

Previously on Mac De Oracle
と言いたいところですが、前回は、読了ネタだったのでw 前々回の話に関連して。。。

前々回は、帰ってきた! 標準はあるにはあるが癖の多いSQL #21 - Table Value Constructer(TVC)- ハードパース時間とメモリ消費量 / BONUS TRACKでした。
おまけのおまけ的な内容で前々回のネタと関連はあるのですが、TVCではなく、Multi Row INSERTの癖の確認というか、メモリ消費量などの傾向を、肌感覚で覚えておきましょうね。 というネタです。

Oracle Databaseで以下のような表を作成、PostgreSQL/MySQLでも同様に作成しておきます。

create table mrows_ins_tab
(
id integer not null primary key,
col1 varchar2(1000),
col2 varchar2(1000),
col3 varchar2(1000),
col4 varchar2(1000),
col5 varchar2(1000),
col6 varchar2(1000),
col7 varchar2(1000),
col8 varchar2(500)
);


Oracle Databaseの方言、multi table insertの対象を単一表にしてmulti row insertのPGA消費傾向を見る。
行数を変えつつ以下のようなINSERT ALL文にて検証。

SCOTT@localhost:1521/freepdb1> !cat sql_mrows_ins_5000.sql
INSERT ALL
INTO mrows_ins_tab(id, col8) VALUES(1,
'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx1')

...略...

INTO mrows_ins_tab(id, col8) VALUES(5000,
'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx5000')
SELECT * FROM dual;

手始めに5000行をガツンとINSERT ALLにて。この程度の行サイズと行数でも300MB超えのPGA消費ですね。

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
---------- ---------------------------------------------------------------- ----------
39 CPU used by this session 4
39 CPU used when call started 3

...略...

39 session pga memory 4254712
39 session pga memory max 5123744
39 session uga memory 1844408
39 session uga memory max 3053904

...略...

SCOTT@localhost:1521/freepdb1> @sql_mrows_ins_5000

5000行が作成されました。

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

SID NAME VALUE
---------- ---------------------------------------------------------------- ----------
39 CPU used by this session 550
39 CPU used when call started 550

...略...

39 session logical reads 26402
39 session pga memory 88534008
39 session pga memory max 339274744
39 session uga memory 84055376
39 session uga memory max 85103896

...略...

続きを読む "帰ってきた! 標準はあるにはあるが癖の多いSQL #22 - Multi Row INSERT"

| | | コメント (0)