2021年12月 1日 (水)

誰がどんな名前のペットを飼っているのかな? その1 / JPOUG Advent Calendar Day 1

今年も師走の風物詩、JPOUGアドベントカレンダーがはじまりましたー。2021も残すところ1ヶ月。来年も元気にOnline, In personでお会いしたいですね!

前置きはごれぐらいにして、

今回の私のエントリー、Oracleというかデータベース使う必要はないのですが、RDBMSというかSQLで解けるじゃん、この問題! 
ということで、中二の期末試験で「時間があったらチャレンジしてね!」という問題をネタにしてみました。

なお、本エントリーと、12/23日のエントリーの二部構成にして、本エントリーではネタ振りのみです!w

SQLがからんでいればどうやって解いても良いと思っています。冬の夜長に、ワイン片手に、頭の体操するのもよいのではないでしょうか? 
皆さんも考えてみてくださいね。

この問題、中学二年の数学のおまけの問題なので、紙と鉛筆、頭の良い方は、頭の中だけでも解けるわけですがw  
あえて、SQLで頑張ってみましょうw

問題は以下の通り。



Hiro, Larry, Scott, Steveは、Cat, Dog, Snake, Turtleのうち、どれか 1 種類のペットを飼っています。同じ種類のペットおよび、同じ名前のペットを飼っている人はいません。 4 人のペットの名前は、Lisa, Taro, TIger, Wendyのいずれかです。

  • Hiro :「僕が飼っているのは、Tiger だよ。 Turtle じゃないよ」
  • Larry : 「Snake の名前は、Lisa じゃないよ」
  • Scott : 「僕は Snake を飼っているよ」
  • Steve : 「Dog の名前は Wendy だよ。僕は Dog はかってないけど」

誰がどんな名前のペットを飼っているのかな?



 

答え合せは12/23の窓で行う予定です。

みなさん、お好きな方法で解いてみてください。。 :)

ちなみに、私は、愚直な方法でw 答えを導きだすつもりです。 みなさんは、よりスマートな方法を考えてみるのもおもしろいかもしれませんね!

答えではないですが、私がパッと考えている脳内イメージをアウトプットしておきます。(私のイメージにこだわる必要はないので、みなさんは自由な発想で取り組んでいただければと思います)

問題から、ざっくりとエンティティをイメージしてみると3つ。

  • ペットのオーナー
  • ペットの名前
  • 動物の種類

ただ、これだと、多:多の関係になってしまうので、関連エンティティぐらいは作ったほうが無難ですよね。そのままデカルト演算して答えを導きだすツワモノもいるかもしれませんがw 

で、関連エンティティをこれまた、ざっくりイメージしてみると、こちらも3つありそうですよね。問題文をよーく読み込んでみてください。3つ見えますよー。

  • 「ペットのオーナー」と「ペットの名前」を関連づけるエンティティ
  • 「ペットの名前」と「動物の種類」を関連づけるエンティティ
  • 「ペットのオーナー」と「動物の種類」を関連づけるエンティティ

こんな感じ、で6つのエンティティが浮かんだのですが、みなさんはどうみえますか?

 

少々悩んだののですが、この問題を解くために、後半の3つのエンティティを表で実装するか、ビューで実装するかってところもあるかなぁと。表にしなくてもビューでもいいかーと。

ということで、私は、以下を3表を元に、

  • ペットのオーナー
  • ペットの名前
  • 動物の種類

関連は、以下の3つのビューで実装してみようかなーと。(妄想中)

  • 「ペットのオーナー」と「ペットの名前」を関連づけるビュー
  • 「ペットの名前」と「動物の種類」を関連づけるビュー
  • 「ペットのオーナー」と「動物の種類」を関連づけるビュー

3つの表と3つのビューを駆使してw SQLだけで、愚直に、解く予定ですw

なお、元になる3エンティティに対応した表のDDLとデータは以下のような感じで。


create table owners (name varchar2(30) not null unique);
create table pets (name varchar2(30) not null unique);
create table animals (kind varchar2(30) not null unique);
-- owners
insert into owners(name) values('Hiro');
insert into owners(name) values('Larry');
insert into owners(name) values('Scott');
insert into owners(name) values('Steve');
-- pets
insert into pets(name) values('Lisa');
insert into pets(name) values('Taro');
insert into pets(name) values('Tiger');
insert into pets(name) values('Wendy');
-- animals
insert into animals(kind) values('Cat');
insert into animals(kind) values('Dog');
insert into animals(kind) values('Snake');
insert into animals(kind) values('Turtle');
commit;

SCOTT@ORCL> select name from owners;

NAME
-------------------------------
Hiro
Larry
Scott
Steve

Elapsed: 00:00:00.01
SCOTT@ORCL> select name from pets;

NAME
------------------------------
Lisa
Taro
Tiger
Wendy

Elapsed: 00:00:00.01
SCOTT@ORCL> select kind from animals;

KIND
------------------------------
Cat
Dog
Snake
Turtle

Elapsed: 00:00:00.01

 

では、12/23の答え合せまで、みなさんも、ワイングラス片手に、(お酒が苦手な方はウィルキンソンでもw)自由にあそんでみてください :)

明日は、12/2、二つ目の窓は、渡部さんです。お楽しみにーっ。

 

| | コメント (0)

2021年9月25日 (土)

古くて新しい? 遅延ブロッククリーンアウト (deferred block cleanout) #12

Previously on Mac De Oracle
前回、前々回とIASでdirect path writeであるか否かで、そのコミットおよび遅延ブロッククリーンアウトの有無が決まるという動きを確認しました。

今回は、DDLですが、親戚みたいな挙動のCTASではどうなるか確認しておきます。CTASはDDLなのでコミットは不要ですよね。また、 direct path writeが前提になっていることも皆さんご存知の通り。

ということは、IAS + APPENDヒントで、direct path write させた時と同じような挙動になるはず。。。。ですよね。

手順はいつもの図でご確認ください。(DDLなので手順も単純になっています)
Ctas_steps




0) 対象表のdrop
対象表のHOGE2は削除しておきます。CTASで作成することになるので。

SCOTT@orcl> @droppurge_hoge2.sql
1* drop table hoge2 purge

Table dropped.

Elapsed: 00:00:02.79


1) 統計をクリアするためOracle再起動

$ sudo service oracle restart


2) PDBのscottでログインしてclient_infoをセット
v$sessionのclient_info列の'TargetSession'文字列で他のSCOTTユーザーのセッションを特定するため。

SCOTT@orcl> @set_client_info
1 begin
2 DBMS_APPLICATION_INFO.SET_CLIENT_INFO('Target Session');
3* end;

PL/SQL procedure successfully completed.

Elapsed: 00:00:00.00
SCOTT@orcl>


3) CDBのSYSで統計取得(初回)
内容は省略!(ベースラインを取得しているだけなので)

SYS$orclcdb> @show_stat scott
...略...


4) PDBのSCOTTユーザーでCTAS(データサイズは、コミットクリーンアウトではクリーンアウト仕切れないサイズ

SCOTT@orcl> @ctas_from_hoge.sql
1* create table hoge2 as select * from hoge

Table created.

Elapsed: 00:00:07.41


5) CDBのSYSで統計取得(CTAS後)
DDLなのでコミットはありませんが、念の為に確認すると、commit cleanouts、commit cleanouts successfully completed はほんの少しだけ。このテストケースではノイズ程度の量です。
DDL終了時にクリーンアウトは発生していないと読み取れます。(この後の手順で遅延クリーンアウトも発生していなければ。direct path writeではクリーンアウトが必要な状態にはならないということは間違いないと判断するできますよね)

参考程度ですが、physical writes 、physical writes direct、physical writes non checkpoint が同数です。物理書き込みが発生し、かつ、direct path writeでチェックポイントで書き出されたものではないということが確認できます。想定通り、CTASは direct path writeで書き出されているということがわかります。
(HOGE表のデータが載っているブロック数は、66667 ブロックであることは以前確認した通りの値です)

また、physical reads と physical reads direct は、HOGE表のブロック数以上あり、HOGE表は direct path readでお読み込まれていることがわかります。このときのfree buffer requested は非常に低いことは、バッファキャッシュを介さず、ストレージへ書き出されていることを示しています。

統計値が変動したもののみ記載
(CDB)システム統計

SOURCE  NAME                                                           VALUE
------- ---------------------------------------------------- ---------------
sysstat commit cleanouts 21
sysstat commit cleanouts successfully completed 21
sysstat consistent gets 72654
sysstat db block changes 3898
sysstat deferred (CURRENT) block cleanout applications 7
sysstat free buffer requested 819
sysstat immediate (CURRENT) block cleanout applications 8
sysstat no work - consistent read gets 69569
sysstat physical reads 67150
sysstat physical reads direct 66709
sysstat physical writes 66667
sysstat physical writes direct 66667
sysstat physical writes non checkpoint 66667

(PDB) SCOTTのセッション統計

SOURCE  NAME                                                           VALUE
------- ---------------------------------------------------- ---------------
sesstat commit cleanouts 21
sesstat commit cleanouts successfully completed 21
sesstat consistent gets 72366
sesstat db block changes 3898
sesstat deferred (CURRENT) block cleanout applications 7
sesstat free buffer requested 818
sesstat immediate (CURRENT) block cleanout applications 8
sesstat no work - consistent read gets 69415
sesstat physical reads 67149
sesstat physical reads direct 66709
sesstat physical writes 66667
sesstat physical writes direct 66667
sesstat physical writes non checkpoint 66667


6) PDBのSCOTTユーザーで遅延ブロッククリーンアウト有無確認(対象表をscattered readで全表走査)

IASで direct path writeさせた場合同様に、direct path writeで書き出された場合、クリーンアウトするブロックは存在しないため、遅延ブロッククリーンアウトも発生しないという状況になります。
REDOは多少生成あれていますが、recursive call 等によるものと考えられ、このテストケースではノイズの類程度です。システム/セッション統計値をみることでその点も確認できます。

SCOTT@orcl> @table_full_scan_hoge2.sql
1* alter session set "_serial_direct_read" = never

Session altered.

Elapsed: 00:00:00.00
1* alter session set "_very_large_object_threshold" = 20400

Session altered.

Elapsed: 00:00:00.00
set autot trace exp stat

1* select * from hoge2

200000 rows selected.

Elapsed: 00:00:06.66

Execution Plan
----------------------------------------------------------
Plan hash value: 1530105727

---------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 200K| 382M| 18174 (1)| 00:00:01 |
| 1 | TABLE ACCESS FULL| HOGE2 | 200K| 382M| 18174 (1)| 00:00:01 |
---------------------------------------------------------------------------

Statistics
----------------------------------------------------------
14 recursive calls
12 db block gets
80022 consistent gets
66669 physical reads
2108 redo size
406775148 bytes sent via SQL*Net to client
147265 bytes received via SQL*Net from client
13335 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
200000 rows processed

set autot off


7) CDBのSYSで統計取得(遅延ブロッククリーンアウト有無確認。対象表をscattered readで全表走査)
deferred (CURRENT) block cleanout applications や、immediate (CURRENT) block cleanout applicationsなど遅延ブロッククリーンアウトで動く統計に極わずかに動きがありますが、数ブロックなので気にする程度ではないです。遅延ブロッククリーンアウトは発生していないと読み取れます。

また、physical reads は該当表のブロック数程度のブロック数となっており、physical reads direct が発生していないことから、 scattered read でバッファキャッシュに載せられたことが確認できます。free buffer requested もほぼ同じ値になっていることからも同様のことが言えます。

統計値が変動したもののみ記載
(CDB)システム統計

SOURCE  NAME                                                           VALUE
------- ---------------------------------------------------- ---------------
sysstat commit cleanouts 16
sysstat commit cleanouts successfully completed 16
sysstat consistent gets 105725
sysstat db block changes 255
sysstat deferred (CURRENT) block cleanout applications 8
sysstat free buffer requested 67608
sysstat immediate (CURRENT) block cleanout applications 2
sysstat no work - consistent read gets 94138
sysstat physical reads 67567

(PDB) SCOTTのセッション統計

SOURCE  NAME                                                           VALUE
------- ---------------------------------------------------- ---------------
sesstat commit cleanouts 6
sesstat commit cleanouts successfully completed 6
sesstat consistent gets 86719
sesstat db block changes 43
sesstat deferred (CURRENT) block cleanout applications 3
sesstat free buffer requested 66791
sesstat immediate (CURRENT) block cleanout applications 2
sesstat no work - consistent read gets 82976
sesstat physical reads 66783




まとめ

CTASはDDLで、 direct path write を伴うため、IASのAPPEND同様、対象データブロックはクリーンアウトが必要な状態にはならず、コミットおよび遅延ブロッククリーンアウトは発生しない!
ことが確認できました。 :)

次回は、一旦中締めにしますか。

つづく。


目がショボショボしてるから、なにか浮遊物の影響を受けてる気がする。ブタクサやヨモギの季節だもんな。(目だけなんだよなー。アレルギーの酷方のように鼻水でたりとかではなくて。疲れ目用の目薬では、効かないw)



古くて新しい? 遅延ブロッククリーンアウト (deferred block cleanout) #1
古くて新しい? 遅延ブロッククリーンアウト (deferred block cleanout) #2
古くて新しい? 遅延ブロッククリーンアウト (deferred block cleanout) #3
古くて新しい? 遅延ブロッククリーンアウト (deferred block cleanout) #4
古くて新しい? 遅延ブロッククリーンアウト (deferred block cleanout) #5
古くて新しい? 遅延ブロッククリーンアウト (deferred block cleanout) #6
古くて新しい? 遅延ブロッククリーンアウト (deferred block cleanout) #7
古くて新しい? 遅延ブロッククリーンアウト (deferred block cleanout) #8
古くて新しい? 遅延ブロッククリーンアウト (deferred block cleanout) #9
古くて新しい? 遅延ブロッククリーンアウト (deferred block cleanout) #10
古くて新しい? 遅延ブロッククリーンアウト (deferred block cleanout) #11



| | コメント (0)

2021年9月24日 (金)

古くて新しい? 遅延ブロッククリーンアウト (deferred block cleanout) #11

Previously on Mac De Oracle
前回は、クリーンアウトの後始末をさせられる側ではなく、そもそも、後始末不要な状況もあるという確認でした。
IAS(Insert as Select)でdirect path writeで書き込まれたブロックは、クリーンアウトする必要がない状態なので、コミットクリーンアウトも遅延ブロッククリーンアウトも発生していないことはシステム統計やセッション統計からも明らかでした。

今回は、今一度確認ということで、IASでも非direct path writeだったら、やはりコミットクリーンアウトや遅延ブロッククリーンアウトは発生するよね! というところだけは見ておこうと思います。

手順は前回と同じ。前回と異なる点は、4) の部分。IASで NOAPPEND ヒントを使い direct path writeを抑止している部分のみ。
Iasstep





0) 対象表のdrop/create

SCOTT@orcl> @droppurge_create_hoge2.sql
1* drop table hoge2 purge

Table dropped.

Elapsed: 00:00:00.67
1* create table hoge2 (id number, data varchar2(2000))

Table created.

Elapsed: 00:00:00.05
1* select segment_name,blocks from user_segments where segment_name like '%HOGE2%'

no rows selected

Elapsed: 00:00:00.16


1) 統計をクリアするためOracle再起動

$ sudo service oracle restart


2) PDBのscottでログインしてclient_infoをセット
v$sessionのclient_info列の'TargetSession'文字列で他のSCOTTユーザーのセッションを特定するため。

SCOTT@orcl> @set_client_info
1 begin
2 DBMS_APPLICATION_INFO.SET_CLIENT_INFO('Target Session');
3* end;

PL/SQL procedure successfully completed.

Elapsed: 00:00:00.00
SCOTT@orcl>


3) CDBのSYSで統計取得(初回)
内容は省略!(ベースラインを取得しているだけなので)

SYS$orclcdb> @show_stat scott
...略...


4) PDBのSCOTTユーザーでIAS(データサイズは、コミットクリーンアウトではクリーンアウト仕切れないサイズ、コミットなし)
このケースでは 非direct path write でINSERTしたいので NOAPPEND ヒントで direct path write を抑止しています。

SCOTT@orcl> @ias_noappend_from_hoge.sql
1* insert /*+ noappend */ into hoge2 select * from hoge

200000 rows created.

Elapsed: 00:00:16.79


5) CDBのSYSで統計取得(APPENDヒント付きのIAS後、未コミット)

IASでHOGE表を読み込み、HOGE2表へ非direct path write している様子が確認できますよね。HOGE表の読み込みは direct path read 、HOGE2表へは 非direct path write していることが読み取れます。
free buffer requested で読み込みブロック相当のブロックがバッファキャッシュへ載せられているように見えますが、読み込みは direct path read なのでバッファキャッシュには載りません。ようするに、HOGE2表向けのデータと考えることができますよね。このキャッシュされたブロックが本当にHOGE2表向けブロックであるかどうかは、これ以降の操作で物理読み込みが発生しないということで確認することができます。


(HOGE表のデータが載っているブロック数は、66667 ブロックであることは前々回も確認した通りの値です)

統計値が変動したもののみ記載
(CDB)システム統計

SOURCE  NAME                                                           VALUE
------- ---------------------------------------------------- ---------------
sysstat DBWR checkpoint buffers written 19158
sysstat DBWR checkpoints 2
sysstat DBWR thread checkpoint buffers written 19158
sysstat DBWR transaction table writes 22
sysstat DBWR undo block writes 299
sysstat commit cleanouts 6
sysstat commit cleanouts successfully completed 6
sysstat consistent gets 110098
sysstat db block changes 443304
sysstat deferred (CURRENT) block cleanout applications 5
sysstat free buffer requested 67998
sysstat immediate (CURRENT) block cleanout applications 1
sysstat no work - consistent read gets 66823
sysstat physical reads 66730
sysstat physical reads direct 66709
sysstat physical writes 19158
sysstat physical writes from cache 19158
sysstat physical writes non checkpoint 19158
sysstat transaction tables consistent reads - undo records applied 2

(PDB) SCOTTのセッション統計

SOURCE  NAME                                                           VALUE
------- ---------------------------------------------------- ---------------
sesstat commit cleanouts 6
sesstat commit cleanouts successfully completed 6
sesstat consistent gets 109971
sesstat db block changes 443304
sesstat deferred (CURRENT) block cleanout applications 5
sesstat free buffer requested 67996
sesstat immediate (CURRENT) block cleanout applications 1
sesstat no work - consistent read gets 66781
sesstat physical reads 66730
sesstat physical reads direct 66709


6) PDBのSCOTTユーザーでコミットの実行

SCOTT@orcl> commit;

Commit complete.


7) CDBのSYSで統計取得(コミット後)
APPENDモードのIASと異なり、NOAAPENDモードでは、はやり、コミットクリーンアウトが発生しています。バッファキャッシュの10%-15%の範囲のブロックがコミット時にクリーンアウトされている状況が commit cleanouts successfully completed および、commit cleanouts から確認することができます。

統計値が変動したもののみ記載
(CDB)システム統計

SOURCE  NAME                                                           VALUE
------- ---------------------------------------------------- ---------------
sysstat commit cleanouts 55709
sysstat commit cleanouts successfully completed 55709
sysstat consistent gets 18547
sysstat db block changes 289
sysstat deferred (CURRENT) block cleanout applications 4
sysstat free buffer requested 791
sysstat no work - consistent read gets 10937
sysstat physical reads 758
sysstat transaction tables consistent reads - undo records applied 1

(PDB) SCOTTのセッション統計

SOURCE  NAME                                                           VALUE
------- ---------------------------------------------------- ---------------
sesstat commit cleanouts 55700
sesstat commit cleanouts successfully completed 55700
sesstat db block changes 1


8) PDBのSCOTTユーザーで遅延ブロッククリーンアウト有無確認(対象表をscattered readで全表走査)

direct path writeと非direct path writeの違いはハッキリでました。REDOログは大量に生成され、遅延ブロッククリーンアウトは発生しているようです。
また、物理読み込みは発生していないので、バッファキャッシュにヒットしているという状況も読み取れます。

SCOTT@orcl> @table_full_scan_hoge2.sql
1* alter session set "_serial_direct_read" = never

Session altered.

Elapsed: 00:00:00.00
1* alter session set "_very_large_object_threshold" = 20400

Session altered.

Elapsed: 00:00:00.00
set autot trace exp stat

1* select * from hoge2

200000 rows selected.

Elapsed: 00:00:05.74

Execution Plan
----------------------------------------------------------
Plan hash value: 1530105727

---------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 172K| 167M| 18223 (1)| 00:00:01 |
| 1 | TABLE ACCESS FULL| HOGE2 | 172K| 167M| 18223 (1)| 00:00:01 |
---------------------------------------------------------------------------

Note
-----
- dynamic statistics used: dynamic sampling (level=2)

Statistics
----------------------------------------------------------
19 recursive calls
13 db block gets
91462 consistent gets
2 physical reads
967388 redo size
406775148 bytes sent via SQL*Net to client
147265 bytes received via SQL*Net from client
13335 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
200000 rows processed
¥
set autot off


9) CDBのSYSで統計取得(遅延ブロッククリーンアウト有無確認。対象表をscattered readで全表走査)
実行統計の示す通り、遅延ブロッククリーンアウトが発生していることは、immediate (CR) block cleanout applications、cleanouts only - consistent read getsのブロック数からもハッキリ確認することができます!(コミットクリーンアウトできなかったブロック数です)

physical readsはほんの少しありますが、発生していないとみなしても良い程度です。このケースはscattered readが発生していない。つまり、非direct path writeでバッファキャッシュに載ったブロックにヒットしていることで、scattered readの必要がなかった! ということを意味しています。もし、この時、バッファキャッシュから該当表のブロックがある程度落ちていれば、physical readsが表のブロック数程度まで増加していたはずです。(多数の同時実行トランザクションが存在する状況であればキャッシュからエージアウトされ、物理読み込みが大量に発生するというケースは珍しくありません。その分処理時間も長くなるわけで、程度とデータサイズサイズしだいで処理時間も延びることが予想できます。場合よっては、処理時間がかかりすぎて、ザワザワしたり。。。w)

統計値が変動したもののみ記載
(CDB)システム統計

SOURCE  NAME                                                           VALUE
------- ---------------------------------------------------- ---------------
sysstat cleanouts only - consistent read gets 10967
sysstat commit cleanouts 19
sysstat commit cleanouts successfully completed 19
sysstat consistent gets 98619
sysstat db block changes 11065
sysstat deferred (CURRENT) block cleanout applications 8
sysstat free buffer requested 180
sysstat immediate (CR) block cleanout applications 10967
sysstat immediate (CURRENT) block cleanout applications 5
sysstat no work - consistent read gets 72340
sysstat physical reads 169

(PDB) SCOTTのセッション統計

SOURCE  NAME                                                           VALUE
------- ---------------------------------------------------- ---------------
sesstat cleanouts only - consistent read gets 10967
sesstat commit cleanouts 6
sesstat commit cleanouts successfully completed 6
sesstat consistent gets 98015
sesstat db block changes 11011
sesstat deferred (CURRENT) block cleanout applications 2
sesstat free buffer requested 121
sesstat immediate (CR) block cleanout applications 10967
sesstat immediate (CURRENT) block cleanout applications 2
sesstat no work - consistent read gets 72013
sesstat physical reads 113




まとめ

IASで 非direct path write してINSERTされた場合、ブロッククリーンアウトが通常通り発生する(コミット時でも遅延でも)
direct path write時との統計値の違いからも明らかですね。

前回のIAS(APPEND)時の遅延ブロッククリーンアウトがなかったケースの統計を再掲しておきます。統計値の違いをよーく確認してみてください。(試験に。。。でないですけどw)

統計値が変動したもののみ記載
(CDB)システム統計

SOURCE  NAME                                                            VALUE
------- ---------------------------------------------------- ---------------
sysstat cleanouts only - consistent read gets 1
sysstat commit cleanouts 16
sysstat commit cleanouts successfully completed 16
sysstat consistent gets 105046
sysstat db block changes 225
sysstat deferred (CURRENT) block cleanout applications 9
sysstat free buffer requested 67576
sysstat immediate (CR) block cleanout applications 1
sysstat immediate (CURRENT) block cleanout applications 2
sysstat no work - consistent read gets 93908
sysstat physical reads 67536

(PDB) SCOTTのセッション統計

SOURCE  NAME                                                           VALUE
------- ---------------------------------------------------- ---------------
sesstat cleanouts only - consistent read gets 1
sesstat commit cleanouts 6
sesstat commit cleanouts successfully completed 6
sesstat consistent gets 86566
sesstat db block changes 44
sesstat deferred (CURRENT) block cleanout applications 3
sesstat free buffer requested 66778
sesstat immediate (CR) block cleanout applications 1
sesstat immediate (CURRENT) block cleanout applications 2
sesstat no work - consistent read gets 82891
sesstat physical reads 66770

次回は、CTAS ( create table as select ) ではどうなるか確かめます。(まだいくつかの関連統計を動かせていないケースありw)

次回へつづく。


東京は、自転車での移動や買い物のほうが渋滞や混雑のストレスがなくていいな。久々に coutry side側をドライブしてたが、ノーストレレスだった。一転機能は、買い物でドライブするも、いちいち渋滞w
WfHも年単位になると、すでに都心の満員電車や渋滞に耐えられない感じになってる気がしないでもないw (渋滞でスタックしている時間がもったいないw)



古くて新しい? 遅延ブロッククリーンアウト (deferred block cleanout) #1
古くて新しい? 遅延ブロッククリーンアウト (deferred block cleanout) #2
古くて新しい? 遅延ブロッククリーンアウト (deferred block cleanout) #3
古くて新しい? 遅延ブロッククリーンアウト (deferred block cleanout) #4
古くて新しい? 遅延ブロッククリーンアウト (deferred block cleanout) #5
古くて新しい? 遅延ブロッククリーンアウト (deferred block cleanout) #6
古くて新しい? 遅延ブロッククリーンアウト (deferred block cleanout) #7
古くて新しい? 遅延ブロッククリーンアウト (deferred block cleanout) #8
古くて新しい? 遅延ブロッククリーンアウト (deferred block cleanout) #9
古くて新しい? 遅延ブロッククリーンアウト (deferred block cleanout) #10



| | コメント (0)

2021年9月22日 (水)

古くて新しい? 遅延ブロッククリーンアウト (deferred block cleanout) #10

Previously on Mac De Oracle
前回は、SELECT文であっても遅延ブロッククリーンアウトが発生すると該当ブロックは更新され、REDOログも生成される。ただし、direct path read で読み込まれた場合を除く。
という動きをみました。

今回もdirect pathがらみです。といっても direct path write だったら、コミットクリーンアウトや、遅延ブロッククリーンアウトはどういう扱いになるのだろう。。。と
(このシリーズの初回で紹介したいろいろなブログに答えはあるのですがw)

システム統計やセッション統計の統計値から、それをどう読み取るか。γGTP高いから肝臓あたりに問題があるか、検査前日に酒飲んじゃったでしょ! 的なところを診て、なにがおきているか診察していくシリーズなので、それぞれの統計と、auto traceによる実行計画と実行統計を診ていくわけですが。。w


ということで、今回は、前回利用していた表を元にIASで別表を作成し、コミット前後の状況を診ていきたいとおもいます。IASと言っても direct path write になるケースと従来型のロードがあるのは皆さんご存知だと思いますが、まずは、 direct path writeの方から挙動を診ていくことにします。手順はざっとこんな感じ
Iasstep

そういえば、以前、IASで、direct path write かどうか判別しやすくなったよねーというネタをやってましたね。実行計画だけでも違いがわかりやすくなっているので便利になりました。:)

実行計画は、SQL文のレントゲン写真だ! No.30より、LOAD TABL CONVENTIONAL vs. LOAD AS SELECTの実行計画の違い。
20210213-150833


20210213-150416





0) 対象表のdrop/create
SCOTT@orcl> @droppurge_create_hoge2.sql
1* drop table hoge2 purge

Table dropped.

Elapsed: 00:00:00.74
1* create table hoge2 (id number, data varchar2(2000))

Table created.

Elapsed: 00:00:00.07
1* select segment_name,blocks from user_segments where segment_name like '%HOGE2%'

no rows selected

Elapsed: 00:00:00.15

1) 統計をクリアするためOracle再起動

$ sudo service oracle restart


2) PDBのscottでログインしてclient_infoをセット
v$sessionのclient_info列の'TargetSession'文字列で他のSCOTTユーザーのセッションを特定するため。

SCOTT@orcl> @set_client_info
1 begin
2 DBMS_APPLICATION_INFO.SET_CLIENT_INFO('Target Session');
3* end;

PL/SQL procedure successfully completed.

Elapsed: 00:00:00.00
SCOTT@orcl>


3) CDBのSYSで統計取得(初回)
内容は省略!(ベースラインを取得しているだけなので)

SYS$orclcdb> @show_stat scott
...略...


4) PDBのSCOTTユーザーでIAS(データサイズは、コミットクリーンアウトではクリーンアウト仕切れないサイズ、コミットなし)
このケースでは direct path write でINSERTしたいので APPEND ヒントで direct path write を強制しています。 direct path read とは異なり、ヒントで制御できるのは楽w

SCOTT@orcl> @ias_from_hoge.sql
1* insert /*+ append */ into hoge2 select * from hoge

200000 rows created.

Elapsed: 00:00:10.42


5) CDBのSYSで統計取得(APPENDヒント付きのIAS後、未コミット)

IASでHOGE表を読み込み、HOGE2表へdirect path write している様子が確認できますよね。HOGE表の読み込みは direct path read 、HOGE2表へは direct path write している状況がはっきりでていてわかりやすい結果を得られました :)
(HOGE表のデータが載っているブロック数は、66667 ブロックであることは前回も確認した通りの値です)

統計値が変動したもののみ記載
(CDB)システム統計

SOURCE  NAME                                                           VALUE
------- ---------------------------------------------------- ---------------
sysstat commit cleanouts 16
sysstat commit cleanouts successfully completed 16
sysstat consistent gets 72460
sysstat db block changes 3131
sysstat deferred (CURRENT) block cleanout applications 12
sysstat free buffer requested 792
sysstat immediate (CURRENT) block cleanout applications 3
sysstat no work - consistent read gets 69328
sysstat physical reads 67121
sysstat physical reads direct 66709
sysstat physical writes 66667
sysstat physical writes direct 66667
sysstat physical writes non checkpoint 66667

(PDB) SCOTTのセッション統計

SOURCE  NAME                                                           VALUE
------- ---------------------------------------------------- ---------------
sesstat commit cleanouts 16
sesstat commit cleanouts successfully completed 16
sesstat consistent gets 72373
sesstat db block changes 3131
sesstat deferred (CURRENT) block cleanout applications 12
sesstat free buffer requested 792
sesstat immediate (CURRENT) block cleanout applications 3
sesstat no work - consistent read gets 69291
sesstat physical reads 67121
sesstat physical reads direct 66709
sesstat physical writes 66667
sesstat physical writes direct 66667
sesstat physical writes non checkpoint 66667


6) PDBのSCOTTユーザーでコミットの実行

SCOTT@orcl> commit;

Commit complete.


7) CDBのSYSで統計取得(コミット後)
direct path writeでバッファキャッシュを経由せず書き出されたブロックはコミット時にはクリーンアウトの対象にはなっていないようですね。。。。統計をみる限りノイズ程度ですね。
ということは全てのブロックが遅延ブロッククリーンアウト対象になってしまうのか、または、その逆で、最初からクリーンアウト対象にもなっていないかということになります。次の全表走査の結果でどちらであるか、わかるはずです!!!!(ニヤニヤ、それ、ねらってやってるので、答えは知っているわけですがw)

統計値が変動したもののみ記載
(CDB)システム統計

SOURCE  NAME                                                           VALUE
------- ---------------------------------------------------- ---------------
sysstat commit cleanouts 25
sysstat commit cleanouts successfully completed 25
sysstat consistent gets 12104
sysstat db block changes 1557
sysstat deferred (CURRENT) block cleanout applications 12
sysstat free buffer requested 714
sysstat immediate (CURRENT) block cleanout applications 4
sysstat no work - consistent read gets 7192
sysstat physical reads 705

(PDB) SCOTTのセッション統計

SOURCE  NAME                                                           VALUE
------- ---------------------------------------------------- ---------------
sesstat commit cleanouts 2
sesstat commit cleanouts successfully completed 2
sesstat consistent gets 864
sesstat db block changes 1474
sesstat deferred (CURRENT) block cleanout applications 1
sesstat free buffer requested 37
sesstat no work - consistent read gets 351
sesstat physical reads 32


8) PDBのSCOTTユーザーで遅延ブロッククリーンアウト有無確認(対象表をscattered readで全表走査)

REDOログは多少生成されていますが、実際に遅延ブロッククリーンアウトが発生した場合REDOログ量この程度では少なすぎますよね。
今回の検証目的からするとノイズの類ですね。むむむ。これは。。。。
(物理読み込みは発生しているので、direct path read か、scattered readのどちらかということにはなります。期待している動きは、Scattered read 。)

SCOTT@orcl> @table_full_scan_hoge2.sql
1* alter session set "_serial_direct_read" = never

Session altered.

Elapsed: 00:00:00.00
1* alter session set "_very_large_object_threshold" = 20400

Session altered.

Elapsed: 00:00:00.00
set autot trace exp stat

1* select * from hoge2

200000 rows selected.

Elapsed: 00:00:06.84

Execution Plan
----------------------------------------------------------
Plan hash value: 1530105727

---------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 200K| 382M| 18174 (1)| 00:00:01 |
| 1 | TABLE ACCESS FULL| HOGE2 | 200K| 382M| 18174 (1)| 00:00:01 |
---------------------------------------------------------------------------

Statistics
----------------------------------------------------------
13 recursive calls
12 db block gets
80022 consistent gets
66668 physical reads
2284 redo size
406775148 bytes sent via SQL*Net to client
147265 bytes received via SQL*Net from client
13335 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
200000 rows processed

set autot off


9) CDBのSYSで統計取得(遅延ブロッククリーンアウト有無確認。対象表をscattered readで全表走査)
physical reads は想定通りのブロック以上になっていますが、physical reads direct は発生していないので、scattered readによる全表走査であると読み取ることができます。
ただ、この状態でも、遅延ブロッククリーンアウトの発生を示す統計値はノイズ程度の値です。

つまり、direct path write でINSERTされたデータブロックはクリーンアウトが必要な状態だということになりますね。興味深い動きですよね。メモしておいたほうが良さそうです :)

統計値が変動したもののみ記載
(CDB)システム統計

SOURCE  NAME                                                           VALUE
------- ---------------------------------------------------- ---------------
sysstat cleanouts only - consistent read gets 1
sysstat commit cleanouts 16
sysstat commit cleanouts successfully completed 16
sysstat consistent gets 105046
sysstat db block changes 225
sysstat deferred (CURRENT) block cleanout applications 9
sysstat free buffer requested 67576
sysstat immediate (CR) block cleanout applications 1
sysstat immediate (CURRENT) block cleanout applications 2
sysstat no work - consistent read gets 93908
sysstat physical reads 67536

(PDB) SCOTTのセッション統計

SOURCE  NAME                                                           VALUE
------- ---------------------------------------------------- ---------------
sesstat cleanouts only - consistent read gets 1
sesstat commit cleanouts 6
sesstat commit cleanouts successfully completed 6
sesstat consistent gets 86566
sesstat db block changes 44
sesstat deferred (CURRENT) block cleanout applications 3
sesstat free buffer requested 66778
sesstat immediate (CR) block cleanout applications 1
sesstat immediate (CURRENT) block cleanout applications 2
sesstat no work - consistent read gets 82891
sesstat physical reads 66770




まとめ

IASで direct path write してINSERTされた場合、ブロッククリーンアウトは発生しない!(コミット時でも遅延でも)
そもそもクリーンアウトが必要な状態になっていないというのが正しいのでしょうね。統計値としては全く動いてないに等しいので。

これも試験にでますよ(嘘w

次回は、同じIASもdirect path write ではないケースではどうなるでしょう。。。(ここまでのエントリーを読んでいる方は、結果は想像できそうではありますが)

次回へつづく。


遅めの夏休みですが、まあ、普段とちがうのは、いろいろなタスクの締め切りに追われずに、マイペースな時間の過ごし方になるぐらいだな。この状況下ではw



古くて新しい? 遅延ブロッククリーンアウト (deferred block cleanout) #1
古くて新しい? 遅延ブロッククリーンアウト (deferred block cleanout) #2
古くて新しい? 遅延ブロッククリーンアウト (deferred block cleanout) #3
古くて新しい? 遅延ブロッククリーンアウト (deferred block cleanout) #4
古くて新しい? 遅延ブロッククリーンアウト (deferred block cleanout) #5
古くて新しい? 遅延ブロッククリーンアウト (deferred block cleanout) #6
古くて新しい? 遅延ブロッククリーンアウト (deferred block cleanout) #7
古くて新しい? 遅延ブロッククリーンアウト (deferred block cleanout) #8
古くて新しい? 遅延ブロッククリーンアウト (deferred block cleanout) #9



| | コメント (0)

2021年9月21日 (火)

古くて新しい? 遅延ブロッククリーンアウト (deferred block cleanout) #9

Previously on Mac De Oracle
バッファキャッシュから溢れ出る程度のデータを登録しコミットした場合は、コミットクリーンアウトがどうなるか、遅延ブロッククリーンアウトされるブロック数はどの程度になるかという、寄り道でしたw

今回は、寄り道し過ぎて忘れるところだった、前回まで、scattered readを伴うtable full scanで発生していた遅延ブロッククリーンアウトが direct path read だったらどうなるか、というシリーズ :) 
(まだ続くのかーーーっ! はいw いろんなケースがありますから。シンプルなケースであっても。それぞれの基本的な挙動を知っいて損はないとおもいます。 複雑なケースだと脳汁出過ぎるくらい複雑なので考えたくもなくなるのでw)

では、早速再現してみましょう。手順はこれまで行なってきたとおりで、違いは遅延ブロッククリーンアウトを発生させるためのtable full scanでdirect path readさせるという部分のみ。手順はscattered readとの比較も入れるので長くなってしまうので、追加ステップを追記した図を見てもらうと何やっているか、流れは理解しやすいかもしれません。Steps


事前準備
バッファキャッシュのサイズは元のサイズに戻してあります

SYS@orclcdb> show sga

Total System Global Area 4294963960 bytes
Fixed Size 9143032 bytes
Variable Size 805306368 bytes
Database Buffers 3472883712 bytes
Redo Buffers 7630848 bytes

200,000行登録したデータ(セグメントサイズ農地純粋にデータが乗っているブロック数)が乗っているブロック数はこんなところ。セグメントサイズはこれより多いですよ。行データが載っているブロックだけカウントしているので。

SCOTT@orcl> select count(distinct dbms_rowid.rowid_block_number(rowid)) as "blocks" from hoge;

blocks
----------
66667

ということで、セグメントサイズも確認。

SCOTT@orcl> select segment_name,blocks from user_segments where segment_name = 'HOGE';

SEGMENT_NAME BLOCKS
------------------------------ ----------
HOGE 67584

バッファキャッシュの10-15%程度はコミットクリーンアウトされるので、間をとってこれぐらいはコミットクリーンアウトされる。。。

SCOTT@orcl> select 3472883712 / 8192 * 0.13 from dual;

3472883712/8192*0.13
--------------------
55111.68

残りは遅延ブロッククリーンアウトする。だいだいこんなもん。

SCOTT@orcl> select 66667 - 55112 from dual;

66667-55112
-----------
11555

direct path read狙いの全表走査(シリアル実行で発動させることを意図していますが、言うこときいてくれるかあなぁ)

$ cat table_full_scan_with_dpr.sql
alter session set "_serial_direct_read" = always
.
l
/
alter session set "_very_large_object_threshold" = 512
.
l
/

!echo set autot trace exp stat
set autot trace exp stat

select * from hoge
.
l
/

!echo set autot off
set autot off

Scattered Read狙いの全表走査のスクリプト

$ cat table_full_scan.sql
alter session set "_serial_direct_read" = never
.
l
/
alter session set "_very_large_object_threshold" = 20400
.
l
/

!echo set autot trace exp stat
set autot trace exp stat


select * from hoge
.
l
/

!echo set autot off
set autot off




さて、うまく再現できるかどうか。。(今回もやったことをほぼすべて載せているので長いです)


0) 対象表をdrop/create
オブジェクトを作り直し前提合せ

SCOTT@orcl> @droppurge_create_hoge

Table dropped.

Table created.

SCOTT@orcl> select segment_name,blocks from user_segments where segment_name like '%HOGE%';

no rows selected


1) 統計をクリアためOracle再起動

$ sudo service oracle restart


2) PDBのscottでログインしてclient_infoをセット
v$sessionのclient_info列の'TargetSession'文字列で他のSCOTTユーザーのセッションを特定するため。

SCOTT@orcl> @set_client_info
1 begin
2 DBMS_APPLICATION_INFO.SET_CLIENT_INFO('TargetSession');
3* end;

PL/SQL procedure successfully completed.

Elapsed: 00:00:00.00
SCOTT@orcl>


3) CDBのSYSで統計取得(初回)
内容は省略!(ベースラインを取得しているだけなので)

SYS$orclcdb> @show_stat scott
...略...


4) PDBのSCOTTユーザーでINSERT(データ量2倍、コミットなし)
データサイズはバッファキャッシュに載るサイズ、コミットクリーンアウトではクリーンアウト仕切れないサイズで、ある程度の遅延ブロッククリーンアウトが発生するサイズになっているのは以前と同じ。

SCOTT@orcl> @insert_each_rows_2
1* begin for i in 1..200000 loop insert into hoge values(i, lpad('*', 2000, '*')); end loop; end;

PL/SQL procedure successfully completed.

Elapsed: 00:00:29.48
SCOTT@orcl>


5) CDBのSYSで統計取得(INSERT後、未コミット)
insertしただけなので、insertしたデータ量に応じたブロック数がバッファキャッシュに確保されたという程度の情報( free buffer requested = 68766 なので事前に確認していた 66667 以上になっています)は確認できます。
(バッファキャッシュに収まるデータ量ですし)ただ、checkpointの発生でいくらか書き出されているのも見えますよね( DBWR checkpoint buffers written )

統計値が変動したもののみ記載
(CDB)システム統計

SOURCE  NAME                                            VALUE
------- ---------------------------------------------------- ---------------
sysstat DBWR checkpoint buffers written 22909
sysstat DBWR checkpoints 3
sysstat DBWR thread checkpoint buffers written 22902
sysstat DBWR transaction table writes 6
sysstat DBWR undo block writes 573
sysstat commit cleanouts 6
sysstat commit cleanouts successfully completed 6
sysstat consistent gets 49682
sysstat db block changes 744727
sysstat deferred (CURRENT) block cleanout applications 4
sysstat free buffer requested 68766
sysstat immediate (CURRENT) block cleanout applications 1
sysstat no work - consistent read gets 82
sysstat physical reads 9
sysstat physical writes 22909
sysstat physical writes from cache 22909
sysstat physical writes non checkpoint 22892

(PDB) SCOTTのセッション統計

SOURCE  NAME                                            VALUE
------- ---------------------------------------------------- ---------------
sesstat commit cleanouts 6
sesstat commit cleanouts successfully completed 6
sesstat consistent gets 49561
sesstat db block changes 744727
sesstat deferred (CURRENT) block cleanout applications 4
sesstat free buffer requested 68766
sesstat immediate (CURRENT) block cleanout applications 1
sesstat no work - consistent read gets 40
sesstat physical reads 9


6) PDBのSCOTTユーザーでコミットの実行

SCOTT@orcl> commit;

Commit complete.


7) CDBのSYSで統計取得(コミット後)
コミットクリーンアウトされているブロック数を見ると、事前に計算していた バッファキャッシュの13%( 55112 blocks )に近い 55700 ブロックがコミットのタイミングでクリーンアウトされていることがわかります。ここまでは想定通りの動きです。

統計値が変動したもののみ記載
(CDB)システム統計

SOURCE  NAME                                            VALUE
------- ---------------------------------------------------- ---------------
sysstat commit cleanout failures: callback failure 15
sysstat commit cleanouts 56077
sysstat commit cleanouts successfully completed 56062
sysstat consistent gets 50494
sysstat db block changes 7894
sysstat deferred (CURRENT) block cleanout applications 158
sysstat free buffer requested 3217
sysstat immediate (CURRENT) block cleanout applications 154
sysstat no work - consistent read gets 32764
sysstat physical reads 2962

(PDB) SCOTTのセッション統計

SOURCE  NAME                                            VALUE
------- ---------------------------------------------------- ---------------
sesstat commit cleanouts 55700
sesstat commit cleanouts successfully completed 55700
sesstat db block changes 1


8) PDBのSCOTTユーザーで、遅延ブロッククリーンアウト影響有無確認(対象表をdirect path readで全表走査)
全表走査させてコミットクリーンアウトされなかったブロックがクリーンアウトを確認します。ただし、全表走査ではありますが、direct path read で読み込ませるように工夫しています。

さて狙い通りになるかどうか。。。パラレルクエリーでない場合の強制はちょいとむずいのですが、見る限り、REDOログは生成されています。

ただ、以前のscattered read ( db file sequential read )で発生させた遅延ブロッククリーンアウトの検証結果に比べると明らかに少ない。。
なにかが違いますね。。。。むむむ。なんだろう?
scattered readでほぼ同じバッファキャッシュサイズで、遅延ブロッククリーンアウトさせた際、967432 redo size というサイズが生成されていたのを思い出してみてください!!! 明らかに少ないです。。。。

SCOTT@orcl> @table_full_scan_with_dpr.sql
1* alter session set "_serial_direct_read" = always

Session altered.

Elapsed: 00:00:00.00
1* alter session set "_very_large_object_threshold" = 512

Session altered.

Elapsed: 00:00:00.00
set autot trace exp stat

1* select * from hoge

200000 rows selected.

Elapsed: 00:00:10.84

Execution Plan
----------------------------------------------------------
Plan hash value: 2339479017

--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 214K| 207M| 18223 (1)| 00:00:01 |
| 1 | TABLE ACCESS FULL| HOGE | 214K| 207M| 18223 (1)| 00:00:01 |
--------------------------------------------------------------------------

Note
-----
- dynamic statistics used: dynamic sampling (level=2)

Statistics
----------------------------------------------------------
23 recursive calls
13 db block gets
113559 consistent gets
66712 physical reads
2996 redo size
4539159 bytes sent via SQL*Net to client
147264 bytes received via SQL*Net from client
13335 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
200000 rows processed

set autot off


9) CDBのSYSで統計取得(遅延ブロッククリーンアウト有無確認)(対象表をdirect path readで全表走査)
direct path read、遅延ブロッククリーンアウトの有無をシステム統計およびセッション統計から読み取ってみます!

物理読み込み( physical writes )とダイレクトパスリードを示す( physical writes from cache )が同じであることから、間違いなく direct path readが発生しています。ブロック数も 66667 ブロックを超えていることは確認できます。
ただ、immediate (CR) block cleanout applications が想定している量の3倍ぐらいあります:)
遅延ブロッククリーンアウトは行われているのは間違いないですが、前述の通りREDOサイズが異常に少ない。どういうことだろう。。(想定通りの結果に、ニヤニヤなわけですがw)

真相を探るため、われわれはアマゾンの奥深くへ入っていくのであった。。。W

少々本題からそれますが、DBWR parallel query checkpoint buffers written で 44793 ブロックほど書き出されています。これが発生するのは direct path readの影響です。direct path read バッファキャッシュを介ず、常にストレージからデータを読み込む必要があります。この検証では、INSERTでバッファキャッシュに載っているデータであるため一旦書き出す必要があります。書き出されたデータを direct path read で読み込むのでこんな動きになっているというわけですね。。。。。

これ、よくよく考えると、コミットクリーンアウトされていないブロックもそのままの状態で書き出されてますよね。。。ここ試験にでますよ(嘘ですw

統計値が変動したもののみ記載
(CDB)システム統計

SOURCE  NAME                                            VALUE
------- ---------------------------------------------------- ---------------
sysstat DBWR checkpoint buffers written 44793
sysstat DBWR checkpoints 2
sysstat DBWR object drop buffers written 2
sysstat DBWR parallel query checkpoint buffers written 44793
sysstat cleanouts only - consistent read gets 33057
sysstat commit cleanouts 18
sysstat commit cleanouts successfully completed 18
sysstat consistent gets 120519
sysstat db block changes 97
sysstat deferred (CURRENT) block cleanout applications 8
sysstat free buffer requested 127
sysstat immediate (CR) block cleanout applications 33057
sysstat immediate (CURRENT) block cleanout applications 5
sysstat no work - consistent read gets 50145
sysstat physical reads 66827
sysstat physical reads direct 66710
sysstat physical writes 44795
sysstat physical writes from cache 44795
sysstat physical writes non checkpoint 44795

(PDB) SCOTTのセッション統計

SOURCE  NAME                                            VALUE
------- ---------------------------------------------------- ---------------
sesstat cleanouts only - consistent read gets 33057
sesstat commit cleanouts 5
sesstat commit cleanouts successfully completed 5
sesstat consistent gets 120131
sesstat db block changes 48
sesstat deferred (CURRENT) block cleanout applications 1
sesstat free buffer requested 120
sesstat immediate (CR) block cleanout applications 33057
sesstat immediate (CURRENT) block cleanout applications 2
sesstat no work - consistent read gets 49952
sesstat physical reads 66823
sesstat physical reads direct 66710


10) Oracle再起動
Oracleを再起動して、諸々綺麗にした状態で、今一度、direct path readで全表走査させてみましょう。

$ sudo service oracle restart


11) PDBのscottでログインしてclient_infoをセット
v$sessionのclient_info列の'TargetSession'文字列で他のSCOTTユーザーのセッションを特定するため。

SCOTT@orcl> @set_client_info
1 begin
2 DBMS_APPLICATION_INFO.SET_CLIENT_INFO('TargetSession');
3* end;

PL/SQL procedure successfully completed.

Elapsed: 00:00:00.00
SCOTT@orcl>


12) CDBのSYSで統計取得(再起動後初回)
内容は省略!(ベースラインを取得しているだけなので)

SYS$orclcdb> @show_stat scott
...略...


13) PDBのSCOTTユーザーで、遅延ブロッククリーンアウト影響有無確認(対象表をdirect path readで全表走査)2回目
お!!! REDOが生成されていないですね。Scattered Readの場合でも、コミット時でも一度クリーンアウトされたブロックはクリーンアウト済みなので、クリーンアウトされるような挙動は発生しませんでしたが、 direct path read でもおなじかなーー。

と。。。。とりあえず、システム統計とセッション統計も確認しておきましょう!

SCOTT@orcl> @table_full_scan_with_dpr.sql
1* alter session set "_serial_direct_read" = always

Session altered.

Elapsed: 00:00:00.00
1* alter session set "_very_large_object_threshold" = 512

Session altered.

Elapsed: 00:00:00.00
set autot trace exp stat

1* select * from hoge

200000 rows selected.

Elapsed: 00:00:03.90

Execution Plan
----------------------------------------------------------
Plan hash value: 2339479017

--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 214K| 207M| 18223 (1)| 00:00:01 |
| 1 | TABLE ACCESS FULL| HOGE | 214K| 207M| 18223 (1)| 00:00:01 |
--------------------------------------------------------------------------

Note
-----
- dynamic statistics used: dynamic sampling (level=2)

Statistics
----------------------------------------------------------
33 recursive calls
0 db block gets
91159 consistent gets
66938 physical reads
0 redo size
4539159 bytes sent via SQL*Net to client
147264 bytes received via SQL*Net from client
13335 SQL*Net roundtrips to/from client
5 sorts (memory)
0 sorts (disk)
200000 rows processed

set autot off


14) CDBのSYSで統計取得(遅延ブロッククリーンアウト有無確認)(対象表をdirect path readで全表走査)2回目
セッション統計のphysical readsとhysical reads direct は同一であることから direct path readになっていることは間違いありません。また、ブロック数も 66667 ブロック以上にはなっているので全ブロック読み込まれているようですね。
ただ、妙な値を示している統計があります。

immediate (CR) block cleanout applications  10959 

遅延ブロッククリーンアウトが行われている時に上がる統計です。しかも、コミットクリーンアウトされたブロック数を差し引いたブロック数にほぼ一致します。(1回目の実行ではこの3倍ぐらいに跳ね上がっていましたが。。一度クリーンアウトされたのでは??)

さらに不思議なことに、REDO生成されないんですね。。。。

ん? ちょっと待ってください。一度、クリーンアウトされたブロックがなぜ、再度クリーンアウトされているのでしょう? scattered readで遅延ブロッククリーンアウトされたケースと動きが違います!!!!!!

Oracleを再起動する前のステップでREDOログが異常に少ないにも関わらず、遅延クリーンアウトされていた統計値が高くなった。Oracleを再起動した後でも、同様に、direct path read で読み込み、遅延ブロッククリーンアウト発生。しかもREDOログはありません。。。これって、クリーンアウト行われているようですが、実際にはメモリー上だけで実祭のブロックはクリーンアウトされずに残っているということですよね。なんども発生しているわけですから。
(ブロックダンプしなくても統計値から状況は見えてきましたよね!!)

direct path readはその名の通り、バッファキャッシュを介さず、常にストレージからデータブロックを読み込み、PGAへ。このケースだとSELECT文なので単純にPGAへ直接読み込み、メモリ上ではクリーンアップは行なっているようですが、クエリーが終了すれば、単に捨てられるのみ。。。なので、クリーンアウトの結果は永続化されない。。。ということになりますよね!

ということは、SELECT文の場合は、scattered read等でバッファキャッシュを経由させないと、遅延ブロッククリーンアウトは、ずーっと先延ばしされる。。。direct path readのSELECT文を2回実行してクリーンアウトさせたわけだが、この後、scattered readで全表走査させれば、遅延ブロッククリーンアウトが発生して、大量のREDOログが生成されるて、完全にクリーンアウトされる。。。。。。はず。。。ですよね。

試してみよう!!!!

統計値が変動したもののみ記載
(CDB)システム統計

SOURCE  NAME                                            VALUE
------- ---------------------------------------------------- ---------------
sysstat DBWR checkpoints 1
sysstat DBWR object drop buffers written 2
sysstat cleanouts only - consistent read gets 10959
sysstat commit cleanouts 36
sysstat commit cleanouts successfully completed 36
sysstat consistent gets 106766
sysstat db block changes 166
sysstat deferred (CURRENT) block cleanout applications 18
sysstat free buffer requested 1130
sysstat immediate (CR) block cleanout applications 10959
sysstat immediate (CURRENT) block cleanout applications 10
sysstat no work - consistent read gets 77392
sysstat physical reads 67827
sysstat physical reads direct 66710
sysstat physical writes 2
sysstat physical writes from cache 2
sysstat physical writes non checkpoint 2

(PDB) SCOTTのセッション統計

SOURCE  NAME                                            VALUE
------- ---------------------------------------------------- ---------------
sesstat cleanouts only - consistent read gets 10959
sesstat commit cleanouts 2
sesstat commit cleanouts successfully completed 2
sesstat consistent gets 98223
sesstat db block changes 30
sesstat deferred (CURRENT) block cleanout applications 1
sesstat free buffer requested 587
sesstat immediate (CR) block cleanout applications 10959
sesstat no work - consistent read gets 72324
sesstat physical reads 67289
sesstat physical reads direct 66710


15) Oracle再起動
諸々情報を綺麗にするので再起動!!

$ sudo service oracle restart


16) PDBのscottでログインしてclient_infoをセット
v$sessionのclient_info列の'TargetSession'文字列で他のSCOTTユーザーのセッションを特定するため。

SCOTT@orcl> @set_client_info
1 begin
2 DBMS_APPLICATION_INFO.SET_CLIENT_INFO('TargetSession');
3* end;

PL/SQL procedure successfully completed.

Elapsed: 00:00:00.00
SCOTT@orcl>


17) CDBのSYSで統計取得(再々起動後初回)
内容は省略!(ベースラインを取得しているだけなので)

SYS$orclcdb> @show_stat scott
...略...


18) PDBのSCOTTユーザーで、遅延ブロッククリーンアウト影響有無確認(対象表をscattered readで全表走査)3回目

キターーーーーーーーーーーーーーっ!。 予想的中!!。(競馬ならいいのにw) 

大量のREDOログが生成され、物理読み込みも初生しています。direct path readで全表走査させた時とは明らかに違う!!!(以前、見た光景!!w

SCOTT@orcl> @table_full_scan.sql
1* alter session set "_serial_direct_read" = never

Session altered.

Elapsed: 00:00:00.00
1* alter session set "_very_large_object_threshold" = 20400

Session altered.

Elapsed: 00:00:00.00
set autot trace exp stat

1* select * from hoge

200000 rows selected.

Elapsed: 00:00:04.84

Execution Plan
----------------------------------------------------------
Plan hash value: 2339479017

--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 214K| 207M| 18223 (1)| 00:00:01 |
| 1 | TABLE ACCESS FULL| HOGE | 214K| 207M| 18223 (1)| 00:00:01 |
--------------------------------------------------------------------------

Note
-----
- dynamic statistics used: dynamic sampling (level=2)

Statistics
----------------------------------------------------------
33 recursive calls
0 db block gets
91170 consistent gets
66720 physical reads
964436 redo size
4539159 bytes sent via SQL*Net to client
147264 bytes received via SQL*Net from client
13335 SQL*Net roundtrips to/from client
5 sorts (memory)
0 sorts (disk)
200000 rows processed

set autot off


19) CDBのSYSで統計取得(遅延ブロッククリーンアウト有無確認)(対象表をscattered readで全表走査)3回目

physical reads が想定ブロック数以上あるため、物理読み込みされ全ブロックが読み込まれていると読み取れます。また、physical reads direct は変化していません。(変化のない統計は記載していません)
つまり direct path read ではなく scattered read で全表走査が行われたことを示しています。

immediate (CR) block cleanout applications                     10959

という統計から、遅延ブロッククリーンアウトが発生し、ほぼ想定していたブロック数であることも確認できます。

統計値が変動したもののみ記載
(CDB)システム統計

SOURCE  NAME                                            VALUE
------- ---------------------------------------------------- ---------------
sysstat cleanouts only - consistent read gets 10959
sysstat commit cleanouts 3
sysstat commit cleanouts successfully completed 3
sysstat consistent gets 98846
sysstat db block changes 10992
sysstat deferred (CURRENT) block cleanout applications 2
sysstat free buffer requested 67078
sysstat immediate (CR) block cleanout applications 10959
sysstat no work - consistent read gets 72660
sysstat physical reads 67069

(PDB) SCOTTのセッション統計

SOURCE  NAME                                            VALUE
------- ---------------------------------------------------- ---------------
sesstat cleanouts only - consistent read gets 10959
sesstat commit cleanouts 2
sesstat commit cleanouts successfully completed 2
sesstat consistent gets 98234
sesstat db block changes 10988
sesstat deferred (CURRENT) block cleanout applications 1
sesstat free buffer requested 67071
sesstat immediate (CR) block cleanout applications 10959
sesstat no work - consistent read gets 72324
sesstat physical reads 67063


20) Oracle再起動
以前の検証で、scattered readでブロッククリーンアウトされた場合のSELECT文であっても結果は永続化されるので、再度読み込ませた場合はクリーンアウト済みなので再度遅延クリーンアウトが発生しないことは確認確認済みですが、今一度確認しておきましょうw

$ sudo service oracle restart


21) PDBのscottでログインしてclient_infoをセット
v$sessionのclient_info列の'TargetSession'文字列で他のSCOTTユーザーのセッションを特定するため。

SCOTT@orcl> @set_client_info
1 begin
2 DBMS_APPLICATION_INFO.SET_CLIENT_INFO('TargetSession');
3* end;

PL/SQL procedure successfully completed.

Elapsed: 00:00:00.00
SCOTT@orcl>


22) CDBのSYSで統計取得(再再々起動後初回)
内容は省略!(ベースラインを取得しているだけなので)

SYS$orclcdb> @show_stat scott
...略...


23) PDBのSCOTTユーザーで、遅延ブロッククリーンアウト影響有無確認(対象表をscattered readで全表走査)4回目

想定通り、遅延ブロッククリーンアウトは発生せず、REDOログも生成されていません! めでたしめでたしw

SCOTT@orcl> @table_full_scan.sql
1* alter session set "_serial_direct_read" = never

Session altered.

Elapsed: 00:00:00.01
1* alter session set "_very_large_object_threshold" = 20400

Session altered.

Elapsed: 00:00:00.00
set autot trace exp stat

1* select * from hoge

200000 rows selected.

Elapsed: 00:00:04.32

Execution Plan
----------------------------------------------------------
Plan hash value: 2339479017

--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 214K| 207M| 18223 (1)| 00:00:01 |
| 1 | TABLE ACCESS FULL| HOGE | 214K| 207M| 18223 (1)| 00:00:01 |
--------------------------------------------------------------------------

Note
-----
- dynamic statistics used: dynamic sampling (level=2)

Statistics
----------------------------------------------------------
33 recursive calls
0 db block gets
80211 consistent gets
66719 physical reads
0 redo size
4539159 bytes sent via SQL*Net to clientyoutub
147264 bytes received via SQL*Net from client
13335 SQL*Net roundtrips to/from client
5 sorts (memory)
0 sorts (disk)
200000 rows processed

set autot off

24) CDBのSYSで統計取得(遅延ブロッククリーンアウト有無確認)(対象表をscattered readで全表走査)4回目
physical reads はありますが、 physical reads direct は変化していません。これは scattered read で全データを読み込んだと見て良いでしょうね。読み込んだブロックサイズも該当表の想定データブロック数程度です。
また、遅延ブロッククリーンアウトが発生したことを示す統計は変化していないことから、遅延ブロッククリーンアウトは発生していないことも読み取れます。(^^)

統計値が変動したもののみ記載
(CDB)システム統計

SOURCE  NAME                                            VALUE
------- ---------------------------------------------------- ---------------
sysstat commit cleanouts 3
sysstat commit cleanouts successfully completed 3
sysstat consistent gets 87659
sysstat db block changes 34
sysstat deferred (CURRENT) block cleanout applications 2
sysstat free buffer requested 67058
sysstat no work - consistent read gets 83510
sysstat physical reads 67048

(PDB) SCOTTのセッション統計

SOURCE  NAME                                            VALUE
------- ---------------------------------------------------- ---------------
sesstat commit cleanouts 2
sesstat commit cleanouts successfully completed 2
sesstat consistent gets 87049
sesstat db block changes 30
sesstat deferred (CURRENT) block cleanout applications 1
sesstat free buffer requested 67051
sesstat no work - consistent read gets 83175
sesstat physical reads 67042



まとめ

SELECT文であっても、遅延ブロッククリーンアウトが発生すると該当ブロックは更新され、REDOログが生成される。ただし、direct path read で読み込まれた場合を除く。
ということのようですね。

ふむふむという興味深い動きですよね。これ。:)

では、次回は direct path に関わる別の動きも確認してみましょうか。。。
このシリーズ、まだまだ引っ張れそうw

ということで次回へつづく。


台風の影響を心配したけどなんとか良い天気の遅い夏休みで。暑くも寒くもないく散歩の気持ちいい秋空 :)



古くて新しい? 遅延ブロッククリーンアウト (deferred block cleanout) #1
古くて新しい? 遅延ブロッククリーンアウト (deferred block cleanout) #2
古くて新しい? 遅延ブロッククリーンアウト (deferred block cleanout) #3
古くて新しい? 遅延ブロッククリーンアウト (deferred block cleanout) #4
古くて新しい? 遅延ブロッククリーンアウト (deferred block cleanout) #5
古くて新しい? 遅延ブロッククリーンアウト (deferred block cleanout) #6
古くて新しい? 遅延ブロッククリーンアウト (deferred block cleanout) #7
古くて新しい? 遅延ブロッククリーンアウト (deferred block cleanout) #8



| | コメント (0)

2021年9月14日 (火)

古くて新しい? 遅延ブロッククリーンアウト (deferred block cleanout) #8

Previously on Mac De Oracle
前回からのつづき(ちょいと寄り道中)
です。

では、とっとと試してみましょうw

バッファキャッシュから溢れ出る程度のデータ量だったら、どうなるのかなーーーー、という検証です。やりたいことは図の通りです。
Photo_20210911234101

検証方法を考えていたのですが、自動共有メモリー管理になっているのと、sga_max_size/sga_targetを小さくしすぎるとOracle Databaseが起動しないなど諸々引きそうなので、shared_pool_sizeを大きく設定して、バッファキャッシュに回せるメモリーを減らすことで、バッファキャッシュを小さく、バッファから溢れる程度のデータ量も少なくて済むようにして試してみることにします。

準備段階から書いてます。再現させる環境をどうセットアップしたかっていうことも重要だと思うのですよね。少々長くなっちゃいますが。



検証準備

CDBに接続して初期化パラメータを調整!!

SGAコンポーネントの状況
Database Buffersが、3G以上になってます。検証データ量も多くなってしまうので、これを1GB程度まで下げたいですね。検証時間も節約できますし、最小の手数で検証できるほうが良いですから:)

SYS@orclcdb> show sga
Total System Global Area 4294963960 bytes
Fixed Size 9143032 bytes
Variable Size 805306368 bytes
Database Buffers 3472883712 bytes
Redo Buffers 7630848 bytes

SYS@orclcdb> select 3472883712 / 1024 / 1024 AS "MB" from dual;

MB
----------
3312

Elapsed: 00:00:00.00


sga_max_size,sga_min_sizeが4GBですが、ここはそのままにします。あまり小さくしすぎると起動しなくなったり。(^^;;;;

SYS@orclcdb> show parameter sga
NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
allow_group_access_to_sga boolean FALSE
lock_sga boolean FALSE
pre_page_sga boolean TRUE
sga_max_size big integer 4G
sga_min_size big integer 0
sga_target big integer 4G
unified_audit_sga_queue_size integer 1048576


自動SGA管理なので、Shared Pool Sizeに大きめの値を設定。
自動SGA管理下で自動管理対象メモリーコンポーネントパラメータに値を設定した場合、その値が下限値となり最低でもその値は確保されるという仕組みを利用します!

SYS@orclcdb> show parameter shared_pool

NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
shared_pool_reserved_size big integer 39426457
shared_pool_size big integer 0


起動しなくなっても戻しやすいようにspfileをpfileに書き出して退避後に、shared_pool_sizeを3GBへ増やします。これで4Gのうちの3G程度がshared poolに割り当てられ、バッファキャッシュは1GBぐらいになるはず。(VirtualBoxなのでスナップショット取得しておいて戻すのもありですけどw)

SYS@orclcdb> create pfile='pfile20210912.ora' from spfile;

File created.

Elapsed: 00:00:00.00
SYS@orclcdb> alter system set shared_pool_size = 3g scope=both;

System altered.

Elapsed: 00:00:00.77


Database Buffersがいい感じにシュリンクしました。1GBぐらいになりました。これで進めますよー。

SYS@orclcdb> show sga
Total System Global Area 4294963960 bytes
Fixed Size 9143032 bytes
Variable Size 3238002688 bytes
Database Buffers 1040187392 bytes
Redo Buffers 7630848 bytes

SYS@orclcdb> select 1040187392 / 1024 / 1024 AS "MB" from dual;

MB
----------
992

Elapsed: 00:00:00.01


ざっくりとブロック数を計算

SYS@orclcdb> select 1040187392 / 8192 AS "blocks" from dual;

blocks
---------------
126976

Elapsed: 00:00:00.01


前回のHOGE表に200,000 rowsで、66,667 blocks のデータを生成したので、126,976 blocks を満たすデータ量にしようとすると 400,000 rowsほど必要になりそうですね。。。。少々多めで、バッファキャッシュから溢れる程度の量で、 500,000 rowsのデータを登録することにしましょう!!!!

SYS@orclcdb> select ceil(126976 / 66667) * 200000 AS "rows" from dual;

rows
----------
400000

Elapsed: 00:00:00.00


これまでの検証から 10%-15%程度がCOMMITクリーンアウトされ、残りが遅延されるのは確認できたので、126976 blocks のバッファキャッシュだと、 17,777 blocks ぐらいがコミットクリーンアウトされそうですね。(今回のテストケースではコミットクリーンアウトされないけど。。された場合は最大でこの程度。。。というメモです。はい)

SYS@orclcdb> select ceil(126976 * 0.14) AS "blocks for commit cleanout" from dual;

blocks for commit cleanout
--------------------------
17777

Elapsed: 00:00:00.00

前回作成したデータは、200,000rowsで、66,667 blocksだったので、500,000 rows だと、ざっくり 166,668 blocks ほど。

SCOTT@orcl> select ceil(66667 / 2 * 5) AS "blocks" from dual;

blocks
----------
166668

Elapsed: 00:00:00.00


なので、遅延ブロッククリーンアウトされると想定される(コミットクリーンアウト分を覗くと)ブロック数は、148,891 blocks 程度にはなりそう。

SYS@orclcdb>  select ceil((66667 / 2 * 5) - 17777) AS "blocks" from dual;
blocks
----------
148891

Elapsed: 00:00:00.01


それに加えて、バッファキャッシュに収まらず、コミットする前にバッファキャッシュから落とされ、ストレージへかきだされてしまうブロック数は、これまた、ざっくり計算すると 39,692 blocks ほどですかね。バッファキャッシュのサイズから全てのブロックは乗り切らないので、最初に読み込まれていたブロックから落とされていくことにはなりますね。。
とはいえ、この検証ではキャッシュ落とされるブロック数は特に気にしてなくて、バッファキャッシュ以上のブロック数が生成されていればいいので、落とされそうなのが確認できればOK.

SYS@orclcdb>  select ceil((66667 / 2 * 5) - 126976) AS "blocks" from dual;

blocks
----------
39692

Elapsed: 00:00:00.00


とりあえず、生成するデータ量(行数)の算出とバッファキャッシュサイズの調整はおわり。


次に、実際にデータを生成してブロック数とセグメントサイズを確認して、実行用スクリプトの調整を行なっておきます。



PDBでテストデータの実サイズの確認
SCOTT@orcl> @droppurge_create_hoge.sql
1* drop table hoge purge

Table dropped.

Elapsed: 00:00:00.25
1* create table hoge (id number, data varchar2(2000))

Table created.

Elapsed: 00:00:00.04
1* select segment_name,blocks from user_segments where segment_name like '%HOGE%'

no rows selected

Elapsed: 00:00:00.11


500,000行登録!!

SCOTT@orcl> @insert_each_rows_5.sql
1* begin for i in 1..500000 loop insert into hoge values(i, lpad('*', 2000, '*')); end loop; end;

PL/SQL procedure successfully completed.

Elapsed: 00:02:37.68


データが登録されているブロック数は、166,667 blocks で、事前に計算していた 166,668 blocks にほぼおなじ。(狙い通り)
セグメントサイズは、約 1344 MB ですね。

SCOTT@orcl> select count(distinct dbms_rowid.rowid_block_number(rowid)) as "blocks" from hoge;

blocks
----------
166667

Elapsed: 00:00:05.03
SCOTT@orcl> select segment_name,blocks,bytes/1024/1024 AS "MB" from user_segments where segment_name = 'HOGE';

SEGMENT_NAME BLOCKS MB
------------------------------ ---------- ----------
HOGE 172032 1344

Elapsed: 00:00:00.17


Scattered read でTable Full Scanできるように少々隠しパラメータを調整しておきますね。念の為。(セッションレベルで調整してます)
セグメントサイズが、1344 MBなので、_very_large_object_threshold は、2048 MBぐらい設定しておけば、Scattered readのまま行けそうですね。

$ cat table_full_scan.sql
alter session set "_serial_direct_read" = never
.
l
/
alter session set "_very_large_object_threshold" = 2040
.
l
/

!echo set autot trace exp stat
set autot trace exp stat


select * from hoge
.
l
/

!echo set autot off
set autot off


準備完了!!!!!





準備長かったけどw やっと本題です!!!w 実行している内容はいままでと同じなのでかなり端折ってポイントだけ記載。

バッファキャッシュから溢れるほどのデータ量で。コミットクリーンアウトはどうなるのだろうか。。。。想定では、ほぼコミットクリーンアウトできないはずではあるのだが。。。。

CDBのSYSで統計取得(コミット後)

commit cleanouts successfully completedはどれぐらいだったのか。。。。。ありません。commit cleanouts successfully completedに差分がなかったので、コミットクリーンアウトしようして失敗、commit cleanout failures: block lostと同数なので、1ブロックもコミットクリーンアウトできない!  commit cleanout failures: block lostがバッファキャッシュに対象ブロックがなかったことを示しています。

つまり、バッファキャッシュに乗り切らなため、最初にINSERTされたブロックはそのままストレージへ物理書き込みされて追い出された結果。。ということになりますね。

登録したブロック全てが遅延クリーンアウト対象になってしまった、ということになります。コミット時にクリーンアウトできてないわけだから!!!!!!!! (イメージ図でざっくり書いたとおりの感じに。。。

差分のあった統計のみ記載

CDB)システム統計

SOURCE  NAME                                                             VALUE
------- ------------------------------------------------- --------------------
sysstat commit cleanout failures: block lost 3028
sysstat commit cleanouts 3028
sysstat consistent gets 274
sysstat db block changes 1
sysstat no work - consistent read gets 149
sysstat physical reads 60

(PDB) SCOTTのセッション統計

SOURCE  NAME                                                             VALUE
------- ------------------------------------------------- --------------------
sesstat commit cleanout failures: block lost 3028
sesstat commit cleanouts 3028
sesstat db block changes 1


次に、Scattered Readが実行される全表走査を行わせ、遅延ブロッククリーンアウトどれだけ発生するか結果確認!

PDBのSCOTTユーザーで、遅延ブロッククリーンアウト影響有無確認(対象表を全表走査)
想定通り、物理読み込み(この時点ではscattered readなのか、direct path readなのかわかりませんが)になっています。また、大量のREDOログが生成されているので遅延ブロッククリーンアウトが発生しています。

SCOTT@orcl> @table_full_scan.sql
1* alter session set "_serial_direct_read" = never

Session altered.

Elapsed: 00:00:00.00
1* alter session set "_very_large_object_threshold" = 2040

Session altered.

Elapsed: 00:00:00.00
set autot trace exp stat

1* select * from hoge

500000 rows selected.

Elapsed: 00:01:03.08

Execution Plan
----------------------------------------------------------
Plan hash value: 2339479017

--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 669K| 647M| 46462 (1)| 00:00:02 |
| 1 | TABLE ACCESS FULL| HOGE | 669K| 647M| 46462 (1)| 00:00:02 |
--------------------------------------------------------------------------

Note
-----
- dynamic statistics used: dynamic sampling (level=2)

Statistics
----------------------------------------------------------
46 recursive calls
13 db block gets
367852 consistent gets
160269 physical reads
14670268 redo size
1016952118 bytes sent via SQL*Net to client
367706 bytes received via SQL*Net from client
33335 SQL*Net roundtrips to/from client
2 sorts (memory)
0 sorts (disk)
500000 rows processed

set autot off


物理読み込みを伴う全表走査でどの程度の遅延ブロッククリーンアウトが発生したか統計を確認!!!!

CDBのSYSで統計取得(遅延ブロッククリーンアウト有無確認)

想定どおり、INSERTした全ブロックが、immediate (CR) block cleanout applications = 166667 で遅延ブロッククリーンアウトされたことがわかります。(冒頭に記載していますが、データが格納されているブロック数は、 166667 blocks でしたよね)
physical readsは意図通り発生していますが、physical reads directが変化していないので、狙い通りScattered Readになったようですね

差分のあった統計のみ記載

CDB)システム統計

SOURCE  NAME                                                             VALUE
------- ------------------------------------------------- --------------------
sysstat DBWR checkpoint buffers written 241
sysstat DBWR thread checkpoint buffers written 241
sysstat DBWR undo block writes 1109
sysstat cleanouts only - consistent read gets 166667
sysstat commit cleanouts 55
sysstat commit cleanouts successfully completed 55
sysstat consistent gets 377331
sysstat db block changes 166904
sysstat deferred (CURRENT) block cleanout applications 29
sysstat immediate (CR) block cleanout applications 166667
sysstat immediate (CURRENT) block cleanout applications 15
sysstat no work - consistent read gets 38449
sysstat physical reads 160805
sysstat physical writes 137551
sysstat physical writes from cache 137551
sysstat physical writes non checkpoint 137466

(PDB) SCOTTのセッション統計

SOURCE  NAME                                                             VALUE
------- ------------------------------------------------- --------------------
sesstat cleanouts only - consistent read gets 166667
sesstat commit cleanouts 6
sesstat commit cleanouts successfully completed 6
sesstat consistent gets 374538
sesstat db block changes 166710
sesstat deferred (CURRENT) block cleanout applications 3
sesstat immediate (CR) block cleanout applications 166667
sesstat immediate (CURRENT) block cleanout applications 1
sesstat no work - consistent read gets 36779
sesstat physical reads 160513


念の為、今一度、物理読み込みを伴う全表走査を行なって、クリーンアウトされたのか確認してみましょうw(疑い深いw)
もう一度、PDBのSCOTTユーザーで、遅延ブロッククリーンアウト影響有無確認(対象表を全表走査)

redo size0 なのでクリーンアウトは発生してない。想定通り

SCOTT@orcl> @table_full_scan.sql
1* alter session set "_serial_direct_read" = never

Session altered.

Elapsed: 00:00:00.00
1* alter session set "_very_large_object_threshold" = 2040

Session altered.

Elapsed: 00:00:00.00
set autot trace exp stat

1* select * from hoge

500000 rows selected.

Elapsed: 00:00:33.17

Execution Plan
----------------------------------------------------------
Plan hash value: 2339479017

--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 669K| 647M| 46462 (1)| 00:00:02 |
| 1 | TABLE ACCESS FULL| HOGE | 669K| 647M| 46462 (1)| 00:00:02 |
--------------------------------------------------------------------------

Note
-----
- dynamic statistics used: dynamic sampling (level=2)

Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
200399 consistent gets
148198 physical reads
0 redo size
1016952118 bytes sent via SQL*Net to client
367706 bytes received via SQL*Net from client
33335 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
500000 rows processed

set autot off

同様に、統計でも確認してみます!
CDBのSYSで統計取得(遅延ブロッククリーンアウト有無確認)

クリーンアウトを示す統計値は上昇していません!!!(うんうんw)

差分のあった統計のみ記載

CDB)システム統計

SOURCE  NAME                                                             VALUE
------- ------------------------------------------------- --------------------
sysstat DBWR checkpoint buffers written 732
sysstat commit cleanouts 1
sysstat commit cleanouts successfully completed 1
sysstat consistent gets 200522
sysstat db block changes 13
sysstat deferred (CURRENT) block cleanout applications 1
sysstat no work - consistent read gets 200403
sysstat physical reads 148200
sysstat physical writes 68570
sysstat physical writes from cache 68570
sysstat physical writes non checkpoint 68331

(PDB) SCOTTのセッション統計

SOURCE  NAME                                                             VALUE
------- ------------------------------------------------- --------------------
sesstat consistent gets 200414
sesstat db block changes 9
sesstat no work - consistent read gets 200366
sesstat physical reads 148198



OK. Done. ということで、まとめ!

バッファキャッシュには収まりきれないデータ量の場合、コミットクリーンアウトしようとしていたブロックも追い出されてしまうので、結果的に、全ブロックが遅延ブロッククリーンアウトになった。というイメージしていた結果の通りでした。
(今回のケースもシンプルケースなので比較的予想しやすい結果ですが、クリーンアウトに関わる統計は以外に多く、複雑な動きになるものもあります。再現するののめんどくさいのでしませんがw)
Photo_20210911234101

寄り道はここまで、次回は、こんどこそ、direct path readと遅延ブロッククリーンアウトの関係をみていきたいと思います。


来週天気いいかなー。遅い夏休みなのに。微妙な気がしてきた。。。。。



古くて新しい? 遅延ブロッククリーンアウト (deferred block cleanout) #1
古くて新しい? 遅延ブロッククリーンアウト (deferred block cleanout) #2
古くて新しい? 遅延ブロッククリーンアウト (deferred block cleanout) #3
古くて新しい? 遅延ブロッククリーンアウト (deferred block cleanout) #4
古くて新しい? 遅延ブロッククリーンアウト (deferred block cleanout) #5
古くて新しい? 遅延ブロッククリーンアウト (deferred block cleanout) #6
古くて新しい? 遅延ブロッククリーンアウト (deferred block cleanout) #7


| | コメント (0)

2021年9月12日 (日)

古くて新しい? 遅延ブロッククリーンアウト (deferred block cleanout) #7

Previously on Mac De Oracle
前回は、コミットクリーンアウトと遅延クリーンアウト、そして、そこにTable Full ScanでScattered Read (待機イベントだと db file scattered read) を絡めてストレージへ永続化されたクリーンアウトが遅延されてしまったブロックを物理読み込みませつつ遅延ブロッククリーンアウトを再現させてみました。
また、次回は、図中のscattered read 部分を direct path read にしつつ、最後の最後で、scattered read にしてみる、とか、そんなイメージをぼやーーーーんと浮かべながら、発生させる方法をどうするか考えてますw。つづく。なんてことを言っていましたが、またまた、ちょいと寄り道ですしますw

バッファキャッシュから溢れるぐらいのデータをぐるぐる系INSERTで、しかも1回のコミットにしたら、コミット前にあふれたデータはストレージへ書き出され、かつ、クリーンアウトも遅延されるよなー。という予想を元に、ちょいと遊んでから次に進みたいw と思います。

これまでの流れから、基本的なクリーンアウトおよび遅延ブロッククリーンアウトとしては以下ようなパターンを確認してきました。

バッファキャッシュの上でコミットクリーンアウトおよび、遅延ブロッククリーンアウト(単純なタイプ)が行われているケース
Photo_20210911234001

ここからが想像というか、私が理解している範囲から想像した動き。バッファキャッシュから溢れはしないけど、いっぱいいっぱいな場合は、クリーンアウトされるブロックがキャッシュ上に多くあるだろうな。と.
とは言っても、バッファキャッシュ上ではあるわけです。
Photo_20210911234002


そこで、ちょいと意地悪をして、バッファキャッシュから溢れ出る程度のデータ量だったどうなるのかなーーーーと。冒頭ですでコメントしているわけですけどもw 多分、以下のような動きだよねー、と。
そういえば、以前、DBTSで行なったセッションの「バッファキャッシュ欠乏症」の部分で、似たようなバッファキャッシュから溢れ出したブロックの挙動をなんとかするみたいな資料も今回の動きを想像するにはよいかもしれないですね。
Photo_20210911234101


と、思い、頭の中のイメージを Pagesでざざっと作ったところで、本日はここまで。次回へつづく。


Beat SaberとWalkingの合わせ技で、効果的な減量継続中w



古くて新しい? 遅延ブロッククリーンアウト (deferred block cleanout) #1
古くて新しい? 遅延ブロッククリーンアウト (deferred block cleanout) #2
古くて新しい? 遅延ブロッククリーンアウト (deferred block cleanout) #3
古くて新しい? 遅延ブロッククリーンアウト (deferred block cleanout) #4
古くて新しい? 遅延ブロッククリーンアウト (deferred block cleanout) #5
古くて新しい? 遅延ブロッククリーンアウト (deferred block cleanout) #6



| | コメント (0)

2021年9月10日 (金)

古くて新しい? 遅延ブロッククリーンアウト (deferred block cleanout) #6

Previously on Mac De Oracle
前々回と前回はバッファキャッシュの10%を超えるデータ量のINSERT文の実行とCOMMITの実行で、バッファキャッシュの10%-15%程度は、COMMIT時にクリーンアウトされ、残ったブロックのクリーンアウトは先送りされる。という検証を2つのパターンで確認してみました。

どのような流れで発生するかを各ステップ毎にシステム統計(CDB)とクエリーを実行するセッションのセッション統計(PDB)を取得し、どのように統計値が変化すれば、コミットクリーンアウトや遅延ブロッククリーンアウトが起きているのかを見ながらすすめました。以下2つのエントリーで確認した動きの違いはイメージできたのか少々不安ではありますがw (そこそこ長いエントリーなのでw)

こちら前々回は、クリーンアウトが遅延されたブロックが永続化される前に、遅延ブロッククリーンアウトさせてみたケース
古くて新しい? 遅延ブロッククリーンアウト (deferred block cleanout) #4
で、

前回は、クリーンアウトが遅延されたブロックが永続化された後に、遅延ブロッククリーンアウトさせてみたケース
古くて新しい? 遅延ブロッククリーンアウト (deferred block cleanout) #5

なんです :) 


まだ、イメージつかめない方もいるかもしれないので

超ざっくりした絵が頭の中に浮かばない方向けに、上記検証を行う前に、私の頭の中にうかんだ、ラフイメージをほぼそのまま

(こまけーとこは気にしないでくださいね。ラフイメージですから、こうだろうなーというのを想像している状態そのままのイメージですのでw)

クリーンアウトが遅延されたブロックが永続化される前に、遅延ブロッククリーンアウトさせてみたケース
古くて新しい? 遅延ブロッククリーンアウト (deferred block cleanout) #4
No4


クリーンアウトが遅延されたブロックが永続化された後に、遅延ブロッククリーンアウトさせてみたケース
古くて新しい? 遅延ブロッククリーンアウト (deferred block cleanout) #5
No5

再現させてるケースはシンプルなものなので処理時間云々を比較してはいないですが、複雑なケースになると、本来スマートスキャンさせたいのにシングルブロックリードが多くなったりするケースなど、以前紹介したURLを見ていただければ参考になるかもしれないですね。
クエリーやDMLの処理時間が伸びてビビるぐらいに仕事量が増えてたり、先送りされたことで、もろもろ後処理が複雑化する場合もあるわけで)

ということで、こんな図をイメージしながら、ネタ作ってます。はいw


次回は、図中のscattered read 部分を direct path read にしつつ、最後の最後で、scattered read にしてみる、とか、そんなイメージをぼやーーーーんと浮かべながら、発生させる方法をどうするか考えてますw。つづく。



古くて新しい? 遅延ブロッククリーンアウト (deferred block cleanout) #1
古くて新しい? 遅延ブロッククリーンアウト (deferred block cleanout) #2
古くて新しい? 遅延ブロッククリーンアウト (deferred block cleanout) #3
古くて新しい? 遅延ブロッククリーンアウト (deferred block cleanout) #4
古くて新しい? 遅延ブロッククリーンアウト (deferred block cleanout) #5



| | コメント (0)

2021年9月 9日 (木)

古くて新しい? 遅延ブロッククリーンアウト (deferred block cleanout) #5

前回はバッファキャッシュの10%を超えるデータブロックへのINSERT文の実行とCOMMITの実行で、バッファキャッシュの13%-15%程度はCOMMIT時にクリーンアウトされ、残りは遅延ブロッククリーンアウト(先送り)される。
direct path readではないSELECT文による(前回のケースでは scattered read))遅延ブロッククリーンアウトは、1度のみ発生するという状況を確認しました。

ところで、
前回のエントリで、2度、全表走査(前回の検証ではscattered read)を実行しているのですが、物理読み込みは発生させていません。(INSERT→COMMIT→SELECT→SELECTという流れで、十分なバッファキャッシュがあるので、当然ではあるのですがw)
バッファキャッシュに乗ったままのブロックが遅延クリーンアウトされていたわけです。

前回のエントリ:古くて新しい? 遅延ブロッククリーンアウト (deferred block cleanout) #4

--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 194K| 188M| 18189 (1)| 00:00:01 |
| 1 | TABLE ACCESS FULL| HOGE | 194K| 188M| 18189 (1)| 00:00:01 |
--------------------------------------------------------------------------

1. 遅延ブロッククリーンアウトを発生させた場合。遅延ブロッククリーンアウト対象のデータがバッファキャッシュ上ににあるためクリーンアウトに伴う物理読み込みはない。

Statistics
----------------------------------------------------------
46 recursive calls
13 db block gets
91636 consistent gets
7 physical reads
967348 redo size
406775148 bytes sent via SQL*Net to client
147264 bytes received via SQL*Net from client
13335 SQL*Net roundtrips to/from client
2 sorts (memory)
0 sorts (disk)
200000 rows processed

2. 直後に再度全表走査した場合も、キャッシュヒットしているので、物理読み込みはない

Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
80061 consistent gets
0 physical reads
0 redo size
406775148 bytes sent via SQL*Net to client
147264 bytes received via SQL*Net from client
13335 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
200000 rows processed

前述の1.2.それぞれの実行で物理読み込みだったなにか変化はあるのだろうか。。。予想では、上記に加えてscattered readに伴う物理読み込みが増えるだけのはずです。その動きを見てみることにします。(こういう動きを見ていると楽しいですよねw)
手順は前回と同じですが、各全表走査の前にインスタンスを再起動してバッファキャッシュを空にしておきます。
(buffer cacheをflushすればいいじゃん。という声も聞こえてきそうですが、今回は再起動でクリアしました。はいw)


前回から多少変更したスクリプトも載せておきます(本文中にもありますが)、細かい解説は後述

$ cat table_full_scan.sql
alter session set "_serial_direct_read" = never
.
l
/
alter session set "_very_large_object_threshold" = 1056
.
l
/

!echo set autot trace exp stat
set autot trace exp stat


select * from hoge
.
l
/

!echo set autot off
set autot off




0) 対象表をdrop/create
オブジェクト作り直し

SCOTT@orcl> @droppurge_create_hoge

Table dropped.

Table created.

SCOTT@orcl> select segment_name,blocks from user_segments where segment_name like '%HOGE%';

no rows selected


1) 統計をクリアするのにインスタンス再起動

$ sudo service oracle restart


2) PDBのscottでログインし、client_infoをセット
v$sessionのclient_info列の'TargetSession'文字列で他のSCOTTユーザーのセッションと区別するため

SCOTT@orcl> @set_client_info
1 begin
2 DBMS_APPLICATION_INFO.SET_CLIENT_INFO('TargetSession');
3* end;

PL/SQL procedure successfully completed.

Elapsed: 00:00:00.00
SCOTT@orcl>


3) CDBのSYSで統計取得(初回)

内容は省略!(統計差分取得のためのベースラインを取得しているだけ)

SYS$orclcdb> @show_stat scott


4) PDBのSCOTTユーザーでデータINSERT(データ量2倍、コミットなし)

SCOTT@orcl> @insert_each_rows_2
1* begin for i in 1..200000 loop insert into hoge values(i, lpad('*', 2000, '*')); end loop; end;

PL/SQL procedure successfully completed.

Elapsed: 00:00:29.48
SCOTT@orcl>


5) CDBのSYSで統計取得(INSERT後、未コミット)

未コミットの状態なので特に、気にせず、ふーーーん。ぐらいの感じで眺めていただければいいですね。前回同様に、commit cleanouts, commit cleanouts successfully completed, deferred (CURRENT) block cleanout applications, immediate (CURRENT) block cleanout applicationsといったクリーンアウト関連統計が極わずかありますが、この時点で発生しているのは本題ではないので気にしなくてOK

差分のある統計のみ記載

(CDB)システム統計

SOURCE  NAME                                                             VALUE
------- ------------------------------------------------- --------------------
sysstat DBWR checkpoint buffers written 23589
sysstat DBWR checkpoints 2
sysstat DBWR thread checkpoint buffers written 22643
sysstat DBWR transaction table writes 50
sysstat DBWR undo block writes 848
sysstat cleanouts and rollbacks - consistent read gets 5
sysstat commit cleanout failures: callback failure 20
sysstat commit cleanouts 1320
sysstat commit cleanouts successfully completed 1300
sysstat consistent gets 124041
sysstat db block changes 757165
sysstat deferred (CURRENT) block cleanout applications 715
sysstat immediate (CR) block cleanout applications 5
sysstat immediate (CURRENT) block cleanout applications 196
sysstat no work - consistent read gets 46398
sysstat physical reads 4063
sysstat physical writes 23589
sysstat physical writes from cache 23589
sysstat physical writes non checkpoint 23494

(PDB) SCOTTのセッション統計

SOURCE  NAME                                                             VALUE
------- ------------------------------------------------- --------------------
sesstat commit cleanouts 6
sesstat commit cleanouts successfully completed 6
sesstat consistent gets 49596
sesstat db block changes 744727
sesstat deferred (CURRENT) block cleanout applications 4
sesstat immediate (CURRENT) block cleanout applications 1
sesstat no work - consistent read gets 49
sesstat physical reads 15


6) PDBのSCOTTユーザーでコミットの実行

SCOTT@orcl> commit;

Commit complete.


7) CDBのSYSで統計取得(コミット後)
前回同様ノイズもなく、綺麗にコミット時のクリーンアウトが発生しています。バッファキャッシュの約14-5%程度なのは前回と変わらずですね。

差分のある統計のみ記載

(CDB)システム統計

SOURCE  NAME                                                             VALUE
------- ------------------------------------------------- --------------------
sysstat commit cleanouts 55700
sysstat commit cleanouts successfully completed 55700
sysstat db block changes 1

(PDB) SCOTTのセッション統計

SOURCE  NAME                                                             VALUE
------- ------------------------------------------------- --------------------
sesstat commit cleanouts 55700
sesstat commit cleanouts successfully completed 55700
sesstat db block changes 1


8) Oracle Databaseを再起動してバッファキャッシュをクリア

ここが前回と違う手順で、クリーンアウトされないブロックはずーーーーーっと残るよね。ということの確認でもあります。(alter system flush buffer_cacheでも同じことができるわけですが、ここでは再起動しています)

$ sudo service oracle restart
[sudo] password for oracle:
Restarting oracle (via systemctl): [ OK ]
$


9) PDBのscottでログインし、client_infoをセット

disconnectしたので再度、client infoをセットし直し!

SCOTT@orcl> @set_client_info
1 begin
2 DBMS_APPLICATION_INFO.SET_CLIENT_INFO('TargetSession');
3* end;

PL/SQL procedure successfully completed.

Elapsed: 00:00:00.00
SCOTT@orcl>


10) CDBのSYSで統計取得(再起動後初回)

内容は省略!(再起動したので統計値の差分取得用ベースライン統計の取得)

SYS$orclcdb> @show_stat scott


11) PDBのSCOTTユーザーで、遅延ブロッククリーンアウト影響有無確認(対象表を全表走査)- scattered read / table full scan の1回目

ここでは待機イベントまでは確認できませんが、Table full scanと実行統計よりRedoログがたっぷり生成されていることは確認できます。SELECT文ですが。。。つまり、遅延ブロッククリーンアウトが発生しているということですね。確認は後述の統計で。
狙い通り、物理読み込みも発生しています!

Note)
"_very_large_object_threshold" = 1056 としているのは、direct path readとなる上限セグメントサイズをhoge表が超えているためdirect path readを抑止するためにこの隠しパラメータで上限値を引き上げ、scattered readになるように強制しています。

SCOTT@orcl> @table_full_scan.sql
1* alter session set "_serial_direct_read" = never

Session altered.

Elapsed: 00:00:00.01
1* alter session set "_very_large_object_threshold" = 1056

Session altered.

Elapsed: 00:00:00.00
set autot trace exp stat

1* select * from hoge

200000 rows selected.

Elapsed: 00:00:06.10

Execution Plan
----------------------------------------------------------
Plan hash value: 2339479017

--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 214K| 207M| 18223 (1)| 00:00:01 |
| 1 | TABLE ACCESS FULL| HOGE | 214K| 207M| 18223 (1)| 00:00:01 |
--------------------------------------------------------------------------

Note
-----
- dynamic statistics used: dynamic sampling (level=2)

Statistics
----------------------------------------------------------
38 recursive calls
13 db block gets
91519 consistent gets
67073 physical reads
967432 redo size
406775148 bytes sent via SQL*Net to client
147264 bytes received via SQL*Net from client
13335 SQL*Net roundtrips to/from client
5 sorts (memory)
0 sorts (disk)
200000 rows processed

set autot off
SCOTT@orcl>


12) CDBのSYSで統計取得(遅延ブロッククリーンアウト有無確認)/ scattered read / table full scan の1回目

遅延ブロッククリーンアウト関連統計値が上昇しているので、遅延ブロッククリーンアウトの発生が確認できます。ここまでは前回と同じ。(同じじゃないと困りますがw)

違う点は、事前にインスタンスを再起動しているため、physical reads が上昇しています。これは hoge表を scattered readで全表走査しているからです。(phsical read directは発生していない)バッファキャッシュを経由するのでconsistent gets,no work - consistent read gets も上昇しています。狙い通りです。

そして、重量な遅延ブロッククリーンアウトですが、バッファキャッシュでヒットしていた時と同数のブロックで発生しています。(ニッコリ

インスタンスの停止や起動があったとしても、クリーンアウトが先送りされたブロックはアクセスされない限りクリーンアウトされず残っているということを示しています!!!!(ここ試験にでますよー。嘘)

(CDB)システム統計

SOURCE  NAME                                                             VALUE
------- ------------------------------------------------- --------------------
sysstat cleanouts only - consistent read gets 10967
sysstat commit cleanouts 7
sysstat commit cleanouts successfully completed 7
sysstat consistent gets 98967
sysstat db block changes 11016
sysstat deferred (CURRENT) block cleanout applications 3
sysstat immediate (CR) block cleanout applications 10967
sysstat immediate (CURRENT) block cleanout applications 2
sysstat no work - consistent read gets 72543
sysstat physical reads 67403

(PDB) SCOTTのセッション統計

SOURCE  NAME                                                             VALUE
------- ------------------------------------------------- --------------------
sesstat cleanouts only - consistent read gets 10967
sesstat commit cleanouts 6
sesstat commit cleanouts successfully completed 6
sesstat consistent gets 98357
sesstat db block changes 11012
sesstat deferred (CURRENT) block cleanout applications 2
sesstat immediate (CR) block cleanout applications 10967
sesstat immediate (CURRENT) block cleanout applications 2
sesstat no work - consistent read gets 72208
sesstat physical reads 67397


13) Oracle Databaseを再起動してバッファキャッシュをクリア

再度、インスタンスを再起動して、バッファキャッシュをクリアします。後続の全表走査では、遅延ブロッククリーンアウトは発生せず、物理読み込み(この検証では scattered readさせています)を伴うTable full scanが行われるだけのはずです。

$ sudo service oracle restart
[sudo] password for oracle:
Restarting oracle (via systemctl): [ OK ]
$


14) PDBのscottでログインし、client_infoをセット

disconnectしたので再度、client infoをセットし直し!

SCOTT@orcl> @set_client_info
1 begin
2 DBMS_APPLICATION_INFO.SET_CLIENT_INFO('TargetSession');
3* end;

PL/SQL procedure successfully completed.

Elapsed: 00:00:00.00
SCOTT@orcl>


15) CDBのSYSで統計取得(再起動後初回)

内容は省略!(再起動したのでベースラインとなる統計を取得)

SYS$orclcdb> @show_stat scott


16) PDBのSCOTTユーザーで、遅延ブロッククリーンアウト影響有無確認(対象表を全表走査)- scattered read / table full scan の2回目

実行統計から、physical readsが、発生しています。Redoは生成されていないことも読み取れるので、遅延ブロッククリーンアウトは発生していないことも確認できます。:) 想定通りですね。

SCOTT@orcl> @table_full_scan.sql
1* alter session set "_serial_direct_read" = never

Session altered.

Elapsed: 00:00:00.00
1* alter session set "_very_large_object_threshold" = 1056

Session altered.

Elapsed: 00:00:00.00
set autot trace exp stat

1* select * from hoge

200000 rows selected.

Elapsed: 00:00:06.44

Execution Plan
----------------------------------------------------------
Plan hash value: 2339479017

--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 214K| 207M| 18223 (1)| 00:00:01 |
| 1 | TABLE ACCESS FULL| HOGE | 214K| 207M| 18223 (1)| 00:00:01 |
--------------------------------------------------------------------------

Note
-----
- dynamic statistics used: dynamic sampling (level=2)

Statistics
----------------------------------------------------------
30 recursive calls
0 db block gets
80211 consistent gets
66719 physical reads
0 redo size
406775148 bytes sent via SQL*Net to client
147264 bytes received via SQL*Net from client
13335 SQL*Net roundtrips to/from client
5 sorts (memory)
0 sorts (disk)
200000 rows processed

set autot off
SCOTT@orcl>


17) CDBのSYSで統計取得(遅延ブロッククリーンアウト有無確認)/ scattered read / table full scan の2回目

physical reads は発生していますが、physical reads directではないことが確認できます。Table full scanをscattered readで読み込んでいるという想定通りの結果。 
遅延ブロッククリーンアウトを示deferred (CURRENT) block cleanout applications 、immediate (CURRENT) block cleanout applicationsや、コミットクリーンアウトを示すcommit cleanouts 、commit cleanouts successfully completed という統計が極わずかに変動していますが、今回の検証ではノイズなので気にしたくてOK。

(CDB)システム統計

SOURCE  NAME                                                             VALUE
------- ------------------------------------------------- --------------------
sysstat DBWR checkpoint buffers written 11
sysstat commit cleanouts 15
sysstat commit cleanouts successfully completed 15
sysstat consistent gets 87375
sysstat db block changes 79
sysstat deferred (CURRENT) block cleanout applications 12
sysstat immediate (CURRENT) block cleanout applications 3
sysstat no work - consistent read gets 83322
sysstat physical reads 67028
sysstat physical writes 11
sysstat physical writes from cache 11
sysstat physical writes non checkpoint 11

(PDB) SCOTTのセッション統計

SOURCE  NAME                                                             VALUE
------- ------------------------------------------------- --------------------
sesstat commit cleanouts 2
sesstat commit cleanouts successfully completed 2
sesstat consistent gets 86936
sesstat db block changes 29
sesstat deferred (CURRENT) block cleanout applications 1
sesstat no work - consistent read gets 83098
sesstat physical reads 67023




まとめ

遅延ブロッククリーンアウトは、インスタンスを停止して残ったままということが確認できました。(クリアされるまで残るのですよねー)
クリーンアウトが遅延されているブロックが物理読み込みされた(アクセスされた)タイミングで遅延ブロッククリーンアウトが発生することも確認できました。(物理読み込みの有無には関係しない)
バッファキャッシュ上の遅延ブロッククリーンアウト同様、クリーンアウトされたブロックでは、再度、クリーンアウト対象になるような更新が発生しなければ、遅延ブロッククリーンアウトは発生しない

久しぶりにシステム統計やセッション統計を見ててワクワクしてきましたよーーーーっw

ところで、
冒頭でも記載しましたが、バッファキャッシュ上の遅延ブロッククリーンアウト(再掲)に加え、物理読み込みを伴う遅延ブロッククリーンアウトのauto traceの結果をまとめて記載しておきます。SELECT文ですが、REDOログが生成されている場合は遅延ブロッククリーンアウトが発生しているということになります。

実行計画

--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 194K| 188M| 18189 (1)| 00:00:01 |
| 1 | TABLE ACCESS FULL| HOGE | 194K| 188M| 18189 (1)| 00:00:01 |
--------------------------------------------------------------------------

1. 遅延ブロッククリーンアウトを発生させた場合。遅延ブロッククリーンアウト対象のデータがバッファキャッシュ上ににあるためクリーンアウトに伴う物理読み込みはない。

Statistics
----------------------------------------------------------
46 recursive calls
13 db block gets
91636 consistent gets
7 physical reads
967348 redo size
406775148 bytes sent via SQL*Net to client
147264 bytes received via SQL*Net from client
13335 SQL*Net roundtrips to/from client
2 sorts (memory)
0 sorts (disk)
200000 rows processed

2. 直後に再度全表走査した場合も、キャッシュヒットしているので、物理読み込みはない

Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
80061 consistent gets
0 physical reads
0 redo size
406775148 bytes sent via SQL*Net to client
147264 bytes received via SQL*Net from client
13335 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
200000 rows processed


3. 遅延ブロッククリーンアウトを発生させた場合。遅延ブロッククリーンアウト対象のデータを物理読み込みし、バッファキャッシュに載せている動きが見えます。

Statistics
----------------------------------------------------------
38 recursive calls
13 db block gets
91519 consistent gets
67073 physical reads
967432 redo size
406775148 bytes sent via SQL*Net to client
147264 bytes received via SQL*Net from client
13335 SQL*Net roundtrips to/from client
5 sorts (memory)
0 sorts (disk)
200000 rows processed

4. 3.の直後に再度全表走査した場合。事前にキャッシュをクリアしているため、物理読み込みがありますが、遅延ブロッククリーンアウトは発生していません。(Redoが生成されていないことで確認できます)

Statistics
----------------------------------------------------------
30 recursive calls
0 db block gets
80211 consistent gets
66719 physical reads
0 redo size
406775148 bytes sent via SQL*Net to client
147264 bytes received via SQL*Net from client
13335 SQL*Net roundtrips to/from client
5 sorts (memory)
0 sorts (disk)
200000 rows processed

ではでは。
次回は、scattered readのtable full scanではなく、direct path readだったらどうなるのか調べてみましょうか。。(いろいろな再現方法があるわけですが、手間のかからないお手軽な再現方法で確認してみようと思いますw)


洗濯機の修理が終わって一安心w ということで、次回へつづく。



古くて新しい? 遅延ブロッククリーンアウト (deferred block cleanout) #1
古くて新しい? 遅延ブロッククリーンアウト (deferred block cleanout) #2
古くて新しい? 遅延ブロッククリーンアウト (deferred block cleanout) #3
古くて新しい? 遅延ブロッククリーンアウト (deferred block cleanout) #4


| | コメント (0)

2021年9月 3日 (金)

古くて新しい? 遅延ブロッククリーンアウト (deferred block cleanout) #4

Previously on Mac De Oracle
前回はバッファキャッシュの10%未満のデータブロックへのINSERT文の実行とCOMMITの実行で、遅延ブロッククリーンアウトは発生せず、COMMIT時にすべての対象ブロックがクリーンアウトされるということを確認しました。

今回は、そのデータ量を倍にして、バッファキャッシュの10%程度を超えるデータブロックが遅延ブロッククリーンアウトされるのかを見ていくことにします。手順は前回と同じですが、遅延ブロッククリーンアウトさせた後で、もう一度全表走査してクリーンアウトが繰り返されないことも確認しておきます(次回以降に予定している確認への伏線なのですがw)


0) 対象表をdrop/create
オブジェクトを作り直して前提条件を合わせておきます

SCOTT@orcl> @droppurge_create_hoge

Table dropped.

Table created.

SCOTT@orcl> select segment_name,blocks from user_segments where segment_name like '%HOGE%';

no rows selected


1) 統計をクリアするのにOracle再起動

$ sudo service oracle restart


2) PDBのscottでログインし、client_infoをセット
v$sessionのclient_info列の'TargetSession'文字列で他のSCOTTユーザーのセッションと区別できるようにしています

SCOTT@orcl> @set_client_info
1 begin
2 DBMS_APPLICATION_INFO.SET_CLIENT_INFO('Target Session');
3* end;

PL/SQL procedure successfully completed.

Elapsed: 00:00:00.00
SCOTT@orcl>


3) CDBのSYSで統計取得(初回)

内容は省略!(ベースラインを取得しているだけなので)

SYS$orclcdb> @show_stat

4) PDBのSCOTTユーザーでデータINSERT(データ量2倍、コミットなし)

SCOTT@orcl> @insert_each_rows_2
1* begin for i in 1..200000 loop insert into hoge values(i, lpad('*', 2000, '*')); end loop; end;

PL/SQL procedure successfully completed.

Elapsed: 00:00:29.48
SCOTT@orcl>


5) CDBのSYSで統計取得(INSERT後、未コミット)

INSERTしただけです。未コミットなので特に気になる情報は現れていません。この値からコミット後にどのように変化するのか? という部分に注目する必要があるんですよー。
deferred (CURRENT) block cleanout applications と immediate (CURRENT) block cleanout applications が僅かにありますが、この時点では気にする部分ではないです

(値の変化が1以上ある統計のみ表示)

(CDB)システム統計

SOURCE  NAME                                                             VALUE
------- ------------------------------------------------- --------------------
sysstat DBWR checkpoint buffers written 22756
sysstat DBWR checkpoints 33
sysstat DBWR thread checkpoint buffers written 22756
sysstat DBWR transaction table writes 22
sysstat DBWR undo block writes 606
sysstat consistent gets 49761
sysstat db block changes 744980
sysstat deferred (CURRENT) block cleanout applications 4
sysstat immediate (CURRENT) block cleanout applications 1
sysstat no work - consistent read gets 192
sysstat physical reads 18
sysstat physical writes 22756
sysstat physical writes from cache 22756
sysstat physical writes non checkpoint 22756

(PDB) SCOTTのセッション統計

SOURCE  NAME                                                             VALUE
------- ------------------------------------------------- --------------------
sesstat consistent gets 49501
sesstat db block changes 744980
sesstat deferred (CURRENT) block cleanout applications 4
sesstat immediate (CURRENT) block cleanout applications 1
sesstat no work - consistent read gets 65
sesstat physical reads 17


6) PDBのSCOTTユーザーでコミットの実行

SCOTT@orcl> commit;

Commit complete.


7) CDBのSYSで統計取得(コミット後)

この結果、ノイズも少なく、綺麗に取れてます!!! w

前々回の事前確認の通り、2倍のデータブロック数は、 66667ブロック で、バッファキャッシュの10%は、ざっくり計算で、42394ブロック。つまり、想定では 42394ブロック ほどが、commit時のブロッククリーンアウトの対象と想定していました。

覚えてますか? みなさん!

実際にcommit時にクリーンアウトされたのはどれぐらいでしょう? 
結果は、55700ブロックとなりました。想定より多いですねw ほぼ合ってはいますが。
実際にはバッファキャッシュの13%〜15%程度が閾値になっているように見えます。とはいえ、commit時にcleanoutされたブロック数は 55700ブロック ですから、残る 10967ブロック のcleanoutは遅延されたということは確実です。commit対象のデータブロック全てをcleanoutするわけではない、ということは確認できたのではないでしょうか?

(差分が1以上ある統計のみ記載)
(CDB)システム統計

SOURCE  NAME                                                             VALUE
------- ------------------------------------------------- --------------------
sysstat commit cleanouts 55700
sysstat commit cleanouts successfully completed 55700
sysstat db block changes 1

(PDB) SCOTTのセッション統計

SOURCE  NAME                                                             VALUE
------- ------------------------------------------------- --------------------
sesstat commit cleanouts 55700
sesstat commit cleanouts successfully completed 55700
sesstat db block changes 1


8) PDBのSCOTTユーザーで、遅延ブロッククリーンアウト影響有無確認(対象表を全表走査)

SCOTT@orcl> sset autot trace exp stat
SCOTT@orcl> salter session set "_serial_direct_read" = never;

Session altered.

Elapsed: 00:00:00.00
SCOTT@orcl> select * from hoge;

200000 rows selected.

Elapsed: 00:00:05.14

Execution Plan
----------------------------------------------------------
Plan hash value: 2339479017

--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 194K| 188M| 18189 (1)| 00:00:01 |
| 1 | TABLE ACCESS FULL| HOGE | 194K| 188M| 18189 (1)| 00:00:01 |
--------------------------------------------------------------------------

Note
-----
- dynamic statistics used: dynamic sampling (level=2)


Statistics
----------------------------------------------------------
46 recursive calls
13 db block gets
91636 consistent gets
7 physical reads
967348 redo size
406775148 bytes sent via SQL*Net to client
147264 bytes received via SQL*Net from client
13335 SQL*Net roundtrips to/from client
2 sorts (memory)
0 sorts (disk)
200000 rows processed


9) CDBのSYSで統計取得(遅延ブロッククリーンアウト有無確認)

遅延ブロッククリーンアウトは、事前の計算通り、 10967ブロック 発生しています。SELECT文では、immediate (CR) block cleanout applications として現れることも確認できます。
また、cleanouts only - consistent read gets として も同数計上されているところが見てます。綺麗に現れています。

commit cleanouts, ommit cleanouts successfully completed がでていますが、ここでは気にしなくてよいですね、極わずかで。SELECT文なので。
immediate (CURRENT) block cleanout applications、deferred (CURRENT) block cleanout applications もでていますが、同じく極わずかで、対象表のものではないと考えられるためここでは気にしなくて良いですね。

しかし、計算通りに発生してくれると確認が楽w (想定外の動きじゃなくてよかったw)

(CDB)システム統計

SOURCE  NAME                                                             VALUE
------- ------------------------------------------------- --------------------
sysstat DBWR checkpoint buffers written 272
sysstat DBWR thread checkpoint buffers written 272
sysstat cleanouts only - consistent read gets 10967
sysstat commit cleanouts 16
sysstat commit cleanouts successfully completed 16
sysstat consistent gets 117000
sysstat db block changes 11207
sysstat deferred (CURRENT) block cleanout applications 10
sysstat immediate (CR) block cleanout applications 10967
sysstat immediate (CURRENT) block cleanout applications 2
sysstat no work - consistent read gets 83351
sysstat physical reads 939
sysstat physical writes 272
sysstat physical writes from cache 272
sysstat physical writes non checkpoint 260

(PDB) SCOTTのセッション統計

SOURCE  NAME                                                             VALUE
------- ------------------------------------------------- --------------------
sesstat cleanouts only - consistent read gets 10967
sesstat commit cleanouts 6
sesstat commit cleanouts successfully completed 6
sesstat consistent gets 98162
sesstat db block changes 11011
sesstat deferred (CURRENT) block cleanout applications 2
sesstat immediate (CR) block cleanout applications 10967
sesstat immediate (CURRENT) block cleanout applications 2
sesstat no work - consistent read gets 72113
sesstat physical reads 122


10) PDBのSCOTTユーザーで、遅延ブロッククリーンアウト影響有無確認(対象表を全表走査)

そして、ここからがおまけの確認ステップです

もう一度、同じ表を全表走査してみます。どうなると思いますか? 遅延されていたブロッククリーンアウトも行われたのですから、当然、該当オブジェクトで遅延ブロッククリーンアウトは発生しない。はず! ですよね。

確認してみましょう。(発生してたらどうしようw、もうしそうなったらバグレポートでも上げようかなw)

.......

Redoは生成されてない! (よかった! 想定どおりだ!w)

SCOTT@orcl> @table_full_scan
1* alter session set "_serial_direct_read" = never

Session altered.

Elapsed: 00:00:00.00
set autot trace exp stat

1* select * from hoge

200000 rows selected.

Elapsed: 00:00:05.43

Execution Plan
----------------------------------------------------------
Plan hash value: 2339479017

--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 214K| 207M| 18223 (1)| 00:00:01 |
| 1 | TABLE ACCESS FULL| HOGE | 214K| 207M| 18223 (1)| 00:00:01 |
--------------------------------------------------------------------------

Note
-----
- dynamic statistics used: dynamic sampling (level=2)

Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
80061 consistent gets
0 physical reads
0 redo size
406775148 bytes sent via SQL*Net to client
147264 bytes received via SQL*Net from client
13335 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
200000 rows processed

set autot off

SCOTT@orcl>

11) CDBのSYSで統計取得(遅延ブロッククリーンアウト有無確認)2回目

これもノイズが少なく綺麗に取れました。該当セッションでは物理読み込みも発生していないので、キャッシュから全データを読み込んだようです。

そして、想定どおり、該当セッションでは遅延ブロッククリーンアウトは発生していません!

commit cleanouts、commit cleanouts successfully completed、deferred (CURRENT) block cleanout applicationsが1ブロックありますがCDB側の管理情報関連でしょうね。気にする部分ではないですね。

(差分のあった統計のみ記載)

(CDB)システム統計

SOURCE  NAME                                                             VALUE
------- ------------------------------------------------- --------------------
sysstat commit cleanouts 1
sysstat commit cleanouts successfully completed 1
sysstat consistent gets 80150
sysstat db block changes 13
sysstat deferred (CURRENT) block cleanout applications 1
sysstat no work - consistent read gets 80075

(PDB) SCOTTのセッション統計

SOURCE  NAME                                                             VALUE
------- ------------------------------------------------- --------------------
sesstat consistent gets 80076
sesstat db block changes 9
sesstat no work - consistent read gets 80043




まとめ

おおよそ、バッファキャッシュの10%程度が commit時にcleanout されるという点については、約15%程度と見ておいたほうが良さそうですが、まあ大きな違いはないので、その辺りに閾値があると考えて問題はなさそうです。
また、それを超えるブロックについては、cleanoutが先送りされ、最初に該当ブロックにアクセスしたSQLがその影響を受ける。

この検証ではSELECT文では、immediate (CR) block cleanout applications という形で統計に現れました。UPDATE文やDELETE文の場合は他の統計として現れそうですね。(CURRENT)関連のcleanoutの統計は今回動いていないのでSQL文を変えて同じような検証をしてみると面白い結果をえられそうです。

そして、SELECT文で、遅延ブロッククリーンアウトされてしまえば、その間に更新が発生しなければ、クリーンアウトは発生しない(おまけで検証した部分ですが、別検証では興味深い動きを紹介する予定です。その伏線でもあります)

次回へつづく


5年目を迎えた、パナソニックのドラム洗濯機がH故障した。慌てて近所のコインランドリーを検索w 近所にあってよかったw



古くて新しい? 遅延ブロッククリーンアウト (deferred block cleanout) #1
古くて新しい? 遅延ブロッククリーンアウト (deferred block cleanout) #2
古くて新しい? 遅延ブロッククリーンアウト (deferred block cleanout) #3



| | コメント (0)

2021年9月 2日 (木)

古くて新しい? 遅延ブロッククリーンアウト (deferred block cleanout) #3

Previously on Mac De Oracle
前回は準備を終えたところまででした。

今日は、簡単なところから確認していきましょう。

もしも、「遅延ブロッククリーンアウトが起きない程度のブロック更新量だったなら。。。」。結果は遅延ブロッククリーンアウトは起きないはず。 ですよね。

ざっと手順を紹介しておきましょう。下図の 1)〜9)の順で行います
20210901-221016

前述の手順で、各操作後の統計の差分(変化量)を見る。マニュアルの統計の説明ってざっくり過ぎてよくわからないのが多いわけですがw、操作と値の変化を合わせて観察すると、それなりには理解できる程度に値が変化していることに気づきますw :)

1) 統計をクリアするのにOracle再起動

$ sudo service oracle restart


2) PDBのscottでログインし、client_infoをセット
v$sessionのclient_info列の'TargetSession'文字列で他のSCOTTユーザーのセッションと区別できるようにしています。

SCOTT@orcl> @set_client_info
1 begin
2 DBMS_APPLICATION_INFO.SET_CLIENT_INFO('TargetSession');
3* end;

PL/SQL procedure successfully completed.


3) CDBのSYSで統計取得(初回)
初回なのですべてリストしていますが、CON_ID=0のCDBのシステム統計([g]v$sysstat)とCON_ID=3のPDBの2)のCLIENT_INFOを設定されたセッションのセッション統計([g]v$sesstat)を取得します。
今回のケースではcleanoutが含まれている統計の差異だけに着目すれば良いのですが。準備運動程度のテストケースなので一応すべて載せておきます :)
(マルチテナントだと、DBRWの動きを見るにはCDBのDBWR関連の統計を見る必要があるため、CDBのシステム統計とPDBの当該セッションのセッション統計を対象にしています)

SYS$orclcdb> @show_stat
SOURCE NAME VALUE CON_ID
------- ------------------------------------------------------------ -------------------- ----------
sysstat DBWR checkpoint buffers written 0 0
sysstat DBWR checkpoints 0 0
sysstat DBWR fusion writes 0 0
sysstat DBWR lru scans 0 0
sysstat DBWR object drop buffers written 0 0
sysstat DBWR parallel query checkpoint buffers written 0 0
sysstat DBWR revisited being-written buffer 0 0
sysstat DBWR tablespace checkpoint buffers written 0 0
sysstat DBWR thread checkpoint buffers written 0 0
sysstat DBWR transaction table writes 0 0
sysstat DBWR undo block writes 0 0
sysstat cleanouts and rollbacks - consistent read gets 6 0
sysstat cleanouts only - consistent read gets 0 0
sysstat commit cleanout failures: block lost 0 0
sysstat commit cleanout failures: buffer being written 0 0
sysstat commit cleanout failures: callback failure 0 0
sysstat commit cleanout failures: cannot pin 0 0
sysstat commit cleanout failures: hot backup in progress 0 0
sysstat commit cleanout failures: write disabled 0 0
sysstat commit cleanouts 570 0
sysstat commit cleanouts successfully completed 570 0
sysstat consistent gets 158,083 0
sysstat db block changes 3,247 0
sysstat deferred (CURRENT) block cleanout applications 316 0
sysstat immediate (CR) block cleanout applications 6 0
sysstat immediate (CURRENT) block cleanout applications 15 0
sysstat no work - consistent read gets 108,516 0
sysstat physical reads 12,551 0
sysstat physical reads direct 0 0
sysstat physical writes 0 0
sysstat physical writes direct 0 0
sysstat physical writes from cache 0 0
sysstat physical writes non checkpoint 0 0
sysstat transaction tables consistent read rollbacks 0 0
sysstat transaction tables consistent reads - undo records applied 0 0
sesstat DBWR checkpoint buffers written 0 3
sesstat DBWR checkpoints 0 3
sesstat DBWR fusion writes 0 3
sesstat DBWR lru scans 0 3
sesstat DBWR object drop buffers written 0 3
sesstat DBWR parallel query checkpoint buffers written 0 3
sesstat DBWR revisited being-written buffer 0 3
sesstat DBWR tablespace checkpoint buffers written 0 3
sesstat DBWR thread checkpoint buffers written 0 3
sesstat DBWR transaction table writes 0 3
sesstat DBWR undo block writes 0 3
sesstat cleanouts and rollbacks - consistent read gets 0 3
sesstat cleanouts only - consistent read gets 0 3
sesstat commit cleanout failures: block lost 0 3
sesstat commit cleanout failures: buffer being written 0 3
sesstat commit cleanout failures: callback failure 0 3
sesstat commit cleanout failures: cannot pin 0 3
sesstat commit cleanout failures: hot backup in progress 0 3
sesstat commit cleanout failures: write disabled 0 3
sesstat commit cleanouts 1 3
sesstat commit cleanouts successfully completed 1 3
sesstat consistent gets 374 3
sesstat db block changes 4 3
sesstat deferred (CURRENT) block cleanout applications 1 3
sesstat immediate (CR) block cleanout applications 0 3
sesstat immediate (CURRENT) block cleanout applications 0 3
sesstat no work - consistent read gets 220 3
sesstat physical reads 28 3
sesstat physical reads direct 0 3
sesstat physical writes 0 3
sesstat physical writes direct 0 3
sesstat physical writes from cache 0 3
sesstat physical writes non checkpoint 0 3
sesstat transaction tables consistent read rollbacks 0 3
sesstat transaction tables consistent reads - undo records applied 0 3


4) PDBのSCOTTユーザーでデータINSERT(コミットなし)
データを1行単位でインサートしています。バルクインサートも使ってないです。綺麗なぐるぐる系ですねw。コミット時の効果を確認しやすいようにコミットは後で実行します!
このインサートで、前回の事前準備の時に確認しておいた、33334ブロックが更新されることになります

SCOTT@orcl> @insert_each_rows
1* begin for i in 1..100000 loop insert into hoge values(i, lpad('*', 2000, '*')); end loop; end;

PL/SQL procedure successfully completed.


5) CDBのSYSで統計取得(INSERT後、未コミット)

注) 3)の統計との差分のみ記載

未コミットであるこの時点で、commitクリーンアウトが発生(該当セッション統計でも同数発生。commit cleanoutsとcommit cleanouts successfully completed)してますが、これは気にしなくてもよいですね。
実行したトランザクションは、未コミットなので、この実行による直接的な影響ではないので。
また、deferred (CURRENT) block cleanout applicationsやimmediate (CURRENT) block cleanout applications の遅延ブロッククリーンアウトを示す統計も微量ですがこれも同様とみて良いでしょう。

この時点で統計取得理由は、操作毎に変化する統計を追うためなので、ふーーん。ぐらいでの雰囲気でOKです :)
コミット後とその後に該当オブジェクトをアクセスさせた時の遅延ブロッククリーンアウトの有無部分の部分が主役ですので。

参考)
INSERTした行の含まれる全ブロックはバッファキャッシュに載り切るブロック数なので、バッファキャッシュから書き出されているような動きも観測されていないのは確認できると思います。
(physical writes from cache,physical writes non checkpoint,physical writesの統計に変化がないので未記載ですが、それらの統計が動いていないということがその理由です)


(CDB)システム統計

SOURCE  NAME                                            VALUE
------- ---------------------------------------------------- ---------------
sysstat DBWR checkpoints 1
sysstat commit cleanouts 6
sysstat commit cleanouts successfully completed 6
sysstat consistent gets 22884
sysstat db block changes 373785
sysstat deferred (CURRENT) block cleanout applications 5
sysstat immediate (CURRENT) block cleanout applications 1
sysstat no work - consistent read gets 59
sysstat physical reads 12


(PDB) SCOTTのセッション統計

SOURCE  NAME                                            VALUE
------- ---------------------------------------------------- ---------------
sesstat commit cleanouts 6
sesstat commit cleanouts successfully completed 6
sesstat consistent gets 22816
sesstat db block changes 373785
sesstat deferred (CURRENT) block cleanout applications 5
sesstat immediate (CURRENT) block cleanout applications 1
sesstat no work - consistent read gets 49
sesstat physical reads 12


6) PDBのSCOTTユーザーでコミットの実行

SCOTT@orcl> commit;

Commit complete.


7) CDBのSYSで統計取得(コミット後)

注)5)と7)で取得した統計の差分のみ記載

ここが主役ですよー。このケースではバッファキャッシュの10%に満たないブロック数になるようにしたINSERT文(繰り返し実行)で 33334ブロックになるようにしました。これらを1度でcommitした場合、すべてのブロックがcommit時にblock cleanoutされるはずです。

では見てみましょう。

SCOTTのセッション統計より、commit cleanouts および commit cleanouts successfully completed から想定どおり全ブロックがcommit時にcleanoutされていることがわかります!
システム統計はインスタンス全体なのでPDBのそれら統計より大きめにでているのも確認できます。CDB側ではほんの少し deferred (CURRENT) block cleanout applications がありますが、管理情報系の遅延ブロッククリーンアウトでしょうね。 
古くて新しい? 遅延ブロッククリーンアウト (deferred block cleanout) #1で紹介したとおり 10% 未満では commit 時点で該当ブロックすべてcleanoutされることが確認できました。


(CDB)システム統計

SOURCE  NAME                                            VALUE
------- ---------------------------------------------------- ---------------
sysstat DBWR checkpoint buffers written 139
sysstat DBWR transaction table writes 22
sysstat DBWR undo block writes 55
sysstat commit cleanouts 33343
sysstat commit cleanouts successfully completed 33343
sysstat consistent gets 18111
sysstat db block changes 138
sysstat deferred (CURRENT) block cleanout applications 5
sysstat no work - consistent read gets 10853
sysstat physical reads 827
sysstat physical writes 139
sysstat physical writes from cache 139
sysstat physical writes non checkpoint 139


(PDB) SCOTTのセッション統計

SOURCE  NAME                                            VALUE
------- ---------------------------------------------------- ---------------
sesstat commit cleanouts 33334
sesstat commit cleanouts successfully completed 33334
sesstat db block changes 1


8) PDBのSCOTTユーザーで、遅延ブロッククリーンアウト影響有無確認(対象表を全表走査)

_serial_direct_read = never はdirect path readさせないためのおまじないです。direct path readで読み込まれたケースの動きは別エントリーで見ていく予定なので、direct path readを発生させずtable full scan (ようするにバッファキャッシュに載せる動き)で読み込むよう強制しています。
また、行数が多いのでその時間の短縮のためにautot trace exp statを有効にしてSELECT文を実行させつつ、termout offと同じ効果とauto explainの機能でSELECT文の実行統計からredoの生成有無を確認しています。(redoがあるということはなんらかの更新が行われているわけで、SELECT文の場合は比較的容易に遅延ブロッククリーンアウトの発生を推測できる統計にもなります)
以下のケースでは多少redoが生成されていますが、おそらく recursive callによるもので、HOGE表のオブジェクトそのものに対するもではなさそうです。(このケースではhoge表のオブジェクトに対する遅延ブロッククリーンアウトや
コミット時のブロッククリーンアウトの観察が主題なので、周りのノイズはあまり気にしなくてもOK(追いかけたい場合は別ですがw)


SCOTT@orcl> set autot trace exp stat
SCOTT@orcl> alter session set "_serial_direct_read" = never;

Session altered.

Elapsed: 00:00:00.00
SCOTT@orcl> select * from hoge;

100000 rows selected.

Elapsed: 00:00:02.59

Execution Plan
----------------------------------------------------------
Plan hash value: 2339479017

--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 57526 | 55M| 9098 (1)| 00:00:01 |
| 1 | TABLE ACCESS FULL| HOGE | 57526 | 55M| 9098 (1)| 00:00:01 |
--------------------------------------------------------------------------

Note
-----
- dynamic statistics used: dynamic sampling (level=2)

Statistics
----------------------------------------------------------
21 recursive calls
13 db block gets
40465 consistent gets
3 physical reads
2212 redo size
203382760 bytes sent via SQL*Net to client
73706 bytes received via SQL*Net from client
6668 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
100000 rows processed

SCOTT@orcl> set autot off


9) CDBのSYSで統計取得(遅延ブロッククリーンアウト有無確認)

注)7)のコミット時点からとの差異のみ記載。

多少ですが、SELECT文でredoが生成されてはいます。これは、commit cleanouts/commit cleanouts successfully completed (commit時に実施されるblock cleanout)と遅延ブロッククリーンアウトの統計の一つ、deferred (CURRENT) block cleanout applications が現れている影響ですね。コミット時点でHOGE表の全ブロックはcleanout済みなので recursive callによる内部管理情報関連で定常的に現れるものと考えられ、この検証では気にするところではないのでスルーしてください。

また、physical reads は、ほぼないため、この全表走査では、物理読み込み(direct path read含む)は、発生していないことも確認できます。
HOGE表はバッファキャッシュに載ったままという意図通りの状態にはなっているようです。
これ、今後のテストケースでも利用するので、キャッシュからエージアウトされないという点が確認できてると、以降の検証やりやすいんです:)


(CDB) システム統計

SOURCE  NAME                                            VALUE
------- ---------------------------------------------------- ---------------
sysstat DBWR checkpoint buffers written 34849
sysstat DBWR transaction table writes 32
sysstat DBWR undo block writes 897
sysstat commit cleanouts 558
sysstat commit cleanouts successfully completed 558
sysstat consistent gets 69973
sysstat db block changes 2862
sysstat deferred (CURRENT) block cleanout applications 311
sysstat immediate (CURRENT) block cleanout applications 28
sysstat no work - consistent read gets 57908
sysstat physical reads 812
sysstat physical writes 34849
sysstat physical writes from cache 34849
sysstat physical writes non checkpoint 34738


(PDB) SCOTTのセッション統計

SOURCE  NAME                                            VALUE
------- ---------------------------------------------------- ---------------
sesstat commit cleanouts 5
sesstat consistent gets 47037
sesstat db block changes 38
sesstat deferred (CURRENT) block cleanout applications 4
sesstat no work - consistent read gets 43103
sesstat physical reads 117


まとめ

DMLにより更新されたブロック数が、バッファキャッシュの10%未満のブロック数である場合、commit時にすべてcleanoutされ、対象表では遅延ブロッククリーンアウトは発生しない。
(想定通りなのですが、ちょいと安心w 19cでどう動くか確認してなかってしので少々ドキドキしてたw のはナイショ)

というわけで、今回はここまで。

いきなり涼しくなって、なんだこりゃ。。。。



古くて新しい? 遅延ブロッククリーンアウト (deferred block cleanout) #1
古くて新しい? 遅延ブロッククリーンアウト (deferred block cleanout) #2



| | コメント (0)

2021年8月31日 (火)

古くて新しい? 遅延ブロッククリーンアウト (deferred block cleanout) #2

Previously on Mac De Oracle

前回は、遅延ブロッククリーンアウトに限らず、大きく変わったわけでも、最近実装された機能でもないのに意外に知られてないのか、良いところ悪いところ含め、現場でロストしてしまっているような知識って意外と多いのかもねー。なんて感じたので遅延ブロッククリーンアウトネタのURLリンクをまとめてみた。

続編書くにしても、同じようなことやっても面白くないので、ブロックダンプのような方法は使わず、[g]v$sysstatや[g]v$sesstatなどの統計から、ちょいと血糖値や尿酸値高めだよね的な角度からどのような変化が起きるか見ていくことにした :)

 

環境はVirtualBox上の19cでこれからの主流になるマルチテナントで試してみます。(非マルチテナントでの変化見ててもこれからはあまり役に立たないので)

今日は準備編

VirtualBox
https://www.virtualbox.org/

Pre-Built Developer VMs (for Oracle VM VirtualBox)のDatabase App Development VMとか
https://www.oracle.com/downloads/developer-vm/community-downloads.html

 

 

事前に準備しておくスクリプトは以下のとおり。繰り返し実行するので作っておくと便利ですよ。:)

まず最初に、遅延ブロッククリーンアウトはバッファキャッシュの10%ほどのブロックをコミット時にクリーンアウトして、残りを先送りするという基本的なお約束があるので、上記環境のOracle 19cがどの程度のバッファキャッシュなのかとブロックサイズを確認。これ大切ですよ。スクリプト準備する上でも :)

メモリサイズは大きめですが。。。w うちのは。(^^;;;


$ VBoxManage -v
6.1.26r145957
$
$ VBoxManage showvminfo 'Oracle DB Developer VM 19.3' | grep -E 'Memory|CPUs'
Memory size: 16384MB
Number of CPUs: 4
$

コミット時にブロッククリーンアウトされそうなブロック数をざっくり算出すると 42394 ブロックぐらいになりそう。


SYS@orclcdb> show sga

Total System Global Area 4294963960 bytes
Fixed Size 9143032 bytes
Variable Size 805306368 bytes
Database Buffers 3472883712 bytes
Redo Buffers 7630848 bytes

SYS@orclcdb>
SYS@orclcdb> show parameter db_block_size

NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
db_block_size integer 8192
SYS@orclcdb>
SYS@orclcdb> select ceil( 3472883712 / 8192 * 0.1 ) from dual;

CEIL(3472883712/8192*0.1)
-------------------------
42394

Elapsed: 00:00:00.00

42394ブロックを超える程度のサイズのデータを生成するINSERT文と、その範囲に収まるデータ量生成INSERT文スクリプトを作れば良さそうですね。

想定されるブロックに収まる程度の量。1ブロック 8KB でデフォルトのPCTFREEは10%なのでざっくり6000bytes/rec超えるぐらい。
で、1ブロックに3行ぐらい入るようにすれば面白いかな。。

ということで、

表はなんどもdrop/createするので以下のDDLで。初回は索引を作らず、表のみので影響をみることにする。


$ cat droppurge_create_hoge.sql

drop table hoge purge;
create table hoge (id number, data varchar2(2000));

データ作成(バッファキャッシュの10%未満のデータ登録)
なお、確実に遅延ブロッククリーンアウトの影響を見たいので1行ごとのINSERTを繰り返し、コミット前後の状態の変化も見たいのでcommitも含めていない。(commitは別途実行する)


$ cat insert_rows.sql

begin for i in 1..100000 loop insert into hoge values(i, lpad('*', 2000, '*')); end loop; end;
.
l
/

ブロック数の事前確認


SCOTT@ORCL> select count(distinct dbms_rowid.rowid_block_number(rowid)) as "blocks" from hoge;

blocks
----------
33334

データ作成(バッファキャッシュの10%を超えるのデータ登録)
単純にループ回数を倍にして増量。これで事前に算出したバッファキャッシュの10%以上のブロック数は更新される。。。はず。


$ cat insert_rows_2.sql

begin for i in 1..200000 loop insert into hoge values(i, lpad('*', 2000, '*')); end loop; end;
.
l
/

ブロック数の事前確認(20,000ブロックぐらい?は遅延される想定)


SCOTT@ORCL> select count(distinct dbms_rowid.rowid_block_number(rowid)) as "blocks" from hoge;

blocks
----------
66667

ここまでが遅延ブロッククリーンアウトを意図的に起こすためのデータ作成SQLスクリプト

以降は、遅延ブロッククリーンアウトの発生等を見るための[g]v$sysstatと[g]v$sestatを取得するスクリプトと、[g]v$sesstatから特定のセッションを取得するためのクライアント情報をセットするスクリプト。


$ cat set_client_info.sql
BEGIN
DBMS_APPLICATION_INFO.SET_CLIENT_INFO('TargetSession');
END;
.
l
/

システム統計とセッション統計を取得して差分を見ていく必要があるので各統計のスナップショット取得用スクリプトが必要なわけですが、今回はマルチテナント環境。なので、システム統計はCDB全体から、セッション統計は該当するPDBかつ、前述のスクリプトでClient Infoが設定されているセッションに限定するスクリプトを作る必要があるんですよね。DBWRの動きも含めてみたいときって。少し多めに統計名を取得していますが、実際に重要なのはcleanout系の統計ですね。いくつかのテストケースを実施する上で合わせてみておきたい統計も事前に入れてあります:)


$ cat show_stat.sql
set linesize 400
set tab off
set pagesize 1000
col name for a60
col value for 999,999,999,999,999
SELECT
'sysstat' AS "SOURCE"
, name
, value
, con_id
FROM
gv$sysstat
WHERE
name IN (
'physical writes direct'
, 'physical writes from cache'
, 'physical writes non checkpoint'
, 'consistent gets'
, 'no work - consistent read gets'
, 'cleanouts and rollbacks - consistent read gets'
, 'cleanouts only - consistent read gets'
, 'deferred (CURRENT) block cleanout applications'
, 'immediate (CR) block cleanout applications'
, 'immediate (CURRENT) block cleanout applications'
, 'commit cleanout failures: block lost'
, 'commit cleanout failures: buffer being written'
, 'commit cleanout failures: callback failure'
, 'commit cleanout failures: cannot pin'
, 'commit cleanout failures: hot backup in progress'
, 'commit cleanout failures: write disabled'
, 'commit cleanouts'
, 'commit cleanouts successfully completed'
, 'db block changes'
, 'physical read requests'
, 'physical reads'
, 'physical reads direct'
, 'physical write requests'
, 'physical writes'
, 'physical writes direct'
, 'DBWR checkpoint buffers written'
, 'DBWR thread checkpoint buffers written'
, 'DBWR tablespace checkpoint buffers written'
, 'DBWR parallel query checkpoint buffers written'
, 'DBWR object drop buffers written'
, 'DBWR transaction table writes'
, 'DBWR undo block writes'
, 'DBWR revisited being-written buffer'
, 'DBWR lru scans'
, 'DBWR checkpoints'
, 'DBWR fusion writes'
, 'transaction tables consistent reads - undo records applied'
, 'transaction tables consistent read rollbacks'
)
UNION ALL
SELECT
'sesstat' AS "SOURCE"
, name
, value
, vsesstat.con_id
FROM
gv$sesstat vsesstat
inner join gv$statname vstatnam
on
vsesstat.statistic# = vstatnam.statistic#
WHERE
name IN (
'physical writes direct'
, 'physical writes from cache'
, 'physical writes non checkpoint'
, 'consistent gets'
, 'no work - consistent read gets'
, 'cleanouts and rollbacks - consistent read gets'
, 'cleanouts only - consistent read gets'
, 'deferred (CURRENT) block cleanout applications'
, 'immediate (CR) block cleanout applications'
, 'immediate (CURRENT) block cleanout applications'
, 'commit cleanout failures: block lost'
, 'commit cleanout failures: buffer being written'
, 'commit cleanout failures: callback failure'
, 'commit cleanout failures: cannot pin'
, 'commit cleanout failures: hot backup in progress'
, 'commit cleanout failures: write disabled'
, 'commit cleanouts'
, 'commit cleanouts successfully completed'
, 'db block changes'
, 'physical read requests'
, 'physical reads'
, 'physical reads direct'
, 'physical write requests'
, 'physical writes'
, 'physical writes direct'
, 'DBWR checkpoint buffers written'
, 'DBWR thread checkpoint buffers written'
, 'DBWR tablespace checkpoint buffers written'
, 'DBWR parallel query checkpoint buffers written'
, 'DBWR object drop buffers written'
, 'DBWR transaction table writes'
, 'DBWR undo block writes'
, 'DBWR revisited being-written buffer'
, 'DBWR lru scans'
, 'DBWR checkpoints'
, 'DBWR fusion writes'
, 'transaction tables consistent reads - undo records applied'
, 'transaction tables consistent read rollbacks'
)
and sid = (
select
sid
from
gv$session
where
username = upper('&1')
and client_info = 'TargetSession'
)
order by
4, 1, 2
;

undefine 1

ちなみに、統計を使って状況を確認する方法って意外に利用されているんですよね。日本だとあまり活用されてないようにも感じることは多いのですが、日々の統計を追っかけてると、どのメトリックが高く跳ね上がるのか把握できるので知ってて損することはないと思います:)

そういえば、Tanel PoderのSnapperもその手のツールではありますね。
Session Snapper
http://tech.e2sn.com/oracle-scripts-and-tools/session-snapper

私の過去のセッションでもElappsed Timeを見せないでチューニング効果を見てもらうネタとしてシステム統計を使ってたりします。
db tech showcase Tokyo 2013 - A35 特濃JPOUG:潮溜まりでジャブジャブ、SQLチューニング
https://www.slideshare.net/discus_hamburg/db-tech-showcase-tokyo-2013-a35-sql

少々脱線しますが、
最近、VirtualBox、なつかしー。なんて言う方もいますが、古いバージョンのOracleを残しておけるので、リリース毎の動きの差などを見たい場合は便利なのですよーw(クラウドだと強制アップグレードされちゃうので旧バージョンとの動作比較をネタにしたいときなどには向いてないw)

次回へつづく


東京では救急車のサイレンがまだまだ通常より多く聞こえます。。。。

Stay home, Stay Safe and Stay Hydrated.


古くて新しい? 遅延ブロッククリーンアウト (deferred block cleanout) #1


 

| | コメント (0)

2021年8月23日 (月)

古くて新しい? 遅延ブロッククリーンアウト (deferred block cleanout) #1

昔からOracle Database触ってると結構当たり前だったことではあるけど、最近、主にExadata以降にOraclerになったエンジニアへ伝承というかノウハウの一つとして継承されていないのかなー。
と感じることが何度かあり、属人化とは少々違う、失われた知識みたいなのもあるのかではないかと。。。そんなアトモスフィアを感じつつ、遅延ブロッククリーンアウトについて軽く書こうかなと。

と、今思ってるだけで、めんどくさくなって続かないかもしれませんw 

 

昔からある有名な遅延ブロッククリーンアウトの情報はMOSにもありますが、読んだことある方はどれぐらいいるのだろう。かなーーーり昔は日本独自?のMetalinkとかKROWNで細かく書かれていた(ような)記憶はあるが、最近はそこまで書かれてないような。。。まあいいかw

遅延ロギング・ブロック・クリーンアウトについて(KROWN:48106) (Doc ID 1716869.1)

こまけーことは置いといて、MOSとか、他のブログを読むと動きはざっくり理解できると思うのですが、

ポイントは、Buffer Cache サイズのおおよそ10%ぐらいまでがcommit時にクリーンアウトされる最大サイズ、それ以外は先送りされるというところ。
commit時にクリーンアウトされないので、後続のSQL文で該当するブロックがアクセスされたタイミングでタイミングでクリーンアウトされる。通常は更新を伴わないSELECT文でも発生する。そこで気づく方は多いわけです。はい。

SELECT文なのになんでREDOが生成されているんだろう???? と。

例えば、Buffer Cacheが 10ブロック分あったとして、UPDATE文で5ブロック更新してcommitした場合、10ブロックの10%の1ブロックだけがcommit時にブロッククリーンアウトされ、残りの 4ブロックのクリーンアウトは遅延される。ざっくり言えばそんな感じ。
DMLでINSERT/DELETE/UPDATEでどのどの程度のブロックが更新されるかで、遅延されるブロック数はざっくり判断できちゃいます。
ちなみに、どのタイミングでどの程度、クリーンアウトされたかという統計情報はあるが、トランザクションがcommitされたタイミングでどれぐらいクリーンアウトが遅延されたブロックが存在するかを示す統計はないので、どの程度の更新ブロックがあるかと、commit時にクリーンアウトできるブロック数の差分からざっくり判断するのがリーズナブル(他の流派の方もいるかもしれないがw)

OLTPのようなショートトランザクションでは、あまりクリーンアウトが先送りされることはないわけですが、ロングトランザクションでコミット1回というタイプだと、commit時にはブロックをクリーンアウトしきれない程度のブロックが更新され、クリーンアウトが遅延されるという状況は仕様どおりなわけです。。。。ロングトランザクションで発生しやすいということにはなりますね。(だったら、ぐるぐる系のバッチ更新処理って最高じゃね?、。。。それはちょっと。。。w 向かう方向が違うかなw)

話は少し代わりますが、前述のようにcommtのタイミングではBuffer Cacheの10%程度までなので、Buffer Cache を大きくすれば、commit時にクリーンアウトされる最大サイズも大きくなる。。。というのは簡単にイメージできると思います。。。

そして、遅延クリーンアウトブロックが発生しないケースがあるのご存知ですか?(知ってて損はないですよ。。)

 



以下のサイトで有益な情報を提供しているので一度は見ておくと良いと思います。

最近のOraclerは知らないかもしれないけど、AskTomでもTomが、遅延グロッククリーンアウトについて答えてます。 


このQAでのポイントは回答にある以下の部分、ここでも10 percent of our buffer cacheと言及されていますよね。これ2005のQAです。この頃まだ小学生だった方達が今Oraclerとしてデビューしてたりするわけですよねw 

”If we were to re-run the above example with the buffer cache set to hold at least 5,000 blocks, we'll find that we generate little to no redo on any of the SELECTs - we will not have to clean dirty blocks during either of our SELECT statements. This is because the 500 blocks we modified fit comfortably into 10 percent of our buffer cache, and we are the only user. There is no one else is mucking around with the data, and no one else is causing our data to be flushed to disk or accessing those blocks. In a live system, it will be normal for at least some of the blocks to not be cleaned out sometimes.”

Does select generate undo ? / AskTom / 2005

これは比較的新しいQAですね
delayed block cleanout / AskTom / 2017

レジェンド、ジョナサンルイスのブログでも
Clean it up / Jonathan Lewis / 2009

MaxGuage for Oracleで有名なエクセムさんのブログ

この記事で引用されているMetalinkは、現在のMOSには存在しないのでMOSのアカウントがあるかたが頑張って検索してもヒットしないのでご注意を。(日付が記載されていないので何年の記事かわからないですが、記事自体かなり古いはずなのでネタ元も古いと思ってください)
遅延ブロッククリーンアウト / エクセムさんのブログ

このブログでも10%ルールの話は出てきています。
Delayed Block Cleanout in Oracle / databasejournal By David Fitzjarrell / 2015


比喩がわかりにくいかもしれないけど、有名な Shit the Oracle さんのブログ (このエントリーも日付がないけど、適当なタイミングでUpdateされているような、気がしないでもない)
遅延ブロッククリーンアウト / SHIFT-the-Oracle


以下、システムサポートさんのブログ、わかりやすいですよね。冒頭で少し紹介した遅延クリーンアウトブロックが発生しないケースにも軽くふれてますね。direct path writeしているケースに注目ですよ!
フルスキャンで何故シングルブロックリードが発生するのか?(2/2)


NTTDのOracle ACE 高橋さんもExadataでの遅延ブロッククリーンアウトの洗礼を受けた模様、比較的最近なのですね。 :)
exadataと遅延ブロッククリーンアウトとシングルブロックリード / オラクルデータベースの技術メモ

ブロックダンプしながら確認するなんて、マニアックですよね。w このかた。前述のシステムサポートさんの記事で紹介されているdirect path writeのケースも検証されています。素敵です。
遅延ブロッククリーンアウトを観測する① / SQL*Plusの使いにくさは異常


ということで、私が書かなくても、これだけの情報があるので、書こうか書かないか、迷うーーーーっw。
紹介したエントリーの内容を確認するための方法こんな方法でも確認できるよー的な内容にしましょうかね。。。

では、Stay Home and Stay Safe.

次回へつづく。

| | コメント (0)

2021年3月31日 (水)

Difference of Initialization Parameters between 11gR2 (11.2.0.4.0) and 19c (19.3.0.0.0) - including hidden params

Previously on Mac De Oracle
19cの初期化パラメータ数や隠しパラメータ数などどう変化したのか、久々に確認してみた


ということで、今回はめでたくサポート終了となった11gR2と19cのパラメータ差分を確認してみた(何年振りだろうこれw)。21cがでたらまたやる予定。

11gR2 : 11.2.0.4.0
19c : 19.3.0.0.0

で比較した結果は以下

Difference of Initialization Parameters between 11gR2 (11.2.0.4.0) and 19c (19.3.0.0.0)



どうやればこの差分が作れるかというと、DBリンクでもできるけどそんなことしてません。というかやりたくないw ので、旧リリースでパラメータをcsv出力して(comma区切りではないですがw)、19c側で外部表として参照して差分を出力.

パラメータの取り出し。linesizeは適当に調整する必要はあるかも

ORACLE-ORCLCDB@SYS> !cat paramout.sql
set linesize 250
set trimspool on
set head off
set feedback off
set timi off
set termout off
set time off
set timi off
spo &1..csv

SELECT
TRIM(a.ksppinm)
||'|'||TRIM(a.ksppdesc)||'|'
FROM
x$ksppi a
/
spo off
undefine 1


上記スクリプトの実行、結果の例

ORACLE-ORCLCDB@SYS> @paramout 11.2.0.4.0_parameters
ORACLE-ORCLCDB@SYS> !cat 11.2.0.4.0_parameters.csv

_appqos_qt|System Queue time retrieval interval|
_ior_serialize_fault|inject fault in the ior serialize code|
_shutdown_completion_timeout_mins|minutes for shutdown operation to wait for sessions to complete|
_inject_startup_fault|inject fault in the startup code|
_latch_recovery_alignment|align latch recovery structures|
_spin_count|Amount to spin waiting for a latch|
_latch_miss_stat_sid|Sid of process for which to collect latch stats|
_max_sleep_holding_latch|max time to sleep while holding a latch|
_max_exponential_sleep|max sleep during exponential backoff|
_other_wait_threshold|threshold wait percentage for event wait class Other|
_other_wait_event_exclusion|exclude event names from _other_wait_threshold calculations|
・・・略・・・

外部表の元ネタであるファイル置き場用ディレクト作製とディレクトリオブジェクトの作製、そして、元ネタの配置は以下の通り

ORACLE-ORCLCDB@SYS> !pwd
/home/oracle
ORACLE-ORCLCDB@SYS> !ls -l exttab
合計 488
-rw-rw-r--. 1 oracle oracle 194319 3月 29 21:26 11.2.0.4_parameters.csv

ORACLE-ORCLCDB@SYS> CREATE DIRECTORY ext_tab AS '/home/oracle/exttab';

ディレクトリが作成されました。

ORACLE-ORCLCDB@SYS> l
1 CREATE TABLE ksppi_11_2_0_4_0 (
2 ksppinm VARCHAR2(80)
3 ,ksppdesc VARCHAR2(255)
4 )
5 ORGANIZATION EXTERNAL (
6 TYPE ORACLE_LOADER
7 DEFAULT DIRECTORY ext_tab
8 ACCESS PARAMETERS (
9 RECORDS DELIMITED BY NEWLINE
10 FIELDS TERMINATED BY '|'
11 (
12 ksppinm
13 ,ksppdesc
14 )
15 )
16 LOCATION (
17 '11.2.0.4_parameters.csv'
18 )
19* )
ORACLE-ORCLCDB@SYS> /

表が作成されました。

ORACLE-ORCLCDB@SYS> SELECT COUNT(1) FROM ksppi_11_2_0_4_0;

COUNT(1)
----------
2915


以下のスクリプトでcdb$rootのx$ksppiと前述の外部表をfull outer joinして差分をhtml形式で出力すればできあがり

col "11g R2 11.2.0.4.0" for a17
col "19c 19.3.0.0.0" for a17
set pagesize 10000
set timi off
set feed off
set markup html on spool on
spo param-diff.html
SELECT
CASE
WHEN prev.ksppinm = curr.ksppinm
OR (
prev.ksppinm IS NULL
AND curr.ksppinm IS NOT NULL
)
THEN curr.ksppinm
ELSE prev.ksppinm
END AS ksppinm
,CASE
WHEN prev.ksppinm = curr.ksppinm THEN '○'
WHEN prev.ksppinm IS NOT NULL AND curr.ksppinm IS NULL THEN '○'
ELSE 'n/a'
END AS "11g R2 11.2.0.4.0"
,CASE
WHEN prev.ksppinm = curr.ksppinm THEN '○'
WHEN prev.ksppinm IS NULL AND curr.ksppinm IS NOT NULL THEN '○'
ELSE 'n/a'
END AS "19c 19.3.0.0.0"
,CASE
WHEN prev.ksppdesc = curr.ksppdesc THEN curr.ksppdesc
WHEN prev.ksppinm IS NULL AND curr.ksppinm IS NOT NULL THEN curr.ksppdesc
WHEN prev.ksppinm iS NOT NULL AND curr.ksppinm IS NULL
THEN prev.ksppdesc
ELSE prev.ksppdesc
END AS kspdesc
,CASE
WHEN prev.ksppdesc = curr.ksppdesc
OR (prev.ksppinm IS NULL AND curr.ksppinm IS NOT NULL)
OR (prev.ksppinm IS NOT NULL AND curr.ksppinm IS NULL)
THEN NULL
ELSE curr.ksppdesc
END AS "New description"
FROM
(
SELECT * FROM x$ksppi WHERE con_id = 0
) curr
FULL OUTER JOIN ksppi_11_2_0_4_0 prev
ON
curr.ksppinm = prev.ksppinm
ORDER BY
1
;
spool off
set feed on
set set markup html off




露天風呂♨️行きたい...




Difference of Initialization Parameters between 11g r1 (11.1.0.6.0) and 12c r1 (12.1.0.1.0) - including hidden params
Difference of Initialization Parameters between 11g and 12c #2
19cの初期化パラメータ数や隠しパラメータ数などどう変化したのか、久々に確認してみた

| | コメント (0)

2021年3月22日 (月)

19cの初期化パラメータ数や隠しパラメータ数などどう変化したのか、久々に確認してみた


ORACLE-ORCLCDB@SYS> select banner_full from v$version;

BANNER_FULL
------------------------------------------------------------------------
Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production
Version 19.3.0.0.0
compute sum label 'Total' of "Num Of Parameters" on report
break on report
WITH cte_params AS
(
SELECT
a.ksppinm
FROM
x$ksppi a JOIN x$ksppcv b
ON a.indx = b.indx
)
SELECT
*
FROM
(
SELECT
'1. Single underscore parameters' AS "CATEGORY"
, COUNT(1) AS "Num Of Parameters"
FROM
cte_params
WHERE
REGEXP_LIKE(ksppinm, '^([_][^_]){1}.*')
UNION
SELECT
'2. Double underscore parameters'
, COUNT(1)
FROM
cte_params
WHERE
REGEXP_LIKE(ksppinm, '^[_]{2}.*')
UNION
SELECT
'3. Non hidden parameters'
, COUNT(1)
FROM
cte_params
WHERE
REGEXP_LIKE(ksppinm, '^[^_].*')
)
ORDER by
category;

カウントした結果は以下のとおり。やはりhidden parameter、かなり増えてますよね。

CATEGORY                        Num Of Parameters
------------------------------- -----------------
1. Single underscore parameters 4934
2. Double underscore parameters 30
3. Non hidden parameters 448
-----------------
Total 5412

経過: 00:00:00.06

20210322-141656

 

ぽかぽか陽気すぎて、海辺でパタパタしたいw

 


Difference of Initialization Parameters between 11g r1 (11.1.0.6.0) and 12c r1 (12.1.0.1.0) - including hidden params
Difference of Initialization Parameters between 11g and 12c #2

 

| | コメント (0)

2021年2月13日 (土)

実行計画は、SQL文のレントゲン写真だ! No.30

OracleのResource Managerネタを書こう書こうと思いつつ類似ネタが他のブログでも扱われていることに気づきw
ネタを被らないようにしたいなぁとw 考えているうちにすでに2月の半ばw もうすこし考えまするw

ということで、今回はこないだ、実行計画という名のレントゲンネタに絡んだtwitterのやりとりがあったついでなので、INSERTの実行計画をいくつか追加しておきます。

Oracleもバージョンが上がるごとに実行計画の改善やオペレーション名を変えたりするので古いバージョンだと、そんなオペレーション出なーーーい。ということもありますが、そんなオペレーションがでたら、こんな意味なんだぁ。

と理解しておけば裏でどう動いているかイメージしやすいのではないかと思います。それがイメージできていれば、もし、性能問題に絡んでいた時にはどう対処するのが良いか、助けになるとはずです (^^)

DIRECT PATH LOADING登場前のOracle Databaseでは気にする必要はなかったのですが、DIRECT PATHが行われるようになってから実行計画のOperationでDIRECT PATHとの区別がつきやすいように追加されたという微かな記憶があります。
(まちがっていたらコメントいただけますと m(_ _)m

ということで、実行計画の見てみましょう。INSERT文なので単純ですw INSERTのoperationが(裏で)どう行われているかの違いです。
(以下の実行計画ではIASを利用して500MBほどの元表から同一定義の別表へ全データをINSERTしています)

LOAD TABLE CONVENTIONALというoperationが該当部分。 覚えておくと何かの役にはたつと思います!

20210213-150833

この実行計画になるように以下のようにNOAPPENDヒントでdirect path writeを抑止しています。ヒントの使い方も覚えておくとなにかのときにや役立ちますよ:)
NO_GATHER_OPTIMIZER_STATISTICSヒントは今回の実行計画には直接関係ないリアルタイム統計の取得を抑止するヒントです。
19cのおそらく後半のリリースから従来型のDMLでもリアルタイム統計が取得されるようになったようです。この例ではじゃまなので抑止。

従来型のDMLでもリアルタイム統計が取得される https://docs.oracle.com/cd/F19136_01/tgsql/optimizer-statistics-concepts.html#GUID-769E609D-0312-43A7-9581-3F3EACF10BA9

Real-Time Statistics https://docs.oracle.com/en/database/oracle/oracle-database/19/dblic/Licensing-Information.html#GUID-0F9EB85D-4610-4EDF-89C2-4916A0E7AC87

INSERT
/*+
MONITOR
NOAPPEND
NO_GATHER_OPTIMIZER_STATISTICS
*/
INTO
hoge2
SELECT
*
FROM
hoge
;

では、つづいて、direct path writeが動作した場合は該当部分のoperationはどうなるでしょうか? :)

LOAD AS SELECT に変わったoperationが該当部分です! operation は LOAD AS SELECT ですが、待機イベントは direct path write です。
どのようなoperationがどのような待機イベントに繋がるのかっていうのもおぼえておくと何かの役に立ちますよ ;)

20210213-150416

実行したINSERT文のヒントがNOAPPPENDからAPPENDに変えてあることに注目。この例ではdirect path writeをヒントで強制しています。

INSERT
/*+
MONITOR
APPEND
NO_GATHER_OPTIMIZER_STATISTICS
*/
INTO
hoge2
SELECT
*
FROM
hoge
;

最後に、NO_GATHER_OPTIMIZER_STATISTICS ヒントを外してリアルタイム統計取得が動いた場合にはどのようなoperationになるかみてみましょう。

20210213-153502

OPTIMIZER STATISTICS GATHERING というoperationが現れました。これは19cの後半で追加された従来型DMLでのリアルタイム統計取得が動作した場合も現れるとマニュアルに記載されているoperationとも同一です。
direct path writeなのかによらず、リアルタイム統計取得の動作有無を確認するためにはこのoperationの有無をチェックする必要があります!

INSERT
/*+
MONITOR
APPEND
*/
INTO
hoge2
SELECT
*
FROM
hoge
;

なかなかよい、レントゲンコレクションが撮れたな :)


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

 

| | コメント (0)

2020年12月26日 (土)

標準はあるにはあるが癖の多いSQL 全部俺 おまけ SQL de 湯婆婆やるにも癖がでるw

恒例の標準はあるにはあるが癖の多いSQL 全部俺w Advent Calendar 2020のおまけですw

忙しすぎて、この手の遊びが疎かになっておりました。完全に乗り遅れておりましたが、湯婆婆やりましたw

スタジオジブリさん、「画像は常識の範囲でご自由にお使いください。」とのことでありがたく使わせていただきます!
https://www.ghibli.jp/works/chihiro/#frame

Chihiro016

では、Oracle (19c)を使って、Oracle 湯婆婆 から
Advent Calendar 標準はあるにはあるが癖の多いSQL 全部俺でも登場したSUBSTR/DBMS_RANDOM.VALUEや文字列連結の違い。
それに、SQLスクリプトでインタラクティブにパラメータを渡せるかという点にも違いがあります。

SQL*Plus/psqlではインタラクティブにパラメータを渡せますが、mysqlにはなさそう(あったらコメントください)

インタラクティブにパラメータを渡せるSQL*Plus/psqlでは、それぞれ、ACCEPTや\promptなどで名前を入力しています。
mysqlでは仕方ないのでSETコマンドで設定する方法をとりました。


ORACLE> @ora_yubaba
契約書だよ。そこに名前を書きな。山田千尋

湯婆婆
--------------------------------------------------------------------------------
フン 山田千尋 というのかい。贅沢な名だねぇ
今からお前の名前は 田 だ。いいかい、田 だよ。
わかったら返事をするんだ、
!!

$ cat ora_yubaba.sql
SET LINESIZE 80
SET TAB OFF
SET VERIFY OFF
ACCEPT fullname CHAR PROMPT '契約書だよ。そこに名前を書きな。'
WITH yourname
AS
(
SELECT
SUBSTR(
'&&fullname'
, DBMS_RANDOM.VALUE(1,LENGTH('&&fullname')), 1
) AS newname
FROM
dual
)
SELECT
'フン '
||'&&fullname'
||' というのかい。贅沢な名だねぇ'
||CHR(13)||CHR(10)
||'今からお前の名前は '
||newname
||' だ。いいかい、'
||newname
||' だよ。'
||CHR(13)||CHR(10)||'わかったら返事をするんだ、'
||CHR(13)||CHR(10)||'!!' AS "湯婆婆"
FROM
yourname;

undefine fullname
SET VERIFY ON

PostgreSQL (12)

次は、PostgreSQL 湯婆婆

postgres=> \i postgresql_yubaba.sql
契約書だよ。そこに名前を書きな : 山田千尋
湯婆婆
----------------------------------------------
フン 山田千尋 というのかい。贅沢な名だねぇ +
今からお前の名は 田 だ。いいかい、田 だよ。+
わかったら返事をするんだ、 +
!!
(1 row)
$ cat postgresql_yubaba.sql
\prompt '契約書だよ。そこに名前を書きな : ' fullname

WITH yourname
AS
(
SELECT
SUBSTR(
:'fullname'::TEXT
, CEIL(RANDOM() * LENGTH(:'fullname'::TEXT))::INTEGER, 1::INTEGER
) AS newname
)
SELECT
'フン '
||:'fullname'
||' というのかい。贅沢な名だねぇ'
||E'\n'
||'今からお前の名は '
||newname
||' だ。いいかい、'
||newname
||' だよ。'
||E'\n'||'わかったら返事をするんだ、'
||E'\n'||'!!' AS "湯婆婆"
FROM
yourname;


MySQL 8.0

最後に、MySQL 湯婆婆

mysql> SET @契約書だよ。そこに名前を書きな = '山田千尋';
Query OK, 0 rows affected (0.13 sec)

mysql> \! vi mysql_yubaba.sql
mysql> \. mysql_yubaba.sql
Query OK, 0 rows affected (0.02 sec)

*************************** 1. row ***************************
湯婆婆: フン 山田千尋 というのかい。贅沢な名だねぇ
今からお前の名は 尋 だ。いいかい、尋 だよ。
わかったら返事をするんだ、
!!
1 row in set (0.02 sec)
$ cat mysql_yubaba.sql
SET sql_mode = 'ANSI';
WITH yourname
AS
(
SELECT
SUBSTRING(
@契約書だよ。そこに名前を書きな
, CEIL(RAND() * CHAR_LENGTH(@契約書だよ。そこに名前を書きな)), 1
) AS newname
)
SELECT
'フン '
||@契約書だよ。そこに名前を書きな
||' というのかい。贅沢な名だねぇ'
||'\r\n'
||'今からお前の名は '
||newname
||' だ。いいかい、'
||newname
||' だよ。'
||'\r\n'||'わかったら返事をするんだ、'
||'\r\n'||'!!' AS "湯婆婆"
FROM
yourname\G



こういう遊びはみなさん好きですよね? 
では、また。



似たようなネタのエントリー
Oracle de Fizzbuzz #1 - いまごろ・・・ですが・・
Oracle de Fizzbuzz #2
Mac de Caché というか MUMPS というか Objectscript か - fizzbuzz
PL/SQL de ケンブリッジ関数
こんなのでいいのかなぁ。ズンドコキヨシ  ObjectScript / MUMPS






標準はあるにはあるが癖の多い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にも癖がある:)

| | コメント (0)

2020年12月25日 (金)

標準はあるにはあるが癖の多いSQL 全部俺 #25 SQL de Fractalsにも癖がある:)

標準はあるにはあるが癖の多いSQL 全部俺w Advent Calendar 2020の25日目です。

5年前にクリスマスのお遊び - SQL de Fractals :)というネタを書いてました。

EXPLAIN EXTENDED - Happy New Year!
元ネタは、ARRAY_TO_STRINGとARRAY_AGGの組み合わせ、とgenerate_seriesを利用した再帰問合せを利用したPostgreSQLバージョンのSQL

今であれば、以下のように書き換え、STRING_AGGでけにした方が良いのではないだろうか。
また、generate_series部分の方言の影響を最小にするのであれば、この部分も再帰問合せを利用した一連番号のセット生成にするなどの変更は可能ですね。

では、オリジナルのPostgreSQLの構文でARRAY_TO_STRINGとARRAY_AGGをSTRING_AGGに変更した例から(generate_seriesを階層再帰問合せにすることも可能)

PostgreSQL

WITH RECURSIVE
q (r, i, rx, ix, g) AS
(
SELECT
r::DOUBLE PRECISION * 0.02
, i::DOUBLE PRECISION * 0.02
, .0::DOUBLE PRECISION
, .0::DOUBLE PRECISION
, 0
FROM
generate_series(-60, 20) r
, generate_series(-50, 50) i
UNION ALL
SELECT
r
, i
, CASE
WHEN ABS(rx * rx + ix * ix) <= 2
THEN rx * rx - ix * ix
END + r
, CASE
WHEN ABS(rx * rx + ix * ix) <= 2
THEN 2 * rx * ix
END + i
, g + 1
FROM
q
WHERE
rx IS NOT NULL AND g < 99
)
SELECT
STRING_AGG(s, '' ORDER BY r) AS Mandelbrot
FROM
(
SELECT
i, r, SUBSTRING(' .:-=+*#%@', MAX(g) / 10 + 1, 1) s
FROM
q
GROUP BY i, r
) q
GROUP BY i
ORDER BY i;

Fractacle_postgresql


Oracle

では、上記、非互換の多いSQLをOracle向けに書き換えてみましょう。一連番号生成はOracleの方言である階層問合せにしてあります。あえてw
また、PostgreSQLのSTRING_AGG部分は、OracleのLISTAGGで代替しています。

WITH
q (r, i, rx, ix, g) AS
(
SELECT
CAST(r.r AS DOUBLE PRECISION) * 0.02 AS r
, CAST(i.i AS DOUBLE PRECISION) * 0.02 AS i
, CAST(.0 AS DOUBLE PRECISION) AS rx
, CAST(.0 AS DOUBLE PRECISION) AS ix
, 0 AS g
FROM
(
SELECT
LEVEL - 61 AS r
FROM
DUAL
CONNECT BY
LEVEL <= 80
) r,
(
SELECT
LEVEL - 51 AS i
FROM
DUAL
CONNECT BY
LEVEL <= 100
) i
UNION ALL
SELECT
r
, i
, CASE
WHEN ABS(rx * rx + ix * ix) <= 2
THEN
rx * rx - ix * ix
END + r AS rx
, CASE
WHEN ABS(rx * rx + ix * ix) <= 2
THEN
2 * rx * ix
END + i AS ix
, g + 1 AS g
FROM
q
WHERE
rx IS NOT NULL
AND g < 99
)
SELECT
LISTAGG(s,'') WITHIN GROUP ( ORDER BY r ) AS Mandelbrot
FROM
(
SELECT
i, r, SUBSTR(' .:-=+*#%@', MAX(g) / 10 + 1, 1) s
FROM
q
GROUP BY i, r
) q
GROUP BY i
ORDER BY i;

Fractacle_oracle

MySQL 8.0

さて、最後は、これまで一連番号生成が辛かったMySQLです。
MySQL 8.0から再帰問合せが利用できるようになったおかげてMySQLのSQLでもこんな遊びができるようになりました!!!!

すげーーーーーーーっ!


再帰問合せを駆使し、PostgreSQLのSTRING_AGG、OracleのLISTAGGの代替としてGROUP_CONCAT関数を利用しています。
部分文字列はSUBSTRINGですね。
そしてもう一つの非互換対応が TRUNCATE(MAX(g) / 10 + 1, 0) 部分です。
OracleとPostgreSQLは MAX(g) / 10 + 1 だけでも問題ないですが、MySQLでは MAX(g) / 10 + 1 の結果は整数にはなりません。
その対策としてTRUNCATEを追加しています。

なかなか痺れますね。これまで紹介してきた非互換対応の総まとめは大げさですが、それらを有効に組み合わせて書き換えてみました。

WITH RECURSIVE
q (r, i, rx, ix, g)
AS
(
SELECT
CAST(r.v AS DOUBLE PRECISION) * 0.02 AS r
, CAST(i.v AS DOUBLE PRECISION) * 0.02 AS i
, CAST(0.0 AS DOUBLE PRECISION) AS rx
, CAST(0.0 AS DOUBLE PRECISION) AS ix
, 0 AS g
FROM
(
WITH RECURSIVE gen_nums(v)
AS
(
SELECT -60
UNION ALL
SELECT v + 1
FROM
gen_nums
WHERE v + 1 < 20
)
SELECT v from gen_nums
) r
,(
WITH RECURSIVE gen_nums(v)
AS
(
SELECT -50
UNION ALL
SELECT v + 1
FROM
gen_nums
WHERE v + 1 < 50
)
SELECT v from gen_nums
) i
UNION ALL
SELECT
CAST(r AS DOUBLE PRECISION) AS r
, CAST(i AS DOUBLE PRECISION) AS i
, CAST(
CASE
WHEN ABS(rx * rx + ix * ix) <= 2
THEN rx * rx - ix * ix
END + r
AS DOUBLE PRECISION
) AS rx
, CAST(
CASE
WHEN ABS(rx * rx + ix * ix) <= 2
THEN 2 * rx * ix
END + i
AS DOUBLE PRECISION
) AS ix
, g + 1 AS g
FROM
q
WHERE
rx IS NOT NULL
AND g < 99
)
SELECT
GROUP_CONCAT(s,'' ORDER BY r SEPARATOR '') AS Mandelbrot
FROM
(
SELECT
i, r, SUBSTRING(' .:-=+*#%@', TRUNCATE(MAX(g) / 10 + 1, 0), 1) s
FROM
q
GROUP BY
i, r
) q
GROUP BY q.i
ORDER BY q.i;

Fractacle_mysql



ちなみに、Redshiftは再帰的なCTEは現時点では未サポートなので再帰問合せが必要なお遊びは今のところできません。

Amazon Redshift - サポートされていないPostgreSQL機能
https://docs.aws.amazon.com/ja_jp/redshift/latest/dg/c_unsupported-postgresql-features.html




さてさて、なんとか25個の窓を開けることができました。

今年は、コロナ禍の中、大変厳しい一年になりましたが、みなさま、お身体を大事に、そして、ご家族と過ごす時間を大切に。

メリークリスマス。(何年か前に作った Pipeline function で christmas treeのムービーで)




標準はあるにはあるが癖の多い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 乱数作るにも癖がある

| | コメント (0)

2020年12月24日 (木)

標準はあるにはあるが癖の多いSQL 全部俺 #24 乱数作るにも癖がある

標準はあるにはあるが癖の多いSQL 全部俺w Advent Calendar 2020の24日目です。

たまに、乱数が必要になることがあるのですが、その乱数生成にも癖があるんですよね。

簡単ですが今日はこれぐらいでw (ラストスパートで息切れ中w


いつものようにOracleから

131.4 DBMS_RANDOMサブプログラムの要約
131.4.7 VALUEファンクション
https://docs.oracle.com/cd/F19136_01/arpls/DBMS_RANDOM.html#GUID-AAD9E936-D74F-440D-9E16-24F3F0DE8D31

Oracleの場合は組み込み関数ではなく、パッケージ関数として提供されています。この点が大きな違いですよね。

ORACLE> SELECT (DBMS_RANDOM.VALUE(1,10)) FROM dual;

(DBMS_RANDOM.VALUE(1,10))
-------------------------
3.37937063

ORACLE> SELECT DBMS_RANDOM.VALUE FROM dual;

VALUE
----------
.853380477


PostgreSQL

表9.6 乱数関数
https://www.postgresql.jp/document/12/html/functions-math.html

postgres=> select random();
random
-------------------
0.774311667308211
(1 row)

MySQL

三者三様で皆関数名も違ったり、提供されている機能も差がありますね。

RAND([N])
https://dev.mysql.com/doc/refman/8.0/en/mathematical-functions.html#function_rand

mysql> select rand();
+--------------------+
| rand() |
+--------------------+
| 0.6516789492700984 |
+--------------------+
1 row in set (0.06 sec)



クリスマス、何食べようか考えているところで、年越しそば予約してないことに気づくw (なんとかなるさw






標準はあるにはあるが癖の多い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にも癖がある

| | コメント (0)

2020年12月23日 (水)

標準はあるにはあるが癖の多いSQL 全部俺 #23 複数行INSERTにも癖がある

標準はあるにはあるが癖の多いSQL 全部俺w Advent Calendar 2020の23日目です。

クリスマスイブイブですね。なんとかここまできたw

ネタ尽きた感がなくもないですが、ほぼ使っている方はいないのではないかという、複数行INSERTにも癖があるというお話

では、Oracleからみてください

Oracle

INESRT
https://docs.oracle.com/cd/F19136_01/sqlrf/INSERT.html#GUID-903F8043-0254-4EE9-ACC1-CB8AC0AF3423


この構文実は、マルチテーブルインサートの変形パターンで同一表へ複数インサートするようにしたもの。。。
そもそもこの構文が方言ではあるのですが、。。。。

ORACLE> desc a
Name Null? Type
----------------------------------------- -------- ----------------------------
ID NUMBER
STR VARCHAR2(100)

ORACLE> INSERT ALL
2 INTO a VALUES(2,'yama')
3 INTO a VALUES(3,'kawa')
4 INTO a VALUES(4,'umi')
5 SELECT * FROM dual;

PostgreSQL

PostgreSQLにはやはりない。そりゃ、Oracleの方言だからねw ですが、一応同一表なら可能です。

INSERT
https://www.postgresql.jp/document/12/html/sql-insert.html


同じく、MySQLも同一構文。。。。

postgres=> \d a
Table "bill.a"
Column | Type | Collation | Nullable | Default
--------+------------------------+-----------+----------+---------
id | integer | | |
str | character varying(100) | | |

postgres=>
postgres=> INSERT
postgres-> INTO a VALUES
postgres-> (2,'yama')
postgres-> ,(3,'kawa')
postgres-> ,(4,'umi');
INSERT 0 3

MySQL(8.0)

INSERT
https://dev.mysql.com/doc/refman/8.0/en/insert.html

mysql> desc a;
+-------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+--------------+------+-----+---------+-------+
| id | int | YES | | NULL | |
| str | varchar(100) | YES | | NULL | |
+-------+--------------+------+-----+---------+-------+
2 rows in set (0.02 sec)
mysql> INSERT
-> INTO a VALUES
-> (2,'yama')
-> ,(3,'kawa')
-> ,(4,'umi');
Query OK, 3 rows affected (0.07 sec)
Records: 3 Duplicates: 0 Warnings: 0



クリスマスイブのネタ何にしよう。本気で浮かばないw (最終日のネタはほぼできているのにw)






標準はあるにはあるが癖の多い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 集合演算にも癖がある

| | コメント (0)

2020年12月22日 (火)

標準はあるにはあるが癖の多いSQL 全部俺 #22 集合演算にも癖がある

標準はあるにはあるが癖の多いSQL 全部俺w Advent Calendar 2020の22日目です。

さて、残すところ、今日をいれてあと4回

なんとなくネタが1つ足りてない気がするがw なんとかするw

ということで、集合演算の癖を見てみましょう。Oracle 20cがリリースされていたら試せた機能もありますが、使える環境がないので、マニュアルだけ貼っておきます。

Oracle 20c - SQL set演算子の拡張 - union [all] / minus [all] / intersect [all] / except[all]
https://docs.oracle.com/cd/F32587_01/ftnew/enhanced-sql-set-operators1.html

19cまではこんな感じ

Oracle 19c - UNION [ALL]、INTERSECTおよびMINUS演算子
https://docs.oracle.com/cd/F19136_01/sqlrf/The-UNION-ALL-INTERSECT-MINUS-Operators.html#GUID-B64FE747-586E-4513-945F-80CB197125EE

MINUSはOracleの方言です。そのうちシノニム扱いされて、EXCEPTが一般的に利用されることになっていくのでしょうね。

Oracle

ORACLE> r
1 SELECT *
2 FROM
3 (
4 WITH gen_nums(v)
5 AS
6 (
7 SELECT 1
8 FROM
9 dual
10 UNION ALL
11 SELECT v + 1
12 FROM
13 gen_nums
14 WHERE v + 1 <= 10
15 )
16 SELECT v FROM gen_nums
17 )
18 UNION
19 SELECT *
20 FROM
21 (
22 WITH gen_nums(v)
23 AS
24 (
25 SELECT 5
26 FROM
27 dual
28 UNION ALL
29 SELECT v + 1
30 FROM
31 gen_nums
32 WHERE v + 1 <= 15
33 )
34 SELECT v FROM gen_nums
35 )
36* ORDER BY 1

V
----------
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

15 rows selected.

ORACLE> r
1 SELECT *
2 FROM
3 (
4 WITH gen_nums(v)
5 AS
6 (
7 SELECT 1
8 FROM
9 dual
10 UNION ALL
11 SELECT v + 1
12 FROM
13 gen_nums
14 WHERE v + 1 <= 10
15 )
16 SELECT v FROM gen_nums
17 )
18 UNION ALL
19 SELECT *
20 FROM
21 (
22 WITH gen_nums(v)
23 AS
24 (
25 SELECT 5
26 FROM
27 dual
28 UNION ALL
29 ELECT v + 1
30 FROM
31 gen_nums
32 WHERE v + 1 <= 15
33 )
34 SELECT v FROM gen_nums
35 )
36* ORDER BY 1

V
----------
1
2
3
4
5
5
6
6
7
7
8
8
9
9
10
10
11
12
13
14
15

21 rows selected.

ORACLE> r
1 SELECT *
2 FROM
3 (
4 WITH gen_nums(v)
5 AS
6 (
7 SELECT 1
8 FROM
9 dual
10 UNION ALL
11 SELECT v + 1
12 FROM
13 gen_nums
14 WHERE v + 1 <= 10
15 )
16 SELECT v FROM gen_nums
17 )
18 INTERSECT
19 SELECT *
20 FROM
21 (
22 WITH gen_nums(v)
23 AS
24 (
25 SELECT 5
26 FROM
27 dual
28 UNION ALL
29 SELECT v + 1
30 FROM
31 gen_nums
32 WHERE v + 1 <= 15
33 )
34 SELECT v FROM gen_nums
35 )
36* ORDER BY 1

V
----------
5
6
7
8
9
10

6 rows selected.

ORACLE> r
1 SELECT *
2 FROM
3 (
4 WITH gen_nums(v)
5 AS
6 (
7 SELECT 1
8 FROM
9 dual
10 UNION ALL
11 SELECT v + 1
12 FROM
13 gen_nums
14 WHERE v + 1 <= 10
15 )
16 SELECT v FROM gen_nums
17 )
18 MINUS
19 SELECT *
20 FROM
21 (
22 WITH gen_nums(v)
23 AS
24 (
25 SELECT 5
26 FROM
27 dual
28 UNION ALL
29 SELECT v + 1
30 FROM
31 gen_nums
32 WHERE v + 1 <= 15
33 )
34 SELECT v FROM gen_nums
35 )
36* ORDER BY 1

V
----------
1
2
3
4

PostgreSQL

union [all] / intersect[all] / except[all]
https://www.postgresql.jp/document/12/html/queries-union.html

これらの構文に関しては、PostgreSQLの方が一歩先でしたね:)

Oracle 20c以降ではこんなことができるようになるよ、というイメージをPostgreSQLで掴んでおくと良いかもしれないですねー

postgres=> SELECT *
postgres-> FROM
postgres-> (
postgres(> WITH RECURSIVE gen_nums(v)
postgres(> AS
postgres(> (
postgres(> SELECT 1
postgres(> UNION ALL
postgres(> SELECT v + 1
postgres(> FROM
postgres(> gen_nums
postgres(> WHERE v + 1 <= 10
postgres(> )
postgres(> SELECT v FROM gen_nums
postgres(> ) a
postgres-> UNION
postgres-> SELECT *
postgres-> FROM
postgres-> (
postgres(> WITH RECURSIVE gen_nums(v)
postgres(> AS
postgres(> (
postgres(> SELECT 5
postgres(> UNION ALL
postgres(> SELECT v + 1
postgres(> FROM
postgres(> gen_nums
postgres(> WHERE v + 1 <= 15
postgres(> )
postgres(> SELECT v FROM gen_nums
postgres(> ) b
postgres-> ORDER BY 1;
v
----
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
(15 rows)

postgres=> SELECT *
postgres-> FROM
postgres-> (
postgres(> WITH RECURSIVE gen_nums(v)
postgres(> AS
postgres(> (
postgres(> SELECT 1
postgres(> UNION ALL
postgres(> SELECT v + 1
postgres(> FROM
postgres(> gen_nums
postgres(> WHERE v + 1 <= 10
postgres(> )
postgres(> SELECT v FROM gen_nums
postgres(> ) a
postgres-> UNION ALL
postgres-> SELECT *
postgres-> FROM
postgres-> (
postgres(> WITH RECURSIVE gen_nums(v)
postgres(> AS
postgres(> (
postgres(> SELECT 5
postgres(> UNION ALL
postgres(> SELECT v + 1
postgres(> FROM
postgres(> gen_nums
postgres(> WHERE v + 1 <= 15
postgres(> )
postgres(> SELECT v FROM gen_nums
postgres(> ) b
postgres-> ORDER BY 1;
v
----
1
2
3
4
5
5
6
6
7
7
8
8
9
9
10
10
11
12
13
14
15
(21 rows)

postgres=> SELECT *
postgres-> FROM
postgres-> (
postgres(> WITH RECURSIVE gen_nums(v)
postgres(> AS
postgres(> (
postgres(> SELECT 1
postgres(> UNION ALL
postgres(> SELECT v + 1
postgres(> FROM
postgres(> gen_nums
postgres(> WHERE v + 1 <= 10
postgres(> )
postgres(> SELECT v FROM gen_nums
postgres(> ) a
postgres-> INTERSECT
postgres-> SELECT *
postgres-> FROM
postgres-> (
postgres(> WITH RECURSIVE gen_nums(v)
postgres(> AS
postgres(> (
postgres(> SELECT 5
postgres(> UNION ALL
postgres(> SELECT v + 1
postgres(> FROM
postgres(> gen_nums
postgres(> WHERE v + 1 <= 15
postgres(> )
postgres(> SELECT v FROM gen_nums
postgres(> ) b
postgres-> ORDER BY 1;
v
----
5
6
7
8
9
10
(6 rows)

postgres=> SELECT *
postgres-> FROM
postgres-> (
postgres(> WITH RECURSIVE gen_nums(v)
postgres(> AS
postgres(> (
postgres(> SELECT 1
postgres(> UNION ALL
postgres(> SELECT v + 1
postgres(> FROM
postgres(> gen_nums
postgres(> WHERE v + 1 <= 10
postgres(> )
postgres(> SELECT v FROM gen_nums
postgres(> ) a
postgres-> INTERSECT ALL
postgres-> SELECT *
postgres-> FROM
postgres-> (
postgres(> WITH RECURSIVE gen_nums(v)
postgres(> AS
postgres(> (
postgres(> SELECT 5
postgres(> UNION ALL
postgres(> SELECT v + 1
postgres(> FROM
postgres(> gen_nums
postgres(> WHERE v + 1 <= 15
postgres(> )
postgres(> SELECT v FROM gen_nums
postgres(> ) b
postgres-> ORDER BY 1;
v
----
5
6
7
8
9
10
(6 rows)

postgres=> SELECT *
postgres-> FROM
postgres-> (
postgres(> WITH RECURSIVE gen_nums(v)
postgres(> AS
postgres(> (
postgres(> SELECT 1
postgres(> UNION ALL
postgres(> SELECT v + 1
postgres(> FROM
postgres(> gen_nums
postgres(> WHERE v + 1 <= 10
postgres(> )
postgres(> SELECT v FROM gen_nums
postgres(> ) a
postgres-> EXCEPT
postgres-> SELECT *
postgres-> FROM
postgres-> (
postgres(> WITH RECURSIVE gen_nums(v)
postgres(> AS
postgres(> (
postgres(> SELECT 5
postgres(> UNION ALL
postgres(> SELECT v + 1
postgres(> FROM
postgres(> gen_nums
postgres(> WHERE v + 1 <= 15
postgres(> )
postgres(> SELECT v FROM gen_nums
postgres(> ) b
postgres-> ORDER BY 1;
v
---
1
2
3
4
(4 rows)

postgres=> SELECT *
postgres-> FROM
postgres-> (
postgres(> WITH RECURSIVE gen_nums(v)
postgres(> AS
postgres(> (
postgres(> SELECT 1
postgres(> UNION ALL
postgres(> SELECT v + 1
postgres(> FROM
postgres(> gen_nums
postgres(> WHERE v + 1 <= 10
postgres(> )
postgres(> SELECT v FROM gen_nums
postgres(> ) a
postgres-> EXCEPT ALL
postgres-> SELECT *
postgres-> FROM
postgres-> (
postgres(> WITH RECURSIVE gen_nums(v)
postgres(> AS
postgres(> (
postgres(> SELECT 5
postgres(> UNION ALL
postgres(> SELECT v + 1
postgres(> FROM
postgres(> gen_nums
postgres(> WHERE v + 1 <= 15
postgres(> )
postgres(> SELECT v FROM gen_nums
postgres(> ) b
postgres-> ORDER BY 1;
v
---
1
2
3
4
(4 rows)


MySQL (8.0)

union [all]

13.2.10.3 UNION Clause
https://dev.mysql.com/doc/refman/8.0/en/union.html

MySQLはこれらの部分では少々遅れてますね。実際同じ結果を得ようとすると工夫しないといけないです。
これまで実装されてこなかったということは、恐そのような用途で利用されることが少なかったということなのでしょうか。(想像でしかないけど。。なんとなく今後は実装されそうな方向に向かっているような雰囲気も感じつつ。)

mysql> SELECT *
-> FROM
-> (
-> WITH RECURSIVE gen_nums(v)
-> AS
-> (
-> SELECT 1
-> UNION ALL
-> SELECT v + 1
-> FROM
-> gen_nums
-> WHERE v + 1 <= 10
-> )
-> SELECT v FROM gen_nums
-> ) a
-> UNION
-> SELECT *
-> FROM
-> (
-> WITH RECURSIVE gen_nums(v)
-> AS
-> (
-> SELECT 5
-> UNION ALL
-> SELECT v + 1
-> FROM
-> gen_nums
-> WHERE v + 1 <= 15
-> )
-> SELECT v FROM gen_nums
-> ) b
-> ORDER BY 1;
+------+
| v |
+------+
| 1 |
| 2 |
| 3 |
| 4 |
| 5 |
| 6 |
| 7 |
| 8 |
| 9 |
| 10 |
| 11 |
| 12 |
| 13 |
| 14 |
| 15 |
+------+
15 rows in set (0.02 sec)

mysql> SELECT *
-> FROM
-> (
-> WITH RECURSIVE gen_nums(v)
-> AS
-> (
-> SELECT 1
-> UNION ALL
-> SELECT v + 1
-> FROM
-> gen_nums
-> WHERE v + 1 <= 10
-> )
-> SELECT v FROM gen_nums
-> ) a
-> UNION ALL
-> SELECT *
-> FROM
-> (
-> WITH RECURSIVE gen_nums(v)
-> AS
-> (
-> SELECT 5
-> UNION ALL
-> SELECT v + 1
-> FROM
-> gen_nums
-> WHERE v + 1 <= 15
-> )
-> SELECT v FROM gen_nums
-> ) b

-> ORDER BY 1;
+------+
| v |
+------+
| 1 |
| 2 |
| 3 |
| 4 |
| 5 |
| 5 |
| 6 |
| 6 |
| 7 |
| 7 |
| 8 |
| 8 |
| 9 |
| 9 |
| 10 |
| 10 |
| 11 |
| 12 |
| 13 |
| 14 |
| 15 |
+------+
21 rows in set (0.02 sec)



来年は全部俺、どうするかな。ネタの一気放出みたいな時間取りやすければいいんだけど。先週までは本気で辛かった。時間ギリギリでw






標準はあるにはあるが癖の多い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 演算結果にも癖がある

| | コメント (0)

2020年12月21日 (月)

標準はあるにはあるが癖の多いSQL 全部俺 #21 演算結果にも癖がある

標準はあるにはあるが癖の多いSQL 全部俺w Advent Calendar 2020の21日目です。

以前取り上げた内容にも近いですが、演算だけに着目した方がわかりやすいだろうということでネタにしてみました。

SQLを移植する場合は、このようなところでも注意しないと。。。ね。デフォルトの挙動に任せたままでは危険ですね

Oracle

ORACLE> SELECT 1 / 3 FROM dual;

1/3
----------
.333333333

ORACLE> SELECT 1 / 3 * 3 FROM dual;

1/3*3
----------
1

ORACLE> SELECT (1 / 3) * 3 FROM dual;

(1/3)*3
----------
1

ORACLE> SELECT CAST(1 AS DOUBLE PRECISION) / CAST(3 AS DOUBLE PRECISION) * CAST(3 AS DOUBLE PRECISION) FROM dual;

CAST(1ASDOUBLEPRECISION)/CAST(3ASDOUBLEPRECISION)*CAST(3ASDOUBLEPRECISION)
--------------------------------------------------------------------------
1

ORACLE> SELECT DUMP(CAST(1 AS DOUBLE PRECISION) / CAST(3 AS DOUBLE PRECISION)) FROM dual;

DUMP(CAST(1ASDOUBLEPRECISION)/CAST(3ASDOUBLEPRECISION))
--------------------------------------------------------------------------------
Typ=2 Len=21: 192,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34

ORACLE> SELECT DUMP(CAST(1 AS DOUBLE PRECISION) / CAST(3 AS DOUBLE PRECISION) * CAST(3 AS DOUBLE PRECISION)) FROM dual;

DUMP(CAST(1ASDOUBLEPRECISION)/CAST(3ASDOUBLEPRECISION)*CAST(3ASDOUBLEPRECISION))
--------------------------------------------------------------------------------
Typ=2 Len=21: 192,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,10
0,100,100,100,100


MySQL

Oracleに近いですが、若干差異がありますね。

mysql> SELECT 1 / 3;
+--------+
| 1 / 3 |
+--------+
| 0.3333 |
+--------+
1 row in set (0.02 sec)

mysql> SELECT 1 / 3 * 3;
+-----------+
| 1 / 3 * 3 |
+-----------+
| 1.0000 |
+-----------+
1 row in set (0.02 sec)

mysql> SELECT CAST(1 AS DOUBLE PRECISION) / 3 * 3;
+---------------------------+
| cast(1 as double) / 3 * 3 |
+---------------------------+
| 1 |
+---------------------------+
1 row in set (0.26 sec)

mysql> SELECT CAST(1 AS DOUBLE) / CAST(3 AS DOUBLE) * 3;
+-------------------------------------------+
| cast(1 as double) / cast(3 as double) * 3 |
+-------------------------------------------+
| 1 |
+-------------------------------------------+
1 row in set (0.02 sec)

mysql> SELECT CAST(1 AS DOUBLE) / CAST(3 AS DOUBLE) * CAST(3 AS DOUBLE);
+-----------------------------------------------------------+
| cast(1 as double) / cast(3 as double) * cast(3 as double) |
+-----------------------------------------------------------+
| 1 |
+-----------------------------------------------------------+
1 row in set (0.01 sec)

PostgreSQL

PostgreSQLはデフォルトの挙動が明らかに異なります。

postgres=> SELECT 1 / 3;
?column?
----------
0
(1 row)

postgres=> SELECT 1 / 3 * 3;
?column?
----------
0
(1 row)

postgres=> SELECT 1::DOUBLE PRECISION / 3::DOUBLE PRECISION * 3::DOUBLE PRECISION;
?column?
----------
1
(1 row)

postgres=> SELECT PG_TYPEOF(1::DOUBLE PRECISION / 3::DOUBLE PRECISION * 3::DOUBLE PRECISION);
pg_typeof
------------------
double precision
(1 row)

postgres=> SELECT PG_TYPEOF(1 / 3 * 3);
pg_typeof
-----------
integer
(1 row)




あと少し :)





標準はあるにはあるが癖の多い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 結果セットを単一列に連結するにも癖がある

| | コメント (0)

2020年12月20日 (日)

標準はあるにはあるが癖の多いSQL 全部俺 #20 結果セットを単一列に連結するにも癖がある

標準はあるにはあるが癖の多いSQL 全部俺w Advent Calendar 2020の20日目です。

また、本記事はJPOUG Advent Calendar 2020の20日目の窓へクロスポストしています。
JPOUG Advent Calendar 2020の19日目はNaotaka ShinogiさんのNutanix Eraで描くDatabase管理とOracleSEのデータ同期でした。

さて、今日は、最終日のネタ作りの途中でどうしても、非互換なところと格闘しないといけないので、その部分の対応をかねてw

今回は、結果セット(複数行)を単一列に連結する集約関数 Oracleでは LISTAGG()という関数の非互換です。
同様の関数はあるものの関数名は違うし多少引数も違うのでぱっと見、どう書き換えるかってなると迷うわけです。知ってれば別ですけども。

では、早速みてみましょう。

Oracle

LISTAGG

LISTAGG( [ ALL ] [ DISTINCT ] measure_expr [, 'delimiter'] [listagg_overflow_clause] ) [ WITHIN GROUP ] (order_by_clause) [OVER query_partition_clause]
https://docs.oracle.com/cd/F19136_01/sqlrf/LISTAGG.html#GUID-B6E50D8E-F467-425B-9436-F7F8BF38D466

使ったことがある方なら、ああ、アレかと思い出せると思います。あまり使う機会はないので私もマニュアル見て思出すことが多いですね。この関数w

ORACLE>
*1 SELECT * FROM list;

ID STR
---------- -------------
1 foo
1 bar
1 tiger
1 scott
2 bill
2 steve

ORACLE> r
1 SELECT
2 id
3 , LISTAGG(str, ',')
4 WITHIN GROUP
5 (
6 ORDER BY str
7 )
8 AS lists
9 FROM
10 list
11 GROUP BY id
12* ORDER BY id

ID LISTS
---------- ----------------------------------------
1 bar,foo,scott,tiger
2 bill,steve

次は、MySQL(8.0)

MySQLでは GROUP_CONCAT()関数が該当します。使い方は似ていますが、セパレータの指定方法に特徴がありますね。

GROUP_CONCAT(expr)
https://dev.mysql.com/doc/refman/8.0/en/aggregate-functions.html#function_group-concat

GROUP_CONCAT([DISTINCT] expr [,expr ...]
[ORDER BY {unsigned_integer | col_name | expr}
[ASC | DESC] [,col_name ...]]
[SEPARATOR str_val])

mysql> SELECT
-> id
-> , GROUP_CONCAT(
-> str
-> ORDER BY str
-> SEPARATOR ','
-> )
-> AS lists
-> FROM
-> list
-> GROUP BY id
-> ORDER BY id;
+------+---------------------+
| id | lists |
+------+---------------------+
| 1 | bar,foo,scott,tiger |
| 2 | bill,steve |
+------+---------------------+
2 rows in set (0.03 sec)

PostgreSQL

PostgreSQLには類似する機能を持つ関数が複数ありますが、LISTAGG()と同じ結果を得る場合には、array_agg+array_to_string関数の組み合わせか、LISTAGGに近いSTRING_AGG()関数を単独で利用します。

array_agg(expression)
string_agg(expression, delimiter)
https://www.postgresql.jp/document/12/html/functions-aggregate.html

array_to_string(anyarray, text [, text])
https://www.postgresql.jp/document/12/html/functions-array.html

postgres=> SELECT
postgres-> id
postgres-> , STRING_AGG(
postgres(> str, ','
postgres(> ORDER BY str
postgres(> )
postgres-> AS lists
postgres-> FROM
postgres-> list
postgres-> GROUP BY id
postgres-> ORDER BY id;
id | lists
----+---------------------
1 | bar,foo,scott,tiger
2 | bill,steve
postgres=> SELECT
postgres-> id
postgres-> , ARRAY_TO_STRING(
postgres(> ARRAY_AGG(str ORDER BY str)
postgres(> , ','
postgres(> )
postgres-> AS lists
postgres-> FROM
postgres-> list
postgres-> GROUP BY id
postgres-> ORDER BY id;
id | lists
----+---------------------
1 | bar,foo,scott,tiger
2 | bill,steve




最終日のエントリーはこの集約関数やSUBSTR()など、標準はあるにはあるが癖の多いSQL 全部俺w Advent Calendar 2020で紹介した複数のSQL構文や関数を利用したネタを予定しています。(ネタが厳しくなったら早めに公開するかもしれませんが)


明日の12月21日のJPOUG Advent Calendar 2020Yohei Azekatsu さんです。何か、やらかして。。。いや、何か、やってくれることでしょうw よろしくおねがいします!






標準はあるにはあるが癖の多い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

| | コメント (0)

2020年12月19日 (土)

標準はあるにはあるが癖の多いSQL 全部俺 #19 帰ってきた、部分文字列の扱いでも癖w

標準はあるにはあるが癖の多いSQL 全部俺w Advent Calendar 2020の19日目です。

標準はあるにはあるが癖の多いSQL 全部俺 #9 部分文字列の扱いでも癖が出る><
で、すっかり忘れてた。非互換ではその手のが多いw

部分文字列の扱いの癖、盲点というかなんというか、小数の扱いの違いを忘れてましたw

Oracle

Positionが大きい場合の挙動では Oracle以外は空文字を返します。これも非互換は非互換ですが。

注目してもらいたいのは、整数じゃないとき。Oracleは、小数点以下切り捨てで動きます。

ORACLE> set tab off
ORACLE> set null [NULL]
ORACLE> col str for a30

ORACLE> SELECT SUBSTR('1234567890', 10, 1) AS str FROM dual;

STR
------------------------------
0

ORACLE> SELECT SUBSTR('1234567890', 11, 1) AS str FROM dual;

STR
------------------------------
[NULL]

ORACLE> SELECT SUBSTR('1234567890',10.4, 1) AS str FROM dual;

STR
------------------------------
0

ORACLE> SELECT SUBSTR('1234567890',10.5, 1) AS str FROM dual;

STR
------------------------------
0

ORACLE> SELECT SUBSTR('1234567890',10.9, 1) AS str FROM dual;

STR
------------------------------
0


MySQL (8.0)

Positionが範囲外であれば空文字を返すのは冒頭で説明した通りですが、Oracleと明らかに違うのは、小数点以下は四捨五入
整数以外も受け付けてくれますが、デフォルトの挙動で、切り捨てか、四捨五入という違いにより取り出される結果に差異が出ます。ハマりますよね。これw



mysql> SELECT SUBSTRING('1234567890', 10, 1) AS str;
+-----+
| str |
+-----+
| 0 |
+-----+
1 row in set (0.01 sec)

mysql> SELECT SUBSTRING('1234567890', 11, 1) AS str;
+-----+
| str |
+-----+
| |
+-----+
1 row in set (0.02 sec)

mysql> SELECT SUBSTRING('1234567890', 10.4, 1) AS str;
+-----+
| str |
+-----+
| 0 |
+-----+
1 row in set (0.02 sec)

mysql> SELECT SUBSTRING('1234567890', 10.5, 1) AS str;
+-----+
| str |
+-----+
| |
+-----+
1 row in set (0.06 sec)

mysql> SELECT SUBSTRING('1234567890', 10.9, 1) AS str;
+-----+
| str |
+-----+
| |
+-----+
1 row in set (0.02 sec)

mysql> SELECT SUBSTRING('1234567890', 1.4, 1) AS str;
+-----+
| str |
+-----+
| 1 |
+-----+
1 row in set (0.01 sec)

mysql> SELECT SUBSTRING('1234567890', 1.5, 1) AS str;
+-----+
| str |
+-----+
| 2 |
+-----+
1 row in set (0.02 sec)

mysql> SELECT CONCAT(CONCAT('''',SUBSTRING('1234567890', 10.9, 1)),'''') AS str;
+-----+
| str |
+-----+
| '' |
+-----+
1 row in set (0.02 sec)


PostgreSQL

こちらPostgreSQLは単純、Positionに指定できるのは整数のみです。ある意味わかりやすいですw 文字列の位置が 1.9とかなかなかですからね。

postgres=> SELECT SUBSTRING('1234567890', 10, 1) AS str;
str
-----
0
(1 row)

postgres=> SELECT SUBSTRING('1234567890', 11, 1) AS str;
str
-----

(1 row)

postgres=> SELECT CONCAT(CONCAT('''',SUBSTRING('1234567890', 11, 1)),'''') AS str;
str
-----
''
(1 row)

postgres=> SELECT SUBSTRING('1234567890', 10.4, 1) AS str;
ERROR: function pg_catalog.substring(unknown, numeric, integer) does not exist
LINE 1: SELECT SUBSTRING('1234567890', 10.4, 1) AS str;


おまけ

Redshift

PostgreSQLの血筋のはずですが、少数はエラーにもならず、そんなのねーよ。的な空文字が帰ってきます。なかなか男前です。素直に考えれば、1.9のところって文字の途中な訳で。。。

これもなかなか気づかいないです。エラーにはならないタイプなので、結果をみて???? としばらく悩むタイプですね。非互換としては事前に判断が難しいタイプ。リテラルで少数指定されていれば気づきやすいですが、バインド変数だったりすると気づくのは、かなり辛いです。

redshift=# SELECT SUBSTRING('1234567890', 10, 1) AS str;
str
-----
0
(1 row)

redshift=# SELECT SUBSTRING('1234567890', 11, 1) AS str;
str
-----

(1 row)

redshift=# SELECT SUBSTRING('1234567890', 10.4, 1) AS str;
str
-----

(1 row)

redshift=# SELECT SUBSTRING('1234567890', 10.5, 1) AS str;
str
-----

(1 row)

redshift=# SELECT SUBSTRING('1234567890', 10.9, 1) AS str;
str
-----

(1 row)

redshift=# SELECT SUBSTRING('1234567890', 1.4, 1) AS str;
str
-----

(1 row)

redshift=# SELECT SUBSTRING('1234567890', 1.5, 1) AS str;
str
-----

(1 row)

redshift=# SELECT CONCAT(CONCAT('''',SUBSTRING('1234567890', 10.9, 1)),'''') AS str;
str
-----
''
(1 row)


hr>
さあ、カウントダウンだw (^^;;;;;





標準はあるにはあるが癖の多い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 (+)の外部結合は方言

| | コメント (0)

2020年12月18日 (金)

標準はあるにはあるが癖の多いSQL 全部俺 #18 (+)の外部結合は方言

標準はあるにはあるが癖の多いSQL 全部俺w Advent Calendar 2020の18日目です。

今日はこまけーことに気づいてしまい、ブログ忘れそうだったw

ということで、2時間を切ったところで書いてますw

今日は、(+)を使った外部結合はOracle以外で通るのか(まあ、通らないですけどねー、Oracleの方言なのでw

と言った結合関連ネタを軽めで m(_ _)m

Oracle

(+)を使ったOracleの外部結合は、方言として有名ですよね。私は随分前から使わなくなってしまったので、今日は久々なにタイプした気がしますw
ANSI構文より(+)をオススメされる時があることはあるのですが、大抵の場合、実行計画がイケてるない時の対策としてだったりします。最近のは調べてないですが、。。。時間があったらネタにしてみたいと思います。。。w

ORACLE> SELECT *
2 FROM
3 m, d
4 WHERE
5 m.id = d.id(+);

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


ORACLE> SELECT *
2 FROM
3 m
4 LEFT OUTER JOIN d
5 ON m.id = d.id;

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

ORACLE> SELECT *
2 FROM
3 m, d;

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

ORACLE> SELECT *
2 FROM
3 m
4 CROSS JOIN d;

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

ORACLE> SELECT *
2 FROM
3 m, d
4 WHERE
5 m.id = d.id;

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

ORACLE> SELECT *
2 FROM
3 m
4 INNER JOIN d
5 ON m.id = d.id;

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


PostgreSQL

お次はPostgreSQL、通りませんよね!

postgres=> SELECT *
postgres-> FROM
postgres-> m
postgres-> LEFT OUTER JOIN d
postgres-> ON m.id = d.id;
id | id | subid
----+----+-------
1 | 1 | 1
2 | 2 | 1
3 | |
(3 rows)

postgres=> SELECT *
postgres-> FROM
postgres-> m, d
postgres-> WHERE
postgres-> m.id = d.id(+);
ERROR: syntax error at or near ")"
LINE 5: m.id = d.id(+);
^
postgres=> SELECT *
postgres-> FROM
postgres-> m, d;
id | id | subid
----+----+-------
1 | 1 | 1
1 | 2 | 1
2 | 1 | 1
2 | 2 | 1
3 | 1 | 1
3 | 2 | 1
(6 rows)

postgres=> SELECT *
postgres-> FROM
postgres-> m
postgres-> CROSS JOIN d;
id | id | subid
----+----+-------
1 | 1 | 1
1 | 2 | 1
2 | 1 | 1
2 | 2 | 1
3 | 1 | 1
3 | 2 | 1
(6 rows)

postgres=> SELECT *
postgres-> FROM
postgres-> m, d
postgres-> WHERE
postgres-> m.id = d.id;
id | id | subid
----+----+-------
1 | 1 | 1
2 | 2 | 1
(2 rows)

postgres=> SELECT *
postgres-> FROM
postgres-> m
postgres-> INNER JOIN d
postgres-> ON m.id = d.id;
id | id | subid
----+----+-------
1 | 1 | 1
2 | 2 | 1
(2 rows)


MySQL (8.0)

それは、MySQLでも同じ。。。で(+)はエラーですよねー

mysql> SELECT *
-> FROM
-> m
-> LEFT OUTER JOIN d
-> ON m.id = d.id;
+------+------+-------+
| id | id | subid |
+------+------+-------+
| 1 | 1 | 1 |
| 2 | 2 | 1 |
| 3 | NULL | NULL |
+------+------+-------+
3 rows in set (0.07 sec)

mysql> SELECT *
-> FROM
-> m, d
-> WHERE
-> m.id = d.id(+);
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 ')' at line 5


mysql> SELECT *
-> FROM
-> m, d;
+------+------+-------+
| id | id | subid |
+------+------+-------+
| 1 | 2 | 1 |
| 1 | 1 | 1 |
| 2 | 2 | 1 |
| 2 | 1 | 1 |
| 3 | 2 | 1 |
| 3 | 1 | 1 |
+------+------+-------+
6 rows in set (0.06 sec)

mysql> SELECT *
-> FROM
-> m
-> CROSS JOIN d;
+------+------+-------+
| id | id | subid |
+------+------+-------+
| 1 | 2 | 1 |
| 1 | 1 | 1 |
| 2 | 2 | 1 |
| 2 | 1 | 1 |
| 3 | 2 | 1 |
| 3 | 1 | 1 |
+------+------+-------+
6 rows in set (0.04 sec)

mysql> SELECT *
-> FROM
-> m, d
-> WHERE
-> m.id = d.id;
+------+------+-------+
| id | id | subid |
+------+------+-------+
| 1 | 1 | 1 |
| 2 | 2 | 1 |
+------+------+-------+
2 rows in set (0.05 sec)

mysql>
mysql> SELECT *
-> FROM
-> m
-> INNER JOIN d
-> ON m.id = d.id;
+------+------+-------+
| id | id | subid |
+------+------+-------+
| 1 | 1 | 1 |
| 2 | 2 | 1 |
+------+------+-------+
2 rows in set (0.03 sec)


Redshift

Redshiftでは〜、通じるんですよね。 (+) の外部結合

WHERE 句の Oracle スタイルの外部結合
https://docs.aws.amazon.com/ja_jp/redshift/latest/dg/r_WHERE_oracle_outer.html



ギリギリ 18個目の窓を開けたw (^^;;;;;





標準はあるにはあるが癖の多い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 その空白は許されないのか?

| | コメント (0)

2020年12月17日 (木)

標準はあるにはあるが癖の多いSQL 全部俺 #17 その空白は許されないのか?

標準はあるにはあるが癖の多いSQL 全部俺w Advent Calendar 2020の17日目です。

もう少しだ頑張れ、自分w

ということで、今日は、そうなの? みたいな違いをみてみます。
関数と()の間に空白が入るとどうなるか。。。

では、いつもの通り Oracle から初めて、PostgreSQL , MySQLの順に見てみます。

Oracle

まあ、普通ですよね

ORACLE> SELECT COUNT(1) FROM dual;

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

ORACLE> SELECT COUNT( 1 ) FROM dual;

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

ORACLE> SELECT COUNT (1) FROM dual;

COUNT(1)
----------
1
¥
ORACLE> SELECT COUNT ( 1 ) FROM dual;

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

PostgreSQL (Redshiftも同じ)

これもなんとことはない。。。

postgres=> SELECT COUNT(1);
count
-------
1
(1 row)

postgres=> SELECT COUNT( 1 );
count
-------
1
(1 row)

postgres=> SELECT COUNT (1);
count
-------
1
(1 row)

postgres=> SELECT COUNT ( 1 );
count
-------
1
(1 row)


MySQL (8.0)

おおおおおー。これは!

mysql> SELECT COUNT(1);
+----------+
| count(1) |
+----------+
| 1 |
+----------+
1 row in set (0.02 sec)
¥
mysql> SELECT COUNT( 1 );
+------------+
| count( 1 ) |
+------------+
| 1 |
+------------+
1 row in set (0.03 sec)

mysql> SELECT COUNT (1);
ERROR 1046 (3D000): No database selected

mysql> SELECT COUNT ( 1 );
ERROR 1046 (3D000): No database selected

ところが、sql_modeをANSIにすると。。。。。

ここ知らないと??ってなりますよね。関数と()の間にスペース入れるかどうかって、私はスペースなし派ですが、流派によってはありそうな。。。知らんけど。

5.1.11 Server SQL Modes
https://dev.mysql.com/doc/refman/8.0/en/sql-mode.html

MySQLに絵文字を保存しようとしたら文字列が消える問題
http://soudai1025.blogspot.com/2016/03/"

mysql> set sql_mode = 'ANSI';
Query OK, 0 rows affected (0.06 sec)

mysql> SELECT COUNT(1);
+----------+
| count(1) |
+----------+
| 1 |
+----------+
1 row in set (0.05 sec)

mysql> SELECT COUNT( 1 );
+------------+
| count( 1 ) |
+------------+
| 1 |
+------------+
1 row in set (0.01 sec)

mysql> SELECT COUNT (1);
+-----------+
| count (1) |
+-----------+
| 1 |
+-----------+
1 row in set (0.06 sec)

mysql> SELECT COUNT ( 1 );
+-------------+
| count ( 1 ) |
+-------------+
| 1 |
+-------------+
1 row in set (0.04 sec)



眠いw





標準はあるにはあるが癖の多い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のレントゲンを撮る方法

| | コメント (0)

2020年12月16日 (水)

標準はあるにはあるが癖の多いSQL 全部俺 #16 SQLのレントゲンを撮る方法

標準はあるにはあるが癖の多いSQL 全部俺w Advent Calendar 2020の16日目です。

さて、別の関数ネタをやろうと思うと予定外の打ち合わせが多く、今日も癖の多いSQLネタのはずが、その癖の多いSQLのレントゲン(実行計画)の撮り方の違いをネタにしてみました。m(_ _)m

大きな進化を遂げたのはいうまでも無く、MySQLですね。8.0になって大幅に機能格納した感があります。チューニングもしやすくなることでしょうね:)

こうやって、CTEの再帰問合せの実行計画見ながらハードリカー飲むのもいいものですw

まず、Oracleの実行計画確認方法はEEオプション含め3つ。SQL*Plusのauto trace以外はActual Planが確認できます。一手間かかりますが。

8 SQL*Plusのチューニング
https://docs.oracle.com/cd/F19136_01/sqpug/tuning-SQL-Plus.html#GUID-233D9103-017C-4832-B5E1-E38D32F9B00D

Oracle その1 / auto trace : SQL*Plusの機能で、オプションなしで利用できますが Actual Plan は見ることができません>< 実行統計は見れるのですけども

ORACLE> set tab off
ORACLE> set linesize 300
ORACLE> set autot trace exp
ORACLE> r
1 WITH gen_nums(v)
2 AS
3 (
4 SELECT 1
5 FROM
6 dual
7 UNION ALL
8 SELECT v + 1
9 FROM
10 gen_nums
11 WHERE v + 1 <= 10
12 )
13 SELECT v from gen_nums
14*

Execution Plan
----------------------------------------------------------
Plan hash value: 1492144221

--------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 2 | 26 | 4 (0)| 00:00:01 |
| 1 | VIEW | | 2 | 26 | 4 (0)| 00:00:01 |
| 2 | UNION ALL (RECURSIVE WITH) BREADTH FIRST| | | | | |
| 3 | FAST DUAL | | 1 | | 2 (0)| 00:00:01 |
|* 4 | RECURSIVE WITH PUMP | | | | | |
--------------------------------------------------------------------------------------------------

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

4 - filter("V"+1<=10)


Oracleその2 / DBMS_XPLAN.DISPLAY_CURSOR()を利用したActual Plan取得(これはSEでも使えるオプション不要の機能

DBMS_XPLAN.DISPLAY_CURSOR
https://docs.oracle.com/cd/F19136_01/tgsql/generating-and-displaying-execution-plans.html#GUID-83F88700-3902-4D19-8182-AF2B92AEA7EB

ORACLE> r
1 WITH gen_nums(v)
2 AS
3 (
4 SELECT /*+ GATHER_PLAN_STATISTICS */ 1
5 FROM
6 dual
7 UNION ALL
8 SELECT v + 1
9 FROM
10 gen_nums
11 WHERE v + 1 <= 10
12 )
13* SELECT v from gen_nums
1
2
3
4
5
6
7
8
9
10

10 rows selected.

ORACLE> SELECT * FROM TABLE(DBMS_XPLAN.display_cursor(format=>'ALLSTATS LAST'));
SQL_ID a8yzv4a008jvr, child number 0
-------------------------------------
WITH gen_nums(v) AS ( SELECT /*+ GATHER_PLAN_STATISTICS */ 1 FROM
dual UNION ALL SELECT v + 1 FROM gen_nums WHERE v + 1 <= 10 )
SELECT v from gen_nums

Plan hash value: 1492144221

--------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time |
--------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 10 |00:00:00.01 |
| 1 | VIEW | | 1 | 2 | 10 |00:00:00.01 |
| 2 | UNION ALL (RECURSIVE WITH) BREADTH FIRST| | 1 | | 10 |00:00:00.01 |
| 3 | FAST DUAL | | 1 | 1 | 1 |00:00:00.01 |
| 4 | RECURSIVE WITH PUMP | | 10 | | 9 |00:00:00.01 |
--------------------------------------------------------------------------------------------------


Oracle その3 / Real Time SQL Monitor (EEオプション)

21 データベース操作の監視
https://docs.oracle.com/cd/F19136_01/tgsql/monitoring-database-operations.html#GUID-C941CE9D-97E1-42F8-91ED-4949B2B710BF

ORACLE> set pages 0
ORACLE> set linesize 1000
ORACLE> set long 1000000
ORACLE> set longchunksize 1000000
r
1 WITH gen_nums(v)
2 AS
3 (
4 SELECT /*+ MONITOR */ 1
5 FROM
6 dual
7 UNION ALL
8 SELECT v + 1
9 FROM
10 gen_nums
11 WHERE v + 1 <= 10
12 )
13* SELECT v from gen_nums
1
2
3
4
5
6
7
8
9
10

10 rows selected.

ORACLE> select dbms_sqltune.report_sql_monitor(type=>'text') from dual;
SQL Monitoring Report

SQL Text
------------------------------
WITH gen_nums(v) AS ( SELECT /*+ MONITOR */ 1 FROM dual
UNION ALL SELECT v + 1 FROM gen_nums WHERE v + 1 <= 10 ) SELECT v from gen_nums

Global Information
------------------------------
Status : DONE (ALL ROWS)
Instance ID : 1
Session : SCOTT (25:48803)
SQL ID : 9g75y7v030mbt
SQL Execution ID : 16777216
Execution Started : 12/15/2020 15:58:45
First Refresh Time : 12/15/2020 15:58:45
Last Refresh Time : 12/15/2020 15:58:45
Duration : .000232s
Module/Action : SQL*Plus/-
Service : orcl
Program : sqlplus@localhost.localdomain (TNS V1-V3)
Fetch Calls : 2

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

SQL Plan Monitoring Details (Plan Hash Value=1492144221)
=================================================================================================================================================
| Id | Operation | Name | Rows | Cost | Time | Start | Execs | Rows | Activity | Activity Detail |
| | | | (Estim) | | Active(s) | Active | | (Actual) | (%) | (# samples) |
=================================================================================================================================================
| 0 | SELECT STATEMENT | | | | 1 | +0 | 1 | 10 | | |
| 1 | VIEW | | 2 | 4 | 1 | +0 | 1 | 10 | | |
| 2 | UNION ALL (RECURSIVE WITH) BREADTH FIRST | | | | 1 | +0 | 1 | 10 | | |
| 3 | FAST DUAL | | 1 | 2 | 1 | +0 | 1 | 1 | | |
| 4 | RECURSIVE WITH PUMP | | | | 1 | +0 | 10 | 9 | | |
=================================================================================================================================================

MySQL

なんと、MySQL8.0から実行計画みやすいし、Actualまで出るじゃないですかーーーーーーー〜。


8.8.2 EXPLAIN Output Format
https://dev.mysql.com/doc/refman/8.0/en/explain-output.html

mysql> explain analyze WITH RECURSIVE gen_nums(v)
-> AS
-> (
-> SELECT 1
-> UNION ALL
-> SELECT v + 1
-> FROM
-> gen_nums
-> WHERE v + 1 <= 10
-> )
-> SELECT v from gen_nums;
+----------------------------------------------------------------------------------------------------------------+
| EXPLAIN |
+----------------------------------------------------------------------------------------------------------------+
| -> Table scan on gen_nums (actual time=0.000..0.001 rows=10 loops=1)
-> Materialize recursive CTE gen_nums (actual time=0.019..0.020 rows=10 loops=1)
-> Rows fetched before execution (actual time=0.000..0.000 rows=1 loops=1)
-> Repeat until convergence
-> Filter: ((gen_nums.v + 1) <= 10) (cost=2.73 rows=2) (actual time=0.002..0.003 rows=4 loops=2)
-> Scan new records on gen_nums (cost=2.73 rows=2) (actual time=0.001..0.001 rows=5 loops=2)
|
+----------------------------------------------------------------------------------------------------------------+
1 row in set (0.06 sec)

PostgreSQL

そういえば、なんと無くMySQLの実行計画の見え方とPostgreSQLのは似てる気がします:)

14.1. EXPLAINの利用
https://www.postgresql.jp/document/12/html/using-explain.html

postgresql=> explain (analyze, buffers, verbose) WITH RECURSIVE gen_nums(v)
AS
(
SELECT 1
UNION ALL
SELECT v + 1
FROM
gen_nums
WHERE v + 1 <= 10
)
SELECT v from gen_nums;
QUERY PLAN
----------------------------------------------------------------------------------------------------------------------------------
CTE Scan on gen_nums (cost=3.21..3.83 rows=31 width=4) (actual time=0.004..0.016 rows=10 loops=1)
Output: gen_nums.v
CTE gen_nums
-> Recursive Union (cost=0.00..3.21 rows=31 width=4) (actual time=0.003..0.013 rows=10 loops=1)
-> Result (cost=0.00..0.01 rows=1 width=4) (actual time=0.001..0.002 rows=1 loops=1)
Output: 1
-> WorkTable Scan on gen_nums gen_nums_1 (cost=0.00..0.26 rows=3 width=4) (actual time=0.001..0.001 rows=1 loops=10)
Output: (gen_nums_1.v + 1)
Filter: ((gen_nums_1.v + 1) <= 10)
Rows Removed by Filter: 0
Planning Time: 0.055 ms
Execution Time: 0.039 ms
(12 rows)



さて、rebootしますよ。何かを。という話はもう少しあとでw






標準はあるにはあるが癖の多い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

| | コメント (0)

2020年12月15日 (火)

標準はあるにはあるが癖の多いSQL 全部俺 #15 SQL command line client

標準はあるにはあるが癖の多いSQL 全部俺w Advent Calendar 2020の15日目です。

最初に、これSQLじゃないじゃん! はい。その通りです m(_ _)m

如何にもこうにも、時間取れなくて、安易な差異の紹介に走りました。 
とはいえ、SQL command line clentの使い勝手の違いって意外に無視できなかったりします
全ては紹介できないですが、個人的にどのエンジンのSQL command line clientでも使う機能だけですが:)


SQL command line clientでSQL叩いて、一旦、exitしてなんて面倒なことしたくないのでホストコマンドを実行したくなった時は ! とか \! です。

Oracle

OracleのSQL*Plusでは ! でホストコマンドを実行できます(Windowsは host or $)

Use the following command to execute operating system commands. - ! [ command ]
https://docs.oracle.com/en/database/oracle/oracle-database/19/sqpqr/index.html#SQPQR108

ORACLE> ! date
2020年 12月15日 火曜日 0時34分38秒 JST


PostgreSQL

psql - \! [ command ]
https://www.postgresql.jp/document/12/html/app-psql.html

postgres=> \! date
2020年 12月15日 火曜日 0時35分34秒 JST

Mysql

mysql - \! [ command ]
https://dev.mysql.com/doc/refman/8.0/en/mysql-commands.html

mysql> \! date
2020年 12月15日 火曜日 0時39分00秒 JST

そして、無くてはならない編集コマンド, edit や \e と言ったショートカットなどがありますね。一通り覚えておくと便利です。

ORACLE

ED[IT] [file_name[.ext]]
https://docs.oracle.com/cd/F19136_01/sqpug/EDIT.html#GUID-25BC5CA1-4B03-4186-8ED3-715B5C6A6C42


ORACLE> select 1 from dual;

1
----------
1

ORACLE> edit

PostgreSQL

\e, \edit [ filename ] [ line_number ]
https://www.postgresql.jp/document/12/html/app-psql.html

postgres=> select 1;
?column?
----------
1
(1 row)

postgres=> \e


MySQL

edit, \e
https://dev.mysql.com/doc/refman/8.0/en/mysql-commands.html

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

mysql> edit



これ、書いてて思い出した、explainの違いも書いておいた方がいいか。。。。これもSQLそのものではないけど、重要なはず。






標準はあるにはあるが癖の多い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 連番の集合を返すにも癖がある

| | コメント (0)

2020年12月13日 (日)

標準はあるにはあるが癖の多いSQL 全部俺 #13 あると便利ですが意外となかったり

標準はあるにはあるが癖の多いSQL 全部俺w Advent Calendar 2020の13日目です。

ゼェゼェ。半ばに差し掛かりネタはあるものの書くことに疲れつつあるw (頑張れ自分w

と言うことで、今日は、あれば便利なので使ったりしますが、意外とありそうでなかったりする INITCAP()

この関数単語の先頭を大文字にしてくれる関数ですが、 MySQLの組み込み関数にはなかったりします。PostgreSQLにはあったり。

最初は
Oracleから。

INITCAP(char)
https://docs.oracle.com/cd/F19136_01/sqlrf/INITCAP.html#GUID-9FE9E0EE-D6B6-4C2C-BDEF-4FF4E1314560

ORACLE> SELECT INITCAP('oracle') FROM dual;

INITCA
------
Oracle

ORACLE> SELECT INITCAP('oracle-elison') FROM dual;

INITCAP('ORAC
-------------
Oracle-Elison

ORACLE> SELECT INITCAP('oracle,elison') FROM dual;

INITCAP('ORAC
-------------
Oracle,Elison

ORACLE> SELECT INITCAP('oracle|elison') FROM dual;

INITCAP('ORAC
-------------
Oracle|Elison

PostgreSQL

PostgreSQLにはOracleと同じ関数がサポートされています。

initcap(string)
https://www.postgresql.jp/document/12/html/functions-string.html

postgres=> SELECT INITCAP('oracle');
initcap
---------
Oracle
(1 row)

postgres=> SELECT INITCAP('oracle-elison');
initcap
---------------
Oracle-Elison
(1 row)

postgres=> SELECT INITCAP('oracle,elison');
initcap
---------------
Oracle,Elison
(1 row)

postgres=> SELECT INITCAP('oracle|elison');
initcap
---------------
Oracle|Elison
(1 row)


MySQL

個人的に意外だったのはMySQL. INITCAP()サポートされてません。UDFで作り込むしかないですね。

N/A
https://dev.mysql.com/doc/refman/8.0/en/string-functions.html


おまけ、
PostgreSQLを祖先にもつRedshiftにはPostgreSQL同様の関数がありました。
20201213-30538
Redshift

INITCAP(string)
https://docs.aws.amazon.com/ja_jp/redshift/latest/dg/r_INITCAP.html





実行計画は、SQL文のレントゲン写真だ! Oracle Database編 (全部俺) Advent Calendar 2019

標準はあるにはあるが癖の多い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 文字[列]探すにも癖がある

| | コメント (0)

2020年12月12日 (土)

標準はあるにはあるが癖の多いSQL 全部俺 #12 文字[列]探すにも癖がある

標準はあるにはあるが癖の多いSQL 全部俺w Advent Calendar 2020の12日目です。

私も癖多めですw

とうことで、アドベントカレンダーも約半分の折り返し地点です。ふー。

今日は、INSTR()

Oracleでは、SUBSTR()同様のバリエーションと挙動が見られます。ある意味分かり易ですね。
と言うことは、方言になりやすいはず。とも言えるわけです。はい。

では、見ていきましょう。


Oracle

positionは、SUBSTR()同様に負の値が使えます。0は、0しか返しません。
occurrenceは、正の値のみを取ります。

{ INSTR| INSTRB| INSTRC| INSTR2| INSTR4}(string , substring [, position [, occurrence ] ])
https://docs.oracle.com/cd/F19136_01/sqlrf/INSTR.html#GUID-47E3A7C4-ED72-458D-A1FA-25A9AD3BE113

ORACLE> SELECT INSTR('1234a56789a', 'a') FROM dual;

INSTR('1234A56789A','A')
------------------------
5

ORACLE> SELECT INSTR('1234a56789a', 'a', 1) FROM dual;

INSTR('1234A56789A','A',1)
--------------------------
5

ORACLE> SELECT INSTR('1234a56789a', 'a', -1) FROM dual;

INSTR('1234A56789A','A',-1)
---------------------------
11

ORACLE> SELECT INSTR('1234a56789a', 'a', 1, 1) FROM dual;

INSTR('1234A56789A','A',1,1)
----------------------------
           5

ORACLE> SELECT INSTR('1234a56789a', 'a', 1, 2) FROM dual;

INSTR('1234A56789A','A',1,2)
----------------------------
           11

ORACLE> SELECT INSTR('1234a56789a', 'a', -1, 2) FROM dual;

INSTR('1234A56789A','A',-1,2)
-----------------------------
           5

ORACLE> SELECT INSTR('1234a56789a', 'a', -1, 1) FROM dual;

INSTR('1234A56789A','A',-1,1)
-----------------------------
           11

ORACLE> SELECT INSTR('1234a56789a', 'a', 0) FROM dual;

INSTR('1234A56789A','A',0)
--------------------------
           0

ORACLE> set null [NULL]
ORACLE> SELECT INSTR('1234a56789a', 'a', null) FROM dual;

INSTR('1234A56789A','A',NULL)
-----------------------------
[NULL]

ORACLE> SELECT INSTR('1234a56789a', 'a', '') FROM dual;

INSTR('1234A56789A','A','')
---------------------------
[NULL]

ORACLE> SELECT INSTR('1234a56789a', '') FROM dual;

INSTR('1234A56789A','')
-----------------------
[NULL]

ORACLE> SELECT INSTR('1234a56789a', NULL) FROM dual;

INSTR('1234A56789A',NULL)
-------------------------
[NULL]

ORACLE> SELECT INSTR('1234a56789a', 'a', 1, 0) FROM dual;
SELECT INSTR('1234a56789a', 'a', 1, 0) FROM dual
*
ERROR at line 1:
ORA-01428: argument '0' is out of range

ORACLE> SELECT INSTR('1234a56789a', 'a', 1, -1) FROM dual;
SELECT INSTR('1234a56789a', 'a', 1, -1) FROM dual
*
ERROR at line 1:
ORA-01428: argument '-1' is out of range

MySQL

SUBSTR()はOracleに類似した挙動を持つ部分が多かったMySQLもINSTR()についてはそうでもないですね。positionやoccurrenceなどの引数がありません。
ただ、LOCATE()と言う類似した関数があります。LOCATE()と言う関数ではposition引数がありますが、0以上の整数でのみOracleと同じ挙動で負の値は、常に0ゼロを返すようです。

positionやoccurrence を利用している場合の移行は要注意と言うところですね。

INSTR(str,substr)
https://dev.mysql.com/doc/refman/5.6/ja/string-functions.html#function_instr

mysql> SELECT INSTR('1234a56789a', 'a');
+---------------------------+
| instr('1234a56789a', 'a') |
+---------------------------+
| 5 |
+---------------------------+
1 row in set (0.04 sec)

mysql> SELECT INSTR('1234a56789a', '');
+--------------------------+
| instr('1234a56789a', '') |
+--------------------------+
| 1 |
+--------------------------+
1 row in set (0.04 sec)

mysql> SELECT INSTR('1234a56789a', null);
+----------------------------+
| instr('1234a56789a', null) |
+----------------------------+
| NULL |
+----------------------------+
1 row in set (0.03 sec)

mysql> SELECT INSTR('1234a56789a', 'a', 1);
ERROR 1582 (42000): Incorrect parameter count in the call to native function 'instr'
mysql> SELECT INSTR('1234a56789a', 'a', 1, 1);
ERROR 1582 (42000): Incorrect parameter count in the call to native function 'instr'


LOCATE(substr,str), LOCATE(substr,str,pos)
https://dev.mysql.com/doc/refman/8.0/en/string-functions.html#function_locate

mysql> SELECT LOCATE('a', '1234a56789a');
+----------------------------+
| locate('a', '1234a56789a') |
+----------------------------+
| 5 |
+----------------------------+
1 row in set (0.08 sec)

mysql> SELECT LOCATE('a', '1234a56789a', 2);
+-------------------------------+
| locate('a', '1234a56789a', 2) |
+-------------------------------+
| 5 |
+-------------------------------+
1 row in set (0.05 sec)

mysql> SELECT LOCATE('a', '1234a56789a', 5);
+-------------------------------+
| locate('a', '1234a56789a', 5) |
+-------------------------------+
| 5 |
+-------------------------------+
1 row in set (0.08 sec)

mysql> SELECT LOCATE('a', '1234a56789a', 6);
+-------------------------------+
| locate('a', '1234a56789a', 6) |
+-------------------------------+
| 11 |
+-------------------------------+
1 row in set (0.09 sec)

mysql> SELECT LOCATE('a', '1234a56789a', -1);
+--------------------------------+
| locate('a', '1234a56789a', -1) |
+--------------------------------+
| 0 |
+--------------------------------+
1 row in set (0.35 sec)

mysql> SELECT LOCATE('a', '1234a56789a', 1);
+-------------------------------+
| locate('a', '1234a56789a', 1) |
+-------------------------------+
| 5 |
+-------------------------------+
1 row in set (0.13 sec)

mysql> SELECT LOCATE('a', '1234a56789a', 0);
+-------------------------------+
| locate('a', '1234a56789a', 0) |
+-------------------------------+
| 0 |
+-------------------------------+
1 row in set (0.35 sec)


PostgreSQL

42.13.3. 付録 本節には、移植作業を簡略化するために使用できる、Oracle互換のinstr関数のコードがあります。
https://www.postgresql.jp/document/12/html/plpgsql-porting.html#PLPGSQL-PORTING-APPENDIX

INSTR()はないのですが、類似関数として以下があるようです。また、position()と言う関数もあります。ですが、どちらもpositionやoccurrenceといった引数はない。マニュアルにOracleからの移植作業向けUDFの解説がある点は興味深いところ。

strpos(string, substring)
https://www.postgresql.jp/document/7.4/html/functions-string.html

postgres=> SELECT STRPOS('1234a56789a', 'a');
strpos
--------
5
(1 row)

postgres=> SELECT STRPOS('1234a56789a', '');
strpos
--------
1
(1 row)

postgres=> \pset null [NULL]
Null display is "[NULL]".
postgres=> SELECT STRPOS('1234a56789a', NULL);
strpos
--------
[NULL]
(1 row)

position(substring in string)
https://docs.aws.amazon.com/ja_jp/redshift/latest/dg/r_POSITION.html

postgres=> SELECT POSITION('a' in '1234a56789a');
position
----------
5
(1 row)

postgres=> SELECT POSITION('' in '1234a56789a');
position
----------
1
(1 row)

postgres=> SELECT POSITION(NULL in '1234a56789a');
position
----------
[NULL]
(1 row)

postgres=> SELECT POSITION(0 in '1234a56789a');
ERROR: function pg_catalog.position(unknown, integer) does not exist
LINE 1: SELECT POSITION(0 in '1234a56789a');
^
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
postgres=>


Redshift

PostgreSQL系の流れをくむRedshiftに、CHARINDEX()なる関数がある。同名の関数名が見つかるのはSQL Serverですね。それはそれで興味深い。

STRPOS(string, substring )
CHARINDEX( substring, string )
POSITION(substring IN string )
https://docs.aws.amazon.com/ja_jp/redshift/latest/dg/r_POSITION.html






実行計画は、SQL文のレントゲン写真だ! Oracle Database編 (全部俺) Advent Calendar 2019

標準はあるにはあるが癖の多いSQL 全部俺 #1 Pagination
標準はあるにはあるが癖の多いSQL 全部俺 #2 関数名は同じでも引数が逆の罠!
標準はあるにはあるが癖の多いSQL 全部俺 #3 データ型確認したい時あるんです
標準はあるにはあるが癖の多いSQL 全部俺 #4 リテラル値での除算の内部精度も違うのよ!
標準はあるにはあるが癖の多いSQL 全部俺 #5 和暦変換機能ある方が少数派
標準はあるにはあるが癖の多いSQL 全部俺 #6 時間厳守!
標準はあるにはあるが癖の多いSQL 全部俺 #7 期間リテラル!
標準はあるにはあるが癖の多いSQL 全部俺 #8 翌月末日って何日?
標準はあるにはあるが癖の多いSQL 全部俺 #9 部分文字列の扱いでも癖が出る><
標準はあるにはあるが癖の多いSQL 全部俺 #10 文字列連結の罠(有名なやつ)
標準はあるにはあるが癖の多いSQL 全部俺 #11 デュエル、じゃなくて、デュアル

| | コメント (0)

2020年12月11日 (金)

標準はあるにはあるが癖の多いSQL 全部俺 #11 デュエル、じゃなくて、デュアル

標準はあるにはあるが癖の多いSQL 全部俺w Advent Calendar 2020の10日目です。

ネタがなくてw そこ狙って来たか! 

と思われるかもしれませんが、これを語らずして、非互換語るなかれw

とうことで、Oracleでは、当たり前に利用している dual について

定数式をSELECT文で計算する場合などに指定する表です。dual表に、おイタしたりしたネタも過去あったような気がしますw

Oracleの方言なので、単純ですが、非互換では有名ですね。


では、本家から

Oracle

DUAL表からの選択
https://docs.oracle.com/cd/F19136_01/sqlrf/Selecting-from-the-DUAL-Table.html#GUID-0AB153FC-5238-4E79-8522-C9E2A04AB5E4

ORACLE> select 1 from dual;

1
----------
1

ORACLE> select 1;
select 1
*
ERROR at line 1:
ORA-00923: FROM keyword not found where expected


MySQL

昨日のエントリで使ってしまったw ので気づいた方もいると思いますが、MySQLは dual 付けられるんですよね。

13.2.10 SELECT Statement
https://dev.mysql.com/doc/refman/8.0/en/select.html

mysql> select 1 from dual;
+---+
| 1 |
+---+
| 1 |
+---+
1 row in set (0.06 sec)

mysql> select 1;
+---+
| 1 |
+---+
| 1 |
+---+
1 row in set (0.04 sec)


PostgreSQL

PostgreSQLには dual を使うような習慣もないですし、文法的に用意されていません。無理やり dual 表を定義すれば別でしょうけど、無駄なだけなので移行するなら、素直に dualを削除が潔いと思いますw

SELECT
https://www.postgresql.jp/document/12/html/sql-select.html

postgres=> select 1 from dual;
ERROR: relation "dual" does not exist
LINE 1: select 1 from dual;
^
postgres=> select 1;
?column?
----------
1
(1 row)

おまけ

Redshift

Redshiftにも dual はありません。

SELECT
https://docs.aws.amazon.com/ja_jp/redshift/latest/dg/r_SELECT_synopsis.html

redshift=# select 1 from dual;
ERROR: relation "dual" does not exist


redshift=# select 1;
?column?
----------
1
(1 row)


また、Athenaも同様です

SELECT
https://docs.aws.amazon.com/ja_jp/athena/latest/ug/select.html


新しい年には、何か変化が欲しいと感じる今日この頃w 






実行計画は、SQL文のレントゲン写真だ! Oracle Database編 (全部俺) Advent Calendar 2019

標準はあるにはあるが癖の多いSQL 全部俺 #1 Pagination
標準はあるにはあるが癖の多いSQL 全部俺 #2 関数名は同じでも引数が逆の罠!
標準はあるにはあるが癖の多いSQL 全部俺 #3 データ型確認したい時あるんです
標準はあるにはあるが癖の多いSQL 全部俺 #4 リテラル値での除算の内部精度も違うのよ!
標準はあるにはあるが癖の多いSQL 全部俺 #5 和暦変換機能ある方が少数派
標準はあるにはあるが癖の多いSQL 全部俺 #6 時間厳守!
標準はあるにはあるが癖の多いSQL 全部俺 #7 期間リテラル!
標準はあるにはあるが癖の多いSQL 全部俺 #8 翌月末日って何日?
標準はあるにはあるが癖の多いSQL 全部俺 #9 部分文字列の扱いでも癖が出る><
標準はあるにはあるが癖の多いSQL 全部俺 #10 文字列連結の罠(有名なやつ)

| | コメント (0)

2020年12月10日 (木)

標準はあるにはあるが癖の多いSQL 全部俺 #10 文字列連結の罠(有名なやつ)

標準はあるにはあるが癖の多いSQL 全部俺w Advent Calendar 2020の10日目です。


なんとか10日目の窓をあけましたw

今回は、有名な非互換なので、まさか、これに引っかかる方はいないと思いますが、定番のお約束みたいな非互換ネタなので書かないといけないですよね!!

では、いつも通り Oracle から。

NULLと空文字(マニュアルでは長さゼロの文字列値と記載されています。有名な非互換)
https://docs.oracle.com/cd/E82638_01/sqlrf/Nulls.html#GUID-B0BA4751-9D88-426A-84AD-BCDBD5584071

CONCAT(char1, char2)
https://docs.oracle.com/en/database/oracle/oracle-database/19/sqlrf/CONCAT.html#GUID-D8723EA5-C93A-45C3-83FB-1F3D2A4CEAF2

連結演算子
https://docs.oracle.com/cd/F19136_01/sqlrf/Concatenation-Operator.html#GUID-08C10738-706B-4290-B7CD-C279EBC90F7E

空文字をNULLとして扱う点と、||による文字列連結(CONCATと同意)の挙動がOracle以外の世界と違うんですよね。これも有名です。

ORACLE> SELECT 'foo' || 'bar' FROM dual;

'FOO'|
------
foobar

ORACLE> SELECT 'foo' || '' FROM dual;

'FO
---
foo

ORACLE> SELECT 'foo' || NULL FROM dual;

'FO
---
foo

ORACLE> SELECT CONCAT('foo','bar') FROM dual;

CONCAT
------
foobar

ORACLE> SELECT CONCAT('foo','') FROM dual;

CON
---
foo

ORACLE> SELECT CONCAT('foo',null) FROM dual;

CON
---
foo

PostgreSQL

PostgreSQLでは、Oracleと異なり 文字列連結子でNULLを結合すると結果は、NULLになります。ここがOracleと異なる挙動ですね。
これを回避するにはconcat() or concat_ws()のいずれかを利用できます。

string || string
concat(str "any" [, str "any" [, ...] ])
concat_ws(sep text, str "any" [, str "any" [, ...] ])
https://www.postgresql.jp/document/12/html/functions-string.html

そして、これまた、悩ましいのは、 ||でNULLを結合した場合と、CONCAT_WS()でNULLを結合した挙動が異なるんですね。
||でNULLの場合はNULLですが、CONCATでNULLを結合するとOracleと同じ挙動になるんですよ。

postgres=> SELECT 'foo' || 'bar';
?column?
----------
foobar
(1 row)

postgres=> SELECT 'foo' || '';
?column?
----------
foo
(1 row)

postgres=> SELECT 'foo' || null;
?column?
----------
[NULL]
(1 row)

postgres=> SELECT CONCAT('foo', '');
concat
--------
foo
(1 row)

postgres=> SELECT CONCAT('foo', NULL);
concat
--------
foo
(1 row)

postgres=>
postgres=> SELECT CONCAT_WS('','foo','bar' );
concat_ws
-----------
foobar
(1 row)

postgres=> SELECT CONCAT_WS('','foo','' );
concat_ws
-----------
foo
(1 row)

postgres=> SELECT CONCAT_WS('','foo',NULL );
concat_ws
-----------
foo
(1 row)

postgres=>


MySQL

MySQLでは、|| は文字列連結子ではなく、なんと、論理演算子!!!!!! 

え〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜~っ。

12.4.3 Logical Operators - OR, ||
https://dev.mysql.com/doc/refman/8.0/en/logical-operators.html

mysql> SELECT 'foo' || 'bar' FROM dual;
+----------------+
| 'foo' || 'bar' |
+----------------+
| 0 |
+----------------+
1 row in set, 3 warnings (0.03 sec)

mysql> SELECT 'foo' || '' FROM dual;
+-------------+
| 'foo' || '' |
+-------------+
| 0 |
+-------------+
1 row in set, 2 warnings (0.04 sec)

mysql> SELECT 'foo' || NULL FROM dual;
+---------------+
| 'foo' || null |
+---------------+
| NULL |
+---------------+
1 row in set, 2 warnings (0.06 sec)


実は逃げ道があるようで、sql_mode='PIPES_AS_CONCAT' にすると文字列連結子に早変わり!w

ですが、挙動はPostgreSQL同様に、NULLと連結したり演算子すると結果はNULLになると言う一般的な動きをします。
Oracleは演算に関してはNULLが絡むとNULLになりますが、文字列連結だけはNULLが空文字のような扱いを受けると言う挙動を示します。理解しちゃえばあれですが、エラーにならないだけに混乱するタイプの非互換ですね。

PostgreSQLとは異なり、CONCAT_WS()だけがOracleと同じ挙動を示します。


CONCAT(str1,str2,...)
CONCAT_WS(separator,str1,str2,...)
https://dev.mysql.com/doc/refman/8.0/en/string-functions.html


mysql> set sql_mode='PIPES_AS_CONCAT';
Query OK, 0 rows affected (0.03 sec)

mysql> SELECT 'foo' || 'bar' FROM dual;
+----------------+
| 'foo' || 'bar' |
+----------------+
| foobar |
+----------------+
1 row in set (0.02 sec)

mysql> SELECT 'foo' || '' FROM dual;
+-------------+
| 'foo' || '' |
+-------------+
| foo |
+-------------+
1 row in set (0.04 sec)

mysql> SELECT 'foo' || NULL FROM dual;
+---------------+
| 'foo' || null |
+---------------+
| NULL |
+---------------+
1 row in set (0.01 sec)

mysql> SELECT CONCAT('foo','bar');
+---------------------+
| concat('foo','bar') |
+---------------------+
| foobar |
+---------------------+
1 row in set (0.01 sec)

mysql> SELECT CONCAT('foo','');
+------------------+
| concat('foo','') |
+------------------+
| foo |
+------------------+
1 row in set (0.02 sec)

mysql> SELECT CONCAT('foo',NULL);
+--------------------+
| concat('foo',null) |
+--------------------+
| NULL |
+--------------------+
1 row in set (0.03 sec)

mysql> SELECT CONCAT_WS('foo',NULL);
+-----------------------+
| concat_ws('foo',null) |
+-----------------------+
| |
+-----------------------+
1 row in set (0.02 sec)

mysql> SELECT CONCAT_WS('','foo',NULL);
+--------------------------+
| concat_ws('','foo',null) |
+--------------------------+
| foo |
+--------------------------+
1 row in set (0.01 sec)

mysql> SELECT CONCAT_WS('','foo','bar');
+---------------------------+
| concat_ws('','foo','bar') |
+---------------------------+
| foobar |
+---------------------------+
1 row in set (0.02 sec)

mysql> SELECT CONCAT_WS('','foo','');
+------------------------+
| concat_ws('','foo','') |
+------------------------+
| foo |
+------------------------+
1 row in set (0.02 sec)

mysql> SELECT CONCAT_WS('','foo',NULL);
+--------------------------+
| concat_ws('','foo',null) |
+--------------------------+
| foo |
+--------------------------+
1 row in set (0.01 sec)

mysql>

ややこしやー、ややこしやー。

みなさん、ついてこれてますか? この手の内容が25日まで続きますからね。(私が続けられるか次第だが。。。。頑張りマッス!





実行計画は、SQL文のレントゲン写真だ! Oracle Database編 (全部俺) Advent Calendar 2019

標準はあるにはあるが癖の多いSQL 全部俺 #1 Pagination
標準はあるにはあるが癖の多いSQL 全部俺 #2 関数名は同じでも引数が逆の罠!
標準はあるにはあるが癖の多いSQL 全部俺 #3 データ型確認したい時あるんです
標準はあるにはあるが癖の多いSQL 全部俺 #4 リテラル値での除算の内部精度も違うのよ!
標準はあるにはあるが癖の多いSQL 全部俺 #5 和暦変換機能ある方が少数派
標準はあるにはあるが癖の多いSQL 全部俺 #6 時間厳守!
標準はあるにはあるが癖の多いSQL 全部俺 #7 期間リテラル!
標準はあるにはあるが癖の多いSQL 全部俺 #8 翌月末日って何日?
標準はあるにはあるが癖の多いSQL 全部俺 #9 部分文字列の扱いでも癖が出る><

| | コメント (0)

2020年12月 9日 (水)

標準はあるにはあるが癖の多いSQL 全部俺 #9 部分文字列の扱いでも癖が出る><

標準はあるにはあるが癖の多いSQL 全部俺w Advent Calendar 2020の9日目です。

 

それでいいのだ! バカボンのパパより。

 

いや、めんどくさいw

 

と言うことで、今日は単純そうにみえる部分文字列取得の違い。関数名の違いもあれば挙動の違いもあります。

 

そして、ものすごくバリエーションが多い。多すぎるので、SUBSTR()だけに絞りますw

 

 

 

Oracle

 

Unicodeキャラクタ向けSUBSTRCやUCS2コードポイント対応、UCS4コードポイント対応などのバリエーションが豊富ですが、それが方言になってますよね。

 

{ SUBSTR| SUBSTRB| SUBSTRC| SUBSTR2| SUBSTR4}(char, position [, substring_length ])
https://docs.oracle.com/cd/F19136_01/sqlrf/SUBSTR.html#GUID-C8A20B57-C647-4649-A379-8651AA97187E

 

SUBSTR()はこんな感じ。 positionをマイナスにすると一回りして切り出してきます。

ORACLE> select substr('hoge1234',1,4) from dual;

SUBS
----
hoge

ORACLE> select substr('hoge1234',-4,4) from dual;

SUBS
----
1234

 

 

MySQL

 

Oracleと同じ関数名、同じ引数をサポートしています。引数に特徴がありますね。from forを使った方が可読性は良いかもしれませんが、逆にウザがれる可能性も否定できません。その点個人の志向次第か。
positionにマイナスを指定した場合、Oracleと同じ挙動になりますね。興味深い。
そして、SUBSTR()はSUBSTRING()のシノニムと言うことなんですね。と言うことはオリジナルはSUBSTRING()なのか。。

 

SUBSTR() is a synonym for SUBSTRING().
SUBSTR(str,pos), SUBSTR(str FROM pos), SUBSTR(str,pos,len), SUBSTR(str FROM pos FOR len)
SUBSTRING(str,pos), SUBSTRING(str FROM pos), SUBSTRING(str,pos,len), SUBSTRING(str FROM pos FOR len)
https://dev.mysql.com/doc/refman/8.0/en/string-functions.html#function_substr

 

mysql> select substr('hoge1234',1,4);
+------------------------+
| substr('hoge1234',1,4) |
+------------------------+
| hoge |
+------------------------+
1 row in set (0.08 sec)

mysql> select substr('hoge1234',-4,4);
+-------------------------+
| substr('hoge1234',-4,4) |
+-------------------------+
| 1234 |
+-------------------------+
1 row in set (0.07 sec)

 

 

 

PostgreSQL

 

最後にPostgreSQL、こちらはMySQLのオリジナルと同じ関数名SUBSTRING()となっています。 ぱっと見、Oracleから関数名さえ変更すれば移行できそうですが、実はpositionにマイナスを指定した場合の挙動に違いがあります!
一回りせずに、空文字を返してきます!!!! ここ要注意です。

 

substring(string [from int] [for int])
https://www.postgresql.jp/document/12/html/functions-string.html

 

postgres=> \pset null [NULL]
Null display is "[NULL]".
postgres=> select substring('hoge1234',1,4);
substring
-----------
hoge
(1 row)

postgres=> select substring('hoge1234',-4,4);
substring
-----------

(1 row)

 

 

おまけですが、PostgreSQLのSUBSTRING()関数では、パターンマッチングが行えるようです。Oraclerの私には、REGEXP_SUBSTR()をイメージしちゃうのですが、
調べてみると、PostgreSQLにはregexp_matches()関数もあります。@@ 違いがわからなくなってきたので、この辺りはあとでゆっくり勉強しておきます。w
(MySQL8.0になると、regexp_substr()関数がサポートされているようですね...終わりのない世界w)

 

substring(string from pattern)
substring(string from pattern for escape)

 

 



実行計画は、SQL文のレントゲン写真だ! Oracle Database編 (全部俺) Advent Calendar 2019


 

標準はあるにはあるが癖の多いSQL 全部俺 #1 Pagination
標準はあるにはあるが癖の多いSQL 全部俺 #2 関数名は同じでも引数が逆の罠!
標準はあるにはあるが癖の多いSQL 全部俺 #3 データ型確認したい時あるんです
標準はあるにはあるが癖の多いSQL 全部俺 #4 リテラル値での除算の内部精度も違うのよ!
標準はあるにはあるが癖の多いSQL 全部俺 #5 和暦変換機能ある方が少数派
標準はあるにはあるが癖の多いSQL 全部俺 #6 時間厳守!
標準はあるにはあるが癖の多いSQL 全部俺 #7 期間リテラル!
標準はあるにはあるが癖の多いSQL 全部俺 #8 翌月末日って何日?

 

| | コメント (0)

2020年12月 8日 (火)

標準はあるにはあるが癖の多いSQL 全部俺 #8 翌月末日って何日?

標準はあるにはあるが癖の多いSQL 全部俺w Advent Calendar 2020の8日目です。

日付関連の非互換はネタが沢山w 

翌月末日って何日? を求める場合にも違いがあります。ほんとにもうww

Oracle

Oracleには、last_day()関数ががあります。date型の引数をとるので期間リテラルと演算可能。
では、Oracleで翌月末日を求めてみる。シンプルですね。

LAST_DAY(date)
https://docs.oracle.com/en/database/oracle/oracle-database/19/sqlrf/LAST_DAY.html#GUID-296C7C02-7FB9-4AAC-8927-6A79320CE0C6

ORACLE> alter session set nls_date_format = 'yyyy-mm-dd';

Session altered.

ORACLE> select last_day(sysdate + interval '1' month) from dual;

LAST_DAY(S
----------
2021-01-31

Mysql

MySQLにもOracle同様にlast_day()関数を使って、簡単に「翌月末日って何日?」を求めることができますよね。

LAST_DAY(date)
https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html

mysql> select last_day(curdate() + interval 1 month);
+----------------------------------------+
| last_day(curdate() + interval 1 month) |
+----------------------------------------+
| 2021-01-31 |
+----------------------------------------+
1 row in set (0.03 sec)


Postgresql

なぜか、昔から頑なに last_day()関数がありません。UDFで頑張るか、ちょいと頑張って「翌月末日って何日?」を求めなければいけません。
翌々月1日の前日が「翌月末日って何日?」なので、その方法で求めてみます。やれやれ、last_day()ってUDF作った方が楽そうですねw


N/A
https://www.postgresql.jp/document/12/html/functions-datetime.html


postgres=> select cast(date_trunc('month', current_date + interval '2 month') - interval '1 day' as date);
date
------------
2021-01-31
(1 row)


Redshift

PostgreSQLの流れを汲むRedshiftですが、last_day()関数ありました! PostgreSQLに、もしあればこんな構文だろうと想像します。

LAST_DAY ( { date | timestamp } )
https://docs.aws.amazon.com/ja_jp/redshift/latest/dg/r_LAST_DAY.html

redshift=# select last_day(current_date + interval '1 month');
last_day
------------
2021-01-31
(1 row)




ブログ書きながら寝落ちしてたw
20201208-02932






実行計画は、SQL文のレントゲン写真だ! Oracle Database編 (全部俺) Advent Calendar 2019

標準はあるにはあるが癖の多いSQL 全部俺 #1 Pagination
標準はあるにはあるが癖の多いSQL 全部俺 #2 関数名は同じでも引数が逆の罠!
標準はあるにはあるが癖の多いSQL 全部俺 #3 データ型確認したい時あるんです
標準はあるにはあるが癖の多いSQL 全部俺 #4 リテラル値での除算の内部精度も違うのよ!
標準はあるにはあるが癖の多いSQL 全部俺 #5 和暦変換機能ある方が少数派
標準はあるにはあるが癖の多いSQL 全部俺 #6 時間厳守!
標準はあるにはあるが癖の多いSQL 全部俺 #7 期間リテラル!

| | コメント (0)

2020年12月 7日 (月)

標準はあるにはあるが癖の多いSQL 全部俺 #7 期間リテラル!

標準はあるにはあるが癖の多いSQL 全部俺w Advent Calendar 2020の7日目です。

さて、日付関連は非互換の宝庫ではありますが、ほんとなんで違うの。。。と言う微妙な違いだったり、キーーーーってなりますよね。なぜ合わせられないw

今日は期間リテラル。


Oracle

期間リテラル
https://docs.oracle.com/cd/F19136_01/sqlrf/Literals.html#GUID-49FADC66-794D-4763-88C7-B81BB4F26D9E

SQL> ALTER SESSION SET NLS_DATE_FORMAT = 'yyyy-mm-dd';

セッションが変更されました。

SQL> SELECT SYSDATE + INTERVAL '10' DAY FROM DUAL;

SYSDATE+IN
----------
2020-12-16


MySQL

Temporal Intervals
https://dev.mysql.com/doc/refman/8.0/en/expressions.html#temporal-intervals

mysql> SELECT CURDATE() + INTERVAL 10 DAY;
+-----------------------------+
| curdate() + interval 10 day |
+-----------------------------+
| 2020-12-16 |
+-----------------------------+
1 row in set (0.00 sec)

PostgreSQL

8.5. 日付/時刻データ型
https://www.postgresql.jp/document/12/html/datatype-datetime.html

sql=> SELECT CAST(CURRENT_DATE + INTERVAL '10 DAY' AS DATE);

date
------------
2020-12-16
(1 row)



実行計画は、SQL文のレントゲン写真だ! Oracle Database編 (全部俺) Advent Calendar 2020

標準はあるにはあるが癖の多いSQL 全部俺 #1 Pagination
標準はあるにはあるが癖の多いSQL 全部俺 #2 関数名は同じでも引数が逆の罠!
標準はあるにはあるが癖の多いSQL 全部俺 #3 データ型確認したい時あるんです
標準はあるにはあるが癖の多いSQL 全部俺 #4 リテラル値での除算の内部精度も違うのよ!/a>
標準はあるにはあるが癖の多いSQL 全部俺 #5 和暦変換機能ある方が少数派
標準はあるにはあるが癖の多いSQL 全部俺 #6 時間厳守!

| | コメント (0)

2020年12月 6日 (日)

標準はあるにはあるが癖の多いSQL 全部俺 #6 時間厳守!

標準はあるにはあるが癖の多いSQL 全部俺w Advent Calendar 2020の6日目です。

日付、日時関連も非互換の多い部分ですね。

該当関数の挙動を見てみると違いと、以外と違いがあるので面白いですよ。日付、日時関数って多くて全てを取り上げてると大変なので、今回は、OracleのSYSDATEを取り上げて、PostgreSQLではどれ使うのがいいのかなぁ

と言うところを見ていきたいと思います。

まず、このエントリー内で利用している、関数の特性を示す単語の意味を定義しておきたいと思います。

・同一SQL文の上で何度callされても同じ日時を返す特性:文内同一
・同一SQL文の上でcallされる毎に異なる日時を返す特性:文内非同一
・同一トランザクション内で何度callしても同一日時を返す特性:トランザクション内同一
・同一トランザクション内でcallされる毎に異なる日時を返す特性:トランザクション内非同一

関数としては沢山ありすぎて個別に調査した内容を個別に書こうと思うと、アドベントカレンダーの一エントリーとして終わる気がししないのでw

軽めに書いてもこんな感じw


SYSDATEはタイムゾーンを持たないので、PostgreSQLのCURRENT_DATEかなー、と思ってしまうと大きな間違いで、もっとも挙動として近いのは、Oracleで利用していたタイムゾーンに合わせる形で利用するPostgreSQLのstatement_timestamp()と言うことになる。
有名なOrafceで提供されている oracle.sysdate() も中を覗いてみると、statement_timestamp() が利用されている。


このエントリーの後半で挙動の確認方法と oracle.sysdate() が statement_timestamp() を利用しているソースを記載しています。


Oracle Database

SYSDATE
https://docs.oracle.com/cd/E82638_01/sqlrf/SYSDATE.html#GUID-807F8FC5-D72D-4F4D-B66D-B0FE1A8FA7D2

年月日時分秒 タイムゾーンなし

特性
文内同一、トランザクション内非同一


SYSTIMESTAMP
https://docs.oracle.com/cd/E82638_01/sqlrf/SYSTIMESTAMP.html#GUID-FCED18CE-A875-4D5D-9178-3DE4FA956516

年月日時分秒.秒未満精度(9) タイムゾーンあり

特性
文内同一、ランザクション内非同一


CURRENT_DATE
https://docs.oracle.com/cd/E82638_01/sqlrf/CURRENT_DATE.html#GUID-96795097-D6F0-4288-90E7-9D7C49B4F6E5

年月日時分秒 タイムゾーンなし

特性
文内同一、トランザクション内非同一


CURRENT_TIMESTAMP
https://docs.oracle.com/cd/E82638_01/sqlrf/CURRENT_TIMESTAMP.html#GUID-CBD42B84-869D-45C7-9FFC-001DD7712097

年月日時分秒.秒未満精度(9) タイムゾーンあり

特性
文内同一、トランザクション内非同一


LOCALTIMESTAMP
https://docs.oracle.com/cd/E82638_01/sqlrf/LOCALTIMESTAMP.html#GUID-3C3D1F29-5F53-41F2-B2D6-A3767DFB22CA

年月日時分秒.秒未満精度(9) タイムゾーンなし

特性
文内同一、トランザクション内非同一




PostgreSQL
PostgreSQLのtimestamp型の秒未満精度は最大6桁であるため、Oracleのtimestamp型の最大精度より低いことに注意
https://www.postgresql.jp/document/12/html/functions-datetime.html


CURRENT_DATE
年月日(PostgreSQLのDATE型で返す)タイムゾーンなし

特性
文内同一、トランザクション内同一


CURRENT_TIMESTAMP
年月日時分秒.秒未満精度(6) タイムゾーンあり

特性
文内同一、トランザクション内同一


LOCALTIMESTAMP
年月日時分秒.秒未満精度(6) タイムゾーンなし

特性
文内同一、トランザクション内同一


clock_timestamp()
年月日時分秒.秒未満精度(6) タイムゾーンあり

特性
文内非同一、トランザクション内非同一


transaction_timestamp()
CURRENT_TIMESTAMPに同じ
関数名が具体的に何を返すか明確になっている点の違いのみ

特性
文内同一、トランザクション内同一


statement_timestamp()
年月日時分秒.秒未満精度(6) タイムゾーンあり

特性
文内同一、トランザクション内非同一
statement_timestamp()が、もっともOracleのSYSDATE/SYSTIMESTAMPに近い挙動を示す

now()
transaction_timestamp()の別名
利用することは推奨されていない(何を返すかわかりにくい関数名である影響と思われる)

特性
文内同一、トランザクション内同一





Oracle Database

トランザクション内同一性の確認(1秒間隔で3回実行)
Oracle Databaseの日付時刻関数は、トランザクション内非同一

SYSDATE              SYSTIMESTAMP
-------------------- ----------------------------------------
2020/11/08 16:12:03 2020/11/08 16:12:03.345275 +00:00
2020/11/08 16:12:04 2020/11/08 16:12:04.397601 +00:00
2020/11/08 16:12:05 2020/11/08 16:12:05.475719 +00:00

LOCALTIMESTAMP CURRENT_DATE CURRENT_TIMESTAMP
------------------------------ -------------------- ----------------------------------------
2020/11/09 01:12:03.345277 2020/11/09 01:12:03 2020/11/09 01:12:03.345277 +09:00
2020/11/09 01:12:04.397603 2020/11/09 01:12:04 2020/11/09 01:12:04.397603 +09:00
2020/11/09 01:12:05.475721 2020/11/09 01:12:05 2020/11/09 01:12:05.475721 +09:00


文内同一性の確認(最後のカラムは、1秒待機後に返すようにして実行)
(ore_sleep()と言うUDFを作成し、内部で(Oracle 18cまで)dbms_lock.sleep(1) or (Oracle 19c以降)dbms_session.sleep(1) を実行)

以下の結果から、Oracle Databaseの日付時刻関数は、すべて文内同一

SQL> SELECT
sysdate, sysdate, ORE_SLEEP(1), sysdate
FROM
dual;

SYSDATE SYSDATE ORE_SLEEP(1) SYSDATE
------------------- ------------------- -------------- -------------------
2020/11/21 05:49:46 2020/11/21 05:49:46 0 2020/11/21 05:49:46

SQL> r
1 SELECT
2 systimestamp, systimestamp, ORE_SLEEP(1), systimestamp
3 FROM
4* dual

SYSTIMESTAMP SYSTIMESTAMP OREO_SLEEP(1) SYSTIMESTAMP
---------------------------------------- ---------------------------------------- -------------- ----------------------------------------
2020/11/21/05:48:19.459180 +00:00 2020/11/21/05:48:19.459180 +00:00 0 2020/11/21/05:48:19.459180 +00:00

SQL> r
1 SELECT
2 localtimestamp,localtimestamp,ORE_SLEEP(1),localtimestamp
3 FROM
4* dual

LOCALTIMESTAMP LOCALTIMESTAMP ORE_SLEEP(1) LOCALTIMESTAMP
---------------------------------------- ---------------------------------------- -------------- ----------------------------------------
2020/11/21 14:58:13.350655 2020/11/21 14:58:13.350655 0 2020/11/21 14:58:13.350655

SQL> r
1 SELECT
2 current_date,current_date,ORE_SLEEP(1),current_date
3 FROM
4* dual

CURRENT_DATE CURRENT_DATE ORE_SLEEP(1) CURRENT_DATE
------------------- ------------------- -------------- -------------------
2020/11/21 14:59:47 2020/11/21 14:59:47 0 2020/11/21 14:59:47

SQL> r
1 SELECT
2 current_timestamp,current_timestamp,ORE_SLEEP(1),current_timestamp
3 FROM
4* dual

CURRENT_TIMESTAMP CURRENT_TIMESTAMP ORE_SLEEP(1) CURRENT_TIMESTAMP
---------------------------------------- ---------------------------------------- -------------- ----------------------------------------
2020/11/21/15:00:41.661495 +09:00 2020/11/21/15:00:41.661495 +09:00 0 2020/11/21/15:00:41.661495 +09:00





PostgreSQL


トランザクション内同一性の確認(1秒間隔で3回実行)
PostgreSQLの日付時刻関数は、トランザクション内同一と非同一が混在

CURRENT_DATEは時刻を持たないためこの方法では検証不能だが、
マニュアルではトランザクション内で同一と記載されている。
clock_timestamp(),statement_timestamp()はトランザクション内非同一、それ以外は、トランザクション内同一

 current_date |       current_timestamp       |
--------------+-------------------------------+
2020-11-08 | 2020-11-08 16:12:05.897343+00 |
2020-11-08 | 2020-11-08 16:12:05.897343+00 |
2020-11-08 | 2020-11-08 16:12:05.897343+00 |

clock_timestamp | localtimestamp |
------------------------------+----------------------------+
2020-11-08 16:12:05.936468+00 | 2020-11-08 16:12:05.897343 |
2020-11-08 16:12:07.304506+00 | 2020-11-08 16:12:05.897343 |
2020-11-08 16:12:08.532788+00 | 2020-11-08 16:12:05.897343 |

now | statement_timestamp | transaction_timestamp
------------------------------+-------------------------------+-------------------------------
2020-11-08 16:12:05.897343+00 | 2020-11-08 16:12:05.936423+00 | 2020-11-08 16:12:05.897343+00
2020-11-08 16:12:05.897343+00 | 2020-11-08 16:12:07.304408+00 | 2020-11-08 16:12:05.897343+00
2020-11-08 16:12:05.897343+00 | 2020-11-08 16:12:08.532704+00 | 2020-11-08 16:12:05.897343+00


文内同一性の確認(最後のカラムは、1秒待機後に返すようにして実行)
以下の結果から、PostgreSQL日付時刻関数は、文内同一/非同一混在。

current_dateについてはこの方法では検証できないが、ドキュメントより文内同一であると判断。

sql=> SELECT
sql-> current_date, current_date, pg_sleep(1), current_date;

current_date | current_date | pg_sleep | current_date
--------------+--------------+----------+--------------
2020-11-21 | 2020-11-21 | | 2020-11-21


文内同一

sql=> SELECT
sql-> current_timestamp,current_timestamp,pg_sleep(1),current_timestamp;

current_timestamp | current_timestamp | pg_sleep | current_timestamp
-------------------------------+-------------------------------+----------+-------------------------------
2020-11-21 06:05:48.930432+00 | 2020-11-21 06:05:48.930432+00 | | 2020-11-21 06:05:48.930432+00

文内非同一

sql=> SELECT
sql-> clock_timestamp(),clock_timestamp(),pg_sleep(1),clock_timestamp();

clock_timestamp | clock_timestamp | pg_sleep | clock_timestamp
-------------------------------+-------------------------------+----------+-------------------------------
2020-11-21 06:08:48.920466+00 | 2020-11-21 06:08:48.920466+00 | | 2020-11-21 06:08:49.925492+00

文内同一

sql=> SELECT
sql-> localtimestamp,localtimestamp,pg_sleep(1),localtimestamp;

localtimestamp | localtimestamp | pg_sleep | localtimestamp
----------------------------+----------------------------+----------+----------------------------
2020-11-21 06:19:19.547055 | 2020-11-21 06:19:19.547055 | | 2020-11-21 06:19:19.547055


文内同一

sql=> SELECT
sql-> now(),now(),pg_sleep(1),now();

now | now | pg_sleep | now
-------------------------------+-------------------------------+----------+-------------------------------
2020-11-21 06:20:07.457373+00 | 2020-11-21 06:20:07.457373+00 | | 2020-11-21 06:20:07.457373+00

文内同一

sql=> SELECT
sql-> statement_timestamp(),statement_timestamp(),pg_sleep(1),statement_timestamp();

statement_timestamp | statement_timestamp | pg_sleep | statement_timestamp
-------------------------------+-------------------------------+----------+-------------------------------
2020-11-21 06:20:52.502137+00 | 2020-11-21 06:20:52.502137+00 | | 2020-11-21 06:20:52.502137+00


文内同一

sql=> SELECT
sql-> transaction_timestamp(),transaction_timestamp(),pg_sleep(1),transaction_timestamp();

transaction_timestamp | transaction_timestamp | pg_sleep | transaction_timestamp
-------------------------------+-------------------------------+----------+-------------------------------
2020-11-21 06:21:24.562833+00 | 2020-11-21 06:21:24.562833+00 | | 2020-11-21 06:21:24.562833+00







orafce によるエミュレーション関数(参考)
https://github.com/orafce/orafce/blob/master/README.asciidoc


oracle.sysdate()
PostgreSQLのstatement_timestamp()をラップしているため属性はstatement_timestamp()と同じ
sysdate関数のエミュレーションとしては最も近い属性を持っていると見られる。
OracleのSYSDATE代替関数とされている。
特性としては、問題ないと考えられ、文内同一 (OracleのSYSDATEと同じ挙動),トランザクション内非同一(OracleのSYSDATEと同じ挙動)

実装を見てみると、

https://github.com/orafce/orafce/blob/master/orafce--3.14.sql
の関数定義を見るとC言語の関数であり、statement_timestampをと言うコメントがある. 
statement_timestamp()がOracleのSYSDATEの挙動に近いと言う理由からなのだろうと想像する。納得感あり!!!!

CREATE FUNCTION oracle.sysdate()
RETURNS oracle.date
AS 'MODULE_PATHNAME','orafce_sysdate'
LANGUAGE C STABLE STRICT;
COMMENT ON FUNCTION oracle.sysdate() IS 'Ruturns statement timestamp at server time zone';

さらに、orafceのoracle.sysdate()のC言語のソースを追ってみる。。。
datefce.cのorafce_sysdateが本体であることがわかる
https://github.com/orafce/orafce/blob/master/builtins.h

extern PGDLLEXPORT Datum orafce_sysdate(PG_FUNCTION_ARGS);


https://github.com/orafce/orafce/blob/master/datefce.c

/********************************************************************
*
* ora_sysdate - sysdate
*
* Syntax:
*
* timestamp sysdate()
*
* Purpose:
*
* Returns statement_timestamp in server time zone
* Note - server time zone doesn't exists on PostgreSQL - emulated
* by orafce_timezone
*
********************************************************************/

Datum
orafce_sysdate(PG_FUNCTION_ARGS)
{
Datum sysdate;
Datum sysdate_scaled;

sysdate = DirectFunctionCall2(timestamptz_zone,
CStringGetTextDatum(orafce_timezone),
TimestampTzGetDatum(GetCurrentStatementStartTimestamp()));

/* necessary to cast to timestamp(0) to emulate Oracle's date */
sysdate_scaled = DirectFunctionCall2(timestamp_scale,
sysdate,
Int32GetDatum(0));

PG_RETURN_DATUM(sysdate_scaled);
}

および、GetCurrentStatementStartTimestamp()よりstatement_timestamp()であることがわかる
https://docs.huihoo.com/doxygen/postgresql/backend_2utils_2adt_2timestamp_8c_source.html#l01239

01239 statement_timestamp(PG_FUNCTION_ARGS)
01240 {
01241 PG_RETURN_TIMESTAMPTZ(GetCurrentStatementStartTimestamp());
01242 }








Oracleの検証に利用したコード、昔は、DBMS_LOCK.SLEEP()ってなんでDBMS_LOCKパッケージにあるの? と言う感じだったが、最近はわかりやすいDBMS_SESSIONパッケージが推奨で、DBMS_LOCK.SLEEP()は非推奨なのでご注意を
ore_seep(seonds) - UDF sample
CREATE OR REPLACE FUNCTION ore_sleep
(
seconds NUMBER
)
RETURN NUMBER
AS
BEGIN
$IF DBMS_DB_VERSION.VER_LE_12 $THEN
DBMS_LOCK.SLEEP(seconds);
$ELSE
DBMS_SESSION.SLEEP(seconds);
$END
RETURN 0;
END;
/




実行計画は、SQL文のレントゲン写真だ! Oracle Database編 (全部俺) Advent Calendar 2020

標準はあるにはあるが癖の多いSQL 全部俺 #1 Pagination
標準はあるにはあるが癖の多いSQL 全部俺 #2 関数名は同じでも引数が逆の罠!
標準はあるにはあるが癖の多いSQL 全部俺 #3 データ型確認したい時あるんです
標準はあるにはあるが癖の多いSQL 全部俺 #4 リテラル値での除算の内部精度も違うのよ!/a>
標準はあるにはあるが癖の多いSQL 全部俺 #5 和暦変換機能ある方が少数派

| | コメント (0)

2020年12月 5日 (土)

標準はあるにはあるが癖の多いSQL 全部俺 #5 和暦変換機能ある方が少数派

標準はあるにはあるが癖の多いSQL 全部俺w Advent Calendar 2020の5日目です。

これもあるのが当たり前だよねーと思っていると、ないの!! と言うありがちなネタで、日付の和暦変換など、

Oracleだとグローバリゼーション対応で組み込まれてます。昨年令和に切り替わったばかりなので、Oracleが中心の方々は、MySQLやPostgreSQL界隈は大丈夫なの?間に合うの?なんて話題も多かったことだろうと思います。
私もそうでした。でも心配する必要のあるのはOracleだけだったw と言う取り越し苦労でした。はい。

まず、Oracle

SCOTT@orcl> r
1 SELECT
2 TO_CHAR(
3 SYSDATE
4 , 'EEYY/MM/DD'
5 , 'NLS_CALENDAR = ''JAPANESE IMPERIAL'''
6 )
7 FROM
8* DUAL

TO_CHAR(SYSDATE,'EEYY/MM/DD','NLS_CALE
--------------------------------------
令和02/12/05

経過: 00:00:00.01
SCOTT@orcl>


Oracle 19c - Databaseグローバリゼーション・サポート・ガイド 3.7.1.4 紀元の年
https://docs.oracle.com/cd/F19136_01/nlspg/setting-up-globalization-support-environment.html#GUID-9674F2F3-D3A2-436A-83D1-7A8AC0D2B1ED


実は、年号が平成から令和切り替わると言う時になって始めて知ったのですが、みんな対応しているわけではないのですね。。和暦。
そう言う意味では、顧客要求をしっかり拾っていたと言うことなのでしょうね。

まだまだ、知らないことが多いSQLな世界w 


PostgreSQL

ないのでUDF等で対応ですよね

PostgreSQLの新元号への対応について
https://www.ashisuto.co.jp/support/gengo/product/postgresql.html

MySQL

ないのでUDF等で対応ですよね

と言うことで、RDS/Auroraにつても同様 この記事、現在は Snowflake - Principal Cloud Support Engineer の松崎さんの記事ですね!
https://aws.amazon.com/jp/blogs/news/how-to-determine-whether-kaigen-japan-era-name-transition-affects-your-mysql-compatible-engines-running-on-rds/"

Redshift
ないので、必要ならUDF等で対応ですよね




実行計画は、SQL文のレントゲン写真だ! Oracle Database編 (全部俺) Advent Calendar 2019

標準はあるにはあるが癖の多いSQL 全部俺 #1 Pagination
標準はあるにはあるが癖の多いSQL 全部俺 #2 関数名は同じでも引数が逆の罠!
標準はあるにはあるが癖の多いSQL 全部俺 #3 データ型確認したい時あるんです
標準はあるにはあるが癖の多いSQL 全部俺 #4 リテラル値での除算の内部精度も違うのよ!/a>

Oracle, SQL, MySQL, PostgreSQL, AWS | | コメント (0)

2020年12月 4日 (金)

標準はあるにはあるが癖の多いSQL 全部俺 #4 リテラル値での除算の内部精度も違うのよ!

標準はあるにはあるが癖の多いSQL 全部俺w Advent Calendar 2020の4日目です。

モルダー、あなた疲れてるのよ! 的なタイトルになってしまったw

エラーにはならないけど、この手の差異もなかなか嫌らしい差異ですよね。

結論から言うと、この差異の影響を避けるためにはデフォルトの挙動任せは危険かな。と言うことになるのですが、まあ、色々ありますよね。長いこと同じエンジン使って他ところへ乗り換えるとなると。

Oracle Database

なお、SQL*plusのnumformatパラメータは未設定の状態(デフォルト)です。

SQL> SELECT CAST((1.0/6.0) AS NUMBER(38,37)) FROM DUAL;

リテラル値の除算結果は小数点以下1桁の状態でデフォルトのキャストを利用した場合、内部的に小数点以下37桁精度。
実は、表示されている桁数は、SQL*Plusのnumformatの影響を受け、numformat(デフォルト小数点以下7桁)で丸る

一見 小数点以下8桁に見えるが、

SQL> SELECT CAST((9/7) AS NUMBER(38,37)) FROM DUAL;

CAST((9/7)ASNUMBER(38,37))
--------------------------
1.28571429


numformatの桁数を大きくすると内部的は小数点以下37桁精度!

SQL> set numformat "0.0999999999999999999999999999999999999"
SQL> SELECT CAST((9/7) AS NUMBER(38,37)) FROM DUAL;

CAST((9/7)ASNUMBER(38,37))
----------------------------------------
1.2857142857142857142857142857142857143

ね!

SQL> SELECT CAST((9.0/7.0) AS NUMBER(38,37)) FROM DUAL;

CAST((9.0/7.0)ASNUMBER(38,37))
----------------------------------------
1.2857142857142857142857142857142857143

SQL> SELECT CAST(CAST(9.0 AS NUMBER(38,37))/CAST(7.0 AS NUMBER(38,37)) AS NUMBER(38,37)) FROM DUAL;

CAST(CAST(9.0ASNUMBER(38,37))/CAST(7.0ASNUMBER(38,37))ASNUMBER(38,37))
----------------------------------------------------------------------
1.2857142857142857142857142857142857143

SQL> SELECT CAST(CAST(9.0 AS NUMBER(38,37))/CAST(7.0 AS NUMBER(38,37)) AS NUMBER(38,37)) FROM DUAL;

CAST(CAST(9.0ASNUMBER(38,37))/CAST(7.0ASNUMBER(38,37))ASNUMBER(38,37))
----------------------------------------------------------------------
1.2857142857142857142857142857142857143

Oracleの場合、返却時の精度が全ての計算精度に影響

SQL> SELECT CAST(CAST(9.0 AS NUMBER(38,8))/CAST(7.0 AS NUMBER(38,8)) AS NUMBER(38,37)) FROM DUAL;

CAST(CAST(9.0ASNUMBER(38,8))/CAST(7.0ASNUMBER(38,8))ASNUMBER(38,37))
--------------------------------------------------------------------
1.2857142857142857142857142857142857143

SQL> SELECT CAST(CAST(9.0 AS NUMBER(38,8))/CAST(7.0 AS NUMBER(38,8)) AS NUMBER(38,8)) FROM DUAL;

CAST(CAST(9.0ASNUMBER(38,8))/CAST(7.0ASNUMBER(38,8))ASNUMBER(38,8))
-------------------------------------------------------------------
1.2857142900000000000000000000000000000

SQL> SELECT CAST(CAST(9.0 AS NUMBER(38,37))/CAST(7.0 AS NUMBER(38,37)) AS NUMBER(38,8)) FROM DUAL;

CAST(CAST(9.0ASNUMBER(38,37))/CAST(7.0ASNUMBER(38,37))ASNUMBER(38,8))
---------------------------------------------------------------------
1.2857142900000000000000000000000000000

SQL> set numformat "0.09999999999999999999999999999999999999999999999"
SQL> SELECT CAST((9/7) AS NUMBER(38,37)) FROM DUAL;

CAST((9/7)ASNUMBER(38,37))
--------------------------------------------------
1.28571428571428571428571428571428571430000000000

SQL> SELECT CAST((9.0/7.0) AS NUMBER(38,37)) FROM DUAL;

CAST((9.0/7.0)ASNUMBER(38,37))
--------------------------------------------------
1.28571428571428571428571428571428571430000000000

SQL> SELECT CAST(CAST(9.0 AS NUMBER(38,37))/CAST(7.0 AS NUMBER(38,37)) AS NUMBER(38,37)) FROM DUAL;

CAST(CAST(9.0ASNUMBER(38,37))/CAST(7.0ASNUMBER(38,37))ASNUMBER(38,37))
----------------------------------------------------------------------
1.28571428571428571428571428571428571430000000000

PostgreSQLだとどうなるかと言うと、


整数として扱われ、除算結果もinteger型!

sql=> SELECT 9/7;

?column?
----------
1

pg_typeof
-----------
integer


リテラル値は小数点以下1桁の精度だが、除算結果は小数点以下16桁精度のnumeric型で返されるようだ。
PostgreSQLのマニュアルには記載されていないようだが、どこかに記載されてるのだろうか。。。知ってる方がいたらコメントお待ちしております。:)

sql=> SELECT 9.0/7.0;

?column?
--------------------
1.2857142857142857

pg_typeof
-----------
numeric

小数点以下の精度0でnumeric型にキャスト**した場合も、除算結果は小数点以下16桁精度のnumeric型となるようだが、これもPostgreSQLのマニュアルには記載されていないようだ。
なお、PostgreSQLの場合numeric型へのキャストで指定できる最大精度は1000と記載され内部的にはそれ以上の精度となっている
詳細は 

8.1.2. 任意の精度を持つ数
https://www.postgresql.jp/document/11/html/datatype-numeric.html#DATATYPE-NUMERIC-DECIMAL

表8.2 数値データ型
https://www.postgresql.jp/document/11/html/datatype-numeric.html#DATATYPE-NUMERIC-TABLE
を参照のこと

sql=> SELECT 9::NUMERIC(100,0)/7::NUMERIC(100,0);

?column?
--------------------
1.2857142857142857

pg_typeof
-----------
numeric

小数点以下精度1桁でnumeric型へキャスト**した場合も同様に、除算結果は小数点以下16桁のnumeric型になるのな。これ

sql=> SELECT 9::NUMERIC(100,1)/7::NUMERIC(100,1);

?column?
--------------------
1.2857142857142857

pg_typeof
-----------
numeric

同様に小数点以下2桁でnumeric型へキャストし、除算した結果も小数点以下16桁精度のnumeric型として返される模様。

sql=> SELECT 9::NUMERIC(100,2)/7::NUMERIC(100,2);

?column?
--------------------
1.2857142857142857

pg_typeof
-----------
numeric

小数点以下15桁のnumeric型にキャストした場合も結果は小数点以下16桁精度のnumeric型!

sql=> SELECT 9::NUMERIC(100,15)/7::NUMERIC(100,15);

?column?
--------------------
1.2857142857142857

pg_typeof
-----------
numeric

小数点以下16桁のnumber型にキャストした場合は、指定したscaleで返された。

sql=> SELECT 9::NUMERIC(100,16)/7::NUMERIC(100,16);

?column?
--------------------
1.2857142857142857

pg_typeof
--------------------
numeric

小数点以下17桁精度でnumeric型へキャストすると、指定した小数点以下17桁で除算結果が返された。
(どうやら、小数点以下16桁未満は小数点以下の精度を16桁として扱っているように見える

sql=> SELECT 9::NUMERIC(100,17)/7::NUMERIC(100,17);

?column?
---------------------
1.28571428571428571

pg_typeof
-----------
numeric


表示される桁数が16桁なので内部も16桁かと思ったら、少々多めに持っているらしい。このあたりマニュアルに記載がない....
内部でも小数点以下16精度なのか? という疑問を確認するための確認の結果、小数点以下20桁なので多少大きめの精度で持っているだが、この辺りもPostgreSQLのマニュアルを見る限り記載されていないようだ。

sql=> SELECT CAST((1.0/6.0) AS NUMERIC(38,37));

numeric
-----------------------------------------
0.1666666666666666666700000000000000000

しかし、小数点以下1桁のリテラル値については、小数点以下16桁の精度で計算されてしまう。(ルールはあるようだがドキュメントに明確な記載が見当たらないのは辛いとこと。

sql=> SELECT CAST((9.0/7.0) AS NUMERIC (38,37));

numeric
-----------------------------------------
1.2857142857142857000000000000000000000

結局のところ、デフォルトの挙動に任せず、必要な精度にキャストすることで必要な精度を持たせるようにすることでOracleのデフォルトの挙動と同様の精度になりそう。これが無難な対応なんだろうね。

sql=> SELECT CAST((9.0::NUMERIC(38,37)/7.0::NUMERIC(38,37)) AS NUMERIC(38,37));

numeric
-----------------------------------------
1.2857142857142857142857142857142857143


PostgreSQLでは可能な精度の検証。Oracleからの移行ではここまでの精度は必要としない、よね。多分。

sql=> SELECT 9::NUMERIC(100,99)/7::NUMERIC(100,99);

?column?
-------------------------------------------------------------------------------------------------------
1.285714285714285714285714285714285714285714285714285714285714285714285714285714285714285714285714286

pg_typeof
-----------
numeric

PostgreSQLで指定可能な最大精度(内部的な精度は1000を超えるがして可能な精度は1000)  

試して! Oracler皆びっくり! な感じ

sql=> SELECT 9::NUMERIC(1000,999)/7::NUMERIC(1000,999);

そして、
計算結果とそれぞれのリテラル値の精度ではどちらが優先されるのか確認したところ、Oracleとは異なり、最大精度ではなく、リテラル値の制度が優先される結果となった。この点、Oracleからの移行では注意が必要かな。

以下は、小数点以下の精度を37桁に統一した結果だが、この場合Oracleと同様の精度の結果が得られる

sql=> SELECT (9.0::NUMERIC(38,37)/7.0::NUMERIC(38,37))::NUMERIC(38,37);

numeric
-----------------------------------------
1.2857142857142857142857142857142857143

しかし、リテラル側の精度を落とし8桁にすると、16桁以下は全て16桁の精度になるという挙動が見られ流・

sql=> SELECT (9.0::NUMERIC(38,8)/7.0::NUMERIC(38,8))::NUMERIC(38,37);

numeric
-----------------------------------------
1.2857142857142857000000000000000000000

sql=> SELECT (9.0::NUMERIC(38,16)/7.0::NUMERIC(38,16))::NUMERIC(38,37);

numeric
-----------------------------------------
1.2857142857142857000000000000000000000

リテラル値の精度を17桁にすると、指定精度で結果を返すが、やはり計算結果の精度にはならない

sql=> SELECT (9.0::NUMERIC(38,17)/7.0::NUMERIC(38,17))::NUMERIC(38,37);

numeric
-----------------------------------------
1.2857142857142857100000000000000000000

さらに、17桁の精度で計算し結果を16桁精度で返す例。

sql=> SELECT (9.0::NUMERIC(38,17)/7.0::NUMERIC(38,17))::NUMERIC(38,16);

numeric
--------------------
1.2857142857142857

おまけ

Redshiftのnumeric型はPostgreSQL由来ではあるが、デフォルトの精度に関する挙動はPostgreSQLに近い。ただし、多少異なる部分もある。以下の例はPostgreSQL 11.xでは、小数点以下 20桁精度だったが、Redshiftでは16桁精度となっている。
微妙な違いだが違いがあるのは確かなので注意した方が良さげ

sql=# select cast((1.0/6.0) as numeric(38,37));

numeric
-----------------------------------------
0.1666666666666667000000000000000000000

噂のプログラム発動中だったのか。そんなの気にしてなかった。全くwwww



実行計画は、SQL文のレントゲン写真だ! Oracle Database編 (全部俺) Advent Calendar 2019

標準はあるにはあるが癖の多いSQL 全部俺 #1 Pagination
標準はあるにはあるが癖の多いSQL 全部俺 #2 関数名は同じでも引数が逆の罠!
標準はあるにはあるが癖の多いSQL 全部俺 #3 データ型確認したい時あるんです

| | コメント (0)

2020年12月 3日 (木)

標準はあるにはあるが癖の多いSQL 全部俺 #3 データ型確認したい時あるんです

標準はあるにはあるが癖の多いSQL 全部俺w Advent Calendar 2020の3日目です。

忙しい、今年も勢いで始めた割には、事前にネタの構想があったわけでもないというギリギリの状態で書いてますがw
なんとか3つ目の窓をあけました。:)

今回は、データ型確認したいことありませんか? という話。
Oracleを長年使い、PostgreSQL(互換含む)への移行という時に、調査していた時のこと、。。。

データ型見たいよね、これ。Oracleだとdump()で間接的にデータ型見れたなと。。。で他のエンジンではどうなのよ。。。と調べ始めたら結構大変でした。。
という2年半ぐらい前の苦労を思い出しつつ書いてみますw

調べていくと、わかりやすい関数名だったり、ありそうでないものもあるんですよね。。。。まさに、非互換の多い部分だった。。。

まず、Oracle
おなじみのdump()関数ですね。typ=nn の数字でデータ型を判断します. typ=2は、NUMBER型、typ=96は、CHAR型ですね。

SQL> select dump(123) from dual;

DUMP(123)
---------------------
Typ=2 Len=3: 194,2,24

SQL> select dump(123,8) from dual;

DUMP(123,8)
---------------------
Typ=2 Len=3: 302,2,30

SQL> select dump(123,10) from dual;

DUMP(123,10)
---------------------
Typ=2 Len=3: 194,2,24

SQL> select dump(123,16) from dual;

DUMP(123,16)
--------------------
Typ=2 Len=3: c2,2,18

SQL> select dump(123,17) from dual;

DUMP(123,17)
---------------------
Typ=2 Len=3: c2,^B,^X

SQL>
SQL> select dump('123',1016) from dual;

DUMP('123',1016)
--------------------------------------------
Typ=96 Len=3 CharacterSet=AL32UTF8: 31,32,33


次は、Postgresql

pg_typeof()って関数が使えます。結果がデータ型名で返されるのでわかりやすい!

sql=> select pg_typeof(123);
pg_typeof
-----------
integer
(1 row)

sql=> select pg_typeof('123'::text);
pg_typeof
-----------
text
(1 row)

sql=> select pg_typeof(now());
pg_typeof
--------------------------
timestamp with time zone
(1 row)

Athena

Prestoで使える関数なので、そのまま typeof()って関数でこれもデータ型名で返されます。
なぜ、Athenaかって? 勢いですかねぇ。

% aws athena start-query-execution --query-string "select typeof(123);" --result-configuration OutputLocation=s3://xxxx-athena-results
--------------------------------------------------------------
| StartQueryExecution |
+-------------------+----------------------------------------+
| QueryExecutionId | f658de1e-b711-433d-b603-15835b6e5de5 |
+-------------------+----------------------------------------+
%
% aws athena get-query-results --query-execution-id 92f46e33-0b2e-4e94-90b7-8acb3d6fce3b --output text | grep DATA
DATA _col0
DATA integer


Redshift

N/A


MySQL
もし、あったらツッコミよろしくお願いします。 m(_ _)m

N/A
 


参考

Oracle - DUMP
https://docs.oracle.com/en/database/oracle/oracle-database/19/sqlrf/DUMP.html#GUID-A05793C9-B35D-4BA7-B68C-E3693BCF47A5

Oracle Built-in Data Types
https://docs.oracle.com/en/database/oracle/oracle-database/19/sqlrf/Data-Types.html#GUID-7B72E154-677A-4342-A1EA-C74C1EA928E6

PostgreSQL - 表9.63 システムカタログ情報関数 - pg_typeof
https://www.postgresql.jp/document/11/html/functions-info.html#FUNCTIONS-INFO-CATALOG-TABLE

Athena - 6.4. Conversion Functions - typeof
https://prestodb.io/docs/0.172/functions/conversion.html




実行計画は、SQL文のレントゲン写真だ! Oracle Database編 (全部俺) Advent Calendar 2019

標準はあるにはあるが癖の多いSQL 全部俺 #1 Pagination
標準はあるにはあるが癖の多いSQL 全部俺 #2 関数名は同じでも引数が逆の罠!

| | コメント (0)

2020年12月 2日 (水)

標準はあるにはあるが癖の多いSQL 全部俺 #2 関数名は同じでも引数が逆の罠!

標準はあるにはあるが癖の多いSQL 全部俺w Advent Calendar 2020の2日目です。

今日は、心と時間の余裕がないので、軽めですw

いきなりですがタイトルの通り、関数名が同じなら引数の並びや数も一緒だ!

と決めつけちゃいけないw 案件です。 数時間ハマった挙句、マニュアルを読み直すという王道で解決した事案ですはい。マニュアル読みましょうね。読みづらいのもあるけど。。

現在の私、何をやってるかピンボケ感満載なロール名ではあるのですが、その名の通り、OracleのSQLで質問もうけるわ、たまには、SparkSQLでも質問受けたりしますw

そのSparkSQLでハマったのがrtrim(),ltrim()。

長年Oracleを使ってきたので、手癖でタイプしちゃうわけですよ! 思い込み、ダメ絶対!w

では、その大切なマニュアルの解説でRDBMSの有名どころのltrim/rtrimとSparkSQLのltrim/rtrimのシンタックスを確認してみましょう。

まず、Oracleは以下の通り。見たなれ安心感w

LTRIM( str [, trimStr] )str : トリムされるソースの文字列型または、リテラル文字列trimStr : トリムしたい文字列。デフォルトは、半角空白1文字
https://docs.oracle.com/cd/F19136_01/sqlrf/RTRIM.html#GUID-95A7DAFB-F7AB-48F4-BE24-64B3C7A840AA

次、PostgreSQL

RTRIM( str [, trimStr] )str : トリムされるソースの文字列型または、リテラル文字列trimStr : トリムしたい文字列。デフォルトは、半角空白1文字
https://www.postgresql.jp/document/11/html/functions-string.html

ついでなので、Redshift
PostgreSQLと同じですね。

RTRIM( string, trim_chars ) string : 切り捨てる文字列の列または式。 trim_chars : 末尾から切り捨てる文字を表す、文字列の列または式。
https://docs.aws.amazon.com/ja_jp/redshift/latest/dg/r_RTRIM.html


MySQL
MySQLのRTRIMには第二引数は無い! 単体では同じことができないので、他の関数と組み合わせるんでしょうね。(試してないですが)

RTRIM( str )str : トリムされるソースの文字列型または、リテラル文字列
https://dev.mysql.com/doc/refman/5.7/en/string-functions.html#function_rtrim

そして、最後に、今回ハマった
SparkSQL

RTRIM( [trimStr ,] str )str : トリムされるソースの文字列型または、リテラル文字列trimStr : トリムしたい文字列。デフォルトは、半角空白1文字
トリムしたい文字列の引数位置が、Oracle/PostgreSQL/Redshiftとは逆なので引数が少ないMySQLと異なりシンタックスエラーにならない><
https://spark.apache.org/docs/2.3.1/api/sql/index.html#rtrim

rtrim()も同じです。

Oracle
https://docs.oracle.com/cd/F19136_01/sqlrf/RTRIM.html#GUID-95A7DAFB-F7AB-48F4-BE24-64B3C7A840AA

PostgreSQL
https://docs.oracle.com/cd/F19136_01/sqlrf/RTRIM.html#GUID-95A7DAFB-F7AB-48F4-BE24-64B3C7A840AA

Redshift
https://docs.oracle.com/cd/F19136_01/sqlrf/RTRIM.html#GUID-95A7DAFB-F7AB-48F4-BE24-64B3C7A840AA

MySQL
https://docs.oracle.com/cd/F19136_01/sqlrf/RTRIM.html#GUID-95A7DAFB-F7AB-48F4-BE24-64B3C7A840AA

SparkSQL
https://docs.oracle.com/cd/F19136_01/sqlrf/RTRIM.html#GUID-95A7DAFB-F7AB-48F4-BE24-64B3C7A840AA


簡単な例を

SparkSQL

>>> SQL="select rtrim(' ', 'SparkSQL ') as d"
>>> spark.sql(SQL).show()
+--------+
| d |
+--------+
|SparkSQL|
+--------+

Oracle

SQL> select '|' || rtrim('SparkSQL ', ' ') || '|' as d from dual;
D
----------
|SparkSQL|

PostgreSQL / Redshift

test=> select '|' || rtrim('SparkSQL ', ' ') || '|' as d;
d
------------
|SparkSQL|



実行計画は、SQL文のレントゲン写真だ! Oracle Database編 (全部俺) Advent Calendar 2019

標準はあるにはあるが癖の多いSQL 全部俺 #1 Pagination

| | コメント (0)

2020年12月 1日 (火)

標準はあるにはあるが癖の多いSQL 全部俺 #1 Pagination

いよいよ始まりました。Advent Calendar 2020 
今年も勢いで全部俺ですw

JPOUG Advent Calendar 2020もよろしくお願いします!
(最後まで書けるのか、書き抜ける喜びw どこかのCMっぽくなってしまいましたが、第一日めの窓を開けましょうw)


今年の全部俺はレントゲンではなく、標準はあれど、非常に癖の多いSQLを25回に渡り、眠い目を擦りながら書きづつけて行きたい(すでに希望になってるw)と思っております。はい。

先日、AthenaでLIMIT句使おうとして、エラーに遭遇したところからw

Oracle/MySQL/PostgreSQL/Redshiftとか LIMIT OFFSET的ところから違うわけですが(同じ部分もあります)、何も考えずに、Athenaに投げて、撃沈w
Prestoの311以降だとLIMIT OFFSETでPagination可能なわけですが、Amazon Athenaは今の所(2020/12/1現在)Presto 0.172なのをすっかり忘れてたわけです。はい。さーせん。

あ〜、SQLってバージョンでもそうですが、エンジン違えば、気が狂うw程度に違う時があって、き〜〜〜って。なることしばしば。
で、イラっとしたSQLの違いを Oracleの構文と比較しながら自分の備忘録として書いて残しておこうと思った次第です。

(なーんだ、自分の為か、と思わないでくださいね。明日はわが身かもしれませんよw)

以下、どの構文がどのエンジンで通るのかをざっとまとめたもの。

1.ROWNUMとWHERE句によるPagination
Oracle

SELECT
id
FROM (
SELECT
ROWNUM as ln
,id
FROM
hoge
ORDER BY id
)
WHERE
ln BETWEEN 1 AND 100;

2.ROW_NUMBER()ウィンドウ関数とWHERE句によるPagination
意外に使えるw 可読性悪いけどねー

Oracle / PostgreSQL / Redshift / Athena

SELECT
id
FROM (
SELECT
ROW_NUMBER() OVER(
ORDER BY id
) AS ln
,id
FROM
hoge
)
WHERE
ln BETWEEN 1 AND 100;


3.OFFSET句とFETCH FIRST n ROWS ONLYのPagination
Oracle / PostgreSQL

SELECT
id
FROM
hoge
ORDER BY
id
OFFSET 0 ROW
FETCH FIRST 100 ROWS ONLY;


4.LIMIT句とOFFSET句のPagination
PostgreSQL / MySQL / Redshift

SELECT
id
FROM
hoge
ORDER BY
id
LIMIT 100 OFFSET 0;


ちなみに、Oracleでは、2.のROW_NUMBER()と3.のOFFSET + FETCHの構文の実行計画は同じなので、可読性が高い2.と3.いずれかと言われれば3.がおすすめ。

----------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 10 | 260 | 3 (0)| 00:00:01 |
|* 1 | VIEW | | 10 | 260 | 3 (0)| 00:00:01 |
|* 2 | WINDOW NOSORT STOPKEY| | 10 | 50 | 3 (0)| 00:00:01 |
| 3 | INDEX FULL SCAN | HOGE_PK | 1000K| 4882K| 3 (0)| 00:00:01 |
-----------------------------------------------------------------------------------

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

1 - filter("LN">=1 AND "LN"<=100)
2 - filter(ROW_NUMBER() OVER ( ORDER BY "ID")<=100)

----------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 10 | 390 | 3 (0)| 00:00:01 |
|* 1 | VIEW | | 10 | 390 | 3 (0)| 00:00:01 |
|* 2 | WINDOW NOSORT STOPKEY| | 10 | 50 | 3 (0)| 00:00:01 |
| 3 | INDEX FULL SCAN | HOGE_PK | 1000K| 4882K| 3 (0)| 00:00:01 |
-----------------------------------------------------------------------------------

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

1 - filter("from$_subquery$_002"."rowlimit_$$_rownumber"<=100 AND
"from$_subquery$_002"."rowlimit_$$_rownumber">0)
2 - filter(ROW_NUMBER() OVER ( ORDER BY "ID")<=100)



参考
Oracle
https://docs.oracle.com/cd/E82638_01/sqlrf/ROWNUM-Pseudocolumn.html#GUID-2E40EC12-3FCF-4A4F-B5F2-6BC669021726
https://docs.oracle.com/cd/F19136_01/sqlrf/SELECT.html#GUID-CFA006CA-6FF1-4972-821E-6996142A51C6

MySQL
https://dev.mysql.com/doc/refman/8.0/en/select.html

PostgreSQL
https://www.postgresql.jp/document/11/html/queries-limit.html

Reshift
https://docs.aws.amazon.com/ja_jp/redshift/latest/dg/r_ORDER_BY_clause.html

Amazon Athena
https://docs.aws.amazon.com/ja_jp/athena/latest/ug/select.html



実行計画は、SQL文のレントゲン写真だ! Oracle Database編 (全部俺) Advent Calendar 2019


寝ぼけながら書いているので、誤り等ございましたらご指摘願います。
仕事忙しいのに全部俺始めてしまい、かなり不安なスタートw(この時間だし)

| | コメント (0)

2020年7月26日 (日)

RDS Oracle 雑多なメモ#21 / DBMS_DATAPUMPパッケージ Schema mode de expdp/impdp - metadata onlyとデータのインポート

Previously, Mac De Oracle...

RDS Oracle 雑多なメモ#20 / DBMS_DATAPUMPパッケージ Schema mode de expdp/impdpの準備 SQL_FILEモードでDDL抜き出し

でした。

今回は、RDS Oracleへスキーマ単位のインポートでメタデータだけをインポートするにはどうするかというおはなし。

メタデータだけをインポートするにはこれまでに何度か話題にしたエクスポートされたオブジェクトとその階層を表すオブジェクトパスが重要な意味を持っています。

まずはフルエクスポートログにリストされるオブジェクトパスの例をご覧ください。

Processing object type DATABASE_EXPORT/EARLY_OPTIONS/VIEWS_AS_TABLES/TABLE_DATA
Processing object type DATABASE_EXPORT/NORMAL_OPTIONS/TABLE_DATA
Processing object type DATABASE_EXPORT/NORMAL_OPTIONS/VIEWS_AS_TABLES/TABLE_DATA
Processing object type DATABASE_EXPORT/SCHEMA/TABLE/TABLE_DATA
Processing object type DATABASE_EXPORT/SCHEMA/PACKAGE_BODIES/PACKAGE/PACKAGE_BODY
Processing object type DATABASE_EXPORT/SCHEMA/TABLE/INDEX/STATISTICS/INDEX_STATISTICS
Processing object type DATABASE_EXPORT/SCHEMA/TABLE/INDEX/STATISTICS/FUNCTIONAL_INDEX/INDEX_STATISTICS
Processing object type DATABASE_EXPORT/SCHEMA/TABLE/STATISTICS/TABLE_STATISTICS
Processing object type DATABASE_EXPORT/STATISTICS/MARKER
Processing object type DATABASE_EXPORT/PRE_SYSTEM_IMPCALLOUT/MARKER
Processing object type DATABASE_EXPORT/PRE_INSTANCE_IMPCALLOUT/MARKER
Processing object type DATABASE_EXPORT/TABLESPACE
Processing object type DATABASE_EXPORT/PROFILE
Processing object type DATABASE_EXPORT/SCHEMA/USER
Processing object type DATABASE_EXPORT/ROLE
Processing object type DATABASE_EXPORT/RADM_FPTM
Processing object type DATABASE_EXPORT/GRANT/SYSTEM_GRANT/PROC_SYSTEM_GRANT
Processing object type DATABASE_EXPORT/SCHEMA/GRANT/SYSTEM_GRANT
Processing object type DATABASE_EXPORT/SCHEMA/ROLE_GRANT
Processing object type DATABASE_EXPORT/SCHEMA/DEFAULT_ROLE
Processing object type DATABASE_EXPORT/SCHEMA/ON_USER_GRANT
Processing object type DATABASE_EXPORT/SCHEMA/TABLESPACE_QUOTA
Processing object type DATABASE_EXPORT/RESOURCE_COST
Processing object type DATABASE_EXPORT/TRUSTED_DB_LINK
Processing object type DATABASE_EXPORT/SCHEMA/SEQUENCE/SEQUENCE
Processing object type DATABASE_EXPORT/DIRECTORY/DIRECTORY
Processing object type DATABASE_EXPORT/DIRECTORY/GRANT/OWNER_GRANT/OBJECT_GRANT
Processing object type DATABASE_EXPORT/DIRECTORY/GRANT/WITH_GRANT_OPTION/OBJECT_GRANT
Processing object type DATABASE_EXPORT/CONTEXT
Processing object type DATABASE_EXPORT/SCHEMA/PUBLIC_SYNONYM/SYNONYM
Processing object type DATABASE_EXPORT/SCHEMA/TYPE/TYPE_SPEC
Processing object type DATABASE_EXPORT/SYSTEM_PROCOBJACT/PRE_SYSTEM_ACTIONS/PROCACT_SYSTEM
Processing object type DATABASE_EXPORT/SYSTEM_PROCOBJACT/PROCOBJ
Processing object type DATABASE_EXPORT/SYSTEM_PROCOBJACT/POST_SYSTEM_ACTIONS/PROCACT_SYSTEM
Processing object type DATABASE_EXPORT/SCHEMA/PROCACT_SCHEMA
Processing object type DATABASE_EXPORT/EARLY_OPTIONS/VIEWS_AS_TABLES/TABLE
Processing object type DATABASE_EXPORT/EARLY_POST_INSTANCE_IMPCALLOUT/MARKER
Processing object type DATABASE_EXPORT/NORMAL_OPTIONS/TABLE

上記オブジェクトパスツリーを一部省略しつつ見やすくすると以下のようなツリー構造になっているのが理解しやすいはず。

20200726-10936

図にも書いていますが、メタデータのみをインポートするにはデータを除外(Exclude)してしまえばよいわけです。

DATABASE_EXPORT/SCHEMA/TABLE/TABLE_DATA

また、同じツリーの階層にあるオブジェクトもスキーマレベルのインポートではインポートされないということも理解しやすいはずです。:)

なお、DATAPUMPが扱うオブジェクトパスの詳細は 
データベース・リファレンス - 6.238 SCHEMA_EXPORT_OBJECTS
を参照してくださいね。知らない方は多いですが、DATAPUMPと仲良くなるためには必要なビューです。



では、スキーマモードのメタデータオンリーインポートの仕込みから
同じデータベースへスキーマをインポートするので事前に削除しておきます。

BILL> drop user hoge cascade;

User dropped.

BILL> drop profile fizzbuzz;

Profile dropped.

BILL> drop role fizzbuzz;

Role dropped.

BILL> drop tablespace fizzbuzz including contents and datafiles;

Tablespace dropped.

たとえばこの状態でスキーマレベルのインポートを行ってしまうと、もう、想像はできていると思いますが、依存オブジェクト不足によりインポートは失敗します。
ユーザーのデフォルト表領域や依存するプロファイルが存在しない状態ではインポート時に実行されるCREATE USER文がエラーとなりインポートはエラーで終了することになります。

BILL> @imp_schema_metadataonly data_pump_dir fullexp hoge
Master table "BILL"."SYS_IMPORT_SCHEMA_03" successfully loaded/unloaded
Starting "BILL"."SYS_IMPORT_SCHEMA_03":
Processing object type DATABASE_EXPORT/SCHEMA/USER
ORA-39083: Object type USER:"HOGE" failed to create with error:
ORA-02380: profile FIZZBUZZ does not exist

Failing sql is:
CREATE USER "HOGE" IDENTIFIED BY VALUES

...中略...

TABLESPACE "FIZZBUZZ" TEMPORARY TABLESPACE "TEMP" PROFILE "FIZZBUZZ"

Processing object type DATABASE_EXPORT/SCHEMA/ROLE_GRANT
ORA-39083: Object type ROLE_GRANT failed to create with error:
ORA-01917: user or role 'HOGE' does not exist

Failing sql is:
GRANT "CONNECT" TO "HOGE"

ORA-39083: Object type ROLE_GRANT failed to create with error:
ORA-01924: role 'FIZZBUZZ' not granted or does not exist

Failing sql is:
GRANT "FIZZBUZZ" TO "HOGE"

Processing object type DATABASE_EXPORT/SCHEMA/DEFAULT_ROLE
ORA-39083: Object type DEFAULT_ROLE:"HOGE" failed to create with error:
ORA-01918: user 'HOGE' does not exist

...中略...

Job "BILL"."SYS_IMPORT_SCHEMA_03" completed with 7 error(s) at Fri Jul 24 17:51:45 2020 elapsed 0 00:00:03

PL/SQL procedure successfully completed.


では、上記のようなエラーを回避するため、前回フルエクスポートから取り出したDDL を実行して作成します。

BILL> CREATE BIGFILE TABLESPACE "FIZZBUZZ" DATAFILE
2 SIZE 104857600
3 AUTOEXTEND ON NEXT 104857600 MAXSIZE 1073741824
4 LOGGING ONLINE PERMANENT BLOCKSIZE 8192
5 EXTENT MANAGEMENT LOCAL AUTOALLOCATE DEFAULT
6 NOCOMPRESS SEGMENT SPACE MANAGEMENT AUTO;

Tablespace created.

BILL> CREATE ROLE "FIZZBUZZ";

Role created.

BILL> CREATE PROFILE "FIZZBUZZ"
2 LIMIT
3 COMPOSITE_LIMIT DEFAULT
4 SESSIONS_PER_USER DEFAULT
5 CPU_PER_SESSION DEFAULT
6 CPU_PER_CALL DEFAULT
7 LOGICAL_READS_PER_SESSION DEFAULT
8 LOGICAL_READS_PER_CALL DEFAULT
9 IDLE_TIME UNLIMITED
10 CONNECT_TIME DEFAULT
11 PRIVATE_SGA DEFAULT
12 FAILED_LOGIN_ATTEMPTS DEFAULT
13 PASSWORD_LIFE_TIME DEFAULT
14 PASSWORD_REUSE_TIME DEFAULT
15 PASSWORD_REUSE_MAX DEFAULT
16 PASSWORD_VERIFY_FUNCTION DEFAULT
17 PASSWORD_LOCK_TIME DEFAULT
18 PASSWORD_GRACE_TIME DEFAULT
19 INACTIVE_ACCOUNT_TIME DEFAULT ;

Profile created.


準備ができたので、メタデータオンリーのスキーマモードインポートを試してみます。
スキーマ以下のオブジェクトはインポート(統計情報をフィルタするのを忘れましたがw)できました。hoge表には1行だけデータがありますがデータはインポートされていないことが確認できるはずです。

BILL> @imp_schema_metadataonly data_pump_dir fullexp hoge
Master table "BILL"."SYS_IMPORT_SCHEMA_04" successfully loaded/unloaded
Starting "BILL"."SYS_IMPORT_SCHEMA_04":
Processing object type DATABASE_EXPORT/SCHEMA/USER
Processing object type DATABASE_EXPORT/SCHEMA/ROLE_GRANT
Processing object type DATABASE_EXPORT/SCHEMA/DEFAULT_ROLE
Processing object type DATABASE_EXPORT/SCHEMA/TABLESPACE_QUOTA
Processing object type DATABASE_EXPORT/SCHEMA/PROCACT_SCHEMA
Processing object type DATABASE_EXPORT/SCHEMA/TABLE/TABLE
Processing object type DATABASE_EXPORT/SCHEMA/TABLE/STATISTICS/TABLE_STATISTICS
Processing object type DATABASE_EXPORT/STATISTICS/MARKER
Job "BILL"."SYS_IMPORT_SCHEMA_04" successfully completed at Fri Jul 24 17:56:34 2020 elapsed 0 00:00:13

PL/SQL procedure successfully completed.

BILL> select username from dba_users where username='HOGE';

USERNAME
------------------------------
HOGE

BILL> select count(1) from hoge.hoge;

COUNT(1)
----------
0


では次にデータだけをインポートしてみます。
TABLE_DATAのみをインポートする方法と、スキーマインポートで表が存在する場合に、データをTRUNCATE後、データインポートする方法があります。(表が存在している場合のデフォルトの動作はデータインポートのスキップです)
以下の例では 通常 のスキーマインポートで表が存在する場合 、既存データをTRUNCATEして データをインポートする方法で行ってます。ユーザーが存在する場合にはCREATE USERは失敗し表が存在した場合にtruncate後にデータがインポートされます

BILL> @imp_schema data_pump_dir fullexp hoge
Master table "BILL"."SYS_IMPORT_SCHEMA_01" successfully loaded/unloaded
Starting "BILL"."SYS_IMPORT_SCHEMA_01":
Processing object type DATABASE_EXPORT/SCHEMA/USER
ORA-31684: Object type USER:"HOGE" already exists

Processing object type DATABASE_EXPORT/SCHEMA/ROLE_GRANT
Processing object type DATABASE_EXPORT/SCHEMA/DEFAULT_ROLE
Processing object type DATABASE_EXPORT/SCHEMA/TABLESPACE_QUOTA
Processing object type DATABASE_EXPORT/SCHEMA/PROCACT_SCHEMA
Processing object type DATABASE_EXPORT/SCHEMA/TABLE/TABLE
Table "HOGE"."HOGE" exists and has been truncated.
Data will be loaded but all dependent metadata will be skipped due to table_exists_action of truncate
Processing object type DATABASE_EXPORT/SCHEMA/TABLE/TABLE_DATA
. . imported "HOGE"."HOGE" 5.046 KB 1 rows
Processing object type DATABASE_EXPORT/SCHEMA/TABLE/STATISTICS/TABLE_STATISTICS
Processing object type DATABASE_EXPORT/STATISTICS/MARKER
Job "BILL"."SYS_IMPORT_SCHEMA_01" completed with 1 error(s) at Fri Jul 24 18:01:30 2020 elapsed 0 00:00:05

PL/SQL procedure successfully completed.

BILL> select count(1) from hoge.hoge;

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

スクリプトの例は以下のとおり
DBMS_DATAPUMP.METADATA_FILTER()プロシージャでデータを示すオブジェクトパス(DATABASE_EXPORT/SCHEMA/TABLE/TABLE_DATA)を除外しているところがポイント

BILL> !cat imp_schema_metadataonly.sql
SET VERIFY OFF
SET SERVEROUTPUT ON
DECLARE
v4Debug VARCHAR2(200);
cDirectory CONSTANT VARCHAR2(30) := UPPER('&1');
cDumpFileName CONSTANT VARCHAR2(64) := '&2'||'.dmp';
cLogFileName CONSTANT VARCHAR2(64) := '&2'||'.log';
cSchemaName CONSTANT VARCHAR2(30) := UPPER('&3');
cExcludePath CONSTANT VARCHAR2(128) := 'DATABASE_EXPORT/SCHEMA/TABLE/TABLE_DATA';
i NUMBER;
vDataPumpJobHandle NUMBER;
vProgress_ratio NUMBER;
vJobState VARCHAR2(30);
oLogEntry ku$_LogEntry;
oStatus ku$_Status;
BEGIN
DBMS_OUTPUT.ENABLE;

v4Debug := 'OPEN';
vDataPumpJobHandle
:= DBMS_DATAPUMP.OPEN (
operation => 'IMPORT'
,job_mode => 'SCHEMA'
,job_name => NULL
,remote_link => NULL
);

v4Debug := 'ADD_FILE - dumpfile';
DBMS_DATAPUMP.ADD_FILE (
handle => vDataPumpJobHandle
,filename => cDumpFileName
,directory => cDirectory
,filetype => DBMS_DATAPUMP.KU$_FILE_TYPE_DUMP_FILE
);

v4Debug := 'ADD_FILE - logfile';
DBMS_DATAPUMP.ADD_FILE (
handle => vDataPumpJobHandle
,filename => cLogFileName
,directory => cDirectory
,filetype => DBMS_DATAPUMP.KU$_FILE_TYPE_LOG_FILE
);

v4Debug := 'METADATA_FILTER - schema name';
DBMS_DATAPUMP.METADATA_FILTER (
handle => vDataPumpJobHandle
,name => 'SCHEMA_LIST'
,value => '''' || cSchemaName || ''''
);

v4Debug := 'EXCLUDE_PATH='||cExcludePath;
DBMS_DATAPUMP.METADATA_FILTER (
handle => vDataPumpJobHandle
,name => 'EXCLUDE_PATH_LIST'
,value => '''' || cExcludePath || ''''
);

v4Debug := 'START_JOB';
DBMS_DATAPUMP.START_JOB (
handle => vDataPumpJobHandle
);

v4Debug := 'JOB_STATE';
vProgress_ratio := 0;
vJobState := 'UNDEFINED';
WHILE (vJobState != 'COMPLETED') AND (vJobState != 'STOPPED') LOOP
DBMS_DATAPUMP.GET_STATUS (
vDataPumpJobHandle
,DBMS_DATAPUMP.KU$_STATUS_JOB_ERROR
+ DBMS_DATAPUMP.KU$_STATUS_JOB_STATUS
+ DBMS_DATAPUMP.KU$_STATUS_WIP
,-1
,vJobState
,oStatus
);

IF (BITAND(oStatus.mask, DBMS_DATAPUMP.KU$_STATUS_WIP) != 0)
THEN
oLogEntry := oStatus.wip;
ELSE
IF (BITAND(oStatus.mask, DBMS_DATAPUMP.KU$_STATUS_JOB_ERROR) != 0)
THEN
oLogEntry := oStatus.error;
ELSE
oLogEntry := NULL;
END IF;
END IF;
IF oLogEntry IS NOT NULL
THEN
i := oLogEntry.FIRST;
WHILE i IS NOT NULL LOOP
DBMS_OUTPUT.PUT_LINE(oLogEntry(i).LogText);
i := oLogEntry.NEXT(i);
END LOOP;
END IF;
END LOOP;

DBMS_DATAPUMP.DETACH(vDataPumpJobHandle);
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE(sqlerrm());
DBMS_OUTPUT.PUT_LINE(v4Debug);
RAISE;
END;
/

UNDEFINE 1
UNDEFINE 2
UNDEFINE 3
SET SERVEROUTPUT OFF
SET VERIFY ON

DBMS_DATAPUMP.SET_PARAMETER()でTABLE_EXISTS_ACTION (表が存在する場合)でTRUNCATE(既存データのトランケート後データをインポート)する支持をしています。

BILL> !cat imp_schema.sql
SET VERIFY OFF
SET SERVEROUTPUT ON
DECLARE
v4Debug VARCHAR2(200);
cDirectory CONSTANT VARCHAR2(30) := UPPER('&1');
cDumpFileName CONSTANT VARCHAR2(64) := '&2'||'.dmp';
cLogFileName CONSTANT VARCHAR2(64) := '&2'||'.log';
cSchemaName CONSTANT VARCHAR2(30) := UPPER('&3');
i NUMBER;
vDataPumpJobHandle NUMBER;
vProgress_ratio NUMBER;
vJobState VARCHAR2(30);
oLogEntry ku$_LogEntry;
oStatus ku$_Status;
BEGIN
DBMS_OUTPUT.ENABLE;

v4Debug := 'OPEN';
vDataPumpJobHandle
:= DBMS_DATAPUMP.OPEN (
operation => 'IMPORT'
,job_mode => 'SCHEMA'
,remote_link => NULL
);

v4Debug := 'ADD_FILE - dumpfile';
DBMS_DATAPUMP.ADD_FILE (
handle => vDataPumpJobHandle
,filename => cDumpFileName
,directory => cDirectory
,filetype => DBMS_DATAPUMP.KU$_FILE_TYPE_DUMP_FILE
);

v4Debug := 'ADD_FILE - logfile';
DBMS_DATAPUMP.ADD_FILE (
handle => vDataPumpJobHandle
,filename => cLogFileName
,directory => cDirectory
,filetype => DBMS_DATAPUMP.KU$_FILE_TYPE_LOG_FILE
);

v4Debug := 'METADATA_FILTER - schema name';
DBMS_DATAPUMP.METADATA_FILTER (
handle => vDataPumpJobHandle
,name => 'SCHEMA_LIST'
,value => '''' || cSchemaName || ''''
);

v4Debug := 'TABLE_EXISTS_ACTION=TRUNCATE';
DBMS_DATAPUMP.SET_PARAMETER (
handle => vDataPumpJobHandle
,name => 'TABLE_EXISTS_ACTION'
,value => 'TRUNCATE'
);

v4Debug := 'START_JOB';
DBMS_DATAPUMP.START_JOB (
handle => vDataPumpJobHandle
);

v4Debug := 'JOB_STATE';
vProgress_ratio := 0;
vJobState := 'UNDEFINED';
WHILE (vJobState != 'COMPLETED') AND (vJobState != 'STOPPED') LOOP
DBMS_DATAPUMP.GET_STATUS (
vDataPumpJobHandle
,DBMS_DATAPUMP.KU$_STATUS_JOB_ERROR
+ DBMS_DATAPUMP.KU$_STATUS_JOB_STATUS
+ DBMS_DATAPUMP.KU$_STATUS_WIP
,-1
,vJobState
,oStatus
);

IF (BITAND(oStatus.mask, DBMS_DATAPUMP.KU$_STATUS_WIP) != 0)
THEN
oLogEntry := oStatus.wip;
ELSE
IF (BITAND(oStatus.mask, DBMS_DATAPUMP.KU$_STATUS_JOB_ERROR) != 0)
THEN
oLogEntry := oStatus.error;
ELSE
oLogEntry := NULL;
END IF;
END IF;
IF oLogEntry IS NOT NULL
THEN
i := oLogEntry.FIRST;
WHILE i IS NOT NULL LOOP
DBMS_OUTPUT.PUT_LINE(oLogEntry(i).LogText);
i := oLogEntry.NEXT(i);
END LOOP;
END IF;
END LOOP;

DBMS_DATAPUMP.DETACH(vDataPumpJobHandle);
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE(sqlerrm());
DBMS_OUTPUT.PUT_LINE(v4Debug);
RAISE;
END;
/

UNDEFINE 1
UNDEFINE 2
UNDEFINE 3
SET SERVEROUTPUT OFF
SET VERIFY ON


今回は、上記2つのスクリプトに分けましたが、1つにまとめるように作り変えればより便利できますよ! それはみなさんへの宿題w 

ということで今回のネタはおしまい :)




Data Pumpも癖モノだよね〜w その1 - queryパラメーターの解析タイミング
Data Pumpも癖モノだよね〜w その2 - Materialized ViewをTableとして移行する
Data Pumpも癖モノだよね〜w その3 - dbms_job と dbms_scheduler との複雑な関係
Data Pumpも癖モノだよね〜w その4 - schemaモードでMviewを他のPDBへ複製
Data Pumpも癖モノだよね〜w その4と1/2 - schemaモードでMviewを他のPDBへ複製 (紛らわしいステータスw)
Data Pumpも癖モノだよね〜w その5 - schemaモードでMviewを他のPDBへ複製(オプジェクトパス de 絞り込み)
Data Pumpも癖モノだよね〜w その6 - schemaモードでMviewを他のPDBへ複製(オプジェクトパスが不足すると...


RDS Oracle 雑多なメモ#1 / FAQ
RDS Oracle 雑多なメモ#2 / FAQ
RDS Oracle 雑多なメモ#3 / FAQ
RDS Oracle 雑多なメモ#4 / FAQ
RDS Oracle 雑多なメモ#5 / FAQ
RDS Oracle 雑多なメモ#6 / FAQ
RDS Oracle 雑多なメモ#7 / FAQ
RDS Oracle 雑多なメモ#8 / FAQ
RDS Oracle 雑多なメモ#9 / FAQ
RDS Oracle 雑多なメモ#10 / FAQ
RDS Oracle 雑多なメモ#11 / FAQ
RDS Oracle 雑多なメモ#12 / FAQ
RDS Oracle 雑多なメモ#13 / FAQ
RDS Oracle 雑多なメモ#14 - おまけ / FAQ
RDS Oracle 雑多なメモ#15 - おまけのおまけ / FAQ
RDS Oracle 雑多なメモ#16 - 再び:) / FAQ
RDS Oracle 雑多なメモ#17/ FAQ
RDS Oracle 雑多なメモ#18 / DBMS_DATAPUMPパッケージ de expdp/impdp
RDS Oracle 雑多なメモ#19 FAQ / DBMS_DATAPUMPパッケージ de ジョブの停止
RDS Oracle 雑多なメモ#20 / DBMS_DATAPUMPパッケージ Schema mode de expdp/impdpの準備 SQL_FILEモードでDDL抜き出し

| | コメント (0)

2020年7月25日 (土)

RDS Oracle 雑多なメモ#20 / DBMS_DATAPUMPパッケージ Schema mode de expdp/impdpの準備 SQL_FILEモードでDDL抜き出し

RDS Oracle 雑多なメモ#20 / DBMS_DATAPUMPパッケージ Schema mode de expdp/impdpの準備


Previously, Mac De Oracle...

RDS Oracle 雑多なメモ#19 FAQ / DBMS_DATAPUMPパッケージ de ジョブの停止

でした。

今回は、RDS Oracleへスキーマ単位でインポートを行う準備に必要などを。

実は、RDS Oracleでは、フルインポートはしないようにと記載されています。ということは、つまりスキーマモードでのインポートと、それ以下の単位でのインポートのみを行うこと、となっています。ここがポイント

詳細は以下マニュアルを参照ください。
Amazon RDS での Oracle へのデータのインポート


フルモードでインポートできない場合の注意点として、スキーマレベルでインポートする際に必要となる可能性のあるオブジェクトは事前に何がしかの方法で作成しておく必要があるということを意味します。
代表的なオブジェクトは以下、

  • ユーザーのデフォルトTABLESPACE(USERS表をそのまま利用しているケースは希だと思います)
  • ユーザーのPROFILE(パスワード有効期限管理などで利用しているケースは多いかも)
  • ROLE(直接付与権限以外はロールを付与して権限を管理することは多いはずです)
  • DIRECTORY(Oracle側で事前に作成しているディレクトリ以外のディレクトリへのアクセスが必要な場合にはディレクトリオブジェクトも事前に作成しておく必要があります)

さらに、スキーマ間で依存している場合、特に、他のスキーマのオブジェクト権限を付与する必要がある場合は、スキーマをインポートする順番にも気を遣う必要も出てきます。
インポート時にエラーが出ないものもありますが。。それは今回のテーマではないのでこの辺でw
(依存しているオブジェクトは事前にALL/DBA_DEPENDENCIESビューを利用して調査しておくとよいでしょうね)



では、DDLを取得する前に、ネタを仕込んでおきましょう。

表領域 fizzbuzz をデフォルト表領域とし、プロファイル fizzbuzz が設定されたユーザー hoge を作成します。
また、connectロールとresourceロールを付与された  fizzbuzz ロールが hoge に付与されているとします。


表領域の追加

BILL> create tablespace fizzbuzz datafile size 100m autoextend on maxsize 1g;

Tablespace created.

プロファイルの追加

BILL> create profile fizzbuzz limit idle_time unlimited;

Profile created.

ロールの追加

BILL> create role fizzbuzz;

Role created.

BILL> grant connect to fizzbuzz;

Grant succeeded.

BILL> grant resource to fizzbuzz;

Grant succeeded.


ユーザーの作成(デフォルト表領域とプロファイルの指定)

BILL> create user hoge identified by xxxxxxxxxxxxxxxx
2 default tablespace fizzbuzz
3 temporary tablespace temp
4 quota unlimited on fizzbuzz
5 profile fizzbuzz;

User created.


ロールの付与

BILL> grant fizzbuzz to hoge;

Grant succeeded.


上記のようなユーザーだとするとスキーマ単位のインポート前に表領域の作成、プロファイルの作成、ロールの作成が必要になりますよね。
(スキーマレベルのインポートでは依存オブジェクトが自動的にインポートされるわけでは無いので)

また、元のデータベースでOracle Managed Fileを利用した表領域では無い場合にはOracle Managed Fileを利用した表領域として再作成してあげる必要あります。(ここも重要。元のデータベースもOracle Managed fileを利用していればそのまま利用できます)

ということで、DBMS_METADATA.GET_DDL()または、フルエクスポートしたData Pumpのダンプファイルファイルから上記に該当するDDLを抜き出し、事前にオブジェクトを作成しておく必要がありますよね。
(DDLソースコード管理されているのであれば、それらを再利用することも可能だとは思いますが、世の中広いのでそんな管理されていないところも多いでしょうし。DDLを取り出す複数の方法は覚えてて損は無いですよ :)


今回は、フルエクスポートダンプファイルがあるので、そこからData Pump APIを利用して取り出してみようと思います。(DBMS_METADATA.GET_DDL()の方が楽だとは思います。個人的にはw)

フルダンプからDDLを取り出す際でも、重要なのがオブジェクトパス(このパスの階層を意識していないと思わぬ失敗をするのは昔のエントリの通り)ですが、今回は比較的シンプルなので確認してみましょう。


事前にエクスポートのログから以下のパスを探し出しておきます。
(今回の例では、表領域とプロファイル、それにロールへのオブジェクトパスです。以下がそのオブジェクトパス)

Processing object type DATABASE_EXPORT/TABLESPACE
Processing object type DATABASE_EXPORT/PROFILE
Processing object type DATABASE_EXPORT/ROLE

余談ですが、同じ階層オブジェクトパスにスキーマオブジェクトのパス(DATABASE_EXPORT/SCHEMA)が存在しています。同じ階層なので、スキーマレベルのインポートではTABLESPACE/ROLE/PROFILEはインポートされることはありません。(この階層構造を理解できれば楽)
DATABASE_EXPORT/SCHEMA以下がインポートの対象になるので、メタデータフィルターでEXCLUDE または INCLUDEするか制御できることになります。TABLESPACE,PROFILEやROLEはSCHEMAと同レベルなのでそもそも対象外となりフィルタすることはできません。

Processing object type DATABASE_EXPORT/SCHEMA/

理屈がわかれば癖の強いDATAPUMPなんてw 

では、DDLを取り出してみましょう。

前提のオブジェクトを含むフルエクスポートダンプファイル fullexp.dmp は事前に取得済みであるとします。

BILL> @extract_ddl data_pump_dir fullexp DATABASE_EXPORT/TABLESPACE'',''DATABASE_EXPORT/PROFILE'',''DATABASE_EXPORT/ROLE
Master table "BILL"."SYS_SQL_FILE_FULL_17" successfully loaded/unloaded
Starting "BILL"."SYS_SQL_FILE_FULL_17":
Processing object type DATABASE_EXPORT/TABLESPACE
Processing object type DATABASE_EXPORT/PROFILE
Processing object type DATABASE_EXPORT/ROLE
Job "BILL"."SYS_SQL_FILE_FULL_17" successfully completed at Sun Jul 19 19:12:00 2020 elapsed 0 00:00:02

PL/SQL procedure successfully completed.

取り出したDDLを確認します

BILL> @cat_file data_pump_dir fullexp.txt

TEXT
-----------------------------------------------------------------------------

...中略...

-- new object type path: DATABASE_EXPORT/TABLESPACE
...中略...
CREATE BIGFILE TABLESPACE "FIZZBUZZ" DATAFILE
SIZE 104857600
AUTOEXTEND ON NEXT 104857600 MAXSIZE 1073741824
LOGGING ONLINE PERMANENT BLOCKSIZE 8192
EXTENT MANAGEMENT LOCAL AUTOALLOCATE DEFAULT
NOCOMPRESS SEGMENT SPACE MANAGEMENT AUTO;
-- new object type path: DATABASE_EXPORT/PROFILE
...中略...
CREATE PROFILE "FIZZBUZZ"
LIMIT
COMPOSITE_LIMIT DEFAULT
SESSIONS_PER_USER DEFAULT
CPU_PER_SESSION DEFAULT
CPU_PER_CALL DEFAULT
LOGICAL_READS_PER_SESSION DEFAULT
LOGICAL_READS_PER_CALL DEFAULT
IDLE_TIME UNLIMITED
CONNECT_TIME DEFAULT
PRIVATE_SGA DEFAULT
FAILED_LOGIN_ATTEMPTS DEFAULT
PASSWORD_LIFE_TIME DEFAULT
PASSWORD_REUSE_TIME DEFAULT
PASSWORD_REUSE_MAX DEFAULT
PASSWORD_VERIFY_FUNCTION DEFAULT
PASSWORD_LOCK_TIME DEFAULT
PASSWORD_GRACE_TIME DEFAULT
INACTIVE_ACCOUNT_TIME DEFAULT ;
-- new object type path: DATABASE_EXPORT/ROLE
...中略...
CREATE ROLE "FIZZBUZZ";
...中略...


スキーマ hogeインポート前に作成が必要なオブジェクトのDDLを取得できました。


これでスキーマレベルのインポート準備完了。
つづく。

参考)
DDLをダンプファイルから取り出すスクリプト例は以下の通り。DBMS_DATAPUMP.OPEN()関数でoperationに’SQL_FILE'を渡しているところとDBMS_DATAPUMP.METADATA_FILTER()プロシージャで取り出すDDLのオブジェクトパスリストを渡している箇所がポイントです
PL/SQLパッケージおよびタイプ・リファレンス - 47 DBMS_DATAPUMP

BILL> !cat extract_ddl.sql
SET VERIFY OFF
SET SERVEROUTPUT ON
DECLARE
v4Debug VARCHAR2(50);
cDirectory CONSTANT VARCHAR2(30) := UPPER('&1');
cDumpFileName CONSTANT VARCHAR2(64) := '&2'||'.dmp';
cLogFileName CONSTANT VARCHAR2(64) := '&2'||'.log';
cDdlFileName CONSTANT VARCHAR2(64) := '&2'||'.txt';
cPathList CONSTANT VARCHAR2(4000) := UPPER('&3');
i NUMBER;
vDataPumpJobHandle NUMBER;
vProgress_ratio NUMBER;
vJobState VARCHAR2(30);
oLogEntry ku$_LogEntry;
oStatus ku$_Status;
BEGIN
DBMS_OUTPUT.ENABLE;

v4Debug := 'OPEN';
vDataPumpJobHandle
:= DBMS_DATAPUMP.OPEN (
operation => 'SQL_FILE'
,job_mode => 'FULL'
,remote_link => NULL
);

v4Debug := 'ADD_FILE - dumpfile';
DBMS_DATAPUMP.ADD_FILE (
handle => vDataPumpJobHandle
,filename => cDumpFileName
,directory => cDirectory
,filetype => DBMS_DATAPUMP.KU$_FILE_TYPE_DUMP_FILE
);

v4Debug := 'ADD_FILE - logfile';
DBMS_DATAPUMP.ADD_FILE (
handle => vDataPumpJobHandle
,filename => cLogFileName
,directory => cDirectory
,filetype => DBMS_DATAPUMP.KU$_FILE_TYPE_LOG_FILE
);

v4Debug := 'ADD_FILE - Ddlfile';
DBMS_DATAPUMP.ADD_FILE (
handle => vDataPumpJobHandle
,filename => cDdlFileName
,directory => cDirectory
,filetype => DBMS_DATAPUMP.KU$_FILE_TYPE_SQL_FILE
);

v4Debug := 'METADATA_FILTER - schema name';
DBMS_DATAPUMP.METADATA_FILTER (
handle => vDataPumpJobHandle
,name => 'INCLUDE_PATH_LIST'
,value => '''' || cPathList || ''''
);

v4Debug := 'START_JOB';
DBMS_DATAPUMP.START_JOB (
handle => vDataPumpJobHandle
);

v4Debug := 'JOB_STATE';
vProgress_ratio := 0;
vJobState := 'UNDEFINED';
WHILE (vJobState != 'COMPLETED') AND (vJobState != 'STOPPED') LOOP
DBMS_DATAPUMP.GET_STATUS (
vDataPumpJobHandle
,DBMS_DATAPUMP.KU$_STATUS_JOB_ERROR
+ DBMS_DATAPUMP.KU$_STATUS_JOB_STATUS
+ DBMS_DATAPUMP.KU$_STATUS_WIP
,-1
,vJobState
,oStatus
);

IF (BITAND(oStatus.mask, DBMS_DATAPUMP.KU$_STATUS_WIP) != 0)
THEN
oLogEntry := oStatus.wip;
ELSE
IF (BITAND(oStatus.mask, DBMS_DATAPUMP.KU$_STATUS_JOB_ERROR) != 0)
THEN
oLogEntry := oStatus.error;
ELSE
oLogEntry := NULL;
END IF;
END IF;
IF oLogEntry IS NOT NULL
THEN
i := oLogEntry.FIRST;
WHILE i IS NOT NULL LOOP
DBMS_OUTPUT.PUT_LINE(oLogEntry(i).LogText);
i := oLogEntry.NEXT(i);
END LOOP;
END IF;
END LOOP;

DBMS_DATAPUMP.DETACH(vDataPumpJobHandle);
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE(sqlerrm());
DBMS_OUTPUT.PUT_LINE(v4Debug);
RAISE;
END;
/

UNDEFINE 1
UNDEFINE 2
UNDEFINE 3
SET SERVEROUTPUT OFF
SET VERIFY ON




やっと、いろいろ落ち着いたかと思ったら次から次に似たような事案が落ちてくる今日この頃w。
ということで、しばらくは機嫌悪いかも、ガルーーーーーっw



Data Pumpも癖モノだよね〜w その1 - queryパラメーターの解析タイミング
Data Pumpも癖モノだよね〜w その2 - Materialized ViewをTableとして移行する
Data Pumpも癖モノだよね〜w その3 - dbms_job と dbms_scheduler との複雑な関係
Data Pumpも癖モノだよね〜w その4 - schemaモードでMviewを他のPDBへ複製
Data Pumpも癖モノだよね〜w その4と1/2 - schemaモードでMviewを他のPDBへ複製 (紛らわしいステータスw)
Data Pumpも癖モノだよね〜w その5 - schemaモードでMviewを他のPDBへ複製(オプジェクトパス de 絞り込み)
Data Pumpも癖モノだよね〜w その6 - schemaモードでMviewを他のPDBへ複製(オプジェクトパスが不足すると...


RDS Oracle 雑多なメモ#1 / FAQ
RDS Oracle 雑多なメモ#2 / FAQ
RDS Oracle 雑多なメモ#3 / FAQ
RDS Oracle 雑多なメモ#4 / FAQ
RDS Oracle 雑多なメモ#5 / FAQ
RDS Oracle 雑多なメモ#6 / FAQ
RDS Oracle 雑多なメモ#7 / FAQ
RDS Oracle 雑多なメモ#8 / FAQ
RDS Oracle 雑多なメモ#9 / FAQ
RDS Oracle 雑多なメモ#10 / FAQ
RDS Oracle 雑多なメモ#11 / FAQ
RDS Oracle 雑多なメモ#12 / FAQ
RDS Oracle 雑多なメモ#13 / FAQ
RDS Oracle 雑多なメモ#14 - おまけ / FAQ
RDS Oracle 雑多なメモ#15 - おまけのおまけ / FAQ
RDS Oracle 雑多なメモ#16 - 再び:) / FAQ
RDS Oracle 雑多なメモ#17/ FAQ
RDS Oracle 雑多なメモ#18 / DBMS_DATAPUMPパッケージ de expdp/impdp
RDS Oracle 雑多なメモ#19 FAQ / DBMS_DATAPUMPパッケージ de ジョブの停止

| | コメント (0)

2020年7月20日 (月)

RDS Oracle 雑多なメモ#19 FAQ / DBMS_DATAPUMPパッケージ de ジョブの停止

Previously, Mac De Oracle...

RDS Oracle 雑多なメモ#18 / DBMS_DATAPUMPパッケージ de expdp/impdp

DBMS_DATAPUMPパッケージを利用した Full Export スクリプトと、ディレクトリ名は大文字で渡すことというマニュアルに記載されていない、発生するとしばらく道に迷ってしまいそうなエラーが返るというお話でした。

今日は、その続き、Data PumpジョブはコマンドラインであってもCTRL+Cでは停止することはできないことはみなさんご存知の通りだとは思います。

正しい停止手順は以下の通り

DBA_DATAPUMP_JOBSで停止したいDATAPUMPジョブ名とジョブオーナー名を確認する

4.199 DBA_DATAPUMP_JOBS
https://docs.oracle.com/cd/F19136_01/refrn/DBA_DATAPUMP_JOBS.html#GUID-141B1FA2-9DE4-4EAF-8270-630E68431DDA


expdp/impdpのattachコマンド、または、DBMS_DATAPUMP.ATTACH()ファンクションで該当ジョブへattachする

3.4.4 ATTACH (expdp/impdpとも同じ対話コマンド)
https://docs.oracle.com/cd/F19136_01/sutil/datapump-import-utility.html#GUID-ADF15D47-FD19-4794-A5C4-685740AA04F9

47.5.2 ATTACHファンクション
https://docs.oracle.com/cd/F19136_01/arpls/DBMS_DATAPUMP.html#GUID-E073EA12-363D-4A6B-9596-1E1D40EA747C


expdp/impdpのkill_jobコマンド、または、DBMS_DATAPUMP.STOP_JOB()プロシージャで該当ジョブを停止する

2.5.7 KILL_JOB (expdp/impdpとも同じ対話コマンド)
https://docs.oracle.com/cd/F19136_01/sutil/oracle-data-pump-export-utility.html#GUID-9DA12603-B6FA-4631-8DFA-B75466CAF178

47.5.16 STOP_JOBプロシージャ
https://docs.oracle.com/cd/F19136_01/arpls/DBMS_DATAPUMP.html#GUID-9CE265FA-F9C6-4816-8AE0-AD0BEF3DC3CA


コマンドラインでもAPI経由でも手順は全く同じ。利用するツールが異なるだけでなので、まずは手順を覚えることが大切なんですよね。これ。
あとは、コマンドラインでは以下のマニュアルを参照し、具体的なコマンドオプションを知る
DBMS_DATAPUMPプロシージャを利用する場合は以下のマニュアルを参照し、どのようなスクリプトになるかを知る

あとは、実践のみですよー、みなさん! :)


では、DBMS_DATAPUMPパッケージでの例を(すでにエクスポートは実行中という状況からはじめます)

BILL> @show_datapump_jobs

OWNER_NAME JOB_NAME STATE JOB_MODE OPERATION
----------------- ------------------------- ------------- ------------- -------------
BILL SYS_EXPORT_FULL_01 EXECUTING FULL EXPORT



BILL> @cancel_datapump_job SYS_EXPORT_FULL_01 BILL

PL/SQL procedure successfully completed.


BILL> @show_datapump_jobs

no rows selected

BILL> @ls_dir data_pump_dir

FILENAME TYPE FILESIZE MTIME
--------------------------- ---------- ---------- ---------
fullexp.log file 2761 18-JUL-20
datapump/ directory 4096 18-JUL-20


BILL> @cat_file data_pump_dir fullexp.log

TEXT
----------------------------------------------------------------------------------------
FLASHBACK automatically enabled to preserve database integrity.
Starting "BILL"."SYS_EXPORT_FULL_01":
Processing object type DATABASE_EXPORT/EARLY_OPTIONS/VIEWS_AS_TABLES/TABLE_DATA
Processing object type DATABASE_EXPORT/NORMAL_OPTIONS/TABLE_DATA
Processing object type DATABASE_EXPORT/NORMAL_OPTIONS/VIEWS_AS_TABLES/TABLE_DATA
Processing object type DATABASE_EXPORT/SCHEMA/TABLE/TABLE_DATA
Processing object type DATABASE_EXPORT/SCHEMA/PACKAGE_BODIES/PACKAGE/PACKAGE_BODY
Processing object type DATABASE_EXPORT/SCHEMA/TABLE/INDEX/STATISTICS/INDEX_STATISTICS
Processing object type DATABASE_EXPORT/SCHEMA/TABLE/INDEX/STATISTICS/FUNCTIONAL_INDEX/INDEX_STATISTICS
Processing object type DATABASE_EXPORT/SCHEMA/TABLE/STATISTICS/TABLE_STATISTICS
Processing object type DATABASE_EXPORT/STATISTICS/MARKER
Processing object type DATABASE_EXPORT/PRE_SYSTEM_IMPCALLOUT/MARKER
Processing object type DATABASE_EXPORT/PRE_INSTANCE_IMPCALLOUT/MARKER
Processing object type DATABASE_EXPORT/TABLESPACE
Processing object type DATABASE_EXPORT/PROFILE
Processing object type DATABASE_EXPORT/SCHEMA/USER
Processing object type DATABASE_EXPORT/ROLE
Processing object type DATABASE_EXPORT/RADM_FPTM
Processing object type DATABASE_EXPORT/GRANT/SYSTEM_GRANT/PROC_SYSTEM_GRANT

...中略...

Processing object type DATABASE_EXPORT/NORMAL_OPTIONS/TABLE
Job "BILL"."SYS_EXPORT_FULL_01" stopped due to fatal error at Sat Jul 18 10:02:49 2020 elapsed 0 00:00:50

41 rows selected.


BILL> @rm_file data_pump_dir fullexp.log
DATA_PUMP_DIR/fullexp.log removed.

PL/SQL procedure successfully completed.

BILL> @ls_dir data_pump_dir

FILENAME TYPE FILESIZE MTIME
--------------------------- ---------- ---------- ---------
datapump/ directory 4096 18-JUL-20

停止できましたー


今回利用したDATAPUMPジョブ停止スクリプトの例は以下のとおり。

BILL> !cat show_datapump_jobs.sql

col owner_name for a30
col job_name for a30
col state for a30
col job_mode for a30
col operation for a30
SELECT
owner_name
, job_name
, state
, job_mode
, operation
FROM
DBA_DATAPUMP_JOBS
ORDER BY
owner_name
, job_name
, state
;


BILL> !cat cancel_datapump_job.sql

DECLARE
hdl NUMBER;
BEGIN
hdl := DBMS_DATAPUMP.ATTACH(
job_name => UPPER('&1')
,job_owner => UPPER('&2')
);

DBMS_DATAPUMP.STOP_JOB(
handle => hdl
, immediate => 1
, keep_master => 0
);
END;
/


ls_dir.sql, rm_file.sql そして、cat_file.sqlの例は過去のエントリを参照してみてください。

ls_dir.sql
http://discus-hamburg.cocolog-nifty.com/mac_de_oracle/2018/09/rds-oracle-3-fa.html

rm_file.sql
http://discus-hamburg.cocolog-nifty.com/mac_de_oracle/2018/09/rds-oracle-7-fa.html

cat_file.sql
http://discus-hamburg.cocolog-nifty.com/mac_de_oracle/2018/09/rds-oracle-4-fa.html

では、次回へつづく。




Data Pumpも癖モノだよね〜w その1 - queryパラメーターの解析タイミング
Data Pumpも癖モノだよね〜w その2 - Materialized ViewをTableとして移行する
Data Pumpも癖モノだよね〜w その3 - dbms_job と dbms_scheduler との複雑な関係
Data Pumpも癖モノだよね〜w その4 - schemaモードでMviewを他のPDBへ複製
Data Pumpも癖モノだよね〜w その4と1/2 - schemaモードでMviewを他のPDBへ複製 (紛らわしいステータスw)
Data Pumpも癖モノだよね〜w その5 - schemaモードでMviewを他のPDBへ複製(オプジェクトパス de 絞り込み)
Data Pumpも癖モノだよね〜w その6 - schemaモードでMviewを他のPDBへ複製(オプジェクトパスが不足すると...


RDS Oracle 雑多なメモ#1 / FAQ
RDS Oracle 雑多なメモ#2 / FAQ
RDS Oracle 雑多なメモ#3 / FAQ
RDS Oracle 雑多なメモ#4 / FAQ
RDS Oracle 雑多なメモ#5 / FAQ
RDS Oracle 雑多なメモ#6 / FAQ
RDS Oracle 雑多なメモ#7 / FAQ
RDS Oracle 雑多なメモ#8 / FAQ
RDS Oracle 雑多なメモ#9 / FAQ
RDS Oracle 雑多なメモ#10 / FAQ
RDS Oracle 雑多なメモ#11 / FAQ
RDS Oracle 雑多なメモ#12 / FAQ
RDS Oracle 雑多なメモ#13 / FAQ
RDS Oracle 雑多なメモ#14 - おまけ / FAQ
RDS Oracle 雑多なメモ#15 - おまけのおまけ / FAQ
RDS Oracle 雑多なメモ#16 - 再び:) / FAQ
RDS Oracle 雑多なメモ#17/ FAQ
RDS Oracle 雑多なメモ#18 / DBMS_DATAPUMPパッケージ de expdp/impdp

| | コメント (0)

2020年7月19日 (日)

RDS Oracle 雑多なメモ#18 / DBMS_DATAPUMPパッケージ de expdp/impdp

さて、COVID-19の感染者も再び増加傾向にある今日この頃ですが、みなさま、お変わりありませんか?

半年ぶり以上ぶりのエントリです。(2020年のOracle ACEのKPIカウントもスタートしたのでやっと再始動)
再始動第一段目は、癖者の極み、Data Pumpネタで。

何年か前にも癖者だというエントリは書いたことがありますが、今回はコマンドラインではなく、DBMS_DATAPUMPパッケージ。そう、APIが主人公です

Data Pumpも癖モノだよね〜w その6 - schemaモードでMviewを他のPDBへ複製(オプジェクトパスが不足すると...) http://discus-hamburg.cocolog-nifty.com/mac_de_oracle/2017/04/data-pumpw6---s.html

そして最近では、

DS Oracle 雑多なメモ#1 / FAQ 〜 http://discus-hamburg.cocolog-nifty.com/mac_de_oracle/2018/09/rds-oracle-1-fa.html

から

RDS Oracle 雑多なメモ#17/ FAQ http://discus-hamburg.cocolog-nifty.com/mac_de_oracle/2019/02/rds-oracle-17-f.html


何度かData Pumpネタを取り上げてきました、今回は RDS Oracleでは需要が多そうな
DBMS_DATAPUMPパッケージからAPIを利用してexpdp/impdp相当の操作に特化していくつご紹介しておきます。

普段はコマンドラインだけでした操作したことないData Pumpですが、いざDBMS_DATAPUMPパッケージしか使えないという状況になって、涙目状態は辛いですよね。
そんなことにならないように普段から慣れておくとかスクリプト集を用意しておくと良いと思います。

コマンドラインでも癖もとだよねぇ〜というネタのとおりDBMS_DATAPUMPパッケージでも一癖あるのはおなじですw
とはいえ、コマンドラインである程度ポイントを抑えていればある程度は感でいけますよ。

では、さっそく、DBMS_DATAPUMPパッケージの準備運動として、Data Pump Full exportを試してみましょう。
以前も同類のスクリプトは公開済みなので、過去のエントリを読んだことがあるなら簡単なはず:)

環境 Oracle Client 19c (SQL*Plusパッケージが含まれているパッケージ) https://www.oracle.com/jp/database/technologies/instant-client.html

AWS RDS Oracle Database 19c https://aws.amazon.com/jp/console/

 

実行例)


BILL> @expdp_full data_pump_dir fullexp
FLASHBACK automatically enabled to preserve database integrity.
Starting "BILL"."SYS_EXPORT_FULL_01":
Processing object type DATABASE_EXPORT/EARLY_OPTIONS/VIEWS_AS_TABLES/TABLE_DATA
Processing object type DATABASE_EXPORT/NORMAL_OPTIONS/TABLE_DATA
Processing object type DATABASE_EXPORT/NORMAL_OPTIONS/VIEWS_AS_TABLES/TABLE_DATA
Processing object type DATABASE_EXPORT/SCHEMA/TABLE/TABLE_DATA
Processing object type DATABASE_EXPORT/SCHEMA/PACKAGE_BODIES/PACKAGE/PACKAGE_BODY
Processing object type DATABASE_EXPORT/SCHEMA/TABLE/INDEX/STATISTICS/INDEX_STATISTICS
Processing object type DATABASE_EXPORT/SCHEMA/TABLE/INDEX/STATISTICS/FUNCTIONAL_INDEX/INDEX_STATISTICS
Processing object type DATABASE_EXPORT/SCHEMA/TABLE/STATISTICS/TABLE_STATISTICS
Processing object type DATABASE_EXPORT/STATISTICS/MARKER
Processing object type DATABASE_EXPORT/PRE_SYSTEM_IMPCALLOUT/MARKER
Processing object type DATABASE_EXPORT/PRE_INSTANCE_IMPCALLOUT/MARKER
Processing object type DATABASE_EXPORT/TABLESPACE
Processing object type DATABASE_EXPORT/PROFILE
Processing object type DATABASE_EXPORT/SCHEMA/USER
Processing object type DATABASE_EXPORT/ROLE
Processing object type DATABASE_EXPORT/RADM_FPTM
Processing object type DATABASE_EXPORT/GRANT/SYSTEM_GRANT/PROC_SYSTEM_GRANT

...中略...

Processing object type DATABASE_EXPORT/SCHEMA/VIEW/VIEW
Processing object type DATABASE_EXPORT/SCHEMA/TABLE/INDEX/INDEX
Processing object type DATABASE_EXPORT/SCHEMA/TABLE/INDEX/FUNCTIONAL_INDEX/INDEX
Processing object type DATABASE_EXPORT/SCHEMA/TABLE/CONSTRAINT/CONSTRAINT
Processing object type DATABASE_EXPORT/SCHEMA/TABLE/CONSTRAINT/REF_CONSTRAINT
Processing object type DATABASE_EXPORT/SCHEMA/TABLE/TRIGGER
Processing object type DATABASE_EXPORT/SCHEMA/EVENT/TRIGGER
Processing object type DATABASE_EXPORT/FINAL_POST_INSTANCE_IMPCALLOUT/MARKER
Processing object type DATABASE_EXPORT/SCHEMA/POST_SCHEMA/PROCACT_SCHEMA
Processing object type DATABASE_EXPORT/AUDIT_UNIFIED/AUDIT_POLICY_ENABLE
Processing object type DATABASE_EXPORT/POST_SYSTEM_IMPCALLOUT/MARKER
. . exported "SYS"."KU$_USER_MAPPING_VIEW" 5.921 KB 28 rows

...中略...

. . exported "SCOTT"."TAB31" 541.6 MB 2000000 rows
. . exported "SCOTT"."TAB311" 521.6 MB 2000000 rows
. . exported "SCOTT"."TAB3" 267.9 MB 1000000 rows

...中略...

. . exported "HOGE"."HOGE" 5.093 KB 1 rows

...中略...

Master table "BILL"."SYS_EXPORT_FULL_01" successfully loaded/unloaded
******************************************************************************
Dump file set for BILL.SYS_EXPORT_FULL_01 is:
/rdsdbdata/datapump/fullexp.dmp
Job "BILL"."SYS_EXPORT_FULL_01" successfully completed at Sat Jul 18 10:25:02 2020 elapsed 0 00:04:25

PL/SQL procedure successfully completed.

Elapsed: 00:04:27.32
BILL>
BILL> @ls_dir data_pump_dir

FILENAME TYPE FILESIZE MTIME
---------------------------------------------------------------------- ---------- ---------- ---------
datapump/ directory 4096 18-JUL-20
fullexp.log file 9071 18-JUL-20
fullexp.dmp file 1461907456 18-JUL-20

Elapsed: 00:00:00.15

なお、上記で利用している ls_dir.sql は以下エントリを参照のこと。 
RDS Oracle 雑多なメモ#3 / FAQ http://discus-hamburg.cocolog-nifty.com/mac_de_oracle/2018/09/rds-oracle-3-fa.html

RDS Oracle 雑多なメモ#9 / FAQでも紹介しているスクリプトを多少変更してあります。
Full ExportなのでDBMS_DATAPUMP.OPEN()のjob_modeパラメータが'FULL'になっている点と、DBMS_DATAPUMP.METADATA_FILTER()でEXCLUDEやINCLUDEしていない。つまり、Full Exportになっています。
http://discus-hamburg.cocolog-nifty.com/mac_de_oracle/2018/09/rds-oracle-9-fa.html

参考)PL/SQLパッケージおよびタイプ・リファレンス
https://docs.oracle.com/cd/F19136_01/arpls/DBMS_DATAPUMP.html#GUID-AEA7ED80-DB4A-4A70-B199-592287206348

なお、マニュアルには書かれてないのですが、ディレクトリ名は、"大文字" にするのがポイントです。Case Sensitiveで大文字しか認識しません。スクリプトを注意深く見ていただけると、UPPER()を使っている部分(赤字部分)があることに気づくとおもいます。もし、小文字で渡してしまうとDBMS_DATAPUMPパッケージの癖の強いエラーメッセージを受け取りことになり、意味わからなーーーーい。としばらくは迷子になってしまうことでしょう。後半で、UPPER()なしで小文字で渡してしまった場合にはどのようなエラーが返されるのかお見せしたいと思います。

BILL> !cat expdp_full.sql

SET VERIFY OFF
SET SERVEROUTPUT ON
DECLARE
v4Debug VARCHAR2(50);
cDirectory CONSTANT VARCHAR2(30) := UPPER('&1');
cDumpFileName CONSTANT VARCHAR2(128) := '&2'||'.dmp';
cLogFileName CONSTANT VARCHAR2(128) := '&2'||'.log';
i NUMBER;
vDataPumpJobHandle NUMBER;
vProgress_ratio NUMBER;
vJobState VARCHAR2(30);
oLogEntry ku$_LogEntry;
oStatus ku$_Status;
BEGIN
DBMS_OUTPUT.ENABLE;

v4Debug := 'OPEN';
vDataPumpJobHandle
:= DBMS_DATAPUMP.OPEN (
operation => 'EXPORT'
,job_mode => 'FULL'
,remote_link => NULL
,job_name => NULL
,version => 'LATEST'
);

v4Debug := 'ADD_FILE - dumpfile';
DBMS_DATAPUMP.ADD_FILE (
handle => vDataPumpJobHandle
,filename => cDumpFileName
,directory => cDirectory(
,filetype => DBMS_DATAPUMP.KU$_FILE_TYPE_DUMP_FILE
);

v4Debug := 'ADD_FILE - logfile';
DBMS_DATAPUMP.ADD_FILE (
handle => vDataPumpJobHandle
,filename => cLogFileName
,directory => cDirectory(
,filetype => DBMS_DATAPUMP.KU$_FILE_TYPE_LOG_FILE
);

v4Debug := 'START_JOB';
DBMS_DATAPUMP.START_JOB (
handle => vDataPumpJobHandle
);

v4Debug := 'JOB_STATE';
vProgress_ratio := 0;
vJobState := 'UNDEFINED';
WHILE (vJobState != 'COMPLETED') AND (vJobState != 'STOPPED') LOOP
DBMS_DATAPUMP.GET_STATUS (
vDataPumpJobHandle
,DBMS_DATAPUMP.KU$_STATUS_JOB_ERROR
+ DBMS_DATAPUMP.KU$_STATUS_JOB_STATUS
+ DBMS_DATAPUMP.KU$_STATUS_WIP
,-1
,vJobState
,oStatus
);

IF (BITAND(oStatus.mask, DBMS_DATAPUMP.KU$_STATUS_WIP) != 0)
THEN
oLogEntry := oStatus.wip;
ELSE
IF (BITAND(oStatus.mask, DBMS_DATAPUMP.KU$_STATUS_JOB_ERROR) != 0)
THEN
oLogEntry := oStatus.error;
ELSE
oLogEntry := NULL;
END IF;
END IF;
IF oLogEntry IS NOT NULL
THEN
i := oLogEntry.FIRST;
WHILE i IS NOT NULL LOOP
DBMS_OUTPUT.PUT_LINE(oLogEntry(i).LogText);
i := oLogEntry.NEXT(i);
END LOOP;
END IF;
END LOOP;

DBMS_DATAPUMP.DETACH(vDataPumpJobHandle);
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE(sqlerrm());
DBMS_OUTPUT.PUT_LINE(v4Debug);
RAISE;
END;
/

UNDEFINE 1
UNDEFINE 2
SET SERVEROUTPUT OFF
SET VERIFY ON

 

では、少しだけ前振りしていた、もしも、ディレクトリ名を小文字で渡してしまったら....以下のようなエラーが返されます。

なかなかの癖者なエラーメッセージですよね。このエラーですぐに問題点に気づけたら達人に域ですw (癖者な人よりは扱いやすいとは思いますがw ただのAPIなので)

BILL> @expdp_full data_pump_dir fullexp2
old 3: cDirectory CONSTANT VARCHAR2(30) := '&1';
new 3: cDirectory CONSTANT VARCHAR2(30) := 'data_pump_dir';
old 4: cDumpFileName CONSTANT VARCHAR2(64) := '&2'||'.dmp';
new 4: cDumpFileName CONSTANT VARCHAR2(64) := 'fullexp2'||'.dmp';
old 5: cLogFileName CONSTANT VARCHAR2(64) := '&2'||'.log';
new 5: cLogFileName CONSTANT VARCHAR2(64) := 'fullexp2'||'.log';
ORA-39001: invalid argument value
ADD_FILE - dumpfile
DECLARE
*
ERROR at line 1:
ORA-39001: invalid argument value
ORA-06512: at line 86
ORA-06512: at "SYS.DBMS_SYS_ERROR", line 79
ORA-06512: at "SYS.DBMS_DATAPUMP", line 4929
ORA-06512: at "SYS.DBMS_DATAPUMP", line 5180
ORA-06512: at line 26

では、次回へつづく。


Data Pumpも癖モノだよね〜w その1 - queryパラメーターの解析タイミングData Pumpも癖モノだよね〜w その2 - Materialized ViewをTableとして移行するData Pumpも癖モノだよね〜w その3 - dbms_job と dbms_scheduler との複雑な関係Data Pumpも癖モノだよね〜w その4 - schemaモードでMviewを他のPDBへ複製Data Pumpも癖モノだよね〜w その4と1/2 - schemaモードでMviewを他のPDBへ複製 (紛らわしいステータスw)
Data Pumpも癖モノだよね〜w その5 - schemaモードでMviewを他のPDBへ複製(オプジェクトパス de 絞り込み)
Data Pumpも癖モノだよね〜w その6 - schemaモードでMviewを他のPDBへ複製(オプジェクトパスが不足すると...

 

RDS Oracle 雑多なメモ#1 / FAQ
RDS Oracle 雑多なメモ#2 / FAQ
RDS Oracle 雑多なメモ#3 / FAQ
RDS Oracle 雑多なメモ#4 / FAQ
RDS Oracle 雑多なメモ#5 / FAQ
RDS Oracle 雑多なメモ#6 / FAQ
RDS Oracle 雑多なメモ#7 / FAQ
RDS Oracle 雑多なメモ#8 / FAQ
RDS Oracle 雑多なメモ#9 / FAQ
RDS Oracle 雑多なメモ#10 / FAQ
RDS Oracle 雑多なメモ#11 / FAQ
RDS Oracle 雑多なメモ#12 / FAQ
RDS Oracle 雑多なメモ#13 / FAQ
RDS Oracle 雑多なメモ#14 - おまけ / FAQ
RDS Oracle 雑多なメモ#15 - おまけのおまけ / FAQ
RDS Oracle 雑多なメモ#16 - 再び:) / FAQ
RDS Oracle 雑多なメモ#17/ FAQ

 

| | コメント (0)

2020年2月23日 (日)

実行計画は、SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 おまけ#4

2020年も2ヶ月が終わるところ, かつ, 新型コロナウィルスの影響をいろいろ受けつつ今後どうなるんだろうと, 週末は外出を最小限に入手困難なマスクの消費を抑える意味もあり必要最小限の外出にする作戦....
とはいえ, ネットでググると, 消毒用アルコール詰め替え4Lやマスクが, 想像の斜め上をいく値段で売られてて, なんなのだろうなんて...

余談はこれぐらいにして, 2019年のくれのネタのおまけの追加でございます.


Index Only Scanを利用したmin()/max()で性能チューニングという、比較的レアな治療をしたことのある方なら見覚えのあるレントゲン写真(実行計画)だと思います. (たまたまそうなってたということもありますが, これを狙ったチューニング方法もあります)

当然ですが、Index Only Scanを狙う場面は, 行長が長いがSELECT文では索引にできそうな(しても悪影響なさそうな)一部の列しか利用していない. ほぼ全ての列がSELECT文中で利用されているような場合にはIndex Only Scanは不向きなのはみなさんご存知の通りです.

なつかしいエントリですが, 以下エントリーのスライド(SlideShare使ってなかった頃なので, KeynoteをHTMLへ変換)を参照のこと.
いん!、イン!、Index どっぷり Inde Only Access生活w - Oracle OpenWorld Unconference presented by JPOUG

上記エントリーのスライドでも紹介していますが, MIN()/MAX()関数が利用されており, Index Only Scanが有効なケース(アクセスするブロック数が多くOLTPの性能が性能要件を満たせないようなケース. 大抵の場合、物理IOの影響か, キャッシュにヒットしてもBuffer読み込みが多すぎる、かつ、同時セッション数が多いような場合にはいろいろな改善効果が見込めます)で威力を発揮します.

例えば, db sequential read, read by other session, etc....の削減効果, キャッシュヒット率が高い場合で DB CPUは高いけど実は無駄に高いだけ〜な状況という名の内臓脂肪多くて隠れ肥満なシステムは, 物理IOが少なくてCPU利用率が高い事も多く, リソースうまく使い切ってますねー, スケールアップするしかなさそうですねーと誤診されるケースもあったりw
しっかり診察する必要はありますが, 治療できる可能性がある場合には, Buffer Getsを削減するためIndex Only Scanを利用したチューニングという名の治療(当然副作用を伴います. その点には注意が必要です)を続けることで大きく改善させた例もあります. 実際にそんなことをやってたこともありました.

Statisticsをみるとお判りだと思いますが, Id=2でINDEX FULL SCANとは出ていますが, physical readsが1回, 1blockのアクセスになっている点がポイントです.
Indexonlyscan_min_max

実行計画からは, MAX()なのかMIN()なのかは見えてきません. したがって, 実行計画から判断可能なのは, 以下のいずれかであるというろころまでです.

select 
min(employee_id)
from
employees;

select 
max(employee_id)
from
employees;


-----
社内LT大会で、実行計画は、SQL文のレントゲン写真だ!っぽいLTをした! @ SQL総合診療所目黒分室(当日、医者のコスプレするの忘れたのは内緒w)




previously 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

| | コメント (0)

FAQ / SCOTTスキーマにあるEMP表とかどうすれば作れるの?

SCOTTスキーマをアンロックしたはいいけど、サンプル表がないーーーいなんてときは、utlsampl.sql を実行すればいいよ

SCOTT@orcl> select table_name from user_tables;

no rows selected

SCOTT@orcl> !
SCOTT@orcl> @?/rdbms/admin/utlsampl
Disconnected from Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production
Version0.0.0
[oracle@localhost ~]$ sqlplus scott@orcl

Enter password:
Last Successful login time: Sun Feb 23 2020 06:24:56 -05:00

SQL*Plus: Release 19.0.0.0.0 - Production on Sun Feb 23 06:24:56 2020
Version 19.3.0.0.0

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

Last Successful login time: Sun Feb 23 2020 06:24:46 -05:00

Connected to:
Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production
Version 19.3.0.0.0

SCOTT@orcl> select table_name from user_tables;

TABLE_NAME
------------------------------
DEPT
EMP
BONUS
SALGRADE

SCOTT@orcl> select * from emp;

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

14 rows selected.

--
最近、英会話のレベルチェックうけて、1年半振りにレベルアップ:)

| | コメント (0)

2020年1月 6日 (月)

How to fix when can't boot VM - VirtualBox error : Trying to open a VM config ".... .vbox" which has the same UUID as an existing virtual machine / FAQ

なにがどうしてなのか、まったくわかりませんが、VirtualBoXのVMが突然アクセスできなくなり以下のような状況になった。
理由は不明ですが、似たような症状の方は意外に多いようですが、解決方法がわかりやすくまとまってるエントリーもなさそうだったので、対処した手順を備忘録として書いておきます。

先日まで問題なく使えてなのですが、なにかのはずみでこうなっちゃうこともあるらしい。まさにその状態だったのがこれ。
Vbox000

どのようなエラーなのかも不明だったのですが、.vboxファイルと.vmdkそして、Snapshotsの場所を確認...

$ cd /Volumes/Macintosh\ HD/VirtualBoxDisks/test 
$ ll
-rw------- 1 hoge foobar 21147287552 1 4 18:26 test-disk1.vmdk
-rw-------@ 1 hoge foobar 16163 11 14 2017 test.vbox
-rw------- 1 hoge foobar 16163 11 14 2017 test.vbox-prev
drwx------ 6 hoge foobar 192 11 14 2017 Logs
drwx------ 4 hoge foobar 128 11 11 2017 Snapshots

.vboxを特定、直接起動してやっとエラーの詳細までたどり着いた:)
上記の例では、test.vboxをダブルクリックして起動します。(Oracle VM VirtualBoxマネージャだと冒頭の画面のままうんともすんとも言わないので、直接起動してエラー詳細ダイアログまでたどり着けました。logからはそれっぽいのは見つからず。)

以下エラーダイアログの".vbox' which has the same UUID as an existing virtual machine."から判断すると、test.vbox で起動するVMに割り当てられているUUIDが重複してるということらしい。ん〜、たしかに、VMイメージインポートはしたがそれぐらいなんだよなー以前と違うのは。
ではあるのだが、それ以上深追いするより、起動できなくなったVMを起動できるように回復させる方が重要なので、解決策を探ると。。。。
Vbox001

VBoxManage internalcommands sethduuidで、重複しているとされるVMのUUIDを新たに取得。
ただ、前述のコマンドは vdi やvmdkなどの仮想ディスクイメージファイルのUUIDを設定するもの。
VMのUUIDを再設定するためのコマンドは現時点では提供されていない(参考 VBoxManage internalcommands uage参照のこと)
では、どうやって、VMのUUIDを取得するかというと、実は苦肉の策っぽいのですが、

VBoxManage internalcommands sethduuidで仮想ディスクイメージファイルのUUIDを2度設定する VBoxManage internalcommands sethduuidで仮想ディスクイメージファイルのUUIDを2度設定する

大切なので二度書きました。

一度目の実行で得たUUIDをVM向けに利用し、二度目の実行で、仮想ディスクイメージファイルのHD向けUUIDを設定するのがコツとのこと。

問題のVMは仮想ディスクが1つ、スナップショットが2つあります。VBoxManage internalcommands sethduuid でUUIDを二回変更する対象は、 test-disk1.vmdkです。

test-disk1.vmdkのUUIDをVBoxManage internalcommands sethduuidでセットします。ただ、ここで設定したUUIDはVMのUUID重複の解消に利用します。

$ VBoxManage internalcommands sethduuid test-disk1.vmdk
UUID changed to: 5c46b404-42e2-4389-a0cc-a451d614b039

再度、test-disk1.vmdkのUUIDをVBoxManage internalcommands sethduuidでセットします。ここで設定したUUIDはtest-disk1.vmdkのUUIDを変更するために行います。
(なお、複数の仮想ディスクイメージがあってもどれか一つを利用して行えばOKです。VMのUUIDを変更したいだけの操作なので)

$ VBoxManage internalcommands sethduuid test-disk1.vmdk
UUID changed to: 3f99c052-ab4f-4c59-ada7-50553b46a35e

2度の操作で得られた2つのUUID
以下は、VM用
5c46b404-42e2-4389-a0cc-a451d614b039

以下は、仮想ディスク test-disk1.vmdk のUUIDです。
3f99c052-ab4f-4c59-ada7-50553b46a35e

これらを元に、test.vboxをテキストエディタで編集して以下の部分を変更します。
Vbox002
Vbox003

さて、次がポイントです。このVMには既存のスナップショットが2世代存在します。(test.vboxをテキストエディタで開いた状態)
2世代のスナップショットは以下のように階層化されて管理されており、ぞれぞれのスナップショット(仮想ディスクイメージ)がその親のUUIDを Parent UUIDとして保持しています。保持しているParent UUIDを確認する方法は、参考 VBoxManage internalcommands dumphdinfo を参照のこと。
Vbox004

今回ルートとなるtest-disk1.vmdのUUIDを3f99c052-ab4f-4c59-ada7-50553b46a35eへ変更したため、直下のスナップショットのParent UUIDを3f99c052-ab4f-4c59-ada7-50553b46a35eに設定する必要があります。

$ VBoxManage internalcommands sethdparentuuid Snapshots/{d7c94038-b98d-46d2-9241-4bac71bf14b7}.vmdk 3f99c052-ab4f-4c59-ada7-50553b46a35e
UUID changed to: 3f99c052-ab4f-4c59-ada7-50553b46a35e

UUID=d7c94038-b98d-46d2-9241-4bac71bf14b7をParent UUIDとして持つのはUUID=02415676-9386-4bf2-931d-df2891ecfdffのスナップショットです。今回影響ありませんでしたが、念のためd7c94038-b98d-46d2-9241-4bac71bf14b7で設定し直しています。

$ VBoxManage internalcommands sethdparentuuid Snapshots/{02415676-9386-4bf2-931d-df2891ecfdff}.vmdk d7c94038-b98d-46d2-9241-4bac71bf14b7
UUID changed to: d7c94038-b98d-46d2-9241-4bac71bf14b7

仮想ディスクイメージ上のUUIDを設定し直した後で、text.vboxの該当箇所も合わせて変更します。それぞれのUUIDは複数の箇所で参照されているので一括して変更すると変更もれなく変更することができます。
Vbox005
Vbox006

変更した test.vboxを保存後して、test.vboxをダブルクリックするとVMが起動できるようになります。

ただし、以下のようにアクセスできない状態となった Oracle VM VirtualBoxマネージャの状態は前述の手順では改善できませんでした。
Vbox000

少々面倒なのですが、該当VMを一旦除去(物理削除はしない)Oracle VM VirtualBoxマネージャから除去して、追加し直すだけで復活させることができました。ʅ(◞‿◟)ʃ
20200104-230253
20200104-223203
20200104-223539
20200104-230054



参考 VBoxManage internalcommands dumphdinfo
$ VBoxManage internalcommands dumphdinfo test-disk1.vmdk
--- Dumping VD Disk, Images=1
Dumping VD image "test-disk1.vmdk" (Backend=VMDK)
Header: Geometry PCHS=16383/16/63 LCHS=1024/255/63 cbSector=209715200
Header: uuidCreation={3f99c052-ab4f-4c59-ada7-50553b46a35e}
Header: uuidModification={bb2f68b6-c9b0-480d-9eab-3b2eb81b9b3f}
Header: uuidParent={00000000-0000-0000-0000-000000000000}
Header: uuidParentModification={00000000-0000-0000-0000-000000000000}

参考 VBoxManage internalcommands usage

$ VBoxManage internalcommands
Oracle VM VirtualBox Command Line Management Interface Version 6.0.14
(C) 2005-2019 Oracle Corporation
All rights reserved.

Usage: VBoxManage internalcommands [command arguments]

Commands:

loadmap <vmname|uuid> <symfile> <address> [module] [subtrahend] [segment]
This will instruct DBGF to load the given map file
during initialization. (See also loadmap in the debugger.)

loadsyms <vmname|uuid> <symfile> [delta] [module] [module address]
This will instruct DBGF to load the given symbol file
during initialization.

sethduuid <filepath> [<uuid>]
Assigns a new UUID to the given image file. This way, multiple copies
of a container can be registered.

sethdparentuuid <filepath> <uuid>
Assigns a new parent UUID to the given image file.

dumphdinfo <filepath>
Prints information about the image at the given location.

listpartitions -rawdisk <diskname>
Lists all partitions on <diskname>.

createrawvmdk -filename <filename> -rawdisk <diskname>
[-partitions <list of partition numbers> [-mbr <filename>] ]
[-relative]
Creates a new VMDK image which gives access to an entire host disk (if
the parameter -partitions is not specified) or some partitions of a
host disk. If access to individual partitions is granted, then the
parameter -mbr can be used to specify an alternative MBR to be used
(the partitioning information in the MBR file is ignored).
The diskname is on Linux e.g. /dev/sda, and on Windows e.g.
\\.\PhysicalDrive0).
On Linux or FreeBSD host the parameter -relative causes a VMDK file to
be created which refers to individual partitions instead to the entire
disk.
The necessary partition numbers can be queried with
VBoxManage internalcommands listpartitions

renamevmdk -from <filename> -to <filename>
Renames an existing VMDK image, including the base file and all its extents.

converttoraw [-format <fileformat>] <filename> <outputfile>
Convert image to raw, writing to file.

converthd [-srcformat VDI|VMDK|VHD|RAW]
[-dstformat VDI|VMDK|VHD|RAW]
<inputfile> <outputfile>
converts hard disk images between formats

repairhd [-dry-run]
[-format VDI|VMDK|VHD|...]
<filename>
Tries to repair corrupted disk images

debuglog <vmname|uuid> [--enable|--disable] [--flags todo]
[--groups todo] [--destinations todo]
Controls debug logging.

passwordhash <passsword>
Generates a password hash.

gueststats <vmname|uuid> [--interval <seconds>]
Obtains and prints internal guest statistics.
Sets the update interval if specified.

WARNING: This is a development tool and shall only be used to analyse
problems. It is completely unsupported and will change in
incompatible ways without warning.

Syntax error: Command missing

| | コメント (0)

2019年12月31日 (火)

Mac De Oracle - 気づいたら15年たってた / メモ

カーグラフィックTV(おじさんたちしか見ないだろうけどw)って結構振り返りネタしてるので、Mac De Oracleもたまにはそんなネタを。

ところで、このブログのタイトルですが、当時Mac de Zope(後にCube de Zopeに改名)というPythonというかZopeネタ扱っていたサイトがお気に入りで、その名称などにインスパイアされたのが、このMac De Oracle。
http://discus-hamburg.cocolog-nifty.com/mac_de_oracle/2007/08/post_5133.html

Mac De Oracle season 1 episode 1! 記念すべき第一回話w うちの奥さんからBlog楽しいよー、書いてみなよーと、そそのかされたのが運の尽きw (嘘
2005/5/24 - Panther De Oracle10g その1

Cube G4からPowerMac G5になったので、season 2 かだよな〜。OracleからGeneric ConnectivityでPostgreSQL、MySQLそして、FirebirdとかDB Linkでぜーんぶ繋いでた。仕事でしらべてたとはいえ、いろいろ熱いなw
2005/12/31 - Mac De Oracle Heterogeneous! #3

2006年ぐらいからRACも避けて通れなくなりつつあり、資金のない中とうやってお勉強しましょうかということになるわけです。はい。OTN Professional というやつがあって、それを十二分に活用してたのがこと時期かな〜
まだリアルな環境ですね。
2006/12/30 - Mac De Oracle - 10万円 de RAC #2

実はこのころから開発片手に、チューニング案件が多くなってきました。ネタにもしてましたが、このころ多かったのが Rule Base OptimizerからCost base Optimizerに切り替わってCost Baseなにそれ、バインドピークなにそれー
みたいなところからシステムテストやら負荷テスト時期になる、あちこちで、火の手が上がる。みたいな時期でしたーw

バインド変数を全く使ってないシステムで、結合テストで負荷試験したらCPUリソース枯渇 - HPのデカイサーバーがw - バインド変数使えよ案件 とか

32bitのWindowsでメモリ不足が様々な問題を引き起こしてた、それにバインド変数つかってねーし、ORA-12518連発 - バインド変数使えよ、階層問合使えよ、32bitのメモリ空間のサイズ考えてねー 案件 とか

火消しでいろいろ呼ばれましたーw

という、今ではあまりお目にかからなくなってきたチューニングの数々ですが、これ以降SQLチューニング案件に関わることが多くなっていきますw が、子供がうまれて、それどころじゃない、という感じにもなったのがこのころですねw 保育園待機児童問題に気づいたのもこのころでした。
2007/12/31 - よいお年を! 2008/12/28 - よいお年を! 2009/12/31 - よいお年を!

子育てでドタバタしている間にも、世の中は変わっていきます、そして、VirtualBox de RAC というリアルな環境から仮想環境で Oracleと戯れ始めます。  
2010/12/31 - VirtualBox de Oracle11g R2 RAC #13

この年に、JPOUG (Japan Oracle User Group)がBootしました。そして、そのきっかけを作ったGuutaraと先日で飲んだばかりw。twitterやjjugとかGoogle Waveとかゆるーいつながりがすべての始まりでしたね〜。
2011/12/31 - よいお年を!

このころRACネタを封印、s4r_agentさんがRAC何ノード起動できるかシリーズをスタート。SQLチューニングでスクランブルしたり、DBおそーいと呼ばれていったら、javascript遅いだけーみたいな IEのjs遅い案件に巻き込まれることもおおかった年w でした。
2012/12/25 - Indexがあれば、いいってもんじゃない。中身がたいせつ

こんなネタもやってましたねー
2013/12/31 - SELECT ~ FOR UPDATE SKIP LOCKED その2

SQLチューニングキャラが確立されてきたこともあり、ネタ傾向が徐々に変わってきたような気がします。
2014/12/17 - 机上SQLチューニング、クイズ! 駆動表(外部表)はどれだ!!!!

細かいテクニックをおぼえるのに遊びながら覚えてたようなw
2015/12/30 - Pipelined table function で ascii art

昔のmacOSというかMacOSというか、Kanji Talkというか無駄なところにいろいろニッコリするような仕掛けがあってある意味余裕がある感じがしなくもないわけですが、最近のOS含め、そんなのあるのかなー。
2016/12/30 - 昔、Mac OSがやってようなことを... VirtualBox の GuestOS起動スプラッシュ

いろいろと悩み始めてた年ですw
2017/12/4 - ”utl_file I/O” - この症状はあれの可能性が高いですね。

そして, 移籍後、気持ちの余裕がなくてあまり書けてない年だったw
2018/11/25 - MacPro (mid2012)をmacOS Mojaveにアップデート / FAQ

気持ちの余裕は無いなりにw いろいろやってますw
2019/12/30 - 実行計画は、SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 おまけ#3

2019/12/31
そして、16年目へ
52700470

| | コメント (0)

2019年12月30日 (月)

実行計画は,SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 おまけ#3

この実行計画がなにを行っているか見抜けたかたは, 前日のエントリーを読んだか, RDFVIEWを利用したRDF Graphを試したことがある方ぐらいだと思います.
RDF Semantic Graph「RDF 超入門」

RDFトリプルをRelational表にマップしてダイレクトにアクセスする方式なのですが, ご存じない方には何のこっちゃというのも仕方ないと思います.
3,4年前ぐらいに, なんとなーく流れ的に関わることになって, 寝る暇も惜しんでRDFトリプルストア (実態はオブジェクト表だったはず. 違ったらコメント頂けますと幸いです) とこのRDFVIEWのSQLチューニング方法を調べていたもんですw

そのころは余裕なさすぎてブログにも書けずじまいでしたが, 良い機会なのでRDFVIEWを問い合わせた実行計画をレントゲン写真として載せておきます.
詳細は前日の準備段階のエントリーを読んでいただけると良いかと思いますが, 知らない用語とかいきなりでてきているので, なんとなーくそんなもんかなーぐらいの理解よいと思います.

RDFVIEWのを問い合わせるSQL文は, SEM_MATCH()を利用するのが特徴で, RDFVIEW最大の特徴であるRelational表を直接よみながら, 最終的に RDFトリプルを返すという点にあります.
R2RML: RDB to RDF Mapping Language / W3Cあたりを読んでもらうと想像できるのではないかと思います. 読んで最初にきづくのは,それに関わっているのは Oracle社の方だったりしてるので納得感があります.

ということで、
SQLは以下のとおり. 関わったことがない方はこれまた見たこともない SEM_MATCH()関数が大量のパラメータを取って呼び出されていることが見えるぐらいですね。
裏では, SEM_MODEL()で指定したRDF Graphのモデルに対応したRelational表のEMPLOYEES表からEMPLOYEE_IDを元に, FIRST_NAME, LAST_NAME, MANAGER_IDの3列を, それぞれをトリプルとして返すようなマッピングになっています.

SELECT
s
, p
, o
FROM
TABLE (
SEM_MATCH (
'{?s ?p ?o}'
, SEM_MODELS('TEST_MODEL1')
, null
, null
, null
, null
, ' '
, null
, null
, 'RDFUSER'
, 'LOCALNET'
)
)
ORDER BY
s
,p;
RDFUSER@orcl> desc employees
Name Null? Type
----------------------------------------- -------- ----------------------------
EMPLOYEE_ID NOT NULL NUMBER(6)
FIRST_NAME VARCHAR2(20)
LAST_NAME NOT NULL VARCHAR2(25)
EMAIL NOT NULL VARCHAR2(25)
PHONE_NUMBER VARCHAR2(20)
HIRE_DATE NOT NULL DATE
JOB_ID NOT NULL VARCHAR2(10)
SALARY NUMBER(8,2)
COMMISSION_PCT NUMBER(2,2)
MANAGER_ID NUMBER(6)
DEPARTMENT_ID NUMBER(4)

RDFUSER@orcl> break on index_name skip 1
RDFUSER@orcl> select index_name,column_name from user_ind_columns where table_name='EMPLOYEES' order by 1,2;

INDEX_NAME COLUMN_NAME
------------------------------ ------------------------------
EMP_DEPARTMENT_IX DEPARTMENT_ID

EMP_EMAIL_UK EMAIL

EMP_EMP_ID_PK EMPLOYEE_ID

EMP_JOB_IX JOB_ID

EMP_MANAGER_IX MANAGER_ID

EMP_NAME_IX FIRST_NAME
LAST_NAME

では, 実行計画を読み解いてみましょう.

EMPLOYEES表からEMPLOYEE_IDを元に, FIRST_NAME, LAST_NAME, MANAGER_IDの3列と説明しましたが, それぞれの列に索引が存在しているため, Index Only Scanで索引のみをアクセスし,
Id=7,8,9でEMPLOYEE_IDをEMP_EMP_ID_PK索引から, MANAGER_IDをEMP_MANAGER_IX索引から EMPLOYEE_IDとMANAGER_IDの2列からなら行を結合で作り出しています.
Id=11,12,13で同じく, EMPLOYEE_IDとEMP_NAME_IX索引から, EMPLOYEE_IDとLAST_NAMEの2列からなる行を結合で作り出してます.
Id=15,16,17でも, EMPLOYEE_IDとEM_NAME_IX索引から, EMPLOYEE_IDとFAST_NAMEの2列からなる行を結合でつくりだしています.

これらの動きから, トリプルを作成するために, EMPLOYEE_ID列, MANAGER_ID, FAST_NAME, FIRST_NAME列ぞれぞれを取得するために複数回索引にアクセスしています.
もし索引がなかったら, それぞれの列を取得するために, 複数回全表走査を行うだろうということは容易に想像できます. これらの動きは、RDFVIEWの特性の一つになっています. Relational表に格納されたデータを即刻RDFトリプルとして参照したいという目的のために性能にはある程度目をつぶっている姿が見えてきます.
列持ちのデータをトリプルという, ある意味, 行持ちのデータへ縦横変換しているわけですから仕方ない動作ではあります.

データの新鮮さよりも性能を, というケースでは, ロードという作業は必要になりますがトリプルストアを利用したほうが有利にはなります. トリプルストアをアクセスする実行計画は気が向いたら載せるかもしれません.
覚えておいてほしいことは, Id=19やPredicate InformationにRDF_RRのようなオブジェクトとUNION ALLのVIEWが1~3個登場したらRDFVIEWだろうということです. 治療が必要になった場合などには役にたつかもしれません.

Rdfview

-----
それでは, みなさま, 良いお年をお迎えください.



previously 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)

| | コメント (0)

2019年12月29日 (日)

実行計画は、SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 おまけ#2

Id=1とId=2のMERGE STATEMENTMERGEですぐにわかるとおもいます. MERGE文(通称UPSERT)の実行計画というレントゲン写真w

merge into sample_table
using sample_table_temp
on (sample_table.id = sample_table_temp.id)
when matched then
update set
sample_table.data = sample_table_temp.data,
sample_table.update_timestamp = systimestamp
when not matched then
insert values
(
sample_table_temp.id,
sample_table_temp.data,
systimestamp,
null
);

Merge

過去のMERGE文のエントリー, 少ないけど書いてた :)
MERGE文 #1 - 重複行の削除
MERGE文 #2 - 同一表でマージ?!
----
PIVOT / UNPIVOTやWITH句でinlineになるかtemp tableとしてマテリアライズされるかなんてものありだよなぁと思いつつ。多分いつか書くということにして、別のネタを思いついたのでそれを先に書くか



previously 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向け)

| | コメント (0)

2019年12月28日 (土)

実行計画は、SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 おまけ#1

ヒントで無理やりSQL transformationーーーん, してますが、DWH系、スタースキーマで利用する star transformationです.
ファクト表から各ディメンジョン表への参照整合性制約とビットマップ索引が必須となります. また, BITMAP MERGE/BITMAP CONVERSION TO ROWIDS/TABLE ACCESS BY USER ROWID (Id=33)にあるようにROWIDで1行1行アクセスする動きからも想像できると思いますが, ディメンジョン表のデータでファクト表が十分に絞り込めないケースでは性能的メリットはありません。ファクト表が絞り込めずに, 数億行を1行1行取得(シリアルに)していることを思い描ければどのようなケースが使いどころかも想像できるのではないでしょうか?
実行計画の特徴は, BITMAP MERGE/BITMAP CONVERSION TO ROWIDS というディメンジョン表のビットマップ索引を利用したアクセスと, ファクト表をなる表をBITMAP CONVERSION TO ROWIDSでえられるROWIDでアクセスしているとという点.
そして、Noteセクションにリストされる - star transformation used for this statement で判断できます.

SELECT
/*+
STAR_TRANSFORMATION
*/
ch.channel_class
, c.cust_city
, t.calendar_quarter_desc
, SUM(s.amount_sold) sales_amount
FROM
sales s
, times t
, customers c
, channels ch
WHERE
s.time_id = t.time_id
AND s.cust_id = c.cust_id
AND s.channel_id = ch.channel_id
AND c.cust_state_province = 'CA'
AND ch.channel_desc in ('Internet','Catalog')
AND t.calendar_quarter_desc IN ('1999-Q1','1999-Q2')
GROUP BY
ch.channel_class
, c.cust_city
, t.calendar_quarter_desc;


Star_transform

もう一つ, star transformationといえば, vector transformationも書かないと. この実行計画という名のレントゲン写真も一目見れば忘れることはないという特徴を持っています.
全く同じSQLでも可能ですが、star transformationのようにディメンジョン表でファクト表のデータが十分に絞りきれない場合やright-deep joinでもハッシュ結合が重すぎてParallel Queryにしても伸び悩むケースでは, ほぼ結合を行わない(行っても結合する行数が少ないので影響がすくない) vector transformの出番ですよね.
KEY VECTOR USEでディメンジョン表からin-memory accumulatorと呼ばれる多次元構造体を作成し, TABLE ACCESS INMEMORY FULLでファクト表を高速に読み出しつつ, in-memory accumulator上で集計. ディメンジョン表をファクト表を結合しないので巨大なハッシュ結合によるtemp落ちからも解放されます.
Noteセクションに- vector transformation used for this statementとリストされます. 特徴を見分けやすいですよね.

SELECT
/*+
VECTOR_TRANSFORM
*/
ch.channel_class
, c.cust_city
, t.calendar_quarter_desc
, SUM(s.amount_sold) sales_amount
FROM
sales s
, times t
, customers c
, channels ch
WHERE
s.time_id = t.time_id
AND s.cust_id = c.cust_id
AND s.channel_id = ch.channel_id
GROUP BY
ch.channel_class
, c.cust_city
, t.calendar_quarter_desc;

Vector_transform

JPOUG Advent Calendar 2016の17日目のエントリーでも書いてました.
スタースキーマを扱う実行計画の特徴
-----
30日が私の仕事納めなので, あと2つかくかも



previously 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

| | コメント (0)

2019年12月25日 (水)

実行計画は、SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 Day 25

実行計画は、SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 Day 25のエントリーです.
そして, ついに Advent Calendar 2019 全部俺 完走でございます. T_T 感涙w

Day 24 のつづきから.



CONNECT BY NO FILTERING WITH START-WITHとPredicate Information の 1 - access("MGR"=PRIOR "EMPNO")という部分から, Oracle Databaseの方言であると気づけた方は正解です.

CONNECT BY と PRIOR を利用した階層問合です. この手の問合ができなかったRDBMSではアンチパターンとされていましたが, Oracle Databasedでは..思い出せない, Oracle 7のころにはすでに存在していた構文です.

以下のようなSQL文をイメージできたら正解だと思います.

select
empno
,ename
,job
,mgr
,level
from
emp
start with
mgr is null
connect by
prior empno = mgr;


Connect-by-no-filtering-with-startwith





では, Advent Calendar最後なので, 本題と、あわせて解説もしてしまいましょう!

実行計画は以下のような感じになります.
Union-all-recursive-with-depth-first-rec


最後のお題は, 他のRDBMSでも利用できるようになったものが多い, 再帰問合です. 階層問合と同じことも行えます.
ただし、実行計画を見ていただくとわかりますが, 階層問合より再帰問合のほうが実行計画で行う必要のある操作が多いことに気づくはずです. この例の再帰問合では, EMP表に加え, IX_EMP索引を INDEX FULL SCANしたうえで, EMP表を統べてアクセスしているように見えます. TABLE ACCESS FULLでもよいとは思いますが, オプティマイザのミスかもしれませんね.(詳細まで調べてないですが)
つまり, 階層問合のTABLE ACCESS FULLが一度だけの実行計画と比較しても明らかに操作が多いことがわかります. この結果から, 階層問合と同じ結果を再帰問合で得るより, 方言ではありますが, 階層問合を利用したほうがコストは低いと考えることができます. 標準的な再帰問合を利用するか方言の階層問合を利用するかはその時の判断にはなりますが, これらの特徴を理解したうで, どちらを利用するか判断したようが良いと, 私は考えています.

with
employees (
empno
, ename
, job
, mgr
, lvl
) as
(
select
empno
, ename
, job
, mgr
, 1 lvl
from
emp
where
mgr is null
union all
select
e1.empno
, e1.ename
, e1.job
, e1.mgr
, e2.lvl + 1
from
emp e1
inner join employees e2
on
e2.empno = e1.mgr
)
search depth first by
mgr
, empno
set order#
select
empno
, ename
, job
, mgr
, lvl
from
employees
order by
order#;

そういえば, 昔, 階層問合と再帰問合ネタを書いてましたw
階層問合せか、再帰問合せか、それが問題だ
階層問合せか、再帰問合せか、それが問題だ #2
階層問合せか、再帰問合せか、それが問題だ #3 おまけ

--------
来年も JPOUG をよろしくお願いいたします。

では、皆様、メリークリスマス、そして、良いお年をお迎えください。



previously 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

| | コメント (0)

2019年12月24日 (火)

実行計画は、SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 Day 24

実行計画は、SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 Day 24のエントリーです.

Day 23 のつづきから.



2つのHASH JOINのなにが違うのか. 実行計画の見た目は異なりますが, SQL文はどちらも同じです. (ただし, 2つめの実行計画はヒントを利用して強制した実行計画です.)
どちらの実行計画も3表をINNER JOINしています.

違いは結合順序.

一つ目は一般的なバッチ系処理でよく見かけますが, 二つ目はDWH系で見かけることが多いのではないでしょうか? 
バッチ系でも必要があれば同様の最適化は行われますが ;)

一つ目は小さいと見積もられているTAB3表をビルド表にして、次に小さいと見積もられているTAB311を結合、その結合結果をビルド表にしてTAB31と結合しています.

二つ目はヒントで無理やり変更している影響で実行計画の見積もり行数やサイズに惑わされてしまいますが, そこは気にしないでください. m(_ _)m
ビルド表が, TAB311とTAB31になっていることに気づければ100点です.
ハッシュ結合のビルド表には結果セットの小さいものが選ばれます.
つまり, TAB3表が実はDWHでいうFACT表になっているようなケースで, 結合するディメンジョン表の表が小さい表となる状況(スタースキーマ)をイメージできればOKだと思います.

SQL文は同じでもハッシュ結合するビルド表を適宜入れ替えています.
DWH系では, ファクト表が巨大であるケースが多く一つ目の実行計画場合, TAB3と結合した結果巨大なビルド表を持ち回ることになりハッシュ結合の特性上どうしても不利になります.
それを避けるため, ファクト表より小さいディメンジョン表が常にビルド表になるような実行計画が, 二つ目の実行計画です.

以下、津島さんが紹介している left-deep joinとright-deep joinも参考するとよいと思います.
津島博士のパフォーマンス講座 第46回 パーティション・プルーニングとハッシュ結合について
https://www.oracle.com/technetwork/jp/database/articles/tsushima/tsushima-hakushi-46-2547814-ja.html


以下のようなSQL文をイメージできたら正解だと思います.

select
*
from
tab3
inner join tab31
on
tab3.item_code = tab31.item_code
inner join tab311
on
tab3.unique_id = tab311.unique_id;

RIGHT-DEEP joinの実行計画へ強制変更させたヒントは以下のとおり. 二つ目の実行計画はこのヒントでオプティマイザの意思に反しw むりやり作り出した実行計画です.

select
/*+
swap_join_inputs(tab31)
swap_join_inputs(tab311)
*/
*
from
tab3
inner join tab31
on
tab3.item_code = tab31.item_code
inner join tab311
on
tab3.unique_id = tab311.unique_id;


Leftdeep-join
Rightdeep-join




では、本題.


この実行計画という名のレントゲン写真から, どのようなSQL文をイメージしますか? また, どのような特徴をもっていると思いますか?

CONNECT BY NO FILTERING WITH START-WITHはむかしからあるOracle Databaseの方言で, 最近は他のRDBMSでも似たような構文が使えるようになりましたよね...なんとなく, 最終日のヒントを書いてしまったような気がしないでもない.
Connect-by-no-filtering-with-startwith


--------
全部俺 Advent Calendarももう少し。がんばれ、俺w


Day 25 へつづく



previously 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

| | コメント (0)

2019年12月23日 (月)

実行計画は、SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 Day 23

実行計画は、SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 Day 23のエントリーです.

Day 22 のつづきから.



COUNT STOPKEY前日のWINDOW NOSORT STOPKEYに似てはいます. もうお気づきですよね? 方言のほうです.

STOPKEYなので, 行数をカウントしています. Predicate Informationをみると答えもでています. 1 - filter(ROWNUM<=3) が構文のヒントですよね.

以下のようなSQL文をイメージできたら正解だと思います.

select 
*
from
tab3
where
rownum <= 3;

Count_stopkey




では、本題.

今回は, なんと, 2のレントゲン写真.

この実行計画という名のレントゲン写真から, どのようなSQL文をイメージしますか? また, どのような特徴をもっていると思いますか?

どちらもDay 12に紹介したHASH JOINですが, 何かがちがいますよね? どのような状況なのでしょうか?
Leftdeep-join
Rightdeep-join


--------
ねむけをこらえつつw


Day 24 へつづく



previously 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

| | コメント (0)

2019年12月22日 (日)

実行計画は、SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 Day 22

実行計画は、SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 Day 22のエントリーです.

Day 21 のつづきから.



WINDOW NOSORT STOPKEY STOPKEY とでて行数をカウントしてるってイメージが浮かんだらほぼ正解で, 方言をつかうか, SQL:2008 な違いになってきます. とは言っても多少癖が違ったりしますが.

比較的あたらしいと昨日書いていたのがヒントではあるのですが, WINDOW というところと, Predicate Information に 内部的には、ROW_NUMBER() OVER() とWINDOWS関数を利用しているところに気がつけば, SQL:2008 側の構文であるこに気づけるはずです.

以下のようなSQL文をイメージできたら正解だと思います.

select 
*
from
tab3
fetch first 3 rows only;

Window_nosort_stopkey




では、本題.

この実行計画という名のレントゲン写真から, どのようなSQL文をイメージしますか? また, どのような特徴をもっていると思いますか?

これ, すでにヒント出ちゃってるので簡単ですよね.
Count_stopkey

--------
Advent Calendarもあと少し.

Day 23 へつづく


previously 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

| | コメント (0)

2019年12月21日 (土)

実行計画は、SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 Day 21

実行計画は、SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 Day 21のエントリーです.
Day 20 のつづきから.



UNION, UNION ALLやINTERSECTIONににていますが, Operationがちがいますよね. UNION/INTERSCTIONときたら残るは..... MINUS そのまんまですw
Predicate InformationやOperetion部分から, UNIONやUNION ALLで使われた述語と同じなであることが確認できる2つのSELECT文が見えてきます. あとはそれらの結果セットをどうするかという違いですよね.

Minus_image

以下のようなSQL文をイメージできたら正解だと思います.

select 
*
from
tab311
where
unique_id between 1 and 100
minus
select
*
from
tab311
where
sub_item_code in ('0000000100','0100000000');


Minus


では、本題.

この実行計画という名のレントゲン写真から, どのようなSQL文をイメージしますか? また, どのような特徴をもっていると思いますか?

おお, これは! 比較的あたらしい部類ですね. Oracle Databaseの実行計画では.

Window_nosort_stopkey

 


--------
ながいーーーーーい、ほぼ一ヶ月を抜けた....ほっとして熱でないといいけどw

Day 22 へつづく



previously 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

| | コメント (0)

2019年12月20日 (金)

実行計画は、SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 Day 20

実行計画は、SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 Day 20のエントリーです.

Day 19 のつづきから.



UNIONやUNION ALLににていますが, Operationがちがいますよね. しかもわかりやすいです. INTERSECTION そのまんまです.

Predicate InformationやOperetion部分から, UNIONやUNION ALLで使った述語と同じで, 2つのSELECT文が見えてきます. あとはそれらの結果セットをどうするかという違いです.
Intersect_img


以下のようなSQL文をイメージできたら正解だと思います.

select 
*
from
tab311
where
unique_id between 1 and 100
intersect
select
*
from
tab311
where
sub_item_code in ('0000000100','0100000000');

Intersection




では、本題.


この実行計画という名のレントゲン写真から, どのようなSQL文をイメージしますか? また, どのような特徴をもっていると思いますか?

MINUS...そこに気づけば簡単ですよね.
Minus


--------
お通しがカニっていいよなー(謎

Day 21 へつづく



previously 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

| | コメント (0)

2019年12月19日 (木)

実行計画は、SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 Day 19

実行計画は、SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 Day 19のエントリーです.

Day 18 のつづきから.



Day 17のレントゲン写真とDay 18のレントゲン写真を比較するとすぐに気づけるとおもいます.
Day 17 - UNION
Sort-unique_union_all

Day 18 - ? Similar to UNION
Union-all


SORT UNIQUEというOperationがないだけです. :) となると答えは簡単.

Id = 1 がUNION-ALLというOperationから, UNION ALL という構文なのは明らかです.

Id = 3,2 そして,  Predicate Informationの ”3 - access("UNIQUE_ID">=1 AND "UNIQUE_ID"<=100)” から 一つ目のSELECT文は, 索引範囲検索で表をアクセス.

Id = 6.5.4 そして,  Predicate Informationの "6 - access("SUB_ITEM_CODE"='0000000100' OR "SUB_ITEM_CODE"='0100000000')" から 二つ目のSELECT文は, INLIST ITERATORで索引範囲検索で表を繰り返しアクセス.

以下のようなSQL文をイメージできたら正解だと思います.

select 
*
from
tab311
where
unique_id between 1 and 100
union all
select
*
from
tab311
where
sub_item_code in ('0000000100','0100000000');

UNION ALLも複数のSELECT文を実行するより1つのSQL文にしたほうが効率が良いのであれば、手術という名の書き換えしかないのは, UINONの場合と同じです. Index Only Scanが使える場合はUNION ALLのままにしておくなんてケースはあると思いますが, そもそも索引の追加はしてほしくないという, 大人の事情があるったり, なかったり.

大人って大変なんです. むーりーなものはむーりーと言われることはあって, それでも, こちらは, Index Only Scan or Die? って突きつけないといけないこともあるのでw Vector Transformな案件はそんなアトモスフィアだった, 遠ーい目w

そして, 「私, 失敗しないので!」 的なw 言葉を残しつつサクッと帰宅しちゃいましょ! (またかよw
フリーランスにはメロンおじさんが必要だなw





では、本題.


この実行計画という名のレントゲン写真から, どのようなSQL文をイメージしますか? また, どのような特徴をもっていると思いますか?

INTERSECTION...そこに気づけば簡単ですよね.
Intersection


--------


Day 20 へつづく



previously 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

| | コメント (0)

2019年12月18日 (水)

実行計画は、SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 Day 18

実行計画は、SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 Day 18のエントリーです.

Day 17 のつづきから.



Day 17のレントゲン写真を読み解いてみましょう.

Id = 2 の UNION-ALLというOperationから, UNION ALL という構文であることが読み取れます.

Id = 1 から UNION ALL であるが, SORT UNIQUE されている. つまり, UNION ALL した後に、各SELECT文から返された行から重複行を排除していることが読み取, 実際には, UNION ALL ではなく UNION であること希読み取れればあとは簡単.

Id = 4,3 そして,  Predicate Informationの ”4 - access("UNIQUE_ID">=1 AND "UNIQUE_ID"<=100)” から 一つ目のSELECT文は, 索引範囲検索で表をアクセス.

Id = 7, 6, 5 そして,  Predicate Informationの "7 - access("SUB_ITEM_CODE"='0000000100' OR "SUB_ITEM_CODE"='0100000000')" から 二つ目のSELECT文は, INLIST ITERATORで索引範囲検索で表を繰り返しアクセス.

以下のようなSQL文をイメージできたら正解だと思います.

select 
*
from
tab311
where
unique_id between 1 and 100
union
select
*
from
tab311
where
sub_item_code in ('0000000100','0100000000');

INDEX RANGE SCANで表をアクセスしているので、この例では無理ですが、可能ならCovering IndexでIndex Only Scanの持ち込む治療も行える可能性はあります. それはあくまで治療の必要のある大人の事情がある場合ですがw

なお、Day 16 の CONCATENATION という, 最適化と同じ意味ではあるのですが、UNION のOperationと区別されている点に注目してください.

重要. 治療が必要な場合, NO_EXPANDヒントという注射で治療するか, SQL書き換えという手術が必要なのか判断できるポイントになるからです!!!

重要. 治療が必要な場合, NO_EXPANDヒントという注射で治療するか, SQL書き換えという手術が必要なのか判断できるポイントになるからです!!!

たいせつなので二度書きましたw (ひさびさw


UNION の場合, オプティマイザは, Day 16のようなSQL文へ内部的に書き換える最適化は行いません. (将来はどうなるかしりませんが) なので, UNION で索引使ってくれるかと思ってたが、使ってくれない. 無理に使わせても全表走査のほうが効率がよいのなら, Day 16のような構文に書き換える手術をおこない, 2回の全表走査から1回の全表走査で済むようにしちゃいましょ.

そして, 「私, 失敗しないので!」 的なw 言葉を残しつつサクッと帰宅しちゃいましょ!

Sort-unique_union_all




では、本題.


この実行計画という名のレントゲン写真から, どのようなSQL文をイメージしますか? また, どのような特徴をもっていると思いますか?

UNON系構文ぽい...簡単です. ちがいに気づけば.
Union-all


--------
やらないことを決めないと時間がないw

そういえば, Doctor X で, やらないことを事前に伝えてるのに気づく.


Day 18 へつづく
そして、JPOUG Advent Calendar 2019も Day 18 へつづく



previously 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 / UNION

| | コメント (0)

2019年12月17日 (火)

実行計画は、SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 Day 17

実行計画は、SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 Day 17のエントリーです.
また、
JPOUG Advent Calendar 2019 Day 17のエントリーとのクロスポストとなっています.


Day 16 のつづきから.
そして、JPOUG Advent Calendar 2019 Day 16のエントリーは, 「 Oracle Advanced Queuing(AQ)使ってみませんか? / kjmtgm さん」でした



昨日の実行計画の特徴は, CONCATENATIONこのオペレーションを見たら, あれだ! と気が付けるように日々精進しておくと, 一目置かれるような存在に, なれるとか, なれないとかw (保証はしませんw

このオペレーションは、SQLトランスフォームの一つです. 表を検索する際に、同一表の異なる列が OR 条件で利用されており、単一索引利用するより、OR条件のそれぞれの列で個別の索引を利用させることで複数の索引を同時に利用させるようにUNIONを利用し個別のSELECT文に分割統合します. (内部でどう書き換えているかは後半でお見せします)


実際のSQL文は、以下のようなSQL文をイメージできたら正解だと思います. USE_CONCATヒントで強制することもありますが, もちろんオプティマイザの判断で行うこともあります. オプティマイザの判断が誤っている場合には, NO_EXPANDヒントというヒントで抑止することも可能です.

select 
*
from
tab311
where
unique_id= 1
or sub_item_code = '0001000000';

select 
/*+
use_concat
*/
*
from
tab311
where
unique_id= 1
or sub_item_code = '0001000000';


SQLヒントや, オプティマイザに任せず, 書き換えるという昔のスタイルだと, 上記SQL文を以下のように書き換えると同じ意味になります ;) オプティマイザは偉い. まちがいもするけど. それは人も同じw 失敗を肥やしにして訂正するのも, 最近のオプティマイザの賢いところ. ですが, それでもだめなら, 人の手でw

このような書き換えが行われる, もしくは有利な場面は、ORで利用されている列がそれぞれ個別の索引を持ちそれぞれの条件で索引アクセスのコストが低くなる一意検索だったり, 比較的狭い範囲の索引範囲検索が有効な場合です. 統計情報と実態の乖離が大きい場合にはオプティマイザが誤って選択してしまうケースもあります. このままで行くか, 治療するかの見極めが必要になることも意外に多いタイプですね.
以下のような書き換えをした場合, 最悪のケースは, どちらのSELECT文でも全表走査してしまうケースで, どちらも索引を利用しないのが正しいのであれば, 2つのSELECT文で全表走査を2回行わせるより, 書き換える前のSQL文で1度だけ全表走査させたほうがはるかに効率できてきすw (セグメントサイズにもよりますが)

ポイントは, 2つのSQL文にしてUNIONしたほうが無駄ないのかどうかを考える! ということです.

select 
*
from
tab311
where
unique_id = 1
union
select
*
from
tab311
where
sub_item_code = '0001000000';

あ、しまった....あ...いいや、構文おなじだけだしw


Concatenation





では、本題.


この実行計画という名のレントゲン写真から, どのようなSQL文をイメージしますか? また, どのような特徴をもっていると思いますか?

少しだけネタバレしましたが今回も特徴のあるわかりやすいOperationがでてますよね. 見た目は違いますが同じですが, ヒントw
Sort-unique_union_all


--------
外資系って, 31まで仕事なのな, というのに気づいて 2 年目ですw 私個人の営業は 30までですがw


Day 18 へつづく
そして、JPOUG Advent Calendar 2019も Day 18 へつづく



previously 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

| | コメント (0)

2019年12月16日 (月)

実行計画は、SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 Day 16

実行計画は、SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 Day 16のエントリーです.

Day 15 のつづきから.



Id = 4のOperationはTABLE ACCESS FULLですが, Id = 1から Id = 3に特徴があります.
PX ときたら! そう, Parallel Executionですよね.

PX BLOCK ITERATORで非パーティションをパラレルにアクセスしていいます.

Note部分に, Degree of Parallelism is 4 because of hint なんてあるので、HINTを使ってパラレル化していることも読み取れます. HINTなしでもTABLE等に並列度が設定されている場合には設定されている並列度でパラレル化されます. 意図せずパラレル実行されている場合には、NO_PARALLELヒントで抑止したり, そもそも表や索引に並列度設定するつもりじゃなかったという場合には、表や索引の並列度をNOPARALLELにしましょう. 昔、そんな事故がありましたw

この場合, HINTが利用されているのはあきらかなので, 以下のようなSQL文をイメージできたら正解でしょうね.

select 
/*+
parallel(4)
*/
*
from
tab3;

ちなみに, このテーブルの並列度は, 以下の通りに設定されておりました.

SCOTT> select table_name,degree from user_tables where table_name='TAB3';

TABLE_NAME DEGREE
------------------------------ ---------------
TAB3 1


Px





では、本題.


この実行計画という名のレントゲン写真から, どのようなSQL文をイメージしますか? また, どのような特徴をもっていると思いますか?

CONCATENATIONなのはわかると思いますが, わかりやすいOperationがでてますよね. それが, ポイント.
Concatenation


--------
3ヶ月がはえーよw


Day 17 へつづく



previously 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

| | コメント (0)

2019年12月15日 (日)

実行計画は、SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 Day 15

実行計画は、SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 Day 15のエントリーです.

Day 14 のつづきから.



この実行計画はわかりやすいですよね, 読んだまんまです. HASH JOIN FULL OUTER

もうそのまま, SQLに書いちゃえばいいですよね. 結合条件は, Predicate Information に Id=2 の部分は 2 - access("TAB3"."UNIQUE_ID"="TAB311"."UNIQUE_ID") としてリストされています.

以下のようなSQL文をイメージできたら正解でしょうね.

select 
*
from
tab3
full outer join tab311
on
tab3.unique_id = tab311.unique_id;


Fullouterj





では、本題.


この実行計画という名のレントゲン写真から, どのようなSQL文をイメージしますか? また, どのような特徴をもっていると思いますか?

TABLE FULL SCANなのはわかると思いますが, 特殊なOperationがでてますよね. それが, ポイント.
Px

--------
一日中缶詰で, チューナーっぽくない物書き、俺一番萌えないやつじゃん, それw


Day 16 へつづく



previously 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

| | コメント (0)

2019年12月14日 (土)

実行計画は、SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 Day 14

実行計画は、SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 Day 14のエントリーです.

Day 13 のつづきから.



眠気と戦いながらw 書いているので, タイポ多目とか. ケンブリッジ関数通してないのに文字の順序入れ替わっているとかありましたら, ここまでご連絡くださいませ.(どこだよーw

というジャブはこれぐらいにしておいて,

この実行計画も adaptive plan となっているので, 実際には NESTED LOOPS で実行されている可能性のある HASH JOIN ですよね? 

HASH JOINのナカーマではありますが, HASH JOIN OUTER という部分で気づくかもしれませんが, OUTER という部分で外部結合であることがわかります.
また、Predicate Information には結合条件にOracleの方言に書き換えられた結合条件に気づけるとおもいましす. Id=1に対応するPredicate Informationの1 - access("TAB3"."UNIQUE_ID"="TAB311"."UNIQUE_ID"(+))がそれですね.

Predicate Informationも含め, 以下のようなSQL文をイメージできたら正解だとおもいます.

select 
*
from
tab3
left join tab311
on
tab3.unique_id = tab311.unique_id
where
tab3.unique_id between 1 and 100;

Hjouter





では, 本題.


この実行計画という名のレントゲン写真から, どのようなSQL文をイメージしますか? また, どのような特徴をもっていると思いますか?

Fullouterj

今日は結合は結合でもあまり使わないですね. 業務系で使いどころがあまりなく....w....何年か前にExadataへの移行案件で, 出会った結構痺れるチューニング案件を思い出す, この結合.

--------
今日は寝落ちしてないけど、なんでこんなに忙しいんだw


Day 15 へつづく



previously 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

| | コメント (0)

2019年12月13日 (金)

実行計画は、SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 Day 13

実行計画は、SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 Day 13のエントリーです.

Day 12 のつづきから.



さてさて、Advent Calendarも半分ぐらい. あともうひと頑張りw

HASH JOINとは出ていても、TABLE ACCESS FULL SCANとはかぎらず、INDEX RANGE SCANとTABLE ACCESS BY INDEX ROWID BATCHEDとの組み合わせも意外に見かけます. このようなケースでは, 全表走査や高速索引走査(INDEX FAST FULL SCAN)でIndex Only Scan狙いの治療も考えられますが, それはおいといて.

ハッシュ結合で最初に見るべきポイントは、結合順. NESTED LOOPSも同じですが、結果セットの小さい方がビルド表(外部表, NESTED LOOPSの駆動表)になっているかを確認しておきましょう. もし違うのであれば、統計情報を最新化(実態との乖離が大きければ)、そうでなければヒント等で実行計画を管理する方向にするか. オプティマイザがなんとなく理解してくれるまでまつ.
ということになります.

また, Note部分に - this is an adaptive plan が現れています. これは HASH JOIN かもしれないし、 NESTED LOOPSかもしれない 実行計画であることをしめしています. 実際にヒットする行数によってどちらになるかがきまります. この例ではSQL*Plusのautotraceを利用しているため, 静的な統計情報を基にした, 見積もりなので実際にはどちらのプランで動作したのかはわかりません.
動作時の実行計画を確認するには, Actural Planを確認する必要があります.

Enterprise Editionでオプションが利用できる状況であれば、SQLモニター, そうでなければ、DBMS_XPLAN.DISPLAY_CURSOR()を利用してActual Planを確認できます.

dbms_sqltune.report_sql_monitorを利用する. (typeパラメタータを 'text' にすることでhtmlではなく、textでレポートを出力することもできます)
「高度なSQL実行計画の取得」を実践する (2/3)

/*+ gather_plan_statistics */ やalter session set statistics_level=all;とDBMS_XPLAN.DISPLAY_CURSOR()を利用したActual Planの確認
DBMS_XPLAN.DISPLAY_CURSORの使い方とちょっとした落とし穴


余談がおおくなってしまいましたが, Predicate Informationも含めてイメージすれば, 以下のようなSQL文をイメージできたら正解だとおもいます.

select 
*
from
tab3
inner join tab311
on
tab3.unique_id = tab311.unique_id
where
tab3.unique_id between 1 and 100;


Hj





では、本題.


この実行計画という名のレントゲン写真から, どのようなSQL文をイメージしますか? また, どのような特徴をもっていると思いますか?

Hjouter


HASH JOIN だけどちょいとちがう.
--------
二日連続で寝落ちしてたw


Day 14 へつづく



previously 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

| | コメント (0)

2019年12月12日 (木)

実行計画は、SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 Day 12

実行計画は、SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 Day 12のエントリーです.

Day 11 のつづきから.



MERGE JOINは最近のOracle Databaseではあまり見かけなくなりましたが, 結合対象データが多い場合かつ, 特定の結合条件ではかならず選択されますよね?

等価結合(=)以外の結合条件で, データ量が多い場合には MERGE JOIN が選ばれます.

Predicate Informationの情報などから次のようなSQL文がメージできれば正解でしょう.

select 
*
from
tab3
inner join tab311
on
tab3.unique_id > tab311.unique_id
where
tab3.unique_id between 1 and 100;

結合条件がMERGE JOINは, ソート処理を伴うこともありソート処理をバイパスできるような索引がない場合はかなり重くなる傾向があります.
今日の本題も予想できちゃいそうですが, ソートをバイパスできそうであれば,MERGE JOINを利用してチューニングしちゃうこともなくはないです. (巨大なデータのソート処理はやはり重いので避けたいところ)

そういえば, HASH JOINもMERGE JOINでも, Temp落ちが激しくて遅かったころは, あえて, NESTED LOOPSに倒すなんてこともありました.... Temp落ちしても早くなってきたので, そこまでするかってのは微妙ではありますが, 最近は.
いずれにしても, 症状と手術の副作用も考えてどうするかってところにはなりますが, 術後のリスクは相手にもしっかり伝えておくことは重要です.

この例の場合も, 大人の事情とSQLの列の利用状況などにもよりもよりますが, Index Only Scanを組み合わせたチューニングすることはあります. アクセスするブロック数がどれだけ減らせるかの検証は必要ですが.

また, 結合条件がない(意図的に行なっている場合も, 結合条件が漏れている場合もあり)場合もMERGE JOINにはなりますが, その場合は, ”MERGE JOIN (CARTESIAN)" というOperationに変わるので区別しやすいとおもいます.
Mj





では、本題.


この実行計画という名のレントゲン写真から, どのようなSQL文をイメージしますか? また, どのような特徴をもっていると思いますか?

Hj

--------
晩御飯たべて、少し横になったら爆睡してて、さっき目覚めたのはナイショw


Day 13 へつづく



previously 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

| | コメント (0)

2019年12月11日 (水)

実行計画は、SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 Day 11

実行計画は、SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 Day 11のエントリーです.

Day 10 のつづきから.



Day 10 でついに結合の登場. 駆動表となるTAB3のTAB3_PK索引をINDEX UNIQUE SCAN(一意検索)してROWIDを取得(Id=3) 、Id=2でId=3で取得したROWIDを元にTAB3をTABLE ACCESS BY INDEX ROWIDでアクセス後、id=5でPredicate Informationにリストされている結合条件TAB311.UNIQUE_IDでTAB311_PK索引をINDEX RANGE SCAN して複数件のROWIDを取得、最後に、id=4で内部表となっているTAB311から、TABLE ACCESS BY INDEX ROWID BATCHEDで複数のROWIDに対応する複数の行を取得という実行計画になっています.
Nested Loop Joinの基本系といってもよい実行計画になっています。 Id=3,2でアクセスされている表が駆動表(外部表)で、この表は一般的に、内部表(Id=5,4でアクセスされている表)です.
一般的に、駆動表の結果セットは内部表の結果セットより少ないことが、Nested Loop Joinでの性能上重要な意味があります. 統計情報が不正確だったりすると本来内部表であるべき表が駆動表となって思わぬ処理遅延を引き起こします. この実行計画では索引スキャンが妥当か、妥当であること、駆動表が妥当であることなごが性能検証でのポイントになります.

以下のようなSQL文をイメージできたら大体あっていると思います.

select 
*
from
tab3
inner join tab311
on
tab3.unique_id = tab311.unique_id
where
tab3.unique_id = 2;

また、大人の事情とSQLの列の利用状況などにもよりもよりますが、Index Only Scanを組み合わせて、Nested Loop Joinをチューニングすることもあります.
Nlj






では、本題.


この実行計画という名のレントゲン写真から、どのようなSQL文をイメージしますか? また、どのような特徴をもっていると思いますか?

Mj

比較的少量の等価結合では Nested Loop Joinが無難ですが、データ量が多い場合には、これでした. 古いバージョンのOracle Databaseで大量データの結合といえば、この結合という時代もありました. 最近はあまり見かけないのですが、特定の状況ではこれしか使えないという状況もあります. :)

--------
昨日は、ポンギ方面へ久々に行った. むかーし、むかーし、あの辺で仕事してたなぁ〜. 遠い目. そして、10年ぐらい前とは違うビル群...

Day 12 へつづく



previously 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

| | コメント (0)

2019年12月10日 (火)

実行計画は、SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 Day 10

実行計画は、SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 Day 10のエントリーです.

Day 9 のつづきから.


TABLE ACCESS INMEMORY FULL となっているので、INMEMORYのTABLE ACCESS FULL という状況なのはすぐに読み取れるのではないでしょうか?
また、Predicate Information はリストされていないので、WHERE句がないという点にもきづくと思います. そう Day 11)のSQL文と同じ.
INMEMORYはEnterprise Editionの機能(SEに降りてくる機能もありますが、今のところ)なので、そのあたりも想像できます. (SQL文自体には関係ないわけで)

select * from tab3;

INMEMORYというoperationをみたら、in-memoryが有効化されていると判断すればよいとおもいます. (inmemory_sizeに100MB以上の値がセットされているはずです)
第53回 Oracle Database In-Memoryについて / 津島博士のパフォーマンス講座
in-memory関連の謎パラメータ 18c / Mac De Oracle

 

TABLE ACCESS FULLで物理読み込みがきついのであれば、こんな手も使えなくもないということで....

Table_access-inmemory_full


 


 

では、Day 10の本題

この実行計画という名のレントゲン写真から、どのようなSQL文をイメージしますか? また、どのような特徴をもっていると思いますか?

Nlj

よく見かける実行計画なので、簡単だと思います. :)

 


昨日は、ポンギ方面へ久々に行った. むかーし、むかーし、あの辺で仕事してたなぁ〜. 遠い目. そして、10年ぐらい前とも違うビル群....

 

Day 11 へつづく


previously 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

 

| | コメント (0)

2019年12月 9日 (月)

実行計画は、SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 Day 9

実行計画は、SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 Day 9のエントリーです.

Day 8 のつづきから.


INDEX SKIP SCANとでていて、Predicate Information に "2 - access("SUB_ITEM_CODE"='0000000001') filter("SUB_ITEM_CODE"='0000000001')" とでている.
そして、TABLE ACCESS BY INDEX ROWID BATCHED あるとなれば、実行計画というレントゲンからSQL文をイメージできるのではないでしょうか?

ヒントで強制されていたり、オプティマイザが判断したかのいずれかのパターンなので以下のようなSQLが浮かぶのではないでしょうか?

select /*+ index_skip(tab31 tab31_pk) */ * from tab31 where sub_item_code='0000000001';
select * from tab31 where sub_item_code='0000000001';

 

Index-skip-scan

ところで、INDEX SKIP SCAN はどのような状況かというと、 
TAB31_PK は複合索引であることが前提になります。複数の列からなるこの索引の列のうち、第2キー以降にPredicate Informationにリストされている sub_item_code列があることになります. たとえば、2列の複合索引があるとして、この実行計画では第2キーのsub_item_code列だけで検索されている. WHERE句で検索条件に利用されているのは sub_item_code列だけということになります.

20191208-03531

INDEX SKIP SCANはINDEX RANGE SCANになるような索引を作成した方が効率がよいことが多いですが、大人の事情縛りのチューニングなどでは、索引の最適化までは行えず、SKIP SCANの効果ができるようであれば、それ以上治療しないという選択もあります.
ただ、可能ならINDEX RANGE SCANになるような物理的な手術を行ったほうがよいケースのほうが圧倒的に多いです. SKIP SCANでもいよいよダメだ、という状況になってから慌てるぐらいなら、バッサリやっちゃったほうがスッキリすると思うんですね. そういうところに限って、夜中や休日に緊急オペで呼び出されるなんてことも意外におおかったです.
最終的には判断患者さんの判断にはなりますが、リスクは伝えておいた方がよいと思います.



さて、本題、Day 9の実行計画というレントゲン写真はこれ!

これは!
とにかく、実行計画をしっかり診てください.

Table_access-inmemory_full

この実行計画という名のレントゲン写真から、どのようなSQL文をイメージしますか? また、どのような特徴をもっていると思いますか?

これは Enterprise Editionの機能ですよね...(ヒント:)

Day 10 へつづく


previously 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

 

| | コメント (0)

2019年12月 8日 (日)

実行計画は、SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 Day 8

実行計画は、SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 Day 8のエントリーです.

Day 7 のつづきから.


Predicate Informationには何もない、かつ、TAB3_PKという索引を参照しているだけとなれば、Index Only Scanですよね. unique_id列でTAB3_PKという索引があったとして、Day 7のように、INDEX FAST FULL SCANでもない.
索引のキー順に読まむ必要のあるような句があるということ. 索引のキー順に読ままなければならないのは、ORDER BY ですよね?

unique_idという列が索引に含まれていたとして、それ以外の列は参照されていない. そして、ORDER BY unique_id で昇順ソート要求があるなれば、以下のようなSQL文をイメージできていたら正解だと思います.
なお、降順ソートの場合もありますが、その場合は INDEX FULL SCAN DESCENDINGとなります.

select unique_id from tab3 order by unique_id;

Index_full_scan



さて、本題、Day 8の実行計画というレントゲン写真はこれ!

ほ、ほう、これは、めずらしい、INDEX SKIP SCAN

Index-skip-scan

この実行計画という名のレントゲン写真から、どのようなSQL文をイメージしますか? また、どのような特徴をもっていると思いますか?

あえて、SKIP SCANで治療したのはかなり少ないのですが、実際に効くケースもあるので、治療の選択肢としてはなくなないですね..索引を変更したりするリスクを避けたいという、大人の事情がある場合、ヒントで SKIP SCANをすることで、試験範囲を限定できたりすることもあります.
ポケットはたくさんあったほうがなにかと便利 :)

Day 9 へつづく


previously 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
・実行計画は、SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 7 / INDEX FULL SCAN、Index Only Scan

 

| | コメント (0)

2019年12月 7日 (土)

実行計画は、SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 Day 7

実行計画は、SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 Day 7のエントリーです.

Day 6 のつづきから.



どのようなSQL文かイメージできたでしょうか? その特徴は?

TABLE ACCESS BY INDEX ROWID BATCHEDも無いし、Predicate Information もない. ということはWHERE句はないと読み取れます.

Index Only Scanなのは間違いないですが、INDEX FAST FULL SCAN

このOperationは、高速全索引スキャンは索引順に読む必要のない場合に考慮される実行計画です。例えば、索引の順序づけにしたがって読み出したい場合、order by unique_idのように索引順に読み出したい場合には選択されません.

と、ここまでくれば、 WHERE句なし、ORDER BY句なしで、かつIndex Only Scanなので、SELECTリスト等、参照されている列すべてが索引にふうまれている問い合せと見て良いのではない.

オプティマイザの判断(判断に影響を与えるパラメータがある)で INDEX_FFSヒントを利用しているか、オプティマイザ判断でヒントはないかもしれない場合くらい、以下のようなヒント付きか、ヒントなしの以下SQLをイメージできていれば正解ではないでしょうか.
SCOTT> select /*+ index_ffs(tab3 tab3_pk) */ unique_id from tab3;
SCOTT> select unique_id from tab3;


Index_fast-full-scan-with-index-only-sca


グリーンペペさんのこんなエントリーを思い出しました:)
OraOraOracle Full / Scanを速くしちゃう その6 / ペンネーム:グリーンペペ

yohei-aさんもこんな straceしてたりして
ablog 不器用で落着きのない技術者のメモ / SQLトレースとstrace / yohei-a




さて、本題、Day 7の実行計画というレントゲン写真はこれ!


INDEX FULL SCAN ?

Day 6のOperationに似ていますが、FASTではありません.

Index_full_scan


この実行計画という名のレントゲン写真から、どのようなSQL文をイメージしますか? また、どのような特徴をもっていると思いますか?


いろいろ考えちゃいますね〜。いろいろw

Day 8 へつづく



previously 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 FULL SCAN

| | コメント (0)

2019年12月 6日 (金)

実行計画は、SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 Day 6

実行計画は、SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 Day 6のエントリーです.

Day 5 のつづきから.



どのようなSQL文かイメージできたでしょうか? その特徴は?

"あれ? INDEX RANGE SCAN + TABLE ACCESS BY INDEX ROWID BATCHED って Day 4 と同じ? と思ったあなた! よーく見てください〜. 違うんですよ〜っ!"

INLIST ITERATORPredicate Information3 - access("UNIQUE_ID"=1 OR "UNIQUE_ID"=10)

3 - access("UNIQUE_ID"=1 OR "UNIQUE_ID"=10) という述語をみれば、 WHERE句に OR 条件があるのは明らかです. :) OR があるのは明らかですが、 実はINLIST ITERATOR というオペレーションは IN句を利用した場合にも発生します。 IN (a, b) って結局、 a or b なので内部的には同じ状況になっています。

この実行計画は、 id=1のINLIST ITERATOR 以下のid=2,3が2回実行されています. 3 - access("UNIQUE_ID"=1 OR "UNIQUE_ID"=10) = UNIQUE_ID IN (1, 10) となり、IN句の中の値の個数分繰り返されている = 2回.

select * from tab311 where unique_id = 1 or unique_id = 10;
select * from tab311 where unique_id in (1, 10);

のいずれかということになります :) INLIST ITERATORで繰り返すのがよいのかはデータ量しだいだと思います。この場合、unique_idが主キーなので2回繰り返しても問題はないと思います。とはいえ、INDEX RANGE SCANだけを2回実行してROWIDをあつめて、TABLE ACCESS BY INDEX ROWID BATCHEDを1回実行したほうがよいのではないかと思わなくもない.
id=1とid=2のOperationを入れ替えれば、INLIST ITERATIONで繰り返すのはINDEX RANGE SCAN(実質、INDEX UNIQUE SCAN を 2回ですが)を2回実行してUNIQUE KEYから2つのROWIDをあつめ、そのあと、TABLE ACCESS BY INDEX ROWID BATCHEDをやったらいいんじゃないかなぁ(細かいこというと)と実行計画をみながら思ったのでした.
Inlist-iterator




さて、本題、Day 6の実行計画というレントゲン写真はこれ!

? TABLE ACCESS BY INDEX ROWID BATCHED がないですね. でもちょっと違う.

INDEX FAST FULL SCANとでています
Index_fast-full-scan-with-index-only-sca

この実行計画という名のレントゲン写真から、どのようなSQL文をイメージしますか? また、どのような特徴をもっていると思いますか?

いろいろ考えちゃいますね〜。いろいろw

Day 7 へつづく



previously 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

| | コメント (0)

2019年12月 5日 (木)

実行計画は、SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 Day 5

実行計画は、SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 Day 5のエントリーです.

Day 4 のつづきから.



どのようなSQL文かイメージできたでしょうか? その特徴は?

"あれ? INDEX RANGE SCANって Day 3 と同じ? と思ったあなた! よーく見てください〜. 違うんですよ〜っ!"

なにが Day 3 のINDEX RANGE SCANと違うか.... それは Index Only Scanではないというところ.

Predicate Informationは、Day 3とほぼおなじ(リレラル値は異なりますが)、2 - access("UNIQUE_ID">=1 AND "UNIQUE_ID"<=2) となっています. WHERE unique_id BETWEEN 1 AND 2 のようなWHERE句が浮かびますよね?

残るOperationは、Id=1のTABLE ACCESS BY INDEX ROWID BATCHEDです. その他の句を思い浮かべるようなOperationはりません. WHERE句以外で、索引に含まれていない列がどこかに含まれているということに気づけば答えは簡単.

SELECTリストで TAB3_PK索引に含まれていない列が参照されているということになります. 次のようなSQL文をイメージできたら正解だと思います.
SELECTリストは * にしてあるのは、SQL*Plusのautotraceでは、それらを特定するまでの情報はリストされないため、SELECTリストを * にしています. 索引に含まれている列以外を参照させればよいので.

select * from tab3 where unique_id between 1 and 2;
Index_range_scan

ちなみに、TABLE ACCESS BY INDEX ROWID BATCHEDというOperationは、Oracle Database 12cR1 から見られるようになったOperationです.
それまでは、TABLE ACCESS BY INDEX ROWID というOperationだけで、裏では、db file parallel read だったり、db file sequential readだったりしてたのが、実行計画からも判断できるようになって、おお〜っ. と感じたことを思い出した ;)
TABLE ACCESS BY INDEX ROWID BATCHED (Oracle Database 12c R1) ってなに! #3




さて、本題、Day 5の実行計画というレントゲン写真はこれ!

INDEX RANGE SCANN + TABLE ACCESS BY INDEX ROWID BATCHED

Day 4 の実行計画に似てる、でもちょっと違う!

Inlist-iterator

この実行計画という名のレントゲン写真から、どのようなSQL文をイメージしますか? また、どのような特徴をもっていると思いますか?

本気で余裕のない師走w なんだこりゃw というアトモスフィアになってきましたが、皆様、そんな時こそ、体調管理しっかりしましょうね。(自分への注意喚起も込めてw)

Day 6 へつづく



previously 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

| | コメント (0)

2019年12月 4日 (水)

実行計画は、SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 Day 4

実行計画は、SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 Day 4のエントリーです.

Day 3 のつづきから.



どのようなSQL文かイメージできたでしょうか? その特徴は?

これ私がなんどもネタにしてきた、大好きな、Index Only Scan (Index Only Access という呼び方もあります)でっす:)

Id=1で、INDEX RANGE SCAN となっているので、TAB3_PK索引の特定の範囲、範囲は、Predicate Informationでリストされている 1 - access("UNIQUE_ID">=1 AND "UNIQUE_ID"<=10) なので、 TAB3_PK 索引を UNIQUE_IDが1〜10の範囲で検索していることがわかります.
また、この実行計画のポイントは、Day 2に見られたような、索引から得られる行の位置情報であるROWIDを利用したへのアクセスがないところ.

これの意味するとこは、索引はアクセスするが、表はアクセスしないということを意味しています. つまり、索引だけをアクセスしています.

1 - access("UNIQUE_ID">=1 AND "UNIQUE_ID"<=10) といく述語があるので、WHERE句はあるはずですが、SELECTリストでは、索引列のみが参照されている! = Index Only Scanということになります.

以下のようなSQL文を想像できていれば正解です. :)

select unique_id from tab3 where unique_id between 1 and 10;

Index-range-scan

Index Only Scanのイメージ図は以下のとおり.
20191201-231357

Index Only Scanは表へのアクセスを省略できるのがメリットですが、複数のIndex Only Scanを狙いすぎため結果索引が多くなり、アンチパターンで有名なインデックスショットガンにならないような注意を必要とする点はみなさんご存知なのではないかと思います.
更新系処理の性能要件を満たせている限りガチで使った案件もなくはないですが、それはそれで索引のメンテナンスなども大変になることもあり、用法・用量には注意してくださいね. ;)





ということで、Day 4の実行計画というレントゲン写真はこれ!

INDEX RANGE SCAN

あれ? INDEX RANGE SCANって Day 3 と同じ? と思ったあなた! よーく見てください〜. 違うんですよ〜っ!
Day 3との違いに気づければ、該当するSQL文をイメージするのは簡単なのではないかと思います.
Index_range_scan

この実行計画というなのレントゲン写真から、どのようなSQL文をイメージしますか? また、どのような特徴をもっていると思いますか?

本気で余裕のない師走w なんだこりゃw というアトモスフィアになってきました、体調管理しっかりしないと...

Day 5 へつづく



previously 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

| | コメント (0)

2019年12月 3日 (火)

実行計画は、SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 3

実行計画は、SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 Day 3のエントリーです.

Day 2 のつづきから.



どのようなSQL文かイメージできたでしょうか? その特徴は?
Id = 2 で INDEX UNIQUE SCAN を行なっている点、Predicate Information に 2 - access("UNIQUE_ID"=1) とあるので、 unique_id列に一意索引または主キー索引があり、 = 1 で一意検索して、得られた行を特定する情報(Oracleの場合ははrowid)を使って、TABLEから該当行をアクセスしているのが id = 1 の TABLE ACCESS BY INDEX ROWID.
Predicate Information には他の情報はリストされていないので、以下のような SQL文をイメージされたとしたら、正解ではないでしょうか。
(ちなみに、SELECTリストは * にしています. SELECTリストに関わる情報は特にないので. 今回は、SQL*Plusのautotraceを利用していますが、SQLモニター等より詳細な情報を取得することができる機能もあります。必要に応じてツールを使い分けることも重要なスキルだと思います)

select * from tab3 where unique_id = 1;

Index-unique-scan

そう言えば、2009か2010年ごろ昔某所某プロジェクトで、SQLから実行計画をイメージする千本ノック(大げさですが)みたいなことを依頼されてやったことがありましてw。その逆をやってるだけですね、これ!w よーく考えたらw

20191201-122138


ということで、Day 3の実行計画というレントゲン写真はこれ!

INDEX RANGE SCAN
Index-range-scan

この実行計画というなのレントゲン写真から、どのようなSQL文をイメージしますか? また、どのような特徴をもっていると思いますか?
今回のAdvent Calendarに絡めたネタにも慣れてきたころだと思うので、このレントゲン写真から自由に読み取ってみてくだしぁ ;)

Day 4 へつづく



previously 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

| | コメント (0)

2019年12月 2日 (月)

実行計画は、SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 2

実行計画は、SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 Day 2のエントリーです.

まずは、Day 1の答え



以下の実行計画 (SQL*Plusのauto trace機能を利用) は、TABLE ACCESS FULL ではありますが、Execution PlanセクションとStatisticsセクションしかありません。
また、SQL文にWHERE句がある場合、実行計画の補足情報として、Predicate Information (identified by operation id) セクションがリストされます。
このセクションでは述語、つまり、WHERE句に関わる情報がリストされます。
Predicate Information (identified by operation id) セクションが一切リストされていないこのケースでは、WHERE句自体がSQL文中に存在しないことも読み取ることができます。

ということで、以下の3パターンの可能性はなくなりました。理由はすでにお分かりですよね?

2) select * from tab3 where id + 1 = 10;
3) select * from tab3 where id between 1 and 400000;
4) select /*+ FULL(tab3) */ * from tab3 where id between 1 and 10;

結果として、単純な全表走査を行うSQL文である 1) が正解ということになります。

治療の必要は基本的にありませんが、全表走査しているだけで性能要件を満たせない場合には、全表走査を早くするための治療が必要になる場合があります.
必要があって全表走査しているのであれば全表走査は悪ではありません。
(性能要件は事前に問診等で確認しておくことをおすすめします)

1) select * from tab3;

20191130-192926_20191201010101



では、本題であるDay 2のレントゲン写真は、以下!

これには、先ほど解説したばかりのPredicate Information (identified by operation id) がリストされ、2 - access("UNIQUE_ID"=1) という部分から unique_id列でアクセスしていることが読み取れます。

20191201-05116

Id=2のoperationでは、INDEX UNIQUE SCANが行われています。INDEX UNIQUE SCANしている対象オブジェクトは、TAB3_PK です。 INDEX という部分から TAB3_PK は索引であることも読み取れます。
かつ、UNIQUE SCAN ということなので、索引は一意索引または、主キー索引で、一意に値を特定できる索引であることも合わせて読み取れます。

この実行計画という名のレントゲン写真から、どのようなSQL文をイメージしますか? また、どのような特徴をもっていると思いますか?

つづきは、Day 3にて。:)



寒いのも、寒い場所も嫌いですw

| | コメント (0)

2019年12月 1日 (日)

実行計画は、SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 1

実行計画は、SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 Day1のエントリーです.

Day 1のSQL文のレントゲンはこれ.

TABLE ACCESS FULL

この実行計画にSQL文をイメージしてみましょう. 目を閉じて〜
どのようなSQL文が浮かびましたか?

20191130-192926

1) select * from tab3;

where句がない、とか

2) select * from tab3 where id + 1 = 10;

id列にユニーク索引または主キー作成があったとしても、索引を利用できないような構文だったり、とか

3) select * from tab3 where id between 1 and 400000;

id列にユニーク索引または主キー索引があったとしても、索引スキャンより全表走査が効率良いのでオプティマイザが選択した場合(一般的に30%程度未満が目安ですが)とか

4) select /*+ FULL(tab3) */ * from tab3 where id between 1 and 10;

id列にユニーク索引または主キー索引ががあり、オプティマイザに任せておけば、間違いなく、索引アクセスされるはずなのに、なぜか、FULLヒントが付いている場合とか

といくつかの状況になっている可能性があります。

TABLE ACCESS FULLが妥当な状況であれば、治療不要なわけですが、それ以外の場合、患者さんのリクエストや大人の事情を考慮かつ、治療誓約書にサインいただいたうえでw、治療する必要がありますよね。

今回の実行計画をみて上記のどの状態である可能性が高いでしょうか?

答えは、明日の窓にて。



ついに今年も残すところ今日を含め31日。 今年もいろいろ激動日々だったw
そう言えば、ことしは、飲み会でしか、湘南方面に行ってなかった。

| | コメント (0)

2019年11月30日 (土)

実行計画は、SQL文のレントゲン写真だ! Oracle Database編 (全部俺) Advent Calendar 2019

なんとなく、勢いではじめてみました、実行計画は、SQLのレントゲン写真だ! (Oracle Database編)

https://adventar.org/calendars/4737

20191130-194542

なお、12/17分のエントリーは、JPOUG Advent Calendar 2019とクロスポストします。

| | コメント (0)

2019年11月 9日 (土)

MySQL/PostgreSQL/Oracleのクライアント

macdeoracle:~ discus$ brew install mysql-client

...

macdeoracle:~ discus$ mysql --version
mysql Ver 14.14 Distrib 5.7.23, for osx10.14 (x86_64) using EditLine wrapper
macdeoracle:~ discus$ psql --version
psql (PostgreSQL) 11.5
macdeoracle:~ discus$ sqlplus -v

SQL*Plus: Release 19.0.0.0.0 - Production
Version 19.3.0.0.0

そういえば、10年ぐらい前は、複数のDBと戯れつつ、Index Only Acesssネタなんかもやってたっけw (時代は繰り返すw のかw)

ひとまず、ここまで.



ずーっと前のエントリー
Index Only Accessネタのおまけ


今日は、防寒具とか見に行かないと。

| | コメント (0)

2019年9月30日 (月)

なぜ、そこに、LONG型があるんだ / FAQ

all/dba/user_tab_columns

https://docs.oracle.com/cd/E82638_01/refrn/ALL_TAB_COLUMNS.html#GUID-F218205C-7D76-4A83-8691-BFD2AD372B63

これらのビューは、列の属性関連の情報を持つビューです。
たまに、便利なびゅーではあるのですが、これらのビューをアクセスする使うスクリプトというかPL/SQLでコード書くこともあるのですが、一箇所だけ、使いにくいところがあります。

 

どこかわかります?

下位互換のためだろうと思われるのですが、一般には推奨されていない LONG型の列 が残っています。

ご存知だとは思いますが、一般的なガイドだと、CLOBの利用が推奨されています。
下位互換のためだから仕方ないのだとは思うのですが。

LONG型といえば、とにかく制約が多くて、文字列操作を行うにもめんどくさいわけで、実際に利用したい状況になると、うううううっとなることしばしば。

LONG型

で、普段どうやって、その面倒くさいところを回避しているかといえば、CLOBに変換してしまうことがが多いです。
CLOBにしてしまえば、沢山の制約から解放されますしね :)

以下のような感じで。


SCOTT> l
1 CREATE TABLE my_dba_tab_columns
2 AS
3 SELECT
4 owner
5 ,table_name
6 ,column_name
7 ,data_type
8 ,data_type_mod
9 ,data_type_owner
10 ,data_length
11 ,data_precision
12 ,data_scale
13 ,nullable
14 ,column_id
15 ,TO_CLOB(default_length) AS default_length
16 ,num_distinct
17 ,low_value
18 ,high_value
19 ,density
20 ,num_nulls
21 ,num_buckets
22 ,last_analyzed
23 ,sample_size
24 ,character_set_name
25 ,char_col_decl_length
26 ,global_stats
27 ,user_stats
28 ,avg_col_len
29 ,char_length
30 ,char_used
31 ,v80_fmt_image
32 ,data_upgraded
33 ,histogram
34 ,default_on_null
35 ,identity_column
36 ,sensitive_column
37 ,evaluation_edition
38 ,unusable_before
39 ,unusable_beginning
40 ,collation
41 FROM
42* dba_tab_columns
SCOTT> /

Table created.

SCOTT> desc dba_tab_columns
Name Null? Type
----------------------------------------- -------- ----------------------------
OWNER NOT NULL VARCHAR2(128)
TABLE_NAME NOT NULL VARCHAR2(128)
COLUMN_NAME NOT NULL VARCHAR2(128)
DATA_TYPE VARCHAR2(128)
DATA_TYPE_MOD VARCHAR2(3)
DATA_TYPE_OWNER VARCHAR2(128)
DATA_LENGTH NOT NULL NUMBER
DATA_PRECISION NUMBER
DATA_SCALE NUMBER
NULLABLE VARCHAR2(1)
COLUMN_ID NUMBER
DEFAULT_LENGTH NUMBER
DATA_DEFAULT LONG
NUM_DISTINCT NUMBER
LOW_VALUE RAW(2000)
HIGH_VALUE RAW(2000)
DENSITY NUMBER
NUM_NULLS NUMBER
NUM_BUCKETS NUMBER
LAST_ANALYZED DATE
SAMPLE_SIZE NUMBER
CHARACTER_SET_NAME VARCHAR2(44)
CHAR_COL_DECL_LENGTH NUMBER
GLOBAL_STATS VARCHAR2(3)
USER_STATS VARCHAR2(3)
AVG_COL_LEN NUMBER
CHAR_LENGTH NUMBER
CHAR_USED VARCHAR2(1)
V80_FMT_IMAGE VARCHAR2(3)
DATA_UPGRADED VARCHAR2(3)
HISTOGRAM VARCHAR2(15)
DEFAULT_ON_NULL VARCHAR2(3)
IDENTITY_COLUMN VARCHAR2(3)
SENSITIVE_COLUMN VARCHAR2(3)
EVALUATION_EDITION VARCHAR2(128)
UNUSABLE_BEFORE VARCHAR2(128)
UNUSABLE_BEGINNING VARCHAR2(128)
COLLATION VARCHAR2(100)

SCOTT> desc my_dba_tab_columns
Name Null? Type
----------------------------------------- -------- ----------------------------
OWNER NOT NULL VARCHAR2(128)
TABLE_NAME NOT NULL VARCHAR2(128)
COLUMN_NAME NOT NULL VARCHAR2(128)
DATA_TYPE VARCHAR2(128)
DATA_TYPE_MOD VARCHAR2(3)
DATA_TYPE_OWNER VARCHAR2(128)
DATA_LENGTH NOT NULL NUMBER
DATA_PRECISION NUMBER
DATA_SCALE NUMBER
NULLABLE VARCHAR2(1)
COLUMN_ID NUMBER
DEFAULT_LENGTH CLOB
NUM_DISTINCT NUMBER
LOW_VALUE RAW(2000)
HIGH_VALUE RAW(2000)
DENSITY NUMBER
NUM_NULLS NUMBER
NUM_BUCKETS NUMBER
LAST_ANALYZED DATE
SAMPLE_SIZE NUMBER
CHARACTER_SET_NAME VARCHAR2(44)
CHAR_COL_DECL_LENGTH NUMBER
GLOBAL_STATS VARCHAR2(3)
USER_STATS VARCHAR2(3)
AVG_COL_LEN NUMBER
CHAR_LENGTH NUMBER
CHAR_USED VARCHAR2(1)
V80_FMT_IMAGE VARCHAR2(3)
DATA_UPGRADED VARCHAR2(3)
HISTOGRAM VARCHAR2(15)
DEFAULT_ON_NULL VARCHAR2(3)
IDENTITY_COLUMN VARCHAR2(3)
SENSITIVE_COLUMN VARCHAR2(3)
EVALUATION_EDITION VARCHAR2(128)
UNUSABLE_BEFORE VARCHAR2(128)
UNUSABLE_BEGINNING VARCHAR2(128)
COLLATION VARCHAR2(100)

 


db tech showcase 2019もおわり、今年も残すところ 3ヶ月あまり。一年早い. そして。
来週は、開催時期を秋に変更してから2回目の多摩川花火大会。天気がよいといいのですが:)

ではまた。

| | コメント (0)

2019年3月22日 (金)

ORA_HASH()を使ってリストパーティションにハッシュパーティションのような均一配分を

ハッシュパーティションってリストパーティションみたいにパーティション狙い撃ちできて、かつ、ハッシュパーティションみたいに、データをパーティション間で均一化できないのかなぁ
というずいぶん昔の話を思い出して、そう言えば書いてないかもしれない。いつの話だよってぐらい昔の話だけどw
どうやったかというと、
ハッシュキーにふさわしい値をもつ列を決める(一意キーとか主キー列が理想、カーディナリティの低い、分布に偏りのあるデータを持つ列は使わない)

で、ハッシュキーが決まったら、話は早くて、ORA_HASH()関数で取得できるハッシュ値を利用したリストパーティションを作成するだけ。
ゴニョゴニュ言わなくても、SQLとPL/SQLのコードを見ていただければ、理解していただけるかと。

ORCL@SCOTT> l
1 CREATE TABLE list_p_tab
2 (
3 id_code VARCHAR2(10) NOT NULL
4 , foo VARCHAR2(30)
5 , id_code_hash_value NUMBER(2) NOT NULL
6 )
7 PARTITION BY LIST (id_code_hash_value)
8 (
9 PARTITION list_p_tab_p1 VALUES(0)
10 ,PARTITION list_p_tab_p2 VALUES(1)
11 ,PARTITION list_p_tab_p3 VALUES(2)
12 ,PARTITION list_p_tab_p4 VALUES(3)
13* )
ORCL@SCOTT> /

Table created.

ORCL@SCOTT> ALTER TABLE list_p_tab ADD CONSTRAINT gpk_list_p_tab PRIMARY KEY(id_code) USING INDEX GLOBAL;

Table altered.

ORCL@SCOTT> l
1 DECLARE
2 TYPE id_code_t IS TABLE OF list_p_tab.id_code%TYPE INDEX BY PLS_INTEGER;
3 TYPE foo_t IS TABLE OF list_p_tab.foo%TYPE INDEX BY PLS_INTEGER;
4 id_codes id_code_t;
5 foos foo_t;
6 k PLS_INTEGER := 1;
7 BEGIN
8 FOR i IN 1..400000 LOOP
9 id_codes(k) := TO_CHAR(i,'fm0000000009');
10 foos(k) := i;
11 k := k + 1;
12 IF k > 1000 THEN
13 FORALL j in 1..k-1
14 INSERT INTO list_p_tab VALUES(id_codes(j), foos(j), ORA_HASH(id_codes(j),3));
15 COMMIT;
16 k := 1;
17 END IF;
18 END LOOP;
19* END;
ORCL@SCOTT> /

PL/SQL procedure successfully completed.

Elapsed: 00:00:12.28

ORCL@SCOTT> exec dbms_stats.gather_table_stats(ownname=>'SCOTT',tabname=>'LIST_P_TAB',granularity=>'ALL',cascade=>true,no_invalidate=>false,degree=>4);

PL/SQL procedure successfully completed.

Elapsed: 00:00:02.51

ORCL@SCOTT> r
1 select
2 table_name
3 ,partition_name
4 ,num_rows
5 from
6 user_tab_partitions
7 where
8 table_name = 'LIST_P_TAB'
9 order by
10* 1,2

TABLE_NAME PARTITION_NAME NUM_ROWS
------------------------------ ------------------------------ ----------
LIST_P_TAB LIST_P_TAB_P1 99901
LIST_P_TAB LIST_P_TAB_P2 100194
LIST_P_TAB LIST_P_TAB_P3 100056
LIST_P_TAB LIST_P_TAB_P4 99849

ORCL@SCOTT> select id_code_hash_value,count(1) from list_p_tab group by id_code_hash_value order by 1;

ID_CODE_HASH_VALUE COUNT(1)
------------------ ----------
0 99901
1 100194
2 100056
3 99849

Elapsed: 00:00:00.06

ORCL@SCOTT> explain plan for
2 select
3 *
4 from
5 list_p_tab
6 where
7 id_code_hash_value = 1;

Explained.

Elapsed: 00:00:00.10
ORCL@SCOTT> @?/rdbms/admin/utlxpls

PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------
Plan hash value: 2143708561

----------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Pstart| Pstop |
----------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 100K| 2054K| 275 (1)| 00:00:01 | | |
| 1 | PARTITION LIST SINGLE| | 100K| 2054K| 275 (1)| 00:00:01 | 2 | 2 |
| 2 | TABLE ACCESS FULL | LIST_P_TAB | 100K| 2054K| 275 (1)| 00:00:01 | 2 | 2 |
----------------------------------------------------------------------------------------------------

グローバル索引を作成してあるので、パーティション関係ない検索は主キー索引経由でも可。

ORCL@SCOTT> explain plan for select * from list_p_tab where id_code = '00004000000';

Explained.

Elapsed: 00:00:00.02
ORCL@SCOTT> @?/rdbms/admin/utlxpls

PLAN_TABLE_OUTPUT
---------------------------------------------------------------------------------------------------------------------
Plan hash value: 4132161764

---------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Pstart| Pstop |
---------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 21 | 3 (0)| 00:00:01 | | |
| 1 | TABLE ACCESS BY GLOBAL INDEX ROWID| LIST_P_TAB | 1 | 21 | 3 (0)| 00:00:01 | ROWID | ROWID |
|* 2 | INDEX UNIQUE SCAN | GPK_LIST_P_TAB | 1 | | 2 (0)| 00:00:01 | | |
---------------------------------------------------------------------------------------------------------------------

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

2 - access("ID_CODE"='00004000000')

| | コメント (0)

2019年3月16日 (土)

Oracle Database入学式 2019 – 保護者の方はご遠慮ください

毎年恒例の
Oracle Database入学式 2019 – 保護者の方はご遠慮ください
https://jpoug.doorkeeper.jp/events/88273
が開催されます。

開催場所は エヌ・ティ・ティ・データ先端技術株式会社コラボレーションルーム です。

すでに満席となっていますが、キャンセル待ち登録可能です。

| | コメント (0) | トラックバック (0)

2019年1月 7日 (月)

SELECT ~ FOR UPDATE その後

あけましておめでとうございます。本年もよろしくお願いいたします。

今年の初エントリーは、随分昔のネタを引っ張り出してみましたw
というのも、最近は、Oracle以外のRDBMSに関わる機会が多くなり、調べていると昔のネタに繋がっていた! という状況も多々あり、ついでなので他のネタを織り交ぜながら書いていったほうがよいのではないか? と遠くを眺めながら思っていますw

さて、本題です。

SELECT ~ FOR UPDATE SKIP LOCKED その