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年2月18日 (木)

MicrosoftのEdgeがChromium版Edgeでたので久々にブラウザベンチマーク

MicrosoftのEdgeがChromium版Edgeになって、なんとMac版もでたので久々に、古い Mac Pro mid2012 Mojaveでベンチマークとってみた

20210218-210959

対処対象ブラウザは、Safari / Firefox / Google Chrome / Microsoft Edge (Chromium版Edge) / Vivaldi / Opera を JetStream2の総合値で比較

昔のBrowser Benchmarkのエントリー(古い順)
IEって遅いんだよー。ってことをあまり気にしてない方へ。 / 2010年

まだ、レガシーブラウザと戦うのですか... / 2013年

あれから1年.....あの恐怖が再びw / 2014年

Edgeも出たし、JetStreamも出たので久々にブラウザのベンチマーク / 2015年

JetStream2の結果(2021版は以下のとおり) Safariが少々良い結果を出していますが、Firefoxを除き、あまり差はなくなってますね。Firefox頑張れ?(WindowsでIE使いたいって方も少数派だと思うので今回はWindowsでの比較は略。気が向いたらやるかもしれませんがWindows BootCampで起動するMacBookしかないんだよなーw)

Safari Safari_20210218205801
Safariresults

 

Firefox
20210218-133230
20210218-133224

 

Google Chrome

Chrome


Chromeresults

 

Microsoft Edge (Chromium版Edge)

Chromemsedge


Chromemsedgeresults

 

Vivaldi

Vivaldi


Vivaldiresults

 

Opera

Operaresults


Opera

 

気軽に食べ歩きにいける世の中になってほしい。。。

| | コメント (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月14日 (月)

標準はあるにはあるが癖の多いSQL 全部俺 #14 連番の集合を返すにも癖がある


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


今回は大作(軽めにしたかったけど、少々難しのでそのまま載せることにしました)

業務上あまり多くないですが、一連番号の集合を作りたくなることがあります。シーケンスを使わずに。。

Oracleには昔から比較的簡単なクエリーで一連番号の集合を作り出せる(本来その目的のた目のクエリーではないですが)クエリーがいくつかあります。
PostgreSQLには、8.0(7.xぐらいから存在していたのか調べきれず。間違っていたらコメントいただけると助かります)ぐらいから 集合を返す関数として、generate_series()が組み込まれています。
MySQLは調べた限りですが、その手の便利関数やクエリーはあまりなさそうでした。

でそれを救う救世主w と言うのは大げさですが、WITH句を使った再帰問い合わせを使うと比較的互換の高い利用ができるようになってきました。
完全に同一構文ということではないのですけども。。。書き換える部分は少ない方だと思います:)

では、

Oracleから

まず、方言から古い順に紹介していきます。

Oracle/その1:階層問合せとlevel擬似列を利用する方法

他の方法に比べると処理時間なども有利ではあるのですが、Oracleだけでしか利用できない方法です。昔から利用している方は手グセでこちらをタイプすることも多いはずw
実行計画もシンプルで、Oracleで利用可能な方法の中では負荷は軽め(私が検証した範囲では)

階層問合せか、再帰問合せか、それが問題だ #2
http://discus-hamburg.cocolog-nifty.com/mac_de_oracle/2011/01/2-8488.html


階層問合せ
https://docs.oracle.com/cd/F19136_01/sqlrf/Hierarchical-Queries.html#GUID-0118DF1D-B9A9-41EB-8556-C6E7D6A5A84E

ORACLE> set tab off
ORACLE> set linesize 300
ORACLE> r
1 SELECT
2 LEVEL AS r
3 FROM
4 dual
5 CONNECT BY
6 LEVEL <= 10
7*

R
----------
1
2
3
4
5
6
7
8
9
10

10 rows selected.
Elapsed: 00:00:00.10
ORACLE>ORACLE> set autot trace exp
ORACLE> r
...略...

Execution Plan
----------------------------------------------------------
Plan hash value: 1236776825

-----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Cost (%CPU)| Time |
-----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 2 (0)| 00:00:01 |
|* 1 | CONNECT BY WITHOUT FILTERING| | | | |
| 2 | FAST DUAL | | 1 | 2 (0)| 00:00:01 |
-----------------------------------------------------------------------------

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

1 - filter(LEVEL<=10)


Oracle/その2:CUBEとrownum擬似列を利用する方法

これOracle 8iぐらいから拡張されたという記憶(間違ってたらごめんなさい)が、CUBEというクロス集計が簡単に書ける構文で長いクエリー書かなくて済むようになったーーーと
リリースされた当時は嬉しかった拡張の一つです。こんな使い方もできるのなーというところですが、実行計画を見るとかなり重めなんですよね。実際階層問合せより重いので、一連番号生成目的で利用することはほぼないですが、できるということで紹介しておきます。


20.3 CUBE(GROUP BYの拡張)
https://docs.oracle.com/cd/F19136_01/dwhsg/sql-aggregation-data-warehouses.html#GUID-C5FDD050-DCE0-4FE1-9741-420E2F970A36

ROWNUM疑似列
https://docs.oracle.com/cd/F19136_01/sqlrf/ROWNUM-Pseudocolumn.html#GUID-2E40EC12-3FCF-4A4F-B5F2-6BC669021726

ORACLE> r
1 SELECT rownum
2 FROM
3 (
4 SELECT 1
5 FROM
6 dual
7 GROUP BY
8 CUBE(1,1,1,1,1)
9 )
10 WHERE
11* rownum <= 10

ROWNUM
----------
1
2
3
4
5
6
7
8
9
10

10 rows selected.
Elapsed: 00:00:00.16

Execution Plan
----------------------------------------------------------
Plan hash value: 2264780677

----------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 66 (0)| 00:00:01 |
|* 1 | COUNT STOPKEY | | | | | |
| 2 | VIEW | | 1 | | 66 (0)| 00:00:01 |
| 3 | TEMP TABLE TRANSFORMATION | | | | | |
| 4 | MULTI-TABLE INSERT | | | | | |
| 5 | SORT GROUP BY NOSORT ROLLUP | | 1 | | 2 (0)| 00:00:01 |
| 6 | FAST DUAL | | 1 | | 2 (0)| 00:00:01 |
| 7 | DIRECT LOAD INTO (CURSOR DURATION MEMORY)| SYS_TEMP_0FD9D698E_276CE9B | | | | |
| 8 | DIRECT LOAD INTO (CURSOR DURATION MEMORY)| SYS_TEMP_0FD9D698F_276CE9B | | | | |
| 9 | VIEW | | 32 | 416 | 64 (0)| 00:00:01 |
| 10 | VIEW | | 32 | 416 | 64 (0)| 00:00:01 |
| 11 | UNION-ALL | | | | | |
| 12 | TABLE ACCESS FULL | SYS_TEMP_0FD9D698E_276CE9B | 1 | 13 | 2 (0)| 00:00:01 |
| 13 | TABLE ACCESS FULL | SYS_TEMP_0FD9D698E_276CE9B | 1 | 13 | 2 (0)| 00:00:01 |
| 14 | TABLE ACCESS FULL | SYS_TEMP_0FD9D698E_276CE9B | 1 | 13 | 2 (0)| 00:00:01 |
| 15 | TABLE ACCESS FULL | SYS_TEMP_0FD9D698E_276CE9B | 1 | 13 | 2 (0)| 00:00:01 |
| 16 | TABLE ACCESS FULL | SYS_TEMP_0FD9D698E_276CE9B | 1 | 13 | 2 (0)| 00:00:01 |
| 17 | TABLE ACCESS FULL | SYS_TEMP_0FD9D698E_276CE9B | 1 | 13 | 2 (0)| 00:00:01 |
| 18 | TABLE ACCESS FULL | SYS_TEMP_0FD9D698E_276CE9B | 1 | 13 | 2 (0)| 00:00:01 |
| 19 | TABLE ACCESS FULL | SYS_TEMP_0FD9D698E_276CE9B | 1 | 13 | 2 (0)| 00:00:01 |
| 20 | TABLE ACCESS FULL | SYS_TEMP_0FD9D698E_276CE9B | 1 | 13 | 2 (0)| 00:00:01 |
| 21 | TABLE ACCESS FULL | SYS_TEMP_0FD9D698E_276CE9B | 1 | 13 | 2 (0)| 00:00:01 |
| 22 | TABLE ACCESS FULL | SYS_TEMP_0FD9D698E_276CE9B | 1 | 13 | 2 (0)| 00:00:01 |
| 23 | TABLE ACCESS FULL | SYS_TEMP_0FD9D698E_276CE9B | 1 | 13 | 2 (0)| 00:00:01 |
| 24 | TABLE ACCESS FULL | SYS_TEMP_0FD9D698E_276CE9B | 1 | 13 | 2 (0)| 00:00:01 |
| 25 | TABLE ACCESS FULL | SYS_TEMP_0FD9D698E_276CE9B | 1 | 13 | 2 (0)| 00:00:01 |
| 26 | TABLE ACCESS FULL | SYS_TEMP_0FD9D698E_276CE9B | 1 | 13 | 2 (0)| 00:00:01 |
| 27 | TABLE ACCESS FULL | SYS_TEMP_0FD9D698E_276CE9B | 1 | 13 | 2 (0)| 00:00:01 |
| 28 | TABLE ACCESS FULL | SYS_TEMP_0FD9D698E_276CE9B | 1 | 13 | 2 (0)| 00:00:01 |
| 29 | TABLE ACCESS FULL | SYS_TEMP_0FD9D698E_276CE9B | 1 | 13 | 2 (0)| 00:00:01 |
| 30 | TABLE ACCESS FULL | SYS_TEMP_0FD9D698E_276CE9B | 1 | 13 | 2 (0)| 00:00:01 |
| 31 | TABLE ACCESS FULL | SYS_TEMP_0FD9D698E_276CE9B | 1 | 13 | 2 (0)| 00:00:01 |
| 32 | TABLE ACCESS FULL | SYS_TEMP_0FD9D698E_276CE9B | 1 | 13 | 2 (0)| 00:00:01 |
| 33 | TABLE ACCESS FULL | SYS_TEMP_0FD9D698E_276CE9B | 1 | 13 | 2 (0)| 00:00:01 |
| 34 | TABLE ACCESS FULL | SYS_TEMP_0FD9D698E_276CE9B | 1 | 13 | 2 (0)| 00:00:01 |
| 35 | TABLE ACCESS FULL | SYS_TEMP_0FD9D698E_276CE9B | 1 | 13 | 2 (0)| 00:00:01 |
| 36 | TABLE ACCESS FULL | SYS_TEMP_0FD9D698E_276CE9B | 1 | 13 | 2 (0)| 00:00:01 |
| 37 | TABLE ACCESS FULL | SYS_TEMP_0FD9D698E_276CE9B | 1 | 13 | 2 (0)| 00:00:01 |
| 38 | TABLE ACCESS FULL | SYS_TEMP_0FD9D698E_276CE9B | 1 | 13 | 2 (0)| 00:00:01 |
| 39 | TABLE ACCESS FULL | SYS_TEMP_0FD9D698E_276CE9B | 1 | 13 | 2 (0)| 00:00:01 |
| 40 | TABLE ACCESS FULL | SYS_TEMP_0FD9D698E_276CE9B | 1 | 13 | 2 (0)| 00:00:01 |
| 41 | TABLE ACCESS FULL | SYS_TEMP_0FD9D698E_276CE9B | 1 | 13 | 2 (0)| 00:00:01 |
| 42 | TABLE ACCESS FULL | SYS_TEMP_0FD9D698E_276CE9B | 1 | 13 | 2 (0)| 00:00:01 |
| 43 | TABLE ACCESS FULL | SYS_TEMP_0FD9D698F_276CE9B | 1 | 13 | 2 (0)| 00:00:01 |
----------------------------------------------------------------------------------------------------------------------------

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

1 - filter(ROWNUM<=10)


Oracle/その3:再帰問合せを利用する方法

冒頭で紹介した階層問合せはOracleの方言ばりばりですが、階層問合せをサポートしているエンジンも多くなってきたこともあり、同一構文とまでは行きませんがかなり互換性は高い方法です。
汎用性のある方法にしたい場合は階層問合せを利用しておくと良いかもしれませんね。

Oracleの再帰問合せ構文では、recursive がないのが大きな違いです。また、dual表の利用も必要なのでこの点が他のエンジンと違うところと思っておけば大丈夫だと思います。
意外と構文はシンプルです。階層問合せに比べるとタイプする文字列は多いですけどw

再帰的副問合せのファクタリング
https://docs.oracle.com/cd/F19136_01/sqlrf/SELECT.html#GUID-CFA006CA-6FF1-4972-821E-6996142A51C6

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*

V
----------
1
2
3
4
5
6
7
8
9
10

10 rows selected.
Elapsed: 00:00:00.16

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)


MySQL

調べた限りですが、MySQLにはPostgreSQLのような集合を返す関数として、generate_series()関数やOracleのような多くの方言はなさそうで
MySQL8.0からサポートされた再帰問合せが利用できます。Oracleで紹介した3つめの方法です。

多少構文は異なりますが、違うのは dual表がないのとrecursiveが必要なところ(MySQLの場合dual表を利用することも可能なので差異はrecursiveだけにすることもできます)

Recursive Common Table Expressions
https://dev.mysql.com/doc/refman/8.0/en/with.html#common-table-expressions-recursive

mysql> 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;
+------+
| v |
+------+
| 1 |
| 2 |
| 3 |
| 4 |
| 5 |
| 6 |
| 7 |
| 8 |
| 9 |
| 10 |
+------+
10 rows in set (0.06 sec)

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

PostgreSQL/その1:generate_series()関数を利用する方法

PostgreSQL方言の関数ですが、使いやすいですねタイプする文字数は一番少ない:)

9.24. 集合を返す関数 - 表9.61 連続値生成関数 - generate_series
https://www.postgresql.jp/document/12/html/functions-srf.html

postgresql=> SELECT r FROM generate_series(1, 10) r;
r
----
1
2
3
4
5
6
7
8
9
10
(10 rows)

test=> explain (analyze,buffers,verbose) SELECT r FROM generate_series(1, 10) r;
QUERY PLAN
--------------------------------------------------------------------------------------------------------------------------------
Function Scan on pg_catalog.generate_series r (cost=0.00..10.00 rows=1000 width=4) (actual time=0.007..0.008 rows=10 loops=1)
Output: r
Function Call: generate_series(1, 10)
Planning Time: 0.025 ms
Execution Time: 0.022 ms
(5 rows)


PostgreSQL/その2:再帰問合せを利用する方法

見ての通り、MySQLで利用した構文がそのまま利用できます。全体で見る再帰問合せを利用する方法がもっとも差異の少ないことがわかります。微妙なさなんですけどね。 無くせないものか。。そこw

7.8. WITH問い合わせ(共通テーブル式)
https://www.postgresql.jp/document/12/html/queries-with.html


postgresql=> WITH RECURSIVE gen_nums(v)
postgresql-> AS
postgresql-> (
postgresql(> SELECT 1
postgresql(> UNION ALL
postgresql(> SELECT v + 1
postgresql(> FROM
postgresql(> gen_nums
postgresql(> WHERE v + 1 <= 10
postgresql(> )
postgresql-> SELECT v from gen_nums;
v
----
1
2
3
4
5
6
7
8
9
10
(10 rows)
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)



ということで、今日は、役に立つような立たないような、でも何かの役に立ちそうなネタにしてみました。:)





標準はあるにはあるが癖の多い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 あると便利ですが意外となかったり

| | コメント (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月 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月 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年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

さて、COVIT-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日 (日)

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月20日 (月)

W3C Translations of Current W3C Technical Reports

ブックマーク代わりのメモ

Translations of Current W3C Technical Reports


not already a completed or ongoing translation for the technical report in the language.

| | コメント (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年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年8月25日 (日)

FAQ / PL/SQL PACKAGEでパプリックスコープを持つ定数をSQL文中で利用するには...

かなーり、ご無沙汰しておりました。(本業でいっぱいいっぱいで、という言い訳はこれぐらいにしてw) 偶に聞かれることがあるので、FAQネタから。 パッケージでパブリックなスコープを持つ定数は無名PL/SQLブロックやパッケージ、プロシージャ、ファンクションでしか参照できないんですよねー 例えば、DBMS_CRYPTOパッケージでHASHファンクションを利用してSH-256を作成したいなーと思って、

39.4 DBMS_CRYPTOのアルゴリズム
https://docs.oracle.com/cd/F19136_01/arpls/DBMS_CRYPTO.html#GUID-CE3CF17D-E781-47CB-AEE7-19A9B2BCD3EC
DBMS_CRYPTO.HASH()は関数なのでSQL文から呼びたーい、と以下のような使い方をすると...

SQL> SELECT DBMS_CRYPTO.HASH(TO_CLOB('hoge'), DBMS_CRYPTO.HASH_SH2569) AS "SH-256" FROM dual;
SELECT DBMS_CRYPTO.HASH(TO_CLOB('hoge'), DBMS_CRYPTO.HASH_SH2569) AS "SH-256" FROM dual
*
ERROR at line 1:
ORA-00904: "DBMS_CRYPTO"."HASH_SH2569": invalid identifier


SQL>
SQL> select DBMS_CRYPTO.HASH_SH256 from dual;
select DBMS_CRYPTO.HASH_SH256 from dual
*
ERROR at line 1:
ORA-06553: PLS-221: 'HASH_SH256' is not a procedure or is undefined
見事にエラーとなるわけです。 DBMS_CRYPTO.HASH_SH256は、パッケージファンクションではないので...利用可能なのはPL/SQLでのみ。
SQL> set serveroutput on
SQL>
¥SQL>
SQL> begin
2 dbms_output.put_line('DBMS_CRYPTO.HASH_SH256 : ' || DBMS_CRYPTO.HASH_SH256);
3 end;
4 /
DBMS_CRYPTO.HASH_SH256 : 4

PL/SQL procedure successfully completed.
SQL文で活用する為には、ファンクションでラップする必要があります。 以下のように。
SQL> l
1 CREATE OR REPLACE FUNCTION get_hash_sh256_type
2 RETURN NUMBER
3 AS
4 BEGIN
5 RETURN DBMS_CRYPTO.HASH_SH256;
6* END;
SQL> /

Function created.

SQL>
冒頭でエラーとなっていたSQL文をDBMS_CRYPTO.HASH_SH256を返すファンクションを使うように書き換えると、 はい、できました。
SQL> l
1 SELECT
2 DBMS_CRYPTO.HASH(
3 TO_CLOB('hoge')
4 , get_hash_sh256_type()
5 ) AS "SH-256"
6 FROM
7* dual
SQL> /

SH-256
--------------------------------------------------------------------------------
ECB666D778725EC97307044D642BF4D160AABB76F56C0069C71EA25B1E926825

SQL>


露店の焼きそばと焼き鳥を食べつつ、晩夏の夏祭りと、涼しい朝晩の気温で熟睡可能な山形より。 では、では。

| | コメント (0)

2019年3月24日 (日)

Oracle VM VirtualBox 6.0 でも治ってなかった、ドラッグするとDesktopが取り残される問題 / FAQ

Oracle VM VirtualBox 5.x台からあった問題、6.0でも修正されていないですね。
ただ、解決方法はあって、一旦、Dockにしまって再度取り出すと症状は治まるんですよね。これw

以下、タイトルバーをクリックしてドラッグするとなぜかデスクトップだけが取り残されてのっぺらぼう状態になってしまったスクリーンショット

20190324-152727

| | コメント (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月21日 (木)

ハッシュパーティションでのデータの偏り / FAQ

ぼやき漫才みたいな感じですが、Oracleに限らず、ハッシュパーティションでパーティション間のデータを均一にしたいなら、ユニークな値かそれに準ずる列を選ぶべきなわけですが、なにを間違ってしまったのか、稀ではありますが、少々残念なことになっていすることもあります。
とは言え、早めに気づけば影響も小さくて済むわけで:)


というわけで、今回はそんなおはなし。

id_code列の値はユニーク
ORCL@SCOTT> select count(*),count(distinct id_code) from org;

COUNT(*) COUNT(DISTINCTID_CODE)
---------- ----------------------
400000 400000
type列の値は、一意性がなくカーディナリティーも低い、かつ、大きな偏りがある。。
ORCL@SCOTT> select type,count(1) from org group by type;

type COUNT(1)
---------- ----------
1 60000
2 60000
9 60000
0 220000
ハッシュパーティションを選択する主な理由は、パーティションへのデータの均一分散なので、列の値がユニークな列をパーティションキーとしてパーティション化することが多いわけですが、。。
以下は、ハッシュキーに一意な値を持つ列を選択した場合の例
ORCL@SCOTT> r
1 create table hash_p_tab
2 partition by hash(id_code)
3 (
4 partition hash_p_tab_p1
5 ,partition hash_p_tab_p2
6 ,partition hash_p_tab_p3
7 ,partition hash_p_tab_p4
8 )
9 as select
10 id_code
11 ,foo
12 ,type
13 from
14* org

Table created.

ORCL@SCOTT> alter table hash_p_tab add constraint gpk_hash_p_tab primary key(id_code) using index global;

Table altered.

ORCL@SCOTT> exec dbms_stats.gather_table_stats(ownname=>'SCOTT',tabname=>'hash_p_tab',cascade=>true,no_invalidate=>false,granularity=>'ALL');


ORCL@SCOTT> select table_name,partition_name,num_rows from user_tab_partitions order by 1,2;

TABLE_NAME PARTITION_NAME NUM_ROWS
------------------------------ ------------------------------ ----------
HASH_P_TAB HASH_P_TAB_P1 99901
HASH_P_TAB HASH_P_TAB_P2 100194
HASH_P_TAB HASH_P_TAB_P3 100056
HASH_P_TAB HASH_P_TAB_P4 99849


しかし、値の分布に偏りのあるカーディナリティの低い列を選んで残念なことになっているケースも稀にあったりします。

なぜ、ハッシュキーにこの列を選んだんだ! みたいな。。。

そんな時は、設計した人に聞くしかないです。何がやりたかったのかを。。。私に聞かれてもハッシュキーの選択をミスったんですよねーたぶん、としか言えないので。
ORCL@SCOTT> r
1 create table hash_p_tab_skew
2 partition by hash(type)
3 (
4 partition hash_p_tab_skew_p1
5 ,partition hash_p_tab_skew_p2
6 ,partition hash_p_tab_skew_p3
7 ,partition hash_p_tab_skew_p4
8 )
9 as select
10 id_code
11 ,foo
12 ,type
13 from
14* org

Table created.

ORCL@SCOTT> alter table hash_p_tab_skew add constraint gpk_hash_p_tab_skew primary key(id_code) using index global;

Table altered.

ORCL@SCOTT> exec dbms_stats.gather_table_stats(ownname=>'SCOTT',tabname=>'hash_p_tab_skew',cascade=>true,no_invalidate=>false,granularity=>'ALL');

PL/SQL procedure successfully completed.

ORCL@SCOTT> select table_name,partition_name,num_rows from user_tab_partitions where table_name = upper('hash_p_tab_skew') order by 1,2

TABLE_NAME PARTITION_NAME NUM_ROWS
------------------------------ ------------------------------ ----------
HASH_P_TAB_SKEW HASH_P_TAB_SKEW_P1 0
HASH_P_TAB_SKEW HASH_P_TAB_SKEW_P2 280000
HASH_P_TAB_SKEW HASH_P_TAB_SKEW_P3 60000
HASH_P_TAB_SKEW HASH_P_TAB_SKEW_P4 60000
で、データを均一にパーティションに分散させることをなんとなーく、イメージしつつ、上記のようなミスをしてしまうと、パラレルクエリーなどで最もデータの多いパーティションの処理時間に引っ張られて想定より処理時間が長くなるなんてことも。。。あるわけで
例がイケてないけど(気にしないでw)、パラレルサーバーのスレーブ間でbuffer gets部分を見ていただくと偏りはわかりやすいはず。(赤字部分):)
偏りあり
orcl2@SCOTT> @sql_skew
1 select
2 /*+
3 monitor
4 parallel(4)
5 */
6 count(1)
7 from
8 hash_p_tab_skew t01
9 inner join hash_p_tab_skew2 t02
10 on
11 t01.id_code = t02.id_code
12* and t01.type = t02.type


Parallel Execution Details (DOP=4 , Servers Allocated=4)
==========================================================================================
| Name | Type | Server# | Elapsed | Cpu | Other | Buffer | Wait Events |
| | | | Time(s) | Time(s) | Waits(s) | Gets | (sample #) |
==========================================================================================
| PX Coordinator | QC | | 0.02 | 0.00 | 0.02 | 72 | |
| p000 | Set 1 | 1 | 0.18 | 0.17 | 0.01 | 1940 | |
| p001 | Set 1 | 2 | 0.05 | 0.05 | 0.00 | 448 | |
| p002 | Set 1 | 3 | 0.05 | 0.05 | 0.00 | 448 | |
| p003 | Set 1 | 4 | 0.00 | 0.00 | 0.00 | | |
==========================================================================================

偏りの悪影響のイメージはこんな感じ
20190321-165450
20190321-165622

偏りなし
orcl2@SCOTT> @sql_noskew
1 select
2 /*+
3 monitor
4 parallel(4)
5 */
6 count(1)
7 from
8 hash_p_tab t01
9 inner join hash_p_tab2 t02
10 on
11 t01.id_code = t02.id_code
12* and t01.type = t02.type


Parallel Execution Details (DOP=4 , Servers Allocated=4)
==========================================================================================
| Name | Type | Server# | Elapsed | Cpu | Other | Buffer | Wait Events |
| | | | Time(s) | Time(s) | Waits(s) | Gets | (sample #) |
==========================================================================================
| PX Coordinator | QC | | 0.01 | 0.00 | 0.00 | 96 | |
| p000 | Set 1 | 1 | 0.08 | 0.08 | | 714 | |
| p001 | Set 1 | 2 | 0.08 | 0.08 | 0.00 | 714 | |
| p002 | Set 1 | 3 | 0.08 | 0.07 | 0.01 | 714 | |
| p003 | Set 1 | 4 | 0.08 | 0.08 | | 712 | |
==========================================================================================
パーティション毎にぞれぞれ得手不得手があります。そこんとこを把握したうえで、有効活用したいものですよね。(パーティションもいろいろ進化してきて便利になってきたわけですが、その分わかりにくいところも増えてきて理解するのに大変だったり 18cのも差分は把握しといたほうがいいかw...:)

| | コメント (0)

Join Elimination(結合の排除)と 参照整合性制約 / FAQ

偶に聞かれることがあるので、再び、Join Elimination(結合の排除)について
まずは、以下のSQL文を。
order表とcustomers表をinner joinしている単純な文ですが、重要なのは、実行計画の方!


order表とcustomers表をinner joinしているのに、order表だけ(この場合、order表の主キー索引だけのIndex Only Scanになっていますが)で、customes表を結合していせん。

理由は単純で、以下のSQL文では、customsers表の結合が不要なだけなんです。なぜかわかりますか?
以前、浅瀬でジャブジャブしていたセッション資料にヒントがあります。
order表に定義されている参照整合性制約によりcustomer_idがcustomsers表に存在していることを確認するための結合は不要と、オプティマイザーが判断した結果なんですよね。これ。
上記以外のケースでも無駄な結合を排除しようとする最適化を行うことがあります。内部的にはSQL文を書き換えてくれているわけですね。無駄に結合を行わないために。。。10053トレースをとって、 Join Elimination で grep をかけてみるとオプティマイザの気持ちが見えてきます:)
ORCL@OE> explain plan for
2 select
3 distinct
4 order_id
5 from
6 orders o
7 , customers c
8 where
9 o.customer_id = c.customer_id
10 and order_id < 2400;

Explained.

ORCL@OE> @?/rdbms/admin/utlxpls

PLAN_TABLE_OUTPUT
-----------------------------------------------------------------------------
Plan hash value: 1653993310

-----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 46 | 184 | 1 (0)| 00:00:01 |
|* 1 | INDEX RANGE SCAN| ORDER_PK | 46 | 184 | 1 (0)| 00:00:01 |
-----------------------------------------------------------------------------

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

1 - access("ORDER_ID"<2400)
上記、SQL文は、参照整合性制約により、orders表に存在するcustomer_idがcustomers表に存在することが保証されているため、結合により存在確認が不要となり、Optimizerは内部的にSQL文を以下のように書き換えたということになります。賢いですよね。
ORCL@OE> r
1 explain plan for
2 select
3 distinct
4 order_id
5 from
6 orders o
7 where
8* order_id < 2400

Explained.

ORCL@OE> @?/rdbms/admin/utlxpls

PLAN_TABLE_OUTPUT
-----------------------------------------------------------------------------
Plan hash value: 1653993310

-----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 46 | 184 | 1 (0)| 00:00:01 |
|* 1 | INDEX RANGE SCAN| ORDER_PK | 46 | 184 | 1 (0)| 00:00:01 |
-----------------------------------------------------------------------------

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

1 - access("ORDER_ID"<2400)

13 rows selected.


order表の参照整合性制約を確認しておきます。

ORCL@OE> r
1 select
2 table_name
3 ,owner
4 ,constraint_name
5 ,constraint_type
6 ,r_owner
7 ,r_constraint_name
8 ,status
9 ,rely
10 from
11 user_constraints
12 where
13* constraint_type='R'

TABLE_NAME OWNER CONSTRAINT_NAME C R_OWNER R_CONSTRAINT_NAME STATUS RELY
------------------------------ ------------------------------ ------------------------------ - ------------------------------ ------------------------------ -------- ----
ORDERS OE ORDERS_CUSTOMER_ID_FK R OE CUSTOMERS_PK ENABLED
INVENTORIES OE INVENTORIES_WAREHOUSES_FK R OE WAREHOUSES_PK ENABLED
INVENTORIES OE INVENTORIES_PRODUCT_ID_FK R OE PRODUCT_INFORMATION_PK ENABLED
ORDER_ITEMS OE ORDER_ITEMS_ORDER_ID_FK R OE ORDER_PK ENABLED
ORDER_ITEMS OE ORDER_ITEMS_PRODUCT_ID_FK R OE PRODUCT_INFORMATION_PK ENABLED
PRODUCT_DESCRIPTIONS OE PD_PRODUCT_ID_FK R OE PRODUCT_INFORMATION_PK ENABLED

ORCL@OE> r
1 select
2 table_name
3 ,column_name
4 ,constraint_name
5 from
6 user_cons_columns
7 where
8 table_name in ('ORDERS','CUSTOMERS')
9 order by
10* table_name

TABLE_NAME COLUMN_NAME CONSTRAINT_NAME
------------------------------ ------------------------------ ------------------------------
CUSTOMERS CUSTOMER_ID CUSTOMERS_PK
CUSTOMERS CUST_FIRST_NAME CUST_FNAME_NN
CUSTOMERS CUSTOMER_ID CUSTOMER_ID_MIN
CUSTOMERS CREDIT_LIMIT CUSTOMER_CREDIT_LIMIT_MAX
CUSTOMERS CUST_LAST_NAME CUST_LNAME_NN
ORDERS ORDER_ID ORDER_PK
ORDERS ORDER_TOTAL ORDER_TOTAL_MIN
ORDERS ORDER_MODE ORDER_MODE_LOV
ORDERS CUSTOMER_ID ORDER_CUSTOMER_ID_NN
ORDERS CUSTOMER_ID ORDERS_CUSTOMER_ID_FK
ORDERS ORDER_DATE ORDER_DATE_NN




Oracle SQL DeveloperでリバースエンジニアリングしたERDは以下のとおり

20190321-144842

では、最後に、参照整合性制約を無効化した場合、実行計画はどうなるか見ておきましょう。
ORCL@OE> alter table orders disable constraint orders_customer_id_fk;

Table altered.

ORCL@OE> r
1 select
2 table_name
3 ,owner
4 ,constraint_name
5 ,constraint_type
6 ,r_owner
7 ,r_constraint_name
8 ,status
9 ,rely
10 from
11 user_constraints
12 where
13* constraint_type='R'

TABLE_NAME OWNER CONSTRAINT_NAME C R_OWNER R_CONSTRAINT_NAME STATUS RELY
------------------------------ ------------------------------ ------------------------------ - ------------------------------ ------------------------------ -------- ----
ORDERS OE ORDERS_CUSTOMER_ID_FK R OE CUSTOMERS_PK DISABLED
INVENTORIES OE INVENTORIES_WAREHOUSES_FK R OE WAREHOUSES_PK ENABLED
INVENTORIES OE INVENTORIES_PRODUCT_ID_FK R OE PRODUCT_INFORMATION_PK ENABLED
ORDER_ITEMS OE ORDER_ITEMS_ORDER_ID_FK R OE ORDER_PK ENABLED
ORDER_ITEMS OE ORDER_ITEMS_PRODUCT_ID_FK R OE PRODUCT_INFORMATION_PK ENABLED
PRODUCT_DESCRIPTIONS OE PD_PRODUCT_ID_FK R OE PRODUCT_INFORMATION_PK ENABLED

あらまあ、不思議w わざとらしいw
customers表げ結合されちゃってネステッドループ結合に!
ORCL@OE> r
1 explain plan for
2 select
3 distinct
4 order_id
5 from
6 orders o
7 , customers c
8 where
9 o.customer_id = c.customer_id
10* and order_id < 2400

Explained.

ORCL@OE> @?/rdbms/admin/utlxpls

PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------
Plan hash value: 2552081916

----------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 46 | 552 | 3 (34)| 00:00:01 |
| 1 | SORT UNIQUE NOSORT | | 46 | 552 | 3 (34)| 00:00:01 |
| 2 | NESTED LOOPS SEMI | | 46 | 552 | 2 (0)| 00:00:01 |
|* 3 | TABLE ACCESS BY INDEX ROWID| ORDERS | 46 | 368 | 2 (0)| 00:00:01 |
|* 4 | INDEX RANGE SCAN | ORDER_PK | 46 | | 1 (0)| 00:00:01 |
|* 5 | INDEX UNIQUE SCAN | CUSTOMERS_PK | 319 | 1276 | 0 (0)| 00:00:01 |
----------------------------------------------------------------------------------------------

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

3 - filter("O"."CUSTOMER_ID">0)
4 - access("ORDER_ID"<2400)
5 - access("O"."CUSTOMER_ID"="C"."CUSTOMER_ID")

目黒方面の密林で、美登利の寿司弁当を食べるのが最近のマイブームw
ではまた。

| | コメント (0)

2019年2月21日 (木)

Wait Events

データベース関連で待機イベントと言えば、これまでは、Oracle Database しか浮かばなかったわけですが、今は、PostgreSQL、そして、MySQL にも実装された。

待機イベントを知らずして、どうするの? でも大丈夫。 今までOracleの待機イベントに親しんできたデータベースエンジニアの活躍の場が広がるんじゃないかなぁ。。。と遠くをみている。。。

Oracle Database Wait Events

PostgreSQL Wait Events

MySQL : 25.12.15.1 Wait Event Summary Tables

| | コメント (0) | トラックバック (0)

2019年2月12日 (火)

RDS Oracle 雑多なメモ#17/ FAQ

Oracle DB インスタンスの一般的な DBA タスクに記載されているAmazon RDS OracleとオンプレのOracleの操作方法の違は意外に多く、長年かけて体に染み付いていて、脊髄反応でタイプしてしまうとエラー、あ”〜っなんてこともしばしばw

仕方ないので、慣れるしかないわけですが、脊髄反応でオンプレのコマンドをタイプして、あ”〜っ! となったことのある個人的な Top5 を備忘録として書いておきます:)
脊髄反応でそんな権限ないよーというショックなエラーうけとる回数を少しでも減らせるようAmazon RDSパッケージのタイプ練習中の日々w (いずれ、うまく切り替えられるようになれるだろうと信じてw

Oracle DB インスタンスの一般的な DBA システムタスク
Oracle DB インスタンスの一般的な DBA データベースタスク
Oracle DB インスタンスの一般的な DBA ログタスク
Oracle DB インスタンスの一般的な DBA のその他のタスク

個人的に、つい、オンプレと同じ操作をして、エラーになってしまった Top5 w

1位. sysオブジェクトへ権限付与で grant文をタイプしてしまう。
2位. つい、alter system kill session をタイプしてしまう。
3位. オンラインログファイルを切り替えたり、追加、削除で、alter database add logfile..をタイプしたり、alter system switch logfileをタイプしてしまう。
4位. ディレクトリオブジェクトを作成しようとして、create directory...をタイプしてしまう。
5位. rmanの検証コマンドを使おうとして、生のrmanは使えなかった、と気づくw

私がつい、脊髄反応でオリジナルのコマンドをタイプして、エラー? なぬ? あ、RDSではAmazon RDS向けのパッケージ使うんだった!!と 気づく典型的な操作の数々(^^;;;;; 長年しみついた手癖で脊髄反応しちゃうのでどうしようもないのですw
みなさんはどのコマンドで、あ”! となることが多いのでしょうか?(おそらく Top.1は、私と同じ、grant関連ではないでしょうか?w 一番使う機会が多いですからね)

話は少々脱線しますが、上記操作を行うAmazon RDSパッケージでデータベースサイズが大きくなると処理時間を要するものもそこそこあります。
Amazon RDSパッケージで提供されていても内部ではOracleの対応する機能を実行しているわけで、処理時間を要するタイプの操作を行った場合、処理の進行状況を確認確認したくなることもあります。そんな時は、v$session_longops を参照するとよいのではないかと思います。全ての機能が詳細な情報をv$session_longopsに載せてくれるわけではないですが。。(オンプレのOracle Databaseを利用していたという方でも、v$session_longops を使ったことはないなんてことも少なくないような気がします)


RDS Oracleでも v$session_longops ビューは効果的に利用できる例として、datapumpやOracle DB インスタンスの一般的な DBA データベースタスクでも解説されているrmanの検証コマンドの実行時など、操作にそれなりの時間を要するタイプのものです。(datapumpについては、詳細なステータスを記録していないようなので、datapumpのlogを覗くほうが状況確認としては便利ではありますが、一応、datapumpもv$session_longopsには記録されます。この点はOracle由来なのでオンプレでも同じです。)

一例として、それなりに時間を要する処理の代表格、Amazon RDS プロシージャ rdsadmin.rdsadmin_rman_util.validate_database(Oracle DB インスタンスの一般的な DBA データベースタスク参照)を利用した関連ファイル検証の進行状況をv$session_longopsを利用してモニターリング:)

今回利用したRDS Oracleのデータファイルはぞれぞれ以下のようなサイズです。

SQL> r
1 select
2 tablespace_name
3 ,file_name
4 ,sum(bytes)/1024/1024 "MB"
5 from
6 dba_data_files
7 group by
8 tablespace_name
9 ,file_name
10 union all
11 select
12 tablespace_name
13 ,file_name
14 ,sum(bytes)/1024/1024 "MB"
15 from
16 dba_temp_files
17 group by
18 tablespace_name
19* ,file_name

TABLESPACE_NAME FILE_NAME MB
------------------------------ ------------------------------------------------------------ ----------
SYSAUX /rdsdbdata/db/ORCL_A/datafile/o1_mf_sysaux_fxpjf1nv_.dbf 498.9375
USERS /rdsdbdata/db/ORCL_A/datafile/o1_mf_users_fxpjf3d2_.dbf 100
UNDO_T1 /rdsdbdata/db/ORCL_A/datafile/o1_mf_undo_t1_fxpjf2lx_.dbf 290
RDSADMIN /rdsdbdata/db/ORCL_A/datafile/o1_mf_rdsadmin_fxpkkz9k_.dbf 7
SYSTEM /rdsdbdata/db/ORCL_A/datafile/o1_mf_system_fxpjdxws_.dbf 500
TEMP /rdsdbdata/db/ORCL_A/datafile/o1_mf_temp_fxpjf34b_.tmp 100
----------
sum 1495.9375


事前に作成しておいたスクリプトでAmazon RDS プロシージャ rdsadmin.rdsadmin_rman_util.validate_databaseの処理状況をモニタリングしています(スクリプトの例は後半参照のこと)

SQL> @show_validate_status

レコードが選択されませんでした。

SQL> /

NOW SID SERIAL# OPNAME CONTEXT SOFAR TOTALWORK % done
-------------------------------- ---------- ---------- ------------------------------ ---------- ---------- ---------- ----------
19-02-11 09:42:18.217701 +00:00 665 51783 RMAN: full datafile backup 1 123322 178680 69.02

SQL> /

NOW SID SERIAL# OPNAME CONTEXT SOFAR TOTALWORK % done
-------------------------------- ---------- ---------- ------------------------------ ---------- ---------- ---------- ----------
19-02-11 09:42:19.298741 +00:00 665 51783 RMAN: full datafile backup 1 139452 178680 78.05

SQL> /

NOW SID SERIAL# OPNAME CONTEXT SOFAR TOTALWORK % done
-------------------------------- ---------- ---------- ------------------------------ ---------- ---------- ---------- ----------
19-02-11 09:42:20.367723 +00:00 665 51783 RMAN: full datafile backup 1 156028 178680 87.32

SQL> /

NOW SID SERIAL# OPNAME CONTEXT SOFAR TOTALWORK % done
-------------------------------- ---------- ---------- ------------------------------ ---------- ---------- ---------- ----------
19-02-11 09:42:21.289310 +00:00 665 51783 RMAN: full datafile backup 1 170428 178680 95.38

SQL> /

レコードが選択されませんでした。

SQL>
SQL> !cat show_validate_status.sql
col "NOW" for a32
col opname for a30
SELECT
systimestamp AS "NOW"
,sid
,serial#
,opname
,context
,sofar
,totalwork
,round(sofar / totalwork * 100, 2) "% done"
FROM
v$session_longops
WHERE
opname LIKE 'RMAN%'
AND opname NOT LIKE '%aggregate%'
AND sofar != totalwork
AND totalwork != 0;


Previously on Mac De Oracle

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

| | コメント (0) | トラックバック (0)

2019年2月11日 (月)

SQL*Plusでcsv出力できるんですよ #2 null はどうなる? / FAQ

前回は、SQL*Plusでcsvファイルをお手軽にできることを確認したので、今回はもう少し細かいところを確認しておきます。

csvファイルを作成するOracle Databaseのバージョン等は以下のとおり。

SQL> select
2 banner_full
3 from
4 v$version;

BANNER_FULL
--------------------------------------------------------------------------------
Oracle Database 18c Enterprise Edition Release 18.0.0.0.0 - Production
Version 18.3.0.0.0

データベースキャラクタセットは最近では一般的なAL32UTF8

SQL> r
1 select
2 parameter
3 , value
4 from
5 nls_database_parameters
6 where
7* parameter in ('NLS_CHARACTERSET')

PARAMETER VALUE
---------------------------------------- ------------------------------
NLS_CHARACTERSET AL32UTF8

SQL>
SQL> !echo $NLS_LANG
Japanese_Japan.AL32UTF8

SQL> !echo $LANG
ja_JP.UTF-8

適当に作成した表は以下のとおり。NULLの取り込みを見ておきたかったのでnullも含めてあります。

SQL> desc test
名前 NULL? 型
----------------------------------------- -------- ----------------------------
ID NOT NULL NUMBER
DATA VARCHAR2(10)
FOO NOT NULL VARCHAR2(10)

SQL> select * from test order by id;

ID DATA FOO
---------- ---------- ----------
1 テスト note
2 平成 note
3 abcdbef note
4 あ note
5 A note
6 note

6行が選択されました。


id=6のdata列は null なのですが空白区別しにくいので可視化して確認しておきます。
注意)set null コマンドで設定した文字列は csv作成時のにも反映されるため空にリセットすることをお忘れなく。

SQL> set null [null]
SQL> select * from test order by id;

ID DATA FOO
---------- ---------- ----------
1 テスト note
2 平成 note
3 abcdbef note
4 あ note
5 A note
6 [null] note

6行が選択されました。

SQL> set null ""

csvファイルの作成。スクリプトの例は前回の記事(SQL*Plusでcsv出力できるんですよ / FAQ)参照のこと。

SQL> @makecsv test
SQL> !cat loaddata_test.csv
1,"テスト","note"
2,"平成","note"
3,"abcdbef","note"
4,"あ","note"
5,"A","note"
6,,"note"

SQL> exit
Oracle Database 18c Enterprise Edition Release 18.0.0.0.0 - Productionとの接続が切断されました。
discus-mother:˜ oracle$


ということで、 nullは、,, としてcsvファイルに書き出されることを確認しました。
だたし、set nullでnullを他の文字列に置き換えている場合には、置換した文字列がそのままcsvファイルへかきだされてしまうので注意が必要です。




previously on Mac De Oracle
SQL*Plusでcsv出力できるんですよ / FAQ


数日前の朝、仕事先に向かおうとしら、ちょいと熱っぽい?、頭痛もあるな! と体温を測ったら37度、インフル?
と思い仕事を休んで夕方まで様子見。。。熱は夜更けすぎに、平熱と変わっていましたw めでたしめでたし:) インフルじゃなくてよかった。
家庭内隔離解除されてほっとしているところ。。
では、また。

| | コメント (0) | トラックバック (0)

SQL*Plusでcsv出力できるんですよ / FAQ

SQL*Plusでcsv出力する簡単な方法って、意外に知られてないようなのでメモ程度に書いておきます。
自分でもコピペネタとするためにw

SQL> select * from q order by id;

ID DATA
---------- ----------
1 テスト
2 平成
3 abcdbef
4 あ
5 A

SQL> set markup csv on
SQL> select * from q order by id;

"ID","DATA"
1,"テスト"
2,"平成"
3,"abcdbef"
4,"あ"
5,"A"

SQL> set markup csv off

set markup csv on でcsv出力を簡単に取得できます。
これがなかったころはパッケージ作ったりしてましたけど、これなら手間いらず:)

スプールしてファイルに書き出すスクリプトを作っておくと便利です。
以下のスクリプトは &1 パラメータでcsv化する表名称を渡すだけ。

SQL> !cat makecsv.sql
--
-- parameter 1 : table name
--
set feed off
set timi off
set head off
set termout off
set veri off
set markup csv on
spool loaddata_&1..csv
select * from &1 order by id;
spo off
set markup csv off
set termout on
set head on
set feed on
set veri on
undefine 1

SQL> @makecsv q
SQL>
SQL> !cat loaddata_q.csv
1,"テスト"
2,"平成"
3,"abcdbef"
4,"あ"
5,"A"

| | コメント (0) | トラックバック (0)

2019年2月10日 (日)

18cのv$versionは列が増えてるのね / FAQ

今気づいたが、Oracle Database 18cのv$versionがいくつかの表示パターンにあわせたのか、3列になったのね。

SQL> select * from v$version;

BANNER BANNER_FULL BANNER_LEGACY CON_ID
-------------------------------------------------------------------------------- -------------------------------------------------------------------------------- -------------------------------------------------------------------------------- ----------
Oracle Database 18c Enterprise Edition Release 18.0.0.0.0 - Production Oracle Database 18c Enterprise Edition Release 18.0.0.0.0 - Production Oracle Database 18c Enterprise Edition Release 18.0.0.0.0 - Production 0
Version 18.3.0.0.0

| | コメント (0) | トラックバック (0)

2019年1月 7日 (月)

PostgreSQL向け、俺よう便利メモ

testdb=> select version();
version
-----------------------------------------------------------------------------
PostgreSQL 10.5 on x86_64-pc-linux-gnu, compiled by gcc (GCC) 4.9.3, 64-bit


以降のスクリプトの動作確認用の表定義

testdb=> \d+ hoge
Table "public.hoge"
Column | Type | Modifiers | Storage | Stats target | Description
--------+------------------------+-----------+----------+--------------+-------------
id | numeric(10,0) | not null | main | |
status | numeric(2,0) | not null | main | |
note | character varying(100) | | extended | |
Indexes:
"hoge_pkey" PRIMARY KEY, btree (id)

PL/pgSQLでPL/SQLっぽい感じの無名ブロックを書いてみた。commit/rollbackは含めふことができないってところはちょいとハマるね。Oraclerには。(なれれば問題ないって感じはするが)

testdb=> \! cat ins10000000.sql
DO $$BEGIN
FOR i IN 1..10000000 LOOP
INSERT INTO hoge
(id, status, note)
VALUES(
i, 0, LPAD('hoge',100,'x')
);
END LOOP;
END$$;
testdb=> \i ins10000000.sql

まあ、いろいろ勝手が違うので、よく使いそうなSQL文も作り置きしておかないと。
以下のSQLは、Oracle Databaseだと表と索引のセグメントサイズの確認で dba_segmentsを問い合わせるのと同じイメージな。ビューは違うけど。

testdb=> \! cat show_segment_size.sql
SELECT
objectname
, TO_CHAR(pg_relation_size(objectname::regclass), '999,999,999,999') AS bytes
FROM
(
SELECT
tablename AS objectname
FROM
pg_tables
WHERE
schemaname = 'public'
UNION
SELECT
indexname AS objectname
FROM
pg_indexes
WHERE
schemaname = 'public'
) AS objects
ORDER BY
bytes DESC
;

testdb=> \i show_segment_size.sql 
objectname | bytes
------------+------------------
hoge | 1,412,415,488
hoge_pkey | 224,632,832
(2 rows)

Oracle Databaseとは異なるアーキテクチャを採用しているPostgreSQLの特徴がよく見える部分。全体の30%ぐらいの行を削除して、dead tupleを確認してみたところ。
Inside vacuum - 第一回PostgreSQLプレ勉強会

testdb=> \! cat show_dead_tup_ratio.sql
SELECT
relname
, n_live_tup
, n_dead_tup
, CASE
WHEN n_live_tup > 0
THEN ROUND(n_dead_tup * 100 / n_live_tup, 2)
ELSE NULL
END AS ratio
FROM
pg_stat_user_tables;

testdb=> delete from hoge where id between 1 and 3000000;
DELETE 3000000

testdb=> \i show_dead_tup_ratio.sql
relname | n_live_tup | n_dead_tup | ratio
---------+------------+------------+-------
hoge | 6973030 | 3020431 | 43.00
(1 row)

最後は、Lockの状態を確認するSQL文。この部分もOracle Databaseとは異なるとこも多いので、Lockがどうなってるか見えるようなSQL文は作り置きしておくと便利。
宣言的パーティションのロックもOracleのPartitionとは異なる部分も多いので事前に確認しておくと、あとから驚くようなことがなくて安心できる、かも。

testdb=> \! cat show_locked_objects.sql
SELECT
clock_timestamp()
, pc.relname
, pl.locktype
, pl.database
, pl.relation
, pl.page
, pl.tuple
, pl.virtualtransaction
, pl.pid
, pl.mode
, pl.granted
FROM
pg_locks pl
INNER JOIN pg_class pc
ON
pl.relation = pc.oid
WHERE
pc.relname !~ '^pg_'
AND pc.relname <> 'activelocks';

testdb=> BEGIN;
BEGIN
testdb=> SELECT * FROM hoge FOR UPDATE SKIP LOCKED;
id | status | note
----+--------+------------------------------------------------------------------------------------------------------
1 | 0 | xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxhogedkdkhoge
(1 row)


testdb=> \i show_locked_objects.sql
clock_timestamp | relname | locktype | database | relation | page | tuple | virtualtransaction | pid | mode | granted
-------------------------------+-----------+----------+----------+----------+------+-------+--------------------+-------+-----------------+---------
2019-01-07 07:45:33.742858+00 | hoge_pkey | relation | 16401 | 16405 | | | 8/11426 | 18445 | AccessShareLock | t
2019-01-07 07:45:33.742879+00 | hoge | relation | 16401 | 16402 | | | 8/11426 | 18445 | RowShareLock | t
(2 rows)

| | コメント (0) | トラックバック (0)

2018年11月 4日 (日)

RDS Oracle 雑多なメモ#16 - 再び:) / FAQ

再び忘れがちなので、備忘録。

RDS Oracleでマスターユーザー以外で、SQL*PLusの Auto trace そして、DBMS_XPLAN.DISPLAY や DBMS_XPLAN.DISPLAY_CURSOR を使おうとすると以下のようなエラーに遭遇! 
なにも準備してないと。(explain plan for文だけは準備していなくても可能なのでが)


TEST> set autot trace exp stat
SP2-0618: Cannot find the Session Identifier. Check PLUSTRACE role is enabled
SP2-0611: Error enabling STATISTICS report

とか

...略...
TEST> select * from table(dbms_xplan.display_cursor(format=>'ALLSTATS LAST'));

PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------
User has no SELECT privilege on V$SESSION

なんてことに、

RDS Oracle、マスターユーザーでは可能なのですが、PLUSTRACEロールも作成されていない、かつ、 plustrce.sql がない.

AWSUSER> select role from dba_roles where role = 'PLUSTRACE';

no rows selected


ということで、いちいち調べるのも面倒なFAQとなっているので、備忘録として書いておきました。

マスターユーザー以外のユーザーに alter session システム権限を付与しておきます。
該当システム権限が付与されていないと、セッションレベルで statistics_level パラメータを変更できません。
このパラメータは、dbms_xplan.display_cursor でactual planを取得する際に必要になるのですが、最悪付与されていない場合には、SQL文に以下のヒントを追加することで代替可能ではありますが、いちいちSQL文に以下のヒントを追加しなければならないので面倒。
とはいえ、alter sessionは付与したくないということもなくはなく、そんな時は以下のヒントで頑張っください。

ex.

SELECT
/*+ gather_plan_statistics */
*
FROM
hoge
WHERE
id = 1;


次に必要なのは、 v$sessionなどを含むいくつかのパフォーマンスビューへのSELECTオブジェクト権限、グローバルな一時表として定義されているplan_tableへの全オブジェクト権限です。
管理面を考えてロールを作成し関連権限をロールに付与、作成したロールを対象ユーザーに付与するようにすると便利です。


alter sessionsシステム権限を含む最低限必要なオブジェクト権限とそれを付与するロール作成スクリプトの例は以下の通り。

foobar$ cat create_dev_role.sql

-- create developer role
create role dev_role;

-- for show parameter
grant alter session to dev_role;
-- for dbms_xplan.display_cursor and auto trace
exec rdsadmin.rdsadmin_util.grant_sys_object('V_$SESSION', 'DEV_ROLE', 'SELECT');

-- for dbms_xplan.display_cursor
exec rdsadmin.rdsadmin_util.grant_sys_object('V_$SQL_PLAN_STATISTICS_ALL', 'DEV_ROLE', 'SELECT');
exec rdsadmin.rdsadmin_util.grant_sys_object('V_$PARAMETER', 'DEV_ROLE', 'SELECT');
exec rdsadmin.rdsadmin_util.grant_sys_object('V_$SQL', 'DEV_ROLE', 'SELECT');
exec rdsadmin.rdsadmin_util.grant_sys_object('V_$SQL_PLAN', 'DEV_ROLE', 'SELECT');

-- for auto trace
exec rdsadmin.rdsadmin_util.grant_sys_object('V_$STATNAME', 'DEV_ROLE', 'SELECT');
exec rdsadmin.rdsadmin_util.grant_sys_object('V_$MYSTAT', 'DEV_ROLE', 'SELECT');
exec rdsadmin.rdsadmin_util.grant_sys_object('V_$SESSTAT', 'DEV_ROLE', 'SELECT');

-- for auto trace (plan_table - temporary table)
exec rdsadmin.rdsadmin_util.grant_sys_object('PLAN_TABLE$', 'DEV_ROLE', 'ALL');

参考
Oracle DB インスタンスの一般的な DBA タスク


ということで、動作確認を兼ねたサンプルは以下のとおり。

まずは、RDS Oracleのマスターユーザーで.
マスターユーザー以外のユーザーの作成と権限とロールの付与(チューニングが必要とされる開発者等)を想定

foobar$ sqlplus awsuser/xxxxxxx@xxxx.xxxxxxxx.rds.amazonaws.com:1521/HOGE

SQL*Plus: Release 12.1.0.2.0 Production on Fri Nov 2 22:05:14 2018

Copyright (c) 1982, 2016, Oracle. All rights reserved.

Last Successful login time: Fri Nov 02 2018 22:01:24 +09:00

...中略...

AWSUSER> l
1 create user test identified by xxxxxx
2 default tablespace users
3 temporary tablespace temp
4* quota unlimited on users
AWSUSER> /

User created.

AWSUSER> grant connect, resource to test;

Grant succeeded.

AWSUSER> @create_dev_role

Role created.

Grant succeeded.

PL/SQL procedure successfully completed.

PL/SQL procedure successfully completed.

PL/SQL procedure successfully completed.

PL/SQL procedure successfully completed.

PL/SQL procedure successfully completed.

PL/SQL procedure successfully completed.

PL/SQL procedure successfully completed.

PL/SQL procedure successfully completed.

PL/SQL procedure successfully completed.

AWSUSER> grant dev_role to test;

Grant succeeded.

AWSUSER> exit


作成したユーザーで接続して、各方法で実行計画を取得できるか確認!
クエリーを実行するため適当な表を作成してデータを登録しておく。

foobar$ sqlplus test/xxxxxxx@xxxx.xxxxxxxx.rds.amazonaws.com:1521/HOGE

SQL*Plus: Release 12.1.0.2.0 Production on Fri Nov 2 22:15:23 2018

Copyright (c) 1982, 2016, Oracle. All rights reserved.

...中略...
TEST>
TEST> l
1 create table hoge (
2 id number not null primary key
3 ,foobar varchar2(20)
4* ) nologging
TEST> /

Table created.

TEST>
TEST> l
1 begin
2 for i in 1..10000 loop
3 insert into
4 hoge (
5 id
6 ,foobar
7 )
8 values (
9 i
10 ,to_char(i)
11 );
12 end loop;
13 commit;
14* end;
TEST> /

PL/SQL procedure successfully completed.


SQL*Plusのauto traceが行えるか確認!

TEST> set autot trace exp stat
TEST> select * from hoge where id = 1;

Elapsed: 00:00:00.07

Execution Plan
----------------------------------------------------------
Plan hash value: 2757398040

-------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 25 | 1 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID| HOGE | 1 | 25 | 1 (0)| 00:00:01 |
|* 2 | INDEX UNIQUE SCAN | SYS_C005687 | 1 | | 1 (0)| 00:00:01 |
-------------------------------------------------------------------------------------------

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

2 - access("ID"=1)

Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
3 consistent gets
0 physical reads
0 redo size
342 bytes sent via SQL*Net to client
488 bytes received via SQL*Net from client
1 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed

参考
文のトレースについて


explain plan for文は準備なしで問題ないのですが、念のための確認! DBMS_XPLAN.DISPLAYプロシージャを利用して実行計画を取得

TEST> 
TEST> explain plan for
2 select * from hoge where id = 1;

explained.

TEST> @show_explain

PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------
Plan hash value: 2757398040

-------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 25 | 1 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID| HOGE | 1 | 25 | 1 (0)| 00:00:01 |
|* 2 | INDEX UNIQUE SCAN | SYS_C005687 | 1 | | 1 (0)| 00:00:01 |
-------------------------------------------------------------------------------------------

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

2 - access("ID"=1)

14 rows selected.

Elapsed: 00:00:00.05

スクリプト例は以下の通り。$ORACLE_HOME/rdbms/admin/utlxpls.sql や、utlxplp.sqlが利用できれば楽なんでが、それら中身は、DBMS_XPLAN.DISPLAYなので大差ない内容。

$ cat show_explain.sql

set linesize 200
set long 100000
set longchunk 200
set tab off

SELECT
*
FROM
TABLE(
DBMS_XPLAN.DISPLAY(
format => 'ALL -PROJECTION -ALIAS'
)
)
;


Actual planをDBMS_XPLAN.DISPLAY_CURSORプロシージャで取得〜

TEST> 
TEST> @show_realplan

NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
statistics_level string TYPICAL

Session altered.

*** SQL that you want to get an actual plan ***
1* select * from hoge where id = 1
***********************************************

PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------
SQL_ID 6f67zkz43kr76, child number 1
-------------------------------------
select * from hoge where id = 1

Plan hash value: 2757398040

-----------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |
-----------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 1 |00:00:00.01 | 3 |
| 1 | TABLE ACCESS BY INDEX ROWID| HOGE | 1 | 1 | 1 |00:00:00.01 | 3 |
|* 2 | INDEX UNIQUE SCAN | SYS_C005687 | 1 | 1 | 1 |00:00:00.01 | 2 |
-----------------------------------------------------------------------------------------------------

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

2 - access("ID"=1)

19 rows selected.

Elapsed: 00:00:00.11

Session altered.


NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
statistics_level string TYPICAL

Actual planを取得するスクリプト例
SQL*Plusのコマンドを駆使してはいますが、ポイントはset statistics_level = allにすることと、DBMS_XPLAN.DISPLAY_CURSORをコールする際のformatパラメータです
set termout off/onでSQL文の結果を表示しないようにしています。この設定はSQLファイルからSQL文を実行した場合にだけ有効です。(ちょっとしたTips :)

$ cat show_realplan.sql

show parameter statistics_level
alter session set statistics_level = all;

set linesize 200
set long 100000
set longchunk 200
set tab off

PROMPT *** SQL that you want to get an actual plan ***

select * from hoge where id = 1
.
l

PROMPT ***********************************************

set termout off
r
set termout on


-- get the actual plan
set timi on
SELECT
*
FROM
TABLE(
DBMS_XPLAN.DISPLAY_CURSOR(
format => 'ALLSTATS LAST'
)
)
;
set timi off
alter session set statistics_level = typical;
show parameter statistics_level

参考
DBMS_XPLANサブプログラムの要約


Apple Store Ginzaで、息子が ”iPadでムービーを作ろう” に参加するので、その合間に、パタパタブログを書き、その足で英会話に向かう日曜日の午後w



Previously on Mac De Oracle

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

| | コメント (0) | トラックバック (0)

2018年10月15日 (月)

備忘録 - ビット演算 / FAQ

備忘録
ビット演算こんな感じでできるはず。

orcl@SCOTT> r
1 SELECT
2 d1
3 ,d2
4 ,x1
5 ,x2
6 ,UTL_RAW.BIT_OR(x1,x2) AS x1_bitor_x2
7 FROM
8 (
9 SELECT
10 POWER(2, 1) AS d1
11 , HEXTORAW(TO_CHAR(POWER(2, 1), 'FM0000000X')) AS x1
12 , POWER(2, 3) AS d2
13 , HEXTORAW(TO_CHAR(POWER(2, 3), 'FM0000000X')) AS x2
14 FROM
15 dual
16* )

D1 D2 X1 X2 X1_BITOR_X2
---------- ---------- ---------- ---------- -----------
2 8 00000002 00000008 0000000A

orcl@SCOTT>

Oracle Database 12cリリース2 PL/SQL Packages and Types Reference 270.3.3 BIT_ORファンクション
Oracle Database 12c Release 2 SQL Language Reference 7.90 HEXTORAW
Oracle Database 12c Release 2 SQL Language Reference 7.159 POWER
Oracle Database 12c Release 2 SQL Language Reference 7.237 TO_CHAR (number)
Oracle Database 12c Release 2 SQL Language Reference 2.4 Format Models 2.4.1 Number Format Models
Oracle Database 12c Release 2 SQL Language Reference 2.4 Format Models FM

| | コメント (0) | トラックバック (0)

2018年9月28日 (金)

RDS Oracle 雑多なメモ#15 - おまけのおまけ / FAQ

やっぱり、改造してしまった。おまけのおまけ編w

前回単純にMD5を取得だけのスクリプトをやっつけで作ったので、それを少し改造して、締めくくり。?(たぶん。。)

前回作成したMD5取得スクリプトを元に、ファイルが同じかどうか比較するスクリプトに作り変えました :)

21:35:35 rdsora121@BILL> @ls_dir test_dir

FILENAME TYPE FILESIZE MTIME
---------------------------------------------------------------------- ---------- ---------- --------
hoge.dmp.gz file 2603349 18-09-24
hoge.log.gz file 512 18-09-24
hoge.dmp.bak file 1083412480 18-09-24
hoge.dmp.gz.bak file 2603349 18-09-24
hoge.log.bak file 1202 18-09-24
hoge.log.gz.bak file 512 18-09-24
01/ directory 4096 18-09-24
hoge.dmp file 1083412480 18-09-24
hoge.log file 904 18-09-24

9行が選択されました。

ダンプファイル(一旦圧縮したファイルを解凍したファイル)とオリジナルのダンプファイルのコピーの比較

21:35:43 rdsora121@BILL> @diff_md5 test_dir hoge.dmp hoge.dmp.bak
Src : 1B84C9E09F13A4FDC6EF2F03137C0338
Dest: 1B84C9E09F13A4FDC6EF2F03137C0338
-- No difference found. --

PL/SQLプロシージャが正常に完了しました。


ダンプファイル(オリジナルを圧縮したファイル)とオリジナルダンプファイルを圧縮したファイルのコピーの比較

21:36:28 rdsora121@BILL> @diff_md5 test_dir hoge.dmp.gz hoge.dmp.gz.bak
Src : D2CB26A7E75C9725F00C30A9280C1599
Dest: D2CB26A7E75C9725F00C30A9280C1599
-- No difference found. --

PL/SQLプロシージャが正常に完了しました。

異なるファイルの比較、ログファイルのコピーと、圧縮したログファイルのコピー。

21:37:35 rdsora121@BILL> @diff_md5 test_dir hoge.log.bak hoge.log.gz.bak
Src : DCE17181C95EACE997F45A2537BC1DA8
Dest: 6398E040E157B4A0CEF50FCF45C76FF7
-- Difference found. --

PL/SQLプロシージャが正常に完了しました。

圧縮したログファイルとそのコピーの比較。同じでなにより:)

21:38:15 rdsora121@BILL> @diff_md5 test_dir hoge.log.gz hoge.log.gz.bak
Src : 6398E040E157B4A0CEF50FCF45C76FF7
Dest: 6398E040E157B4A0CEF50FCF45C76FF7
-- No difference found. --

PL/SQLプロシージャが正常に完了しました。


異なるファイルの比較、どちらもログファイルですが、内容がことなります。

21:38:51 rdsora121@BILL> @cat_file test_dir hoge.log

TEXT
------------------------------------------------------------------------------------------
マスター表"BILL"."SYS_IMPORT_TABLE_01"は正常にロード/アンロードされました
"BILL"."SYS_IMPORT_TABLE_01"を起動しています:
オブジェクト型TABLE_EXPORT/TABLE/TABLEの処理中です
オブジェクト型TABLE_EXPORT/TABLE/TABLE_DATAの処理中です
. . "SCOTT"."HOGE" 1.008 GB 270000行がインポートされました
オブジェクト型TABLE_EXPORT/TABLE/INDEX/INDEXの処理中です
オブジェクト型TABLE_EXPORT/TABLE/CONSTRAINT/CONSTRAINTの処理中です
オブジェクト型TABLE_EXPORT/TABLE/INDEX/STATISTICS/INDEX_STATISTICSの処理中です
オブジェクト型TABLE_EXPORT/TABLE/STATISTICS/TABLE_STATISTICSの処理中です
オブジェクト型TABLE_EXPORT/TABLE/STATISTICS/MARKERの処理中です
ジョブ"BILL"."SYS_IMPORT_TABLE_01"が月 9月 24 04:05:17 2018 elapsed 0 00:00:52で正常に完了しました

11行が選択されました。

21:39:38 rdsora121@BILL> @cat_file test_dir hoge.log.bak

TEXT
------------------------------------------------------------------------------------------
"BILL"."EXPTABLE_HOGE"を起動しています:
BLOCKSメソッドを使用して見積り中です...
オブジェクト型TABLE_EXPORT/TABLE/TABLE_DATAの処理中です
BLOCKSメソッドを使用した見積り合計: 2.125 GB
オブジェクト型TABLE_EXPORT/TABLE/TABLEの処理中です
オブジェクト型TABLE_EXPORT/TABLE/INDEX/INDEXの処理中です
オブジェクト型TABLE_EXPORT/TABLE/CONSTRAINT/CONSTRAINTの処理中です
オブジェクト型TABLE_EXPORT/TABLE/INDEX/STATISTICS/INDEX_STATISTICSの処理中です
オブジェクト型TABLE_EXPORT/TABLE/STATISTICS/TABLE_STATISTICSの処理中です
オブジェクト型TABLE_EXPORT/TABLE/STATISTICS/MARKERの処理中です
. . "SCOTT"."HOGE" 1.008 GB 270000行がエクスポートされました
マスター表"BILL"."EXPTABLE_HOGE"は正常にロード/アンロードされました
******************************************************************************
BILL.EXPTABLE_HOGEに設定されたダンプ・ファイルは次のとおりです:
/rdsdbdata/userdirs/01/hoge.dmp
ジョブ"BILL"."EXPTABLE_HOGE"が日 9月 23 05:36:33 2018 elapsed 0 00:00:35で正常に完了しました

16行が選択されました。

21:39:48 rdsora121@BILL> @diff_md5 test_dir hoge.log hoge.log.bak
Src : 6DA2D7C6150A9C8ACD60D95D6A61C1B5
Dest: DCE17181C95EACE997F45A2537BC1DA8
-- Difference found. --

PL/SQLプロシージャが正常に完了しました。

スクリプトは以下の通り。MD5の比較には、UTL_RAW.COMPARE関数を利用しています。

21:40:05 rdsora121@BILL> !cat diff_md5.sql
SET VERIFY OFF
SET SERVEROUTPUT ON FORMAT WRAPPED
DECLARE
vDirectoryName VARCHAR2(30);
vSrcFileName VARCHAR2(60);
vDestFileName VARCHAR2(60);
vSrcMd5 RAW(16);
vDestMd5 RAW(16);

PROCEDURE close_bfile
(
iBfile IN OUT NOCOPY BFILE
)
IS
BEGIN
IF DBMS_LOB.ISOPEN(iBfile) = 1 THEN
DBMS_LOB.CLOSE(iBfile);
END IF;
END close_bfile;

FUNCTION md5
(
iDirectoryName IN VARCHAR2
, iFileName IN VARCHAR2
) RETURN RAW
IS
vBfile BFILE;
vBlob BLOB;
vMd5 RAW(16);
BEGIN
vBFile := BFILENAME(UPPER(iDirectoryName), iFileName);
DBMS_LOB.OPEN(vBFile);

DBMS_LOB.CREATETEMPORARY(
lob_loc => vBlob
, cache => false
, dur => DBMS_LOB.SESSION
);

DBMS_LOB.LOADFROMFILE(
dest_lob => vBlob
, src_lob => vBFile
, amount => DBMS_LOB.GETLENGTH(vBFile)
, dest_offset => 1
, src_offset => 1
);

vMd5 := DBMS_CRYPTO.HASH(vBlob, DBMS_CRYPTO.HASH_MD5);

DBMS_LOB.FREETEMPORARY(vBlob);
close_bfile(vBFile);
RETURN vMd5;
EXCEPTION
WHEN OTHERS THEN
DBMS_LOB.FREETEMPORARY(vBlob);
close_bfile(vBFile);
RAISE;
END md5;

BEGIN
vDirectoryName := UPPER('&1');
vSrcFileName := '&2';
vDestFileName := '&3';

vSrcMd5 := md5(vDirectoryName, vSrcFileName);
vDestMd5 := md5(vDirectoryName, vDestFileName);

DBMS_OUTPUT.PUT_LINE('Src : '||vSrcMd5);
DBMS_OUTPUT.PUT_LINE('Dest: '||vDestMd5);

IF UTL_RAW.COMPARE(r1 => vSrcMd5, r2 => vDestMd5) = 0
THEN
DBMS_OUTPUT.PUT_LINE('-- No difference found. --');
ELSE
DBMS_OUTPUT.PUT_LINE('-- Difference found. --');
END IF;

EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE(SQLERRM()||':'||SQLCODE());
RAISE;
END;
/

UNDEFINE 1
UNDEFINE 2
UNDEFINE 3
SET SERVEROUTPUT OFF
SET VERIFY ON


たぶん、これで終わりなはず。(なにか浮かばなければw)


Previously on Mac De Oracle

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

| | コメント (0) | トラックバック (0)

2018年9月27日 (木)

RDS Oracle 雑多なメモ#14 - おまけ / FAQ

ということで、done ってしておきながら、おまけ(得意技w)です。

RDS Oracle限定というわけではなくなってきましたがw 勢いでさらに追加。


手作りのcpっぽいスクリプトなので、バグってないか少し不安w ということで、オリジナルファイルと同じなのか確認できるようにメッセージダイジェストを取得するスクリプトも作成しましたw

21:14:43 rdsora121@BILL> @list_dir

DIRECTORY_NAME DIRECTORY_PATH
---------------------------------------- ----------------------------------------------------------------------
ADUMP /rdsdbdata/log/audit
BDUMP /rdsdbdata/log/trace
DATA_PUMP_DIR /rdsdbdata/datapump
HOGE_DIR /rdsdbdata/userdirs/02
OPATCH_INST_DIR /rdsdbbin/oracle/OPatch
OPATCH_LOG_DIR /rdsdbbin/oracle/QOpatch
OPATCH_SCRIPT_DIR /rdsdbbin/oracle/QOpatch
TEST_DIR /rdsdbdata/userdirs/01

8行が選択されました。

21:14:48 rdsora121@BILL> @ls_dir test_dir

FILENAME TYPE FILESIZE MTIME
---------------------------------------------------------------------- ---------- ---------- --------
hoge.dmp.gz file 2603349 18-09-24
hoge.log.gz file 512 18-09-24
hoge.dmp.bak file 1083412480 18-09-24
hoge.dmp.gz.bak file 2603349 18-09-24
hoge.log.bak file 1202 18-09-24
hoge.log.gz.bak file 512 18-09-24
01/ directory 4096 18-09-24
hoge.dmp file 1083412480 18-09-24
hoge.log file 904 18-09-24

9行が選択されました。

ダンプファイルを圧縮ファイル、ログファイル、ダンプファイルなどなど、MD5が取得できるようになりました。ファイルが壊れてないか確認しやすい:)

21:14:55 rdsora121@BILL> @check_md5 test_dir hoge.dmp.gz
TEST_DIR/hoge.dmp.gz MD5 : D2CB26A7E75C9725F00C30A9280C1599

PL/SQLプロシージャが正常に完了しました。

21:15:32 rdsora121@BILL> @check_md5 test_dir hoge.dmp.gz.bak
TEST_DIR/hoge.dmp.gz.bak MD5 : D2CB26A7E75C9725F00C30A9280C1599

PL/SQLプロシージャが正常に完了しました。

21:15:50 rdsora121@BILL> @check_md5 test_dir hoge.log
TEST_DIR/hoge.log MD5 : 6DA2D7C6150A9C8ACD60D95D6A61C1B5

PL/SQLプロシージャが正常に完了しました。

21:16:26 rdsora121@BILL> @check_md5 test_dir hoge.dmp
TEST_DIR/hoge.dmp MD5 : 1B84C9E09F13A4FDC6EF2F03137C0338

PL/SQLプロシージャが正常に完了しました。

21:18:02 rdsora121@BILL> @check_md5 test_dir hoge.dmp.bak
TEST_DIR/hoge.dmp.bak MD5 : 1B84C9E09F13A4FDC6EF2F03137C0338

PL/SQLプロシージャが正常に完了しました。


ざっくり作ったスクリプトは以下の通り。BFILEからファイルを読み込み、一時BLOBとしてBFILEからロード、MD5取得というながれです。
(オンプレでもそのまま使える内容にはなっちゃいましたが、勢いで作ったので:)


21:18:50 rdsora121@BILL> !cat check_md5.sql
SET VERIFY OFF
SET SERVEROUTPUT ON FORMAT WRAPPED
DECLARE
vSrcfile BFILE;
vSrcBlob BLOB;
vSrcDirectoryName VARCHAR2(30);
vSrcFileName VARCHAR2(60);
vSrcFileSize PLS_INTEGER;
vSrcFileMd5 RAW(16);

PROCEDURE close_bfile
(
iBfile IN OUT NOCOPY BFILE
)
IS
BEGIN
IF DBMS_LOB.ISOPEN(iBfile) = 1 THEN
DBMS_LOB.CLOSE(iBfile);
END IF;
END close_bfile;

BEGIN
vSrcDirectoryName := UPPER('&1');
vSrcFileName := '&2';

vSrcFile
:= BFILENAME(UPPER(vSrcDirectoryName), vSrcFileName);

DBMS_LOB.OPEN(vSrcFile);
vSrcFileSize := DBMS_LOB.GETLENGTH(vSrcFile);


DBMS_LOB.CREATETEMPORARY (
lob_loc => vSrcBlob
, cache => false
, dur => DBMS_LOB.SESSION
);

DBMS_LOB.LOADFROMFILE (
dest_lob => vSrcBlob
, src_lob => vSrcFile
, amount => vSrcFileSize
, dest_offset => 1
, src_offset => 1
);

vSrcFileMd5 := DBMS_CRYPTO.HASH(vSrcBlob, DBMS_CRYPTO.HASH_MD5);

DBMS_LOB.FREETEMPORARY(vSrcBlob);
close_bfile(vSrcFile);

DBMS_OUTPUT.PUT_LINE(
vSrcDirectoryName
||'/'||vSrcFileName
||' MD5 : '||vSrcFileMd5
);
EXCEPTION
WHEN OTHERS THEN
DBMS_LOB.FREETEMPORARY(vSrcBlob);
close_bfile(vSrcFile);
RAISE;
END;
/

UNDEFINE 1
UNDEFINE 2
SET SERVEROUTPUT OFF
SET VERIFY ON

ということで、done... これを元にまたまにか作るかもしれない、作らないかもしれないw


Previously on Mac De Oracle

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

| | コメント (0) | トラックバック (0)

2018年9月26日 (水)

RDS Oracle 雑多なメモ#13 / FAQ

メモの続きです。
前回は、圧縮したテキストファイルとダンプファイル(バイナリファイル)を解凍するスクリプトを実行したところまででした。

やっとここまできたw

今回は、解凍したファイルが使えるかなど内容確認をしてみたいと思います。


まず、解凍したログファイル(テキストファイル)の内容を確認
問題なさそうですね。

12:35:01 rdsora121@BILL> @cat_file test_dir hoge.log

TEXT
----------------------------------------------------------------------------------------
"BILL"."EXPTABLE_HOGE"を起動しています:
BLOCKSメソッドを使用して見積り中です...
オブジェクト型TABLE_EXPORT/TABLE/TABLE_DATAの処理中です
BLOCKSメソッドを使用した見積り合計: 2.125 GB
オブジェクト型TABLE_EXPORT/TABLE/TABLEの処理中です
オブジェクト型TABLE_EXPORT/TABLE/INDEX/INDEXの処理中です
オブジェクト型TABLE_EXPORT/TABLE/CONSTRAINT/CONSTRAINTの処理中です
オブジェクト型TABLE_EXPORT/TABLE/INDEX/STATISTICS/INDEX_STATISTICSの処理中です
オブジェクト型TABLE_EXPORT/TABLE/STATISTICS/TABLE_STATISTICSの処理中です
オブジェクト型TABLE_EXPORT/TABLE/STATISTICS/MARKERの処理中です
. . "SCOTT"."HOGE" 1.008 GB 270000行がエクスポートされました
マスター表"BILL"."EXPTABLE_HOGE"は正常にロード/アンロードされました
******************************************************************************
BILL.EXPTABLE_HOGEに設定されたダンプ・ファイルは次のとおりです:
/rdsdbdata/userdirs/01/hoge.dmp
ジョブ"BILL"."EXPTABLE_HOGE"が日 9月 23 05:36:33 2018 elapsed 0 00:00:35で正常に完了しました

16行が選択されました。

解凍したダンプファイルをインポートして確認する前に、元のオブジェクトの確認後、削除しておきます。

12:37:17 rdsora121@BILL> set linesize 80
12:37:20 rdsora121@BILL> desc scott.hoge
名前 NULL? 型
----------------------------------------- -------- ----------------------------
ID NOT NULL NUMBER
FOO VARCHAR2(4000)

12:37:25 rdsora121@BILL> select count(1) from scott.hoge;

COUNT(1)
----------
270000

12:39:07 rdsora121@BILL> r
1 select
2 segment_name
3 ,sum(bytes)/1024/1024/1024 "GB"
4 from
5 dba_segments
6 where
7 owner='SCOTT'
8 and segment_name in ('HOGE','PK_HOGE')
9 group by
10* segment_name

SEGMENT_NAME GB
------------------------------ ----------
PK_HOGE .004882813
HOGE 2.125

12:39:17 rdsora121@BILL> set linesize 400
12:39:21 rdsora121@BILL>
12:40:02 rdsora121@BILL> drop table scott.hoge purge;

表が削除されました。

dbms_datapumpパッケージを利用したスクリプトを作成してインポート可能か確認 :)

13:03:40 rdsora121@BILL> @import_table test_dir hoge scott hoge
マスター表"BILL"."SYS_IMPORT_TABLE_01"は正常にロード/アンロードされました
"BILL"."SYS_IMPORT_TABLE_01"を起動しています:
オブジェクト型TABLE_EXPORT/TABLE/TABLEの処理中です
オブジェクト型TABLE_EXPORT/TABLE/TABLE_DATAの処理中です
. . "SCOTT"."HOGE" 1.008 GB 270000行がインポートされました
オブジェクト型TABLE_EXPORT/TABLE/INDEX/INDEXの処理中です
オブジェクト型TABLE_EXPORT/TABLE/CONSTRAINT/CONSTRAINTの処理中です
オブジェクト型TABLE_EXPORT/TABLE/INDEX/STATISTICS/INDEX_STATISTICSの処理中です
オブジェクト型TABLE_EXPORT/TABLE/STATISTICS/TABLE_STATISTICSの処理中です
オブジェクト型TABLE_EXPORT/TABLE/STATISTICS/MARKERの処理中です
ジョブ"BILL"."SYS_IMPORT_TABLE_01"が月 9月 24 04:05:17 2018 elapsed 0 00:00:52で正常に完了しました

PL/SQLプロシージャが正常に完了しました。

インポート成功!!! 表などの確認!

13:05:54 rdsora121@BILL> set linesize 80
13:06:00 rdsora121@BILL> desc scott.hoge
名前 NULL? 型
----------------------------------------- -------- ----------------------------
ID NOT NULL NUMBER
FOO VARCHAR2(4000)

13:06:04 rdsora121@BILL> select count(1) from scott.hoge;

COUNT(1)
----------
270000

13:07:27 rdsora121@BILL> r
1 select
2 segment_name
3 ,sum(bytes)/1024/1024/1024 "GB"
4 from
5 dba_segments
6 where
7 owner='SCOTT'
8 and segment_name in ('HOGE','PK_HOGE')
9 group by
10* segment_name

SEGMENT_NAME GB
------------------------------ ----------
PK_HOGE .004882813
HOGE 2.125


スクリプトは以下の通り。 表モードのインポートをハードコードしていますが、そのあたりパラメータ化すればそこそこ使いやすくなりますかね。。

13:08:03 rdsora121@BILL> !cat import_table.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';
cSchemaName CONSTANT VARCHAR2(30) := UPPER('&3');
cTableName CONSTANT VARCHAR2(30) := UPPER('&4');
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 => 'TABLE'
,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 := 'METADATA_FILTER - table name';
DBMS_DATAPUMP.METADATA_FILTER (
handle => vDataPumpJobHandle
,name => 'NAME_LIST'
,value => '''' || cTableName || ''''
);

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
UNDEFINE 4
SET SERVEROUTPUT OFF
SET VERIFY ON


ということで、ひとまず、RDS Oracleの雑多なメモ done :)



Previously on Mac De Oracle

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

| | コメント (0) | トラックバック (0)

2018年9月25日 (火)

RDS Oracle 雑多なメモ#12 / FAQ

メモの続きです。

さて、前回、cpっぽいスクリプトの問題を改善したので今回は、圧縮したファイルを解凍するスクリプトを作ろうと思います。

前回の操作でファイルが増えて見づらくなったので、解凍に必要な最小限のファイルだけに整理します

12:20:19 rdsora121@BILL> @ls_dir test_dir

FILENAME TYPE FILESIZE MTIME
---------------------------------------------------------------------- ---------- ---------- --------
hoge.log file 1202 18-09-23
hoge.dmp file 1083412480 18-09-23
hoge.dmp.gz file 2603349 18-09-24
hoge.log.gz file 512 18-09-24
hoge.dmp.bak file 1083412480 18-09-24
hoge.dmp.gz.bak file 2603349 18-09-24
hoge.log.bak file 1202 18-09-24
hoge.log.gz.bak file 512 18-09-24
01/ directory 4096 18-09-24

9行が選択されました。

12:20:25 rdsora121@BILL> @rm_file test_dir hoge.log
TEST_DIR/hoge.log removed.

PL/SQLプロシージャが正常に完了しました。

12:21:49 rdsora121@BILL> @rm_file test_dir hoge.dmp
TEST_DIR/hoge.dmp removed.

PL/SQLプロシージャが正常に完了しました。

12:21:57 rdsora121@BILL> @ls_dir test_dir

FILENAME TYPE FILESIZE MTIME
---------------------------------------------------------------------- ---------- ---------- --------
hoge.dmp.gz file 2603349 18-09-24
hoge.log.gz file 512 18-09-24
hoge.dmp.bak file 1083412480 18-09-24
hoge.dmp.gz.bak file 2603349 18-09-24
hoge.log.bak file 1202 18-09-24
hoge.log.gz.bak file 512 18-09-24
01/ directory 4096 18-09-24

7行が選択されました。

では圧縮したテキストファイルとダンプファイル(バイナリファイル)を解凍してみます。

12:22:06 rdsora121@BILL> @gunzip_file test_dir hoge.log.gz
TEST_DIR/hoge.log.gz uncompressed to hoge.log (1202 bytes)

PL/SQLプロシージャが正常に完了しました。

12:22:44 rdsora121@BILL> @gunzip_file test_dir hoge.dmp.gz
TEST_DIR/hoge.dmp.gz uncompressed to hoge.dmp (1083412480 bytes)

PL/SQLプロシージャが正常に完了しました。

12:23:04 rdsora121@BILL> @ls_dir test_dir

FILENAME TYPE FILESIZE MTIME
---------------------------------------------------------------------- ---------- ---------- --------
hoge.dmp.gz file 2603349 18-09-24
hoge.log.gz file 512 18-09-24
hoge.dmp.bak file 1083412480 18-09-24
hoge.dmp.gz.bak file 2603349 18-09-24
hoge.log.bak file 1202 18-09-24
hoge.log.gz.bak file 512 18-09-24
hoge.log file 1202 18-09-24
01/ directory 4096 18-09-24
hoge.dmp file 1083412480 18-09-24

9行が選択されました。


できた!!!


今回の利用した解凍スクリプトも元は12年前のエントリで利用したコードのほぼ再利用です。
Mac De Oracle (PL/SQL De UNCOMPRESS)

12:24:22 rdsora121@BILL> !cat gunzip_file.sql
SET VERIFY OFF
SET SERVEROUTPUT ON
DECLARE
vSrcGzippedFile BFILE;
vUncompressedBlob BLOB;
vDirectoryName VARCHAR2(30);
vSrcGzippedFileName VARCHAR2(60);
vDestFileName VARCHAR2(60);
VUncompressedSize PLS_INTEGER;

PROCEDURE close_bfile
(
iBfile IN OUT NOCOPY BFILE
)
IS
BEGIN
IF DBMS_LOB.ISOPEN(iBfile) = 1 THEN
DBMS_LOB.CLOSE(iBfile);
END IF;
END close_bfile;

PROCEDURE write_blob_to_file
(
iDirectoryName IN VARCHAR2,
iFileName IN VARCHAR2,
iSrcBlob IN OUT NOCOPY BLOB
)
IS
vFile UTL_FILE.FILE_TYPE;
BEGIN
vFile := UTL_FILE.FOPEN(
UPPER(iDirectoryName),
iFileName,
'wb',
32767
);

DECLARE
cChunkSize CONSTANT PLS_INTEGER := 32767;

vBuffer RAW(32767);
vAmount PLS_INTEGER := cChunkSize;
vNumOfChunk PLS_INTEGER;
BEGIN
vNumOfChunk := CEIL(DBMS_LOB.GETLENGTH(iSrcBlob)/cChunkSize);
FOR chunk# IN 1..vNumOfChunk LOOP
DBMS_LOB.READ(
iSrcBlob,
vAmount,
(cChunkSize * (chunk# - 1)) + 1, /*offet*/
vBuffer
);
UTL_FILE.PUT_RAW(vFile, vBuffer, TRUE);
END LOOP;
END;

UTL_FILE.FCLOSE(vFile);
END write_blob_to_file;

BEGIN
vDirectoryName := UPPER('&1');
vSrcGzippedFileName := '&2';
vDestFileName := SUBSTR('&2', 1, INSTR('&2', '.gz') - 1);

vSrcGzippedFile
:= BFILENAME(UPPER(vDirectoryName), vSrcGzippedFileName);

DBMS_LOB.OPEN(vSrcGzippedFile);
vUncompressedBlob := UTL_COMPRESS.LZ_UNCOMPRESS(vSrcGzippedFile);
vUncompressedSize := DBMS_LOB.GETLENGTH(vUncompressedBlob);

write_blob_to_file(
UPPER(vDirectoryName),
vDestFileName,
vUncompressedBlob
);

DBMS_LOB.FREETEMPORARY(vUncompressedBlob);
close_bfile(vSrcGzippedFile);
DBMS_OUTPUT.PUT_LINE(
vDirectoryName||'/'
||vSrcGzippedFileName
||' uncompressed to '
||vDestFileName
||' ('||vUncompressedSize||' bytes)'
);
EXCEPTION
WHEN OTHERS THEN
DBMS_LOB.FREETEMPORARY(vUncompressedBlob);
close_bfile(vSrcGzippedFile);
RAISE;
END;
/

UNDEFINE 1
UNDEFINE 2
SET SERVEROUTPUT OFF
SET VERIFY ON

ということで、次回、解凍したテキストファイルの内容確認と、解凍したダンプファイルからインポートして内容確認へつづく :)



Previously on Mac De Oracle

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

| | コメント (0) | トラックバック (0)

2018年9月24日 (月)

RDS Oracle 雑多なメモ#11 / FAQ

メモの続きです。

はじめに、
ごねんなさい、ごねんなさい

RDS Oracle 雑多なメモ#6 / FAQ
で作成したUTL_FILE.FCOPYを利用したcpっぽいスクリプトはtextファイルにしか対応できません。
理由は、UTL_FILE.FCOPYプロシージャ自体がtextファイル向けでバイナリファイルに対応していないことが理由ではあるのですが、textファイルしかコピーできないのもなんなので、バイナリファイルにも対応したバージョンに変更したいと思います。

RDS Oracle 雑多なメモ#6 / FAQで作成したスクリプトは今回作成したスクリプトで置き換えていただければ、m(_ _)m


前々回作成したダンプファイル(バイナリファイル)やテキストファイルを使ってみようと思います。

utl_file.fcopyプロシージャでコピーできる例(テキストファイル)

10:48:50 rdsora121@BILL> @ls_dir test_dir

FILENAME TYPE FILESIZE MTIME
---------------------------------------------------------------------- ---------- ---------- --------
hoge.dmp file 1083412480 18-09-23
hoge.log file 1202 18-09-23
hoge.dmp.gz file 2603349 18-09-24
hoge.log.gz file 512 18-09-24
01/ directory 4096 18-09-24

11:14:42 rdsora121@BILL> @cp_file test_dir hoge.log test_dir hoge.log.bak1

source file : test_dir/hoge.log
dest file : test_dir/hoge.log.bak1 copied.

PL/SQLプロシージャが正常に完了しました。

11:15:10 rdsora121@BILL> @ls_dir test_dir

FILENAME TYPE FILESIZE MTIME
---------------------------------------------------------------------- ---------- ---------- --------
hoge.dmp file 1083412480 18-09-23
hoge.log file 1202 18-09-23
hoge.dmp.gz file 2603349 18-09-24
hoge.log.gz file 512 18-09-24
01/ directory 4096 18-09-24
hoge.log.bak1 file 1202 18-09-24

6行が選択されました。

utl_file.fcopyプロシージャでコピーできない例(バイナリファイル)
エラーが発生し、コピー途中のゴミファイルが作成されていまいます。。。。これはこまる。。

11:15:10 rdsora121@BILL> @ls_dir test_dir

FILENAME TYPE FILESIZE MTIME
---------------------------------------------------------------------- ---------- ---------- --------
hoge.dmp file 1083412480 18-09-23
hoge.log file 1202 18-09-23
hoge.dmp.gz file 2603349 18-09-24
hoge.log.gz file 512 18-09-24
01/ directory 4096 18-09-24
hoge.log.bak1 file 1202 18-09-24

11:16:51 rdsora121@BILL> @cp_file test_dir hoge.dmp test_dir hoge.dmp.bak1
-29284:ORA-29284: ファイル読取りエラーが発生しました。

PL/SQLプロシージャが正常に完了しました。

11:17:20 rdsora121@BILL> @ls_dir test_dir

FILENAME TYPE FILESIZE MTIME
---------------------------------------------------------------------- ---------- ---------- --------
hoge.dmp file 1083412480 18-09-23
hoge.log file 1202 18-09-23
hoge.dmp.gz file 2603349 18-09-24
hoge.log.gz file 512 18-09-24
hoge.log.bak1 file 1202 18-09-24
hoge.dmp.bak1 file 45093 18-09-24
01/ directory 4096 18-09-24

7行が選択されました。


RDS Oracle 雑多なメモ#6 / FAQで作成したcp_file.sqlのコードは以下の通り
これでバイナリーファイルもコピーできると嬉しいのにね〜。昔からできないのでしかたない。。

11:25:20 rdsora121@BILL> !cat cp_file.sql
set verify off
set serveroutput on format wrapped
BEGIN
UTL_FILE.FCOPY(
src_location => UPPER('&1')
,src_filename => '&2'
,dest_location => UPPER('&3')
,dest_filename => '&4'
);
DBMS_OUTPUT.PUT_LINE(' ');
DBMS_OUTPUT.PUT_LINE('source file : &1/&2');
DBMS_OUTPUT.PUT_LINE('dest file : &3/&4 copied.');
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE(SQLCODE()||':'||SQLERRM());
END;
/

undefine 1
undefine 2
undefine 3
undefine 4
set verify on
set serveroutput off


他の手はないかな??? あ、dbms_file_transfer.copy_fileプロシージャを使ったらどうか?

ただし、バイナリファイルをうまくコピーできるようになりましたが、このプロシージャにはいくつか制限があります。
Oracle® Database PL/SQLパッケージおよびタイプ・リファレンス 12c リリース1 (12.1) DBMS_FILE_TRANSFER
コピーされるファイルのサイズは512バイトの倍数である必要があります。
コピーされるファイルのサイズは、2TB以下である必要があります。
コピーの進行状況を監視するには、V$SESSION_LONGOPS動的パフォーマンス・ビューを参照します。

コピーできない例
512バイトの倍数でないバイナリファイルをコピーしようとすると。。。

11:17:20 rdsora121@BILL> @ls_dir test_dir

FILENAME TYPE FILESIZE MTIME
---------------------------------------------------------------------- ---------- ---------- --------
hoge.dmp file 1083412480 18-09-23
hoge.log file 1202 18-09-23
hoge.dmp.gz file 2603349 18-09-24
hoge.log.gz file 512 18-09-24
hoge.log.bak1 file 1202 18-09-24
hoge.dmp.bak1 file 45093 18-09-24
01/ directory 4096 18-09-24

7行が選択されました。

11:18:02 rdsora121@BILL> @cp_transferfile test_dir hoge.dmp.gz test_dir hoge.dmp.gz.bak1
-19505:ORA-19505: ファイル"/rdsdbdata/userdirs/01/hoge.dmp.gz"の識別に失敗しました。
ORA-27046: ファイル・サイズが論理ブロック・サイズの倍数ではありません。
Additional information: 1

PL/SQLプロシージャが正常に完了しました。

うまくコピーできる例
512バイトの倍数サイズのバイナリファイルのコピー

11:23:12 rdsora121@BILL> @cp_transferfile test_dir hoge.dmp test_dir hoge.dmp.bak2

source file : test_dir/hoge.dmp
dest file : test_dir/hoge.dmp.bak2 copied.

PL/SQLプロシージャが正常に完了しました。

11:24:01 rdsora121@BILL> @ls_dir test_dir

FILENAME TYPE FILESIZE MTIME
---------------------------------------------------------------------- ---------- ---------- --------
hoge.dmp file 1083412480 18-09-23
hoge.log file 1202 18-09-23
hoge.dmp.gz file 2603349 18-09-24
hoge.log.gz file 512 18-09-24
hoge.log.bak1 file 1202 18-09-24
hoge.dmp.bak1 file 45093 18-09-24
01/ directory 4096 18-09-24
hoge.dmp.bak2 file 1083412480 18-09-24

8行が選択されました。

dbms_transfer_fileパッケージを利用したコードは以下の通り
これも制限が多くなければコードも短くてうれしいわけなんですが。。。しかたなし

11:24:10 rdsora121@BILL> !cat cp_transferfile.sql
set verify off
set serveroutput on format wrapped
BEGIN
DBMS_FILE_TRANSFER.COPY_FILE(
source_directory_object => UPPER('&1')
,source_file_name => '&2'
,destination_directory_object => UPPER('&3')
,destination_file_name => '&4'
);
DBMS_OUTPUT.PUT_LINE(' ');
DBMS_OUTPUT.PUT_LINE('source file : &1/&2');
DBMS_OUTPUT.PUT_LINE('dest file : &3/&4 copied.');
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE(SQLCODE()||':'||SQLERRM());
END;
/

undefine 1
undefine 2
undefine 3
undefine 4
set verify on
set serveroutput off


制限もあるし、使いやすいような使いにくいような...
いろいろ消化不良状態。。。なので

スクリプト長くなってめんどくさいけど、この部分楽はできない模様なので、手作り決定!

最終的に、既存プロシージャにないのなら、作っちゃえ。ということで、cp_file.sqlを全面作り変えw ました。

11:32:13 rdsora121@BILL> @ls_dir test_dir

FILENAME TYPE FILESIZE MTIME
---------------------------------------------------------------------- ---------- ---------- --------
hoge.dmp file 1083412480 18-09-23
hoge.log file 1202 18-09-23
hoge.dmp.gz file 2603349 18-09-24
hoge.log.gz file 512 18-09-24
01/ directory 4096 18-09-24

11:32:21 rdsora121@BILL> @cp_file test_dir hoge.dmp test_dir hoge.dmp.bak
TEST_DIR/hoge.dmp (1083412480) to TEST_DIR/hoge.dmp.bak (1083412480)

PL/SQLプロシージャが正常に完了しました。

11:33:07 rdsora121@BILL> @cp_file test_dir hoge.log test_dir hoge.log.bak
TEST_DIR/hoge.log (1202) to TEST_DIR/hoge.log.bak (1202)

PL/SQLプロシージャが正常に完了しました。

11:33:26 rdsora121@BILL> @cp_file test_dir hoge.dmp.gz test_dir hoge.dmp.gz.bak
TEST_DIR/hoge.dmp.gz (2603349) to TEST_DIR/hoge.dmp.gz.bak (2603349)

PL/SQLプロシージャが正常に完了しました。

11:33:42 rdsora121@BILL> @ls_dir test_dir

FILENAME TYPE FILESIZE MTIME
---------------------------------------------------------------------- ---------- ---------- --------
hoge.log file 1202 18-09-23
hoge.dmp file 1083412480 18-09-23
hoge.dmp.gz file 2603349 18-09-24
hoge.log.gz file 512 18-09-24
hoge.dmp.bak file 1083412480 18-09-24
hoge.log.bak file 1202 18-09-24
01/ directory 4096 18-09-24
hoge.dmp.gz.bak file 2603349 18-09-24

8行が選択されました。

新、cp_file.sqlのスクリプトは以下の通り。基本的に、gzip_file.sql内部で利用していたバイナリファイルのハンドリング部分を抜き出した感じです。一部違うのは DBMS_LOB.CREATETEMPORARYで一時BLOBを読んでいるところ。BFILEからBLOBをロードして、出力先ファイルへ書き出しているかしょは圧縮で利用しているコードと同じです。最後に一時BLOBの解放をお忘れなく

11:34:21 rdsora121@BILL> !cat cp_file.sql
SET VERIFY OFF
SET SERVEROUTPUT ON FORMAT WRAPPED
DECLARE
vSrcfile BFILE;
vSrcBlob BLOB;
vSrcDirectoryName VARCHAR2(30);
vDestDirectoryName VARCHAR2(30);
vSrcFileName VARCHAR2(60);
vDestFileName VARCHAR2(60);
vSrcFileSize PLS_INTEGER;
vDestFileSize PLS_INTEGER;

PROCEDURE close_bfile
(
iBfile IN OUT NOCOPY BFILE
)
IS
BEGIN
IF DBMS_LOB.ISOPEN(iBfile) = 1 THEN
DBMS_LOB.CLOSE(iBfile);
END IF;
END close_bfile;

PROCEDURE write_blob_to_file
(
iDirectoryName IN VARCHAR2
, iFileName IN VARCHAR2
, iSrcBlob IN OUT NOCOPY BLOB
)
IS
vFile UTL_FILE.FILE_TYPE;
BEGIN
vFile := UTL_FILE.FOPEN(
UPPER(iDirectoryName)
, iFileName
, 'wb'
, 32767
);

DECLARE
cChunkSize CONSTANT PLS_INTEGER := 32767;

vBuffer RAW(32767);
vAmount PLS_INTEGER := cChunkSize;
vNumOfChunk PLS_INTEGER;
BEGIN
vNumOfChunk := CEIL(DBMS_LOB.GETLENGTH(iSrcBlob)/cChunkSize);
FOR chunk# IN 1..vNumOfChunk LOOP
DBMS_LOB.READ(
iSrcBlob
, vAmount
, (cChunkSize * (chunk# - 1)) + 1 /*offset*/
, vBuffer
);
UTL_FILE.PUT_RAW(vFile, vBuffer, TRUE);
END LOOP;
END;
UTL_FILE.FCLOSE(vFile);
END write_blob_to_file;

BEGIN
vSrcDirectoryName := UPPER('&1');
vSrcFileName := '&2';
vDestDirectoryName := UPPER('&3');
vDestFileName := '&4';

vSrcFile
:= BFILENAME(UPPER(vSrcDirectoryName), vSrcFileName);

DBMS_LOB.OPEN(vSrcFile);
vSrcFileSize := DBMS_LOB.GETLENGTH(vSrcFile);


DBMS_LOB.CREATETEMPORARY (
lob_loc => vSrcBlob
, cache => false
, dur => DBMS_LOB.SESSION
);

DBMS_LOB.LOADFROMFILE (
dest_lob => vSrcBlob
, src_lob => vSrcFile
, amount => vSrcFileSize
, dest_offset => 1
, src_offset => 1
);
vDestFileSize := DBMS_LOB.GETLENGTH(vSrcBlob);

write_blob_to_file(
UPPER(vDestDirectoryName)
, vDestFileName
, vSrcBlob
);

DBMS_LOB.FREETEMPORARY(vSrcBlob);
close_bfile(vSrcFile);

DBMS_OUTPUT.PUT_LINE(
vSrcDirectoryName||'/'||vSrcFileName||' ('||vDestFileSize||') to '
||vDestDirectoryName||'/'||vDestFileName||' ('||vSrcFileSize||')'
);
EXCEPTION
WHEN OTHERS THEN
DBMS_LOB.FREETEMPORARY(vSrcBlob);
close_bfile(vSrcFile);
RAISE;
END;
/

UNDEFINE 1
UNDEFINE 2
UNDEFINE 3
UNDEFINE 4
SET SERVEROUTPUT OFF
SET VERIFY ON

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


Previously on Mac De Oracle

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

| | コメント (0) | トラックバック (0)

RDS Oracle 雑多なメモ#10 / FAQ

メモの続きです。
前回は、dbms_datapumpパッケージを利用してエクスポートを行うスクリプトを作成しました。
今回は、作成したダンプファイル(バイナリファイルでサイズは1GB越え)をutl_compressパッケージを利用して圧縮するスクリプトを作成します。

このネタ実は、12年前の古いネタが元になっています。
Mac De Oracle (PL/SQL De COMPRESS)
Mac De Oracle (PL/SQL De UNCOMPRESS)

ということで、RDS Oracleのディレクトリオブジェクトにエクポートしたダンプファイル(バイナリファイル)圧縮してみましょう。。動くのか?。。。

ディレクトリを確認

10:48:42 rdsora121@BILL> @list_dir

DIRECTORY_NAME DIRECTORY_PATH
---------------------------------------- ----------------------------------------------------------------------
ADUMP /rdsdbdata/log/audit
BDUMP /rdsdbdata/log/trace
DATA_PUMP_DIR /rdsdbdata/datapump
HOGE_DIR /rdsdbdata/userdirs/02
OPATCH_INST_DIR /rdsdbbin/oracle/OPatch
OPATCH_LOG_DIR /rdsdbbin/oracle/QOpatch
OPATCH_SCRIPT_DIR /rdsdbbin/oracle/QOpatch
TEST_DIR /rdsdbdata/userdirs/01

8行が選択されました。

エクスポートしたダンプファイル(バイナリファイル)とログファイル(テキストファイル)が対象ディレクトリ以下にあることを確認

10:42:05 rdsora121@BILL> @ls_dir test_dir

FILENAME TYPE FILESIZE MTIME
---------------------------------------------------------------------- ---------- ---------- --------
hoge.dmp file 1083412480 18-09-23
hoge.log file 1202 18-09-23
01/ directory 4096 18-09-24

まず、ダンプファイル(バイナリファイル)を圧縮します。ダンプファイルは圧縮効率がいいんですよね。なので転送する際には圧縮するのがオススメ
圧縮はうまくいった?ようですね。解凍スクリプト編で正常に解凍できるか確認する予定なのでしばしお待ちを。

10:46:00 rdsora121@BILL> @gzip_file test_dir hoge.dmp
TEST_DIR/hoge.dmp compressed to hoge.dmp.gz(99.76%)

PL/SQLプロシージャが正常に完了しました。

圧縮したファイルは、.gzの拡張子をつけて出力するようにしています。

10:46:23 rdsora121@BILL> @ls_dir test_dir

FILENAME TYPE FILESIZE MTIME
---------------------------------------------------------------------- ---------- ---------- --------
hoge.dmp file 1083412480 18-09-23
hoge.log file 1202 18-09-23
hoge.dmp.gz file 2603349 18-09-24
01/ directory 4096 18-09-24

次に、テキストファイルも圧縮!

10:46:32 rdsora121@BILL> @gzip_file test_dir hoge.log
TEST_DIR/hoge.log compressed to hoge.log.gz(57.4%)

PL/SQLプロシージャが正常に完了しました。

10:46:51 rdsora121@BILL> @ls_dir test_dir

FILENAME TYPE FILESIZE MTIME
---------------------------------------------------------------------- ---------- ---------- --------
hoge.dmp file 1083412480 18-09-23
hoge.log file 1202 18-09-23
hoge.dmp.gz file 2603349 18-09-24
hoge.log.gz file 512 18-09-24
001/ directory 4096 18-09-24

スクリプトは以下の通り、utl_compressパッケージを利用しています。バイナリファイルはBFILEから読み込み、圧縮、圧縮結果のバイナリは一時BLOBで返されるので、一時BLOBをバイナリファイルとして書き出しています。最後に一時BLOBを解放してあげてゴミ掃除という流れです。

10:46:58 rdsora121@BILL> !cat gzip_file.sql
SET VERIFY OFF
SET SERVEROUTPUT ON FORMAT WRAPPED
DECLARE
vSrcfile BFILE;
vCompressedBlob BLOB;
vDirectoryName VARCHAR2(30);
vSrcFileName VARCHAR2(60);
vDestFileName VARCHAR2(60);
vSrcFileSize PLS_INTEGER;
vDestFileSize PLS_INTEGER;

PROCEDURE close_bfile
(
iBfile IN OUT NOCOPY BFILE
)
IS
BEGIN
IF DBMS_LOB.ISOPEN(iBfile) = 1 THEN
DBMS_LOB.CLOSE(iBfile);
END IF;
END close_bfile;

PROCEDURE write_blob_to_file
(
iDirectoryName IN VARCHAR2,
iFileName IN VARCHAR2,
iSrcBlob IN OUT NOCOPY BLOB
)
IS
vFile UTL_FILE.FILE_TYPE;
BEGIN
vFile := UTL_FILE.FOPEN(
UPPER(iDirectoryName),
iFileName,
'wb',
32767
);

DECLARE
cChunkSize CONSTANT PLS_INTEGER := 32767;

vBuffer RAW(32767);
vAmount PLS_INTEGER := cChunkSize;
vNumOfChunk PLS_INTEGER;
BEGIN
vNumOfChunk := CEIL(DBMS_LOB.GETLENGTH(iSrcBlob)/cChunkSize);
FOR chunk# IN 1..vNumOfChunk LOOP
DBMS_LOB.READ(
iSrcBlob,
vAmount,
(cChunkSize * (chunk# - 1)) + 1, /*offset*/
vBuffer
);
UTL_FILE.PUT_RAW(vFile, vBuffer, TRUE);
END LOOP;
END;

UTL_FILE.FCLOSE(vFile);
END write_blob_to_file;
--
BEGIN
vDirectoryName := UPPER('&1');
vSrcFileName := '&2';
vDestFileName := '&2'||'.gz';

vSrcFile
:= BFILENAME(UPPER(vDirectoryName), vSrcFileName);

DBMS_LOB.OPEN(vSrcFile);
vSrcFileSize := DBMS_LOB.GETLENGTH(vSrcFile);
vCompressedBlob := UTL_COMPRESS.LZ_COMPRESS(vSrcFile);
vDestFileSize := DBMS_LOB.GETLENGTH(vCompressedBlob);

write_blob_to_file(
UPPER(vDirectoryName),
vDestFileName,
vCompressedBlob
);

DBMS_LOB.FREETEMPORARY(vCompressedBlob);
close_bfile(vSrcFile);

DBMS_OUTPUT.PUT_LINE(
vDirectoryName
||'/'||vSrcFileName||' compressed to '
||vDestFileName||'('
||ROUND((1 - (vDestFileSize / vSrcFileSize)) * 100, 2)||'%)'
);
XCEPTION
WHEN OTHERS THEN
DBMS_LOB.FREETEMPORARY(vCompressedBlob);
close_bfile(vSrcFile);
RAISE;
END;
/

UNDEFINE 1
UNDEFINE 2
SET SERVEROUTPUT OFF
SET VERIFY ON

できた〜

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



Previously on Mac De Oracle

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

| | コメント (0) | トラックバック (0)

RDS Oracle 雑多なメモ#9 / FAQ

メモの続きです。
ということで、 (どういうことだ〜っ。久々に一人、ツッコミ)

圧縮解凍ネタに進む前に、dbms_datapumpパッケージを使って、1GB越えのファイルを作っておこうかと。ここで作成したダンプファイルを圧縮解凍ネタにしようと思います。
事前にscottユーザーを作成して、hoge表を作成し、1GB程度のセグメントサイズになるようにデータを登録、その後、主キー索引を追加してあります。

14:29:48 rdsora121@BILL> desc scott.hoge
名前 NULL? 型
----------------------------------------- -------- ----------------------------
ID NOT NULL NUMBER
FOO VARCHAR2(4000)

14:31:24 rdsora121@BILL>select segment_name,sum(bytes)/1024/1024/1024 "GB" from dba_segments where owner='SCOTT' group by segment_name;

SEGMENT_NAME GB
------------------------------ ----------
PK_HOGE .004882813
HOGE 2.125

経過: 00:00:00.09
14:28:59 rdsora121@BILL> @list_dir

DIRECTORY_NAME DIRECTORY_PATH
---------------------------------------- ----------------------------------------------------------------------
ADUMP /rdsdbdata/log/audit
BDUMP /rdsdbdata/log/trace
DATA_PUMP_DIR /rdsdbdata/datapump
HOGE_DIR /rdsdbdata/userdirs/02
OPATCH_INST_DIR /rdsdbbin/oracle/OPatch
OPATCH_LOG_DIR /rdsdbbin/oracle/QOpatch
OPATCH_SCRIPT_DIR /rdsdbbin/oracle/QOpatch
TEST_DIR /rdsdbdata/userdirs/01

8行が選択されました。

経過: 00:00:00.03
14:29:03 rdsora121@BILL> @ls_dir test_dir

FILENAME TYPE FILESIZE MTIME
---------------------------------------------------------------------- ---------- ---------- --------
01/ directory 4096 18-09-22

scottユーザーのhoge表を表モードでエクスポートしてダンプファイルをtest_dirへ出力させます!
以前やっつけで作ったのスクリプトの再利用なので、エクスポートモードなど他のパラメータも変更できるようにすれば、より良く改良できると思います。いまはやりませんがw
(以前の記事も参考にしてみてくさい。SQL Tuning Setのキャプチャから退避までのスクリプト(やっつけ))
出力されたダンプファイルは約1GBってところですね。

14:35:41 rdsora121@BILL> @export_table test_dir hoge scott hoge
"BILL"."EXPTABLE_HOGE"を起動しています:
BLOCKSメソッドを使用して見積り中です...
オブジェクト型TABLE_EXPORT/TABLE/TABLE_DATAの処理中です
BLOCKSメソッドを使用した見積り合計: 2.125 GB
オブジェクト型TABLE_EXPORT/TABLE/TABLEの処理中です
オブジェクト型TABLE_EXPORT/TABLE/INDEX/INDEXの処理中です
オブジェクト型TABLE_EXPORT/TABLE/CONSTRAINT/CONSTRAINTの処理中です
オブジェクト型TABLE_EXPORT/TABLE/INDEX/STATISTICS/INDEX_STATISTICSの処理中です
オブジェクト型TABLE_EXPORT/TABLE/STATISTICS/TABLE_STATISTICSの処理中です
オブジェクト型TABLE_EXPORT/TABLE/STATISTICS/MARKERの処理中です
. . "SCOTT"."HOGE" 1.008 GB 270000行がエクスポートされました
マスター表"BILL"."EXPTABLE_HOGE"は正常にロード/アンロードされました
******************************************************************************

BILL.EXPTABLE_HOGEに設定されたダンプ・ファイルは次のとおりです:
/rdsdbdata/userdirs/01/hoge.dmp
ジョブ"BILL"."EXPTABLE_HOGE"が日 9月 23 05:36:33 2018 elapsed 0 00:00:35で正常に完了しました

PL/SQLプロシージャが正常に完了しました。

経過: 00:00:40.23
14:36:34 rdsora121@BILL>
14:37:04 rdsora121@BILL> @ls_dir test_dir

FILENAME TYPE FILESIZE MTIME
---------------------------------------------------------------------- ---------- ---------- --------
01/ directory 4096 18-09-23
hoge.log file 1202 18-09-23
hoge.dmp file 1083412480 18-09-23

表モードエクスポートのDataPump Exportジョブを実行するスクリプトは以下のとおり。
(表モードに固定してある部分を変更してスキーマモードにしたり、複数の表のエクスポートに対応できるように改造してやれば、より便利なスクリプトにすることもできると思います。)

14:36:34 rdsora121@BILL> !cat export_table.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';
cSchemaName CONSTANT VARCHAR2(30) := UPPER('&3');
cTableName CONSTANT VARCHAR2(30) := UPPER('&4');
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 => 'TABLE'
,remote_link => NULL
,job_name => 'EXPTABLE_'||cTableName
,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 := 'METADATA_FILTER - schema name';
DBMS_DATAPUMP.METADATA_FILTER (
handle => vDataPumpJobHandle
,name => 'SCHEMA_LIST'
,value => '''' || cSchemaName || ''''
);

v4Debug := 'METADATA_FILTER - table name';
DBMS_DATAPUMP.METADATA_FILTER (
handle => vDataPumpJobHandle
,name => 'NAME_LIST'
,value => '''' || cTableName || ''''
);

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
UNDEFINE 4
SET SERVEROUTPUT OFF
SET VERIFY ON


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


Previously on Mac De Oracle

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

| | コメント (0) | トラックバック (0)

RDS Oracle 雑多なメモ#8 / FAQ

メモの続きです。
前回は、utl_fileパッケージでrmっぽいことを行うスクリプトを作成しました。
前回まででutl_fileパッケージを利用したディレクトリオブジェクト配下のファイル操作スクリリプトを作ることができました。

さて、今回はなにをしましょう?。。。。としばし考えて浮かんだのが、昔の圧縮解凍ネタとdbms_datapumpネタの組み合わせ。。。

再利用ネタ、その1は以下。
SQL Tuning Setのキャプチャから退避までのスクリプト(やっつけ
上記ネタの何を利用するかというと、DBMS_DATAPUMPパッケージ。このパッケージもディレクトリオブジェクトを利用するのでネタとしてはちょうどよさげ。

もう一つのネタはかなり古い(12年前?w)
Mac De Oracle (PL/SQL De COMPRESS)
Mac De Oracle (PL/SQL De UNCOMPRESS)
この辺りを使って、圧縮、解凍スクリプトも作っておいたら便利なんじゃないかとおもいます。

それから、kempe さんの記事も利用すればいろいろできそうですね。 プライベートサブネットのVPCエンドポイント経由でS3とやりとりすればパブリックネットワークは経由しなくて良さそうですし:)
RDSとS3でファイルのやり取りを行う

なお、11.2では、aclパラメータに.xml拡張子が必要ですが、12.1以降では必要ありません(いつ変わったw)が、12c以降では以下プロシージャは非推奨で下位互換向けにのこされています
11.2のマニュアルには aclパラメータには、.xml 拡張子が必要とは明記されていないのですが、意味不明なエラーが返されます。例のaclには.xml拡張子が付加されているのですが、パラメータの解説では一切触れられていないのでハマることがあるので注意しましょうね。

15:54:54 orcl@SYS> select version from v$instance;

VERSION
-----------------
11.2.0.4.0

15:54:00 orcl@SYS> !cat test.sql
begin
dbms_network_acl_admin.create_acl (
acl => 'test'
, description => 'acl create test'
, principal => 'SCOTT'
, is_grant => true
, privilege => 'connect'
);
end;
/

15:54:07 orcl@SYS> @test
begin
*
ERROR at line 1:
ORA-46059: Invalid ACL identifier specified
ORA-06512: at "SYS.DBMS_NETWORK_ACL_ADMIN", line 70
ORA-06512: at "SYS.DBMS_NETWORK_ACL_ADMIN", line 218
ORA-06512: at line 2

15:54:19 orcl@SYS> !cat test.sql
begin
dbms_network_acl_admin.create_acl (
acl => 'test.xml'
, description => 'acl create test'
, principal => 'SCOTT'
, is_grant => true
, privilege => 'connect'
);
end;
/

15:54:25 orcl@SYS> @test

PL/SQL procedure successfully completed.

Elapsed: 00:00:00.02
15:54:27 orcl@SYS> exec dbms_network_acl_admin.drop_acl('test.xml');

PL/SQL procedure successfully completed.

dbms_network_acl_adminについては11.2と12.1で考慮はいるかもしれません。(非推奨プロシージャはいずれ廃止されるでしょうから)

というあたりも考慮してネタを作るかどうか。。。
その前に、ファイル、圧縮解凍だけのネタを作っておくか。。

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



Previously on Mac De Oracle

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

| | コメント (0) | トラックバック (0)

2018年9月23日 (日)

RDS Oracle 雑多なメモ#7 / FAQ

メモの続きです。
前回は、utl_fileパッケージでcpっぽいことを行うスクリプトを作成しました。
今回は、ディレクトリオブジェクト以下のファイルにrmっぽい操作が行えるようなスクリプトを作ります :)

作成済みのtest_dirディレクトのファイルを再利用しています。

ディレクトリとファイルを指定してファイル削除!


17:11:54 rdsora121@BILL> @ls_dir test_dir

FILENAME TYPE FILESIZE MTIME
---------------------------------------------------------------------- ---------- ---------- --------
top100_tables_v1.txt file 2277 18-09-19
top100_tables_v2.txt file 2277 18-09-21
01/ directory 4096 18-09-21


17:12:37 rdsora121@BILL> @rm_file test_dir top100_tables_v2.txt
TEST_DIR/top100_tables_v2.txt removed.

PL/SQLプロシージャが正常に完了しました。

経過: 00:00:00.03

17:13:25 rdsora121@BILL> @ls_dir test_dir

FILENAME TYPE FILESIZE MTIME
---------------------------------------------------------------------- ---------- ---------- --------
top100_tables_v1.txt file 2277 18-09-19
01/ directory 4096 18-09-22

スクリプトは以下の通り。UTL_FILE.FREMOVEを呼び出しているだけの単純なスクリプトにしてあります
第一回目にも書きましたが、スクリプトは、EC2など、SQL*Plusを起動しているクライアント側に作成します。

17:14:51 rdsora121@BILL> !cat rm_file.sql
set verify off
set serveroutput on
BEGIN
UTL_FILE.FREMOVE (
location => UPPER('&1')
, filename => '&2'
);
DBMS_OUTPUT.PUT_LINE(UPPER('&1')||'/&2 removed.');
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE(SQLCODE()||':'||SQLERRM());
END;
/

set serveroutput off
undefine 1
undefine 2
set verify on


次回へ続く


Previously on Mac De Oracle

RDS Oracle 雑多なメモ#1 / FAQ
RDS Oracle 雑多なメモ#2 / FAQ
RDS Oracle 雑多なメモ#3 / FAQ
RDS Oracle 雑多なメモ#4 / FAQ
RDS Oracle 雑多なメモ#5 / FAQ
RDS Oracle 雑多なメモ#6 / FAQ




ところで、今年も秋葉原UDXで開催されたdb tech showcase 2018へ参加してきました。
今回、自分のセッションも司会もなしだったので、久々にゆっくりといろいろな方のセッションを聞くことがきたし、毎年このイベント合う多数のデータベースエンジニアとの交流もたのしくてたのしくてw それ以上表現のしようがないw
(ボキャ貧なのでごめんなさい、ごめんなさい)

そして、インサイトテクノロジーの社長を退かれた小幡さん、 ”おもしろった!” ありがとうございました。
おいしいみかんできたら、送ってね :)

| | コメント (0) | トラックバック (0)

2018年9月22日 (土)

RDS Oracle 雑多なメモ#6 / FAQ

メモの続きです。
前回は、utl_fileパッケージでmvっぽいことを行うスクリプトを作成しました。
今回は、ディレクトリオブジェクト以下のファイルにcpっぽい操作が行えるようなスクリプトを作ります :)



ただ、 utl_file.fcopyってテキストファイルしかコピーできないんだよね。という制限付きです。いまのところ。
(バイナリ版は手作りで作ればできたような、。。。昔のネタ引っ張り出すかw)

ということで、utl_file.fcopyもdbms_transfer_fileパッケージも使わずにLOB系操作でバイナリファイルとテキストファイルをコピーするよう、cp_file.sqlスクリプトを作り変えました。

RDS Oracle 雑多なメモ#11 / FAQも合わせて参照ください。m(_ _)m




作成済みのtest_dirとhoge_dirディレクトリとファイルを再利用しています。
ざっくりめで書いたので複数ファイルの一括コピーや引数の指定方法などなど、改善したいところはあるわけですがw 適宜対応ということで。

同一ディレクトリでファイルコピー

00:44:59 SQL> @ls_dir test_dir

FILENAME TYPE FILESIZE MTIME
---------------------------------------------------------------------- ---------- ---------- --------
top100_tables_v1.txt file 2277 18-09-19
01/ directory 4096 18-09-21

経過: 00:00:02.35
00:55:33 SQL> @cp_file test_dir top100_tables_v1.txt test_dir top100_tables_v2.txt

source file : test_dir/top100_tables_v1.txt
dest file : test_dir/top100_tables_v2.txt copied.

PL/SQLプロシージャが正常に完了しました。

経過: 00:00:00.04
00:57:42 SQL> @ls_dir test_dir

FILENAME TYPE FILESIZE MTIME
---------------------------------------------------------------------- ---------- ---------- --------
top100_tables_v1.txt file 2277 18-09-19
top100_tables_v2.txt file 2277 18-09-21
01/ directory 4096 18-09-21

異なるディレクトリへ同一名でファイルコピー

01:01:55 SQL> @cp_file test_dir top100_tables_v2.txt hoge_dir top100_tables_v2.txt

source file : test_dir/top100_tables_v2.txt
dest file : hoge_dir/top100_tables_v2.txt copied.

PL/SQLプロシージャが正常に完了しました。

経過: 00:00:00.05
01:05:13 SQL> @ls_dir hoge_dir

FILENAME TYPE FILESIZE MTIME
---------------------------------------------------------------------- ---------- ---------- --------
top100_tables_v2.txt file 2277 18-09-21
02/ directory 4096 18-09-21

異なるディレクトリへ異なるファイル名でコピー

01:06:30 SQL> @cp_file test_dir top100_tables_v2.txt hoge_dir top100_tables_v3.txt

source file : test_dir/top100_tables_v2.txt
dest file : hoge_dir/top100_tables_v3.txt copied.

PL/SQLプロシージャが正常に完了しました。

経過: 00:00:00.04
01:06:47 SQL> @ls_dir hoge_dir

FILENAME TYPE FILESIZE MTIME
---------------------------------------------------------------------- ---------- ---------- --------
top100_tables_v2.txt file 2277 18-09-21
02/ directory 4096 18-09-21
top100_tables_v3.txt file 2277 18-09-21

スクリプトは以下の通り。


01:09:56 SQL> !cat cp_file.sql
set verify off
set serveroutput on format wrapped
BEGIN
UTL_FILE.FCOPY(
src_location => UPPER('&1')
,src_filename => '&2'
,dest_location => UPPER('&3')
,dest_filename => '&4'
);
DBMS_OUTPUT.PUT_LINE(' ');
DBMS_OUTPUT.PUT_LINE('source file : &1/&2');
DBMS_OUTPUT.PUT_LINE('dest file : &3/&4 copied.');
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE(SQLCODE()||':'||SQLERRM());
END;
/

undefine 1
undefine 2
undefine 3
undefine 4
set verify on
set serveroutput off


次回へ続く



Previously on Mac De Oracle

RDS Oracle 雑多なメモ#1 / FAQ
RDS Oracle 雑多なメモ#2 / FAQ
RDS Oracle 雑多なメモ#3 / FAQ
RDS Oracle 雑多なメモ#4 / FAQ
RDS Oracle 雑多なメモ#5 / FAQ

| | コメント (0) | トラックバック (0)

2018年9月21日 (金)

RDS Oracle 雑多なメモ#5 / FAQ

メモの続きです。
前回は、AWS提供のrdsadmin.rds_file_util.read_text_file関数でcatっぽいスクリプトを作っておきました。(改善したほうがよさげなところもありますがw)
今回は、ディレクトリオブジェクト以下のファイルにmvっぽい操作が行えるようなスクリプトを作ります。

これからの操作はファイルそのものに対しておこなうので、 わかりやすくする意味もあり新たにディレクトオブジェクトを作成して、ファイルを一作っておきます。

実験用ディレクトリオブジェクトの作成

00:49:07 rdsora121@BILL> @create_dir test_dir

PL/SQLプロシージャが正常に完了しました。

経過: 00:00:02.04

DIRECTORY_NAME DIRECTORY_PATH
---------------------------------------- ----------------------------------------------------------------------
TEST_DIR /rdsdbdata/userdirs/01

経過: 00:00:00.03


作成したディレクトリオブジェクト以下に適当なファイル(今回はテキストファイル)を作成

01:05:30 rdsora121@BILL> @query2file.sql

PL/SQLプロシージャが正常に完了しました。

経過: 00:00:00.12

ここでは、”utl_file I/O” - この症状はあれの可能性が高いですね。でも紹介したUTL_FILEパッケージでディレクトオブジェクト以下にファイルを出力するサンプルを再利用してファイルを書き出しました。

01:06:02 rdsora121@BILL> !cat query2file.sql
DECLARE
cDIR_NAME CONSTANT VARCHAR2(30) := 'TEST_DIR';
cFILE_NAME CONSTANT VARCHAR2(128) := 'top100_tablenames__'||TO_CHAR(systimestamp, 'rrmmddhh24miss.ff')||'.txt';
cBufferSize CONSTANT BINARY_INTEGER := 32767;
cOpenMode CONSTANT VARCHAR2(2) := 'w';
fileHandle UTL_FILE.FILE_TYPE;
buffer VARCHAR2(32767);

cBulkReadLimit CONSTANT PLS_INTEGER := 324;
TYPE tBulkReadArray IS TABLE OF VARCHAR2(8192) INDEX BY BINARY_INTEGER;
bulkReadArray tBulkReadArray;
CURSOR cur_top100_tablenames IS
SELECT
table_name
FROM
dba_tables
ORDER BY
table_name
FETCH FIRST 100 ROWS ONLY
;
BEGIN
OPEN cur_top100_tablenames;
fileHandle := UTL_FILE.FOPEN(cDIR_NAME, cFILE_NAME, cOpenMode, cBufferSize);
LOOP
FETCH cur_top100_tablenames
BULK COLLECT INTO bulkReadArray
LIMIT cBulkReadLimit;

EXIT WHEN bulkReadArray.COUNT = 0;

buffer := NULL;
FOR i IN bulkReadArray.FIRST..bulkReadArray.LAST LOOP
buffer := buffer || bulkReadArray(i) || UTL_TCP.CRLF;
END LOOP;
UTL_FILE.PUT(fileHandle, buffer);
UTL_FILE.FFLUSH(fileHandle);
END LOOP;
UTL_FILE.FFLUSH(fileHandle);
UTL_FILE.FCLOSE(fileHandle);
CLOSE cur_top100_tablenames;
EXCEPTION
WHEN OTHERS THEN
IF UTL_FILE.IS_OPEN(fileHandle) THEN
UTL_FILE.FCLOSE(fileHandle);
END IF;

IF cur_top100_tablenames%ISOPEN THEN
CLOSE cur_top100_tablenames;
END IF;
RAISE;
END;
/

テキストファイルがディレクトリオブジェクト以下に作成されましった!

01:06:29 rdsora121@BILL> @ls_dir test_dir

FILENAME TYPE FILESIZE MTIME
---------------------------------------------------------------------- ---------- ---------- --------
top100_tablenames__180919160551.113374000.txt file 2277 18-09-19
01/ directory 4096 18-09-19

念のため中身を確認

01:06:38 rdsora121@BILL> @cat_file test_dir top100_tablenames__180919160551.113374000.txt

TEXT
------------------------------------------------------------------------------------------
ACCESS$
ACLMV$
ACLMV$_REFLOG
ACLMVREFSTAT$


・・・中略・・・

AQ$_SUBSCRIBER_TABLE
AQ$_SYS$SERVICE_METRICS_TAB_G
AQ$_SYS$SERVICE_METRICS_TAB_H
AQ$_SYS$SERVICE_METRICS_TAB_I

100行が選択されました。

同一ディレクトリ内でファイル名を変更

01:29:47 rdsora121@BILL> @mv_file test_dir top100_tablenames__180919160551.113374000.txt test_dir top100_tables.txt

source file : test_dir/top100_tablenames__180919160551.113374000.txt
dest file : test_dir/top100_tables.txt moved.

PL/SQLプロシージャが正常に完了しました。

長いファイル名称を短く変更!

01:29:57 rdsora121@BILL> @ls_dir test_dir

FILENAME TYPE FILESIZE MTIME
---------------------------------------------------------------------- ---------- ---------- --------
top100_tables.txt file 2277 18-09-19
01/ directory 4096 18-09-19

ファイル名は同じままで、別ディレクトリへファイル移動

08:05:17 rdsora121@BILL> @create_dir hoge_dir

PL/SQLプロシージャが正常に完了しました。

経過: 00:00:02.26

DIRECTORY_NAME DIRECTORY_PATH
---------------------------------------- ----------------------------------------------------------------------
HOGE_DIR /rdsdbdata/userdirs/02

経過: 00:00:00.04
08:05:29 rdsora121@BILL> @mv_file test_dir top100_tables.txt hoge_dir top100_tables.txt

source file : test_dir/top100_tables.txt
dest file : hoge_dir/top100_tables.txt moved.

PL/SQLプロシージャが正常に完了しました。

経過: 00:00:00.04
08:06:27 rdsora121@BILL> @ls_dir hoge_dir

FILENAME TYPE FILESIZE MTIME
---------------------------------------------------------------------- ---------- ---------- --------
top100_tables.txt file 2277 18-09-19
02/ directory 4096 18-09-19

経過: 00:00:02.25
08:06:39 rdsora121@BILL> @ls_dir test_dir

FILENAME TYPE FILESIZE MTIME
---------------------------------------------------------------------- ---------- ---------- --------
01/ directory 4096 18-09-19

ファイル名を変更して、ディレクトリ移動

08:08:22 rdsora121@BILL> @mv_file hoge_dir top100_tables.txt test_dir top100_tables_v1.txt

source file : hoge_dir/top100_tables.txt
dest file : test_dir/top100_tables_v1.txt moved.

PL/SQLプロシージャが正常に完了しました。

経過: 00:00:00.02
08:09:00 rdsora121@BILL> @ls_dir hoge_dir

FILENAME TYPE FILESIZE MTIME
---------------------------------------------------------------------- ---------- ---------- --------
02/ directory 4096 18-09-19

経過: 00:00:02.05
08:09:11 rdsora121@BILL> @ls_dir test_dir

FILENAME TYPE FILESIZE MTIME
---------------------------------------------------------------------- ---------- ---------- --------
top100_tables_v1.txt file 2277 18-09-19
01/ directory 4096 18-09-19

経過: 00:00:02.05


スクリプトは以下の通り

01:30:20 rdsora121@BILL> !cat mv_file.sql
set verify off
set serveroutput on format wrapped
BEGIN
UTL_FILE.FRENAME(
src_location => UPPER('&1')
,src_filename => '&2'
,dest_location => UPPER('&3')
,dest_filename => '&4'
,overwrite => false
);
DBMS_OUTPUT.PUT_LINE(' ');
DBMS_OUTPUT.PUT_LINE('source file : &1/&2');
DBMS_OUTPUT.PUT_LINE('dest file : &3/&4 moved.');
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE(SQLCODE()||':'||SQLERRM());
END;
/

undefine 1
undefine 2
undefine 3
undefine 4
set verify on
set serveroutput off

次回へ続く



Previously on Mac De Oracle

RDS Oracle 雑多なメモ#1 / FAQ
RDS Oracle 雑多なメモ#2 / FAQ
RDS Oracle 雑多なメモ#3 / FAQ
RDS Oracle 雑多なメモ#4 / FAQ

| | コメント (0) | トラックバック (0)

2018年9月20日 (木)

RDS Oracle 雑多なメモ#4 / FAQ

メモの続きです。
前回は、AWS提供のrdsadmin.rds_file_util.listdir関数を利用したlsっぽいファイルリストスクリプトを作成しました。
今回は、同じくAWS提供のrdsadmin.rds_file_util.read_text_file関数でcatっぽいスクリプトを。

ディレクト名を確認し。。

05:10:47 rdsora121@BILL> @list_dir

DIRECTORY_NAME DIRECTORY_PATH
---------------------------------------- ----------------------------------------------------------------------
ADUMP /rdsdbdata/log/audit
BDUMP /rdsdbdata/log/trace
DATA_PUMP_DIR /rdsdbdata/datapump
OPATCH_INST_DIR /rdsdbbin/oracle/OPatch
OPATCH_LOG_DIR /rdsdbbin/oracle/QOpatch
OPATCH_SCRIPT_DIR /rdsdbbin/oracle/QOpatch

6行が選択されました。

経過: 00:00:00.02

ファイル名を確認してから。。

05:10:50 rdsora121@BILL> @ls_dir bdump

FILENAME TYPE FILESIZE MTIME
---------------------------------------------------------------------- ---------- ---------- --------
ORCL_ora_12254.trc file 4393 18-09-15
ORCL_ora_12254.trm file 202 18-09-15

・・・中略・・・

ORCL_ora_12841.trm file 71 18-09-17
trace/ directory 12288 18-09-17
ORCL_ora_12841.trc file 990 18-09-17
alert_ORCL.log file 138516 18-09-17
ORCL_mmon_11216.trm file 118 18-09-17
ORCL_mmon_11216.trc file 1503 18-09-17

279行が選択されました。

経過: 00:00:02.28

alertログファイルを覗いて見ましょう。

05:10:57 rdsora121@BILL> @cat_file bdump alert_ORCL.log

TEXT
-----------------------------------------------------------------------------------------------
Sat Sep 15 19:03:04 2018
Starting ORACLE instance (normal) (OS id: 12254)
Sat Sep 15 19:03:04 2018

・・・中略・・・

pga_aggregate_limit is 4809 MB

3376行が選択されました。

経過: 00:00:03.09

スクリプトは以下のとおり。
ん〜。ざっくり作りすぎたかもw Top Nクエリもできるようにしたほうがいいかもねぇ〜と。思わなくもないけど、とりあえずこれで。

ちなみに、ディレクトリ名はUPPER()関数で強制的に大文字変換、ファイル名は入力されたファイル名をそのまま利用するようにしています。

05:12:04 rdsora121@BILL> !cat cat_file.sql
set verify off
set long 100000
set longchunk 100000
SELECT
text
FROM
TABLE (
rdsadmin.rds_file_util.read_text_file (
p_directory => UPPER('&1')
, p_filename => '&2'
)
)
;

undefine 1
undefine 2
set verify on

次回へ続く



Previously on Mac De Oracle

RDS Oracle 雑多なメモ#1 / FAQ
RDS Oracle 雑多なメモ#2 / FAQ
RDS Oracle 雑多なメモ#3 / FAQ

| | コメント (0) | トラックバック (0)

2018年9月19日 (水)

RDS Oracle 雑多なメモ#3 / FAQ

メモの続きです。
これまでに、ディレクトリ作成、削除、ディレクトリリストスクリプトを作成しました。

残る使用頻度の高そうなスクリプトは、ディレクトリオブジェクト以下にあるファイル操作スクリプト。
OSレイヤーに入れないRDS Oracleで、ディレクトリオブジェクト以下にあるファイルの操作に困るのは目に見えてるので。。。w

RDS Oracleでは、rdsadmin.rds_file_utilパッケージが提供されていますが、提供されている関数は以下の通り。
どう見ても全ての操作を行うに不十分なのですが、よーく思い出してみましょう。
ファイルの削除などの操作は、Oracle Databaseに昔からあるビルトインパッケージ、utl_fileパッケージを利用できちゃいそうですよね!!
ということで、これまた、いちいちタイプするのは面倒なので事前に作成しておいたほうが楽なはず。。。

13:40:16 rdsora121@BILL> desc rdsadmin.rds_file_util
FUNCTION LISTDIR RETURNS RDS_FILE_LIST_T
引数名 タイプ In/Out Default?
------------------------------ ----------------------- ------ --------
P_DIRECTORY VARCHAR2 IN
FUNCTION READ_TEXT_FILE RETURNS RDS_TEXT_LIST_T
引数名 タイプ In/Out Default?
------------------------------ ----------------------- ------ --------
P_DIRECTORY VARCHAR2 IN
P_FILENAME VARCHAR2 IN

まず、上記AWSから提供されているrdsadmin.rds_file_util.listdir関数を利用したスクリプトを作成しておきます。

13:53:44 rdsora121@BILL> @list_dir

DIRECTORY_NAME DIRECTORY_PATH
---------------------------------------- ----------------------------------------------------------------------
ADUMP /rdsdbdata/log/audit
BDUMP /rdsdbdata/log/trace
DATA_PUMP_DIR /rdsdbdata/datapump
OPATCH_INST_DIR /rdsdbbin/oracle/OPatch
OPATCH_LOG_DIR /rdsdbbin/oracle/QOpatch
OPATCH_SCRIPT_DIR /rdsdbbin/oracle/QOpatch

6行が選択されました。

経過: 00:00:00.03

ファイルの無い空のディレクトリは以下のようにリストされるか〜。
へぇ〜。

13:53:52 rdsora121@BILL> @ls_dir data_pump_dir

FILENAME TYPE FILESIZE MTIME
---------------------------------------------------------------------- ---------- ---------- --------
datapump/ directory 4096 18-09-17

経過: 00:00:02.25

ディレクトオブジェクトへの読み込み権限がないと以下のようなエラーが返ります。

13:54:07 rdsora121@BILL> @ls_dir opatch_log_dir
rdsadmin.rds_file_util.listdir(UPPER('OPATCH_LOG_DIR'))
*
行5でエラーが発生しました。:
ORA-20900: Directory OPATCH_LOG_DIR does not exist or no privileges.
ORA-06512: "SYS.RDS_SYS_UTIL", 行147
ORA-06512: "SYS.RDS_SYS_UTIL", 行161
ORA-06512: "RDSADMIN.RDS_FILE_UTIL", 行38


経過: 00:00:00.05


対象ディレクトリの読み取り権限が付与され、ディレクトリオブジェクト以下になんらかのファイルがあれば、以下のようなリリストが返ります。
こんな感じにリストされるのな。:)

13:54:42 rdsora121@BILL> @ls_dir adump

FILENAME TYPE FILESIZE MTIME
---------------------------------------------------------------------- ---------- ---------- --------
ORCL_ora_12254_20180915190307342858143795.aud file 805 18-09-15

...中略...

ORCL_ora_12687_20180917043000205002143795.aud file 1549 18-09-17
ORCL_ora_14013_20180917044500213934143795.aud file 1549 18-09-17
audit/ directory 16384 18-09-17

146行が選択されました。

経過: 00:00:02.17


スクリプトは以下のとおり。rdsadmin.rds_file_util.listdir関数は表関数なので以下のような使い方:)

13:55:17 rdsora121@BILL> !cat ls_dir.sql
set verify off
col filename for a70
SELECT
*
FROM
TABLE (
rdsadmin.rds_file_util.listdir(UPPER('&1'))
)
ORDER BY
mtime
;

undefine 1
set verify off


次回へ続く



Previously on Mac De Oracle

RDS Oracle 雑多なメモ#1 / FAQ
RDS Oracle 雑多なメモ#2 / FAQ

| | コメント (0) | トラックバック (0)

2018年9月18日 (火)

RDS Oracle 雑多なメモ#2 / FAQ

メモの続き。

前回、ディレクトリリストとディレクトリオブジェクト作成スクリプトを作ったので、作り忘れてたディレクトリオブジェクト削除スクリプトを。

実行例
前回作成しておいたlist_dir.sqlでディレクトリ名を確認しながら "TEST"ディレクトリを削除しています。

13:30:25 rdsora121@BILL> @list_dir

DIRECTORY_NAME DIRECTORY_PATH
---------------------------------------- ----------------------------------------------------------------------
ADUMP /rdsdbdata/log/audit
BDUMP /rdsdbdata/log/trace
DATA_PUMP_DIR /rdsdbdata/datapump
OPATCH_INST_DIR /rdsdbbin/oracle/OPatch
OPATCH_LOG_DIR /rdsdbbin/oracle/QOpatch
OPATCH_SCRIPT_DIR /rdsdbbin/oracle/QOpatch
TEST /rdsdbdata/userdirs/01

7行が選択されました。

経過: 00:00:00.02
13:30:29 rdsora121@BILL> @drop_dir test

PL/SQLプロシージャが正常に完了しました。

経過: 00:00:00.02
13:30:34 rdsora121@BILL> @list_dir

DIRECTORY_NAME DIRECTORY_PATH
---------------------------------------- ----------------------------------------------------------------------
ADUMP /rdsdbdata/log/audit
BDUMP /rdsdbdata/log/trace
DATA_PUMP_DIR /rdsdbdata/datapump
OPATCH_INST_DIR /rdsdbbin/oracle/OPatch
OPATCH_LOG_DIR /rdsdbbin/oracle/QOpatch
OPATCH_SCRIPT_DIR /rdsdbbin/oracle/QOpatch

6行が選択されました。

スクリプトは以下の通り、rdsadmin.rdsadmin_util.drop_directoryを実行しているだけです:)

13:29:45 rdsora121@BILL> !cat drop_dir.sql
set verify off
exec rdsadmin.rdsadmin_util.drop_directory(p_directory_name => UPPER('&1'));

undefine 1
set verify on

次回へ続く



Previously on Mac De Oracle


RDS Oracle 雑多なメモ#1 / FAQ

| | コメント (0) | トラックバック (0)

2018年9月17日 (月)

RDS Oracle 雑多なメモ#1 / FAQ

さて、さて、ご無沙汰しておりましたw
メモも溜まってきたので、そろそろ RDS Oracle関連の雑多なメモを。。。

新たなスタートをきって1.5ヶ月目にしてRDS Oracleに触れなければいけない状況となり、オンプレのOracleの使い勝手とことなる部分にハマりつつなんとか乗り切ったのでときのメモです。
(みなさん通る道w)

ディレクトリオブジェクト周りはオンプレのOracleと勝手が違いOSレイヤーには入れないので、rdsadmin.rdsadmin_utilパッケージに慣れておく必要があり。
さらに、ファイル操作についても、rdsadmin.rds_file_utilパッケージで提供されている操作は一部なので、utl_fileパッケージを併用しないと削除、コピー、改名などもできません。
また、ダンプファイルの圧縮解答もOSレイヤーでは実行できないので、utl_compressパッケージを利用する必要もありそう。


Oracle DB インスタンスの一般的な DBA システムタスク
https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/UserGuide/Appendix.Oracle.CommonDBATasks.System.html

Oracle DB インスタンスの一般的な DBA ログタスク
https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/UserGuide/Appendix.Oracle.CommonDBATasks.Log.html

Oracle DB インスタンスの一般的な DBA データベース
https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/UserGuide/Appendix.Oracle.CommonDBATasks.Database.html

Oracle DB インスタンスの一般的な DBA のその他のタスク
https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/UserGuide/Appendix.Oracle.CommonDBATasks.Misc.html


ということで、いちいちexecute ほげほげってタイプするのもめんどくさいのでスクリプト化して、楽しましょう。という自分用メモシリーズです。
今後どれくらいRDS Oracleを利用する機会があるのかまったく予想できませんが、備えあれば。。。ということで ;)

まず、RDSADMIN.RDSADMIN_UTILパッケージをdescribeしてみた。
詳細は前述のマニュアルを見てもらうとして、頻繁に利用しそうなのは createdirectoryプロシージャ、drop_directoryプロシージャ、それに rds_versionファンクション
あたりかなぁ。個人的には。
(他のものも頻繁に使いそうなら、スクリプト化しておくと便利かだと思います。)

22:55:55 rdsora121@BILL> desc rdsadmin.rdsadmin_util
PROCEDURE ADD_LOGFILE
引数名 タイプ In/Out Default?
------------------------------ ----------------------- ------ --------
BYTES BINARY_INTEGER IN DEFAULT
PROCEDURE ADD_LOGFILE
引数名 タイプ In/Out Default?
------------------------------ ----------------------- ------ --------
P_SIZE VARCHAR2 IN
PROCEDURE ALTER_DB_TIME_ZONE
引数名 タイプ In/Out Default?
------------------------------ ----------------------- ------ --------
P_NEW_TZ VARCHAR2 IN
PROCEDURE ALTER_DEFAULT_EDITION
引数名 タイプ In/Out Default?
------------------------------ ----------------------- ------ --------
EDITION_NAME VARCHAR2 IN
PROCEDURE ALTER_DEFAULT_TABLESPACE
引数名 タイプ In/Out Default?
------------------------------ ----------------------- ------ --------
TABLESPACE_NAME VARCHAR2 IN
PROCEDURE ALTER_DEFAULT_TEMP_TABLESPACE
引数名 タイプ In/Out Default?
------------------------------ ----------------------- ------ --------
TABLESPACE_NAME VARCHAR2 IN
PROCEDURE ALTER_SUPPLEMENTAL_LOGGING
引数名 タイプ In/Out Default?
------------------------------ ----------------------- ------ --------
P_ACTION VARCHAR2 IN
P_TYPE VARCHAR2 IN DEFAULT
PROCEDURE CHECKPOINT
PROCEDURE CREATE_DIRECTORY
引数名 タイプ In/Out Default?
------------------------------ ----------------------- ------ --------
P_DIRECTORY_NAME VARCHAR2 IN
PROCEDURE DISABLE_DISTR_RECOVERY
PROCEDURE DISCONNECT
引数名 タイプ In/Out Default?
------------------------------ ----------------------- ------ --------
SID NUMBER IN
SERIAL NUMBER IN
METHOD VARCHAR2 IN DEFAULT
PROCEDURE DROP_DIRECTORY
引数名 タイプ In/Out Default?
------------------------------ ----------------------- ------ --------
P_DIRECTORY_NAME VARCHAR2 IN
PROCEDURE DROP_LOGFILE
引数名 タイプ In/Out Default?
------------------------------ ----------------------- ------ --------
GRP BINARY_INTEGER IN
PROCEDURE ENABLE_DISTR_RECOVERY
PROCEDURE FLUSH_BUFFER_CACHE
PROCEDURE FLUSH_SHARED_POOL
PROCEDURE FORCE_LOGGING
引数名 タイプ In/Out Default?
------------------------------ ----------------------- ------ --------
P_ENABLE BOOLEAN IN DEFAULT
PROCEDURE GRANT_APEX_ADMIN_ROLE
PROCEDURE GRANT_SYS_OBJECT
引数名 タイプ In/Out Default?
------------------------------ ----------------------- ------ --------
P_OBJ_NAME VARCHAR2 IN
P_GRANTEE VARCHAR2 IN
P_PRIVILEGE VARCHAR2 IN DEFAULT
P_GRANT_OPTION BOOLEAN IN DEFAULT
PROCEDURE KILL
引数名 タイプ In/Out Default?
------------------------------ ----------------------- ------ --------
SID NUMBER IN
SERIAL NUMBER IN
METHOD VARCHAR2 IN DEFAULT
FUNCTION RDS_VERSION RETURNS VARCHAR2
PROCEDURE RENAME_GLOBAL_NAME
引数名 タイプ In/Out Default?
------------------------------ ----------------------- ------ --------
P_NEW_GLOBAL_NAME VARCHAR2 IN
PROCEDURE RESTRICTED_SESSION
引数名 タイプ In/Out Default?
------------------------------ ----------------------- ------ --------
P_ENABLE BOOLEAN IN DEFAULT
PROCEDURE REVOKE_SYS_OBJECT
引数名 タイプ In/Out Default?
------------------------------ ----------------------- ------ --------
P_OBJ_NAME VARCHAR2 IN
P_REVOKEE VARCHAR2 IN
P_PRIVILEGE VARCHAR2 IN DEFAULT
PROCEDURE SET_CONFIGURATION
引数名 タイプ In/Out Default?
------------------------------ ----------------------- ------ --------
NAME VARCHAR2 IN
VALUE VARCHAR2 IN
PROCEDURE SHOW_CONFIGURATION
引数名 タイプ In/Out Default?
------------------------------ ----------------------- ------ --------
NAME VARCHAR2 IN DEFAULT
PROCEDURE SWITCH_LOGFILE

22:56:11 rdsora121@BILL>

ということで、とりあえず、DBのバージョンと、RDSのバージョンを一括取得するスクリプトを作った。
実行例

23:24:14 rdsora121@BILL> @show_version

VERSION
------------------------------
12.1.0.2.0


RDS_VERSION
------------------------------
1.2

スクリプトは以下の通り。
rdsadmin.rdsadmin_util.rds_versionファンクションを利用しています。
(ちなみに、スクリプトはクライアントとなるEC2などに作成することになります)

23:24:24 rdsora121@BILL> !cat show_version.sql
col version for a30
col rds_version for a30

SELECT
version
FROM
v$instance
;

SELECT
rdsadmin.rdsadmin_util.rds_version AS rds_version
FROM
dual
;


次は、ディレクトリ操作関連の便利スクリプト群の作成。
まずは、どんなディレクトリオブジェクトが存在するのかパスも含めて確認できると嬉しいですよね。RDS Oracleと言えど。

実行例

23:36:26 rdsora121@BILL> @list_dir

DIRECTORY_NAME DIRECTORY_PATH
---------------------------------------- ----------------------------------------------------------------------
ADUMP /rdsdbdata/log/audit
BDUMP /rdsdbdata/log/trace
DATA_PUMP_DIR /rdsdbdata/datapump
OPATCH_INST_DIR /rdsdbbin/oracle/OPatch
OPATCH_LOG_DIR /rdsdbbin/oracle/QOpatch
OPATCH_SCRIPT_DIR /rdsdbbin/oracle/QOpatch

6行が選択されました。

経過: 00:00:00.03

スクリプトは以下のとおり。
dba_directoriesを問い合わせているだけの簡単なお仕事 :)

23:36:31 rdsora121@BILL> !cat list_dir.sql
col directory_name for a40
col directory_path for a70
SELECT
directory_name
,directory_path
FROM
dba_directories
ORDER BY
directory_name
;


お次は、ディレクトリオブジェクトの作成スクリプト。

23:41:24 rdsora121@BILL> @create_dir test

PL/SQLプロシージャが正常に完了しました。

経過: 00:00:02.12

DIRECTORY_NAME DIRECTORY_PATH
---------------------------------------- ----------------------------------------------------------------------
TEST /rdsdbdata/userdirs/01

経過: 00:00:00.06

スクリプトは以下のとおり。
rdsadmin.rdsadmin_util.create_directoryプロシージャを利用してRDS Oracleのディレクトリオブジェクトを作成後、dba_directoriesビューから作成したディレクトリオプジェクトを問い合わせています。

23:41:36 rdsora121@BILL> !cat create_dir.sql
set verify off
col directory_name for a40
col directory_path for a70

exec rdsadmin.rdsadmin_util.create_directory(p_directory_name => UPPER('&1'));

SELECT
directory_name
,directory_path
FROM
dba_directories
WHERE
directory_name = UPPER('&1')
ORDER BY
directory_name
;

undefine 1
set verify on


次回に続く

| | コメント (0) | トラックバック (0)

2018年8月19日 (日)

FAQ::位置情報による時間帯の自動調整 - iPhone/Apple Watch/iPad/Mac

ひさびさのエントリーでございます。

試用期間終わり、ひとまず生き延びておりますw

そして、早々に海外かつ人生はつの海外出張ということで、
Mac De Oracleの中の人として、ここは声を大きくして言っておきたいw

MacとiPhoneとApple Watchって

”国を跨いでも現地時間に自動調整してくれちゃうのは超便利!”

iPhone/Apple Watchを持ってる方は大抵 時間の自動調整はオンになっている方は多いかなーとは思いますが、意外に忘れてたりするのがMac側だったりします。

ということで、FAQとして書いておきますね。

まず、iPhone/Apple Watchについては、iPhone側で自動調整が有効かされていれば、Apple Watchもそれに同期して調整されます。 
日本から海外のどこかに到着すると自動的にに同期してくれちゃう。

20180819_04458


本題のMac側ですが、「システム環境設定」> 「セキュリティーとプライバシー」 > 「プライバシー」タブをクリックしたら以下の通り。
「日付の時間」の「時間帯」タブを設定して「現在の位置情報に基づいて、時間帯を自動的に設定」チェックボックスをチェックするだけ!

20180819_04954


これだけで、海外出張時にも自動的に現地時間に時間が同期されるので、Mac触ってて時間が日本の時間のままで混乱しちゃうなんてことも避けられまっす!!

:)


ついでにiPhoneで世界時計を設定しておくと、さらに便利だったりします。この設定は、Apple Watchへも連携されるのでApple Watchでも確認しやすく重宝します。
20180819_10442

| | コメント (0) | トラックバック (0)

2018年4月18日 (水)

Dead Connection Detection (FAQ)

最近あまりお目にかかったことなく忘れかけてたのと、12cでは改善されてたのでメモ

12cだと、11g以前に比べ、Dead Connection Detection (DCD) までの時間が大幅に短縮されているよ。
というホワイトペーパー

Dead Connection Detection
http://www.oracle.com/technetwork/database/enterprise-edition/oraclenetdcd-2179641.pdf

| | コメント (0) | トラックバック (0)

2018年4月 8日 (日)

textフォーマットのAWRレポートの各セクションをcsvファイル化する際のポイント(メモ)

土日は土日で子供とマイクラのマルチプレイ、平日は平日でなんだか余裕ないぞー。(なんだこれw) ということで、
Temp落ちネタはFBのTLコピペすれば終わりそうなんだが。。。w
再び、別のネタ。気分転換にはなってないけどwww


textフォーマットのAWRレポートをcsvファイル化する際、各セクションの最終行判定が面倒だったのでメモ(12.2版)
(どんな言語で作ってもこの部分、レポートの文字コード、それに、日付書式でハマることが多い印象w、それに、12.2では、 Timeはsecのみではなく、us/msなど時間の単位の扱いが追加されたので変換を忘れるとハマる)

例えば、Top 10 Foreground Events by Total Wait Timeの場合、
"Top 10 Foreground Events by Total Wait Time"というセクションヘッダーから、次のセクションヘッダーの"Wait Classes by Total Wait Time"の直前の行までを、Top 10 Wait Eventとしてcsv化する。

この場合、”Wait Classes by Total Wait Time”の直前の行は、2バイトで<FF><LF>なので、<FF><LF>の行が"Top 10 Foreground Events by Total Wait Time"セクションの終わり。

なのだが、"Top 10 Foreground Events by Total Wait Time"セクションの直前の行は、1バイトで<LF>のみとなり、 <FF>を含まないケースもある.....
各セクションの最終行の判定は、2バイトで<FF><LF>または、1バイトで<LF> で判定する必要がある。と。

TextフォーマットのAWRレポートの例
viでTextフォーマットのAWRレポートを開いて、eol部分を!で表示。

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~!
Buffer Nowait %: 99.99 Redo NoWait %: 100.00!
Buffer Hit %: 97.86 In-memory Sort %: 100.00!
Library Hit %: 90.46 Soft Parse %: 93.77!
Execute to Parse %: 62.59 Latch Hit %: 99.82!
Parse CPU to Parse Elapsd %: 75.51 % Non-Parse CPU: 89.49!
Flash Cache Hit %: 0.00!
!
Top 10 Foreground Events by Total Wait Time!
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~!
Total Wait Avg % DB Wait!
Event Waits Time (sec) Wait time Class!
------------------------------ ----------- ---------- --------- ------ --------!
DB CPU 3.5 167.2!
library cache: mutex X 81 .1 1.15ms 4.4 Concurre!
PX Deq: Slave Session Stats 229 .1 231.53us 2.5 Other!
log file sync 10 0 2.11ms 1.0 Commit!
library cache: bucket mutex X 3 0 4.96ms .7 Concurre!
db file sequential read 24 0 583.13us .7 User I/O!
PGA memory operation 600 0 11.39us .3 Other!
enq: BF - allocation contentio 6 0 390.50us .1 Other!
latch: call allocation 3 0 240.67us .0 Other!
latch: shared pool 3 0 226.33us .0 Concurre!
^L!
Wait Classes by Total Wait Time!
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~!
Avg Avg!
Total Wait Wait % DB Active!
Wait Class Waits Time (sec) Time time Sessions!
---------------- ---------------- ---------------- ---------- ------ --------!
DB CPU 4 167.2 0.0!
System I/O 3,469 3 734.15us 120.9 0.0!
Other 3,482 2 689.81us 114.0 0.0!
User I/O 1,261 1 421.44us 25.2 0.0!
Concurrency 95 0 1.20ms 5.4 0.0!
Commit 14 0 2.40ms 1.6 0.0!
Configuration 1 0 108.00us .0 0.0!
!
Host CPU!
~~~~~~~~ Load Average!
CPUs Cores Sockets Begin End %User %System %WIO %Idle!
----- ----- ------- --------- --------- --------- --------- --------- ---------!
12 12 1 0.14 0.12 0.1 0.0 0.0 99.8!
!
Instance CPU!
~~~~~~~~~~~~!
% of total CPU for Instance: 0.1!
% of busy CPU for Instance: 82.3!
%DB time waiting for CPU - Resource Mgr: 0.0!
:set listchars=eol:!

おまけ。上記、テキスト部分のバイナリダンプ
<LF>部分の確認
20180408_215624


<FF><LF>部分の確認
20180408_215736




Textモードで出力したAWRレポートをCSV化しようなんて、めんどくさい事しないほうがいいよね。
悪いことは言わないから、htmlで出力してCSV化した方が楽だからw 絶対!
ちなみに、わたしは、Top 10 wait eventセクションだけしかやりませんでしたw(時間ないし)

| | コメント (0) | トラックバック (0)

2018年3月29日 (木)

Oracle JavaScript Extention Toolkit(JET) de ブラウザの性能比較

なんだか余裕ないので、ちょいと、息抜きw

Oracle JavaScript Extention Toolkit(JET)
Oracle JET

さあ、あなたのIE11とそれ以外のモダンブラウザで 10,000 nodesを描画してPerformanceを比較してみましょう!。
Oracle JET > Visualizations > Diagram > Performance

以下、Safari 11.3 (macOS High Sierra/2 x 2.4 GHz 6-Core Intel Xeon/Mac Pro Mid(2012))
20180329_225621


こちらも、どうぞ。
Edgeも出たし、JetStreamも出たので久々にブラウザのベンチマーク

| | コメント (0) | トラックバック (0)

2018年3月18日 (日)

Temp落ち #9 - 自動PGA管理で_pga_max_sizeと戯れたPGAサイズって本当に使えるのか? 12.2.0.1版

Previously on Mac De Oracle

自動PGA管理下で、_pga_max_size隠しパラメータとpga_aggregate_targetを最大値に設定するした場合、global memory boundは
最大で、約839GBまで増加することがわかりました。

ただ、これは、内部的なパラメータ上の話。


今日は、実際にソートやハッシュ結合を行なわせ、PGAのSQL Work Areaサイズがどこまで利用できるものなのか確認してみることにします。

さて、どういう結末になりますやら(w

随分前から同じようなことを試している方はいますし....:)

なぜ今そこをdiggingしちゃってるのか? って?

メモリーたっぷりあるのに、何故Temp落ち? が話題になったからに決まってるじゃないですかw

 

まず、デフォルト設定では最大サイズだった 1GB を超えられるか? の確認

注意) 事前にpga_aggregate_target および _pga_max_size をそれぞれ 4TB - 1に設定し、パラメータの上では、global memory boundが約839GBにしてあります。

なお、Temp落ちの確認データやスクリプトはTemp落ち #4 - 手動PGA管理で作業領域として指定可能な最大サイズ de Temp落ちの確認のエントリーを参照のこと。

ソートやハッシュ結合は2GB程度になるように調整しています。
2GBのソート

ORCL@SCOTT> @auto_sortwk2gb_optimal.sql

NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
workarea_size_policy string AUTO

NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
pga_aggregate_target big integer 4398046511103

NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
_pga_max_size big integer 4398046511103

NAME VALUE UNIT CON_ID
---------------------------------------------------------------- ---------------- ------------ ----------
global memory bound 879609302016 bytes 0

1 SELECT
2 /*+
3 MONITOR
4 */
5 *
6 FROM
7 m1
8 WHERE
9 id <= 'C750000'
10 ORDER BY
11 id
12* ,rev#
old 1: select dbms_sqltune.report_sql_monitor(sql_id=>'&1', type=>'text') from dual
new 1: select dbms_sqltune.report_sql_monitor(sql_id=>'', type=>'text') from dual

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

・・・中略・・・

SQL Plan Monitoring Details (Plan Hash Value=3534657201)
========================================================================================================================================================
| Id | Operation | Name | Rows | Cost | Time | Start | Execs | Rows | Read | Read | Mem | Activity | Activity Detail |
| | | | (Estim) | | Active(s) | Active | | (Actual) | Reqs | Bytes | (Max) | (%) | (# samples) |
========================================================================================================================================================
| 0 | SELECT STATEMENT | | | | 34 | +2 | 1 | 1M | | | . | 5.26 | Cpu (1) |
| 1 | SORT ORDER BY | | 1M | 553K | 34 | +2 | 1 | 1M | | | 2GB | 26.32 | Cpu (5) |
| 2 | TABLE ACCESS FULL | M1 | 1M | 90829 | 17 | +1 | 1 | 1M | 2637 | 3GB | . | 68.42 | Cpu (3) |
| | | | | | | | | | | | | | direct path read (10) |
========================================================================================================================================================

2GBのハッシュ結合

ORCL@SCOTT> @auto_hashwk2gb_optimal.sql

・・・中略・・・

NAME VALUE UNIT CON_ID
---------------------------------------------------------------- ------------- ------------ ----------
global memory bound 879609302016 bytes 0

1 SELECT
2 /*+
3 MONITOR
4 LEADING(m1 m2)
5 USE_HASH(m2)
6 */
7 *
8 FROM
9 m1
10 INNER JOIN m2
11 ON
12 m1.id = m2.id
13 AND m1.rev# = m2.rev#
14 WHERE
15* m1.id <= 'C084000'
old 1: select dbms_sqltune.report_sql_monitor(sql_id=>'&1', type=>'text') from dual
new 1: select dbms_sqltune.report_sql_monitor(sql_id=>'', type=>'text') from dual

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

・・・中略・・・

SQL Plan Monitoring Details (Plan Hash Value=1822065247)
===========================================================================================================================================================
| Id | Operation | Name | Rows | Cost | Time | Start | Execs | Rows | Read | Read | Mem | Activity | Activity Detail |
| | | | (Estim) | | Active(s) | Active | | (Actual) | Reqs | Bytes | (Max) | (%) | (# samples) |
===========================================================================================================================================================
| 0 | SELECT STATEMENT | | | | 37 | +2 | 1 | 840K | | | . | 4.35 | Cpu (1) |
| 1 | HASH JOIN | | 843K | 351K | 37 | +2 | 1 | 840K | | | 2GB | 26.09 | Cpu (5) |
| | | | | | | | | | | | | | PGA memory operation (1) |
| 2 | TABLE ACCESS FULL | M1 | 843K | 90828 | 15 | +1 | 1 | 840K | 2633 | 3GB | . | 52.17 | Cpu (1) |
| | | | | | | | | | | | | | direct path read (11) |
| 3 | TABLE ACCESS FULL | M2 | 846K | 90581 | 23 | +16 | 1 | 840K | 2619 | 3GB | . | 17.39 | Cpu (2) |
| | | | | | | | | | | | | | direct path read (2) |
===========================================================================================================================================================

ソートやハッシュ結合は4GB程度になるように調整しています。
見ての通り、ソートは4GBのメモリー内ソートですが、ハッシュ結合は、2GBまで使ったところで Temp落ち! (こんなもんなんですよ。実は!)
4GBのソート

ORCL@SCOTT> @auto_sortwk4gb_optimal.sql

・・・中略・・・

NAME VALUE UNIT CON_ID
---------------------------------------------------------------- ------------- ------------ ----------
global memory bound 879609302016 bytes 0

1 SELECT
2 /*+
3 MONITOR
4 */
5 *
6 FROM
7 m1
8 WHERE
9 id <= 'C085000'
10 UNION ALL
11 SELECT *
12 FROM
13 m1 m12
14 WHERE
15 id <= 'C085000'
16 ORDER BY
17* 1, 2
old 1: select dbms_sqltune.report_sql_monitor(sql_id=>'&1', type=>'text') from dual
new 1: select dbms_sqltune.report_sql_monitor(sql_id=>'', type=>'text') from dual

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

・・・中略・・・

SQL Plan Monitoring Details (Plan Hash Value=2686238998)
============================================================================================================================================================
| Id | Operation | Name | Rows | Cost | Time | Start | Execs | Rows | Read | Read | Mem | Activity | Activity Detail |
| | | | (Estim) | | Active(s) | Active | | (Actual) | Reqs | Bytes | (Max) | (%) | (# samples) |
============================================================================================================================================================
| 0 | SELECT STATEMENT | | | | 40 | +2 | 1 | 2M | | | . | 27.78 | Cpu (5) |
| 1 | SORT ORDER BY | | 2M | 182K | 41 | +1 | 1 | 2M | | | 4GB | 38.89 | Cpu (6) |
| | | | | | | | | | | | | | PGA memory operation (1) |
| 2 | UNION-ALL | | | | 12 | +2 | 1 | 2M | | | . | | |
| 3 | TABLE ACCESS FULL | M1 | 855K | 90828 | 6 | +2 | 1 | 850K | 2633 | 3GB | . | 22.22 | Cpu (2) |
| | | | | | | | | | | | | | direct path read (2) |
| 4 | TABLE ACCESS FULL | M1 | 855K | 90828 | 6 | +8 | 1 | 850K | 2633 | 3GB | . | 11.11 | Cpu (2) |
============================================================================================================================================================

4GBのハッシュ結合 最大3GBのPGAが消費されていますが、Temp落ちしないサイズ、つまり、optimalで処理する場合には、最大2GBが最大サイズとなっています。以下を3GBのハッシュ結合にすると、2GBまでPGAを消費し、一時表領域が3GB利用されます。

ORCL@SCOTT> @auto_hashwk4gb_optimal.sql
old 1: select dbms_sqltune.report_sql_monitor(sql_id=>'&1', type=>'text') from dual
new 1: select dbms_sqltune.report_sql_monitor(sql_id=>'', type=>'text') from dual

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

・・・中略・・・

SQL Plan Monitoring Details (Plan Hash Value=3532417599)
=========================================================================================================================================================================================
| Id | Operation | Name | Rows | Cost | Time | Start | Execs | Rows | Read | Read | Write | Write | Mem | Temp | Activity | Activity Detail |
| | | | (Estim) | | Active(s) | Active | | (Actual) | Reqs | Bytes | Reqs | Bytes | (Max) | (Max) | (%) | (# samples) |
=========================================================================================================================================================================================
| 0 | SELECT STATEMENT | | | | 216 | +2 | 1 | 3M | | | | | . | . | 4.49 | Cpu (7) |
| 1 | HASH JOIN | | 2M | 670K | 217 | +1 | 1 | 3M | 18091 | 4GB | 18091 | 4GB | 3GB | 4GB | 79.49 | Cpu (87) |
| | | | | | | | | | | | | | | | | direct path read temp (19) |
| | | | | | | | | | | | | | | | | direct path write temp (18) |
| 2 | VIEW | | 2M | 182K | 9 | +2 | 1 | 2M | | | | | . | . | | |
| 3 | UNION-ALL | | | | 9 | +2 | 1 | 2M | | | | | . | . | | |
| 4 | TABLE ACCESS FULL | M1 | 752K | 90828 | 5 | +2 | 1 | 750K | 2633 | 3GB | | | . | . | 1.92 | Cpu (3) |
| 5 | TABLE ACCESS FULL | M1 | 752K | 90828 | 4 | +7 | 1 | 750K | 2633 | 3GB | | | . | . | 1.92 | Cpu (3) |
| 6 | VIEW | | 2M | 181K | 78 | +99 | 1 | 2M | | | | | . | . | 0.64 | Cpu (1) |
| 7 | UNION-ALL | | | | 78 | +99 | 1 | 2M | | | | | . | . | | |
| 8 | TABLE ACCESS FULL | M2 | 759K | 90581 | 50 | +92 | 1 | 750K | 2618 | 3GB | | | . | . | 9.62 | Cpu (2) |
| | | | | | | | | | | | | | | | | direct path read (13) |
| 9 | TABLE ACCESS FULL | M2 | 759K | 90581 | 36 | +141 | 1 | 750K | 2618 | 3GB | | | . | . | 1.92 | Cpu (2) |
| | | | | | | | | | | | | | | | | direct path read (1) |
=========================================================================================================================================================================================

では、最後に
ソートやハッシュ結合のサイズが8GB程度ならどうでしょうか?
結果は、ソートは4GBを使い切ったのち、Temp落ち、ハッシュ結合は、やはり、3GBまで利用したのちTemp落ちでした。なんと!(ちょっとわざとらしいリアクションしてすみませんw)

8GBのソート

ORCL@SCOTT> @auto_sortwk8gb_optimal.sql

・・・中略・・・

NAME VALUE UNIT CON_ID
---------------------------------------------------------------- ------------- ------------ ----------
global memory bound 879609302016 bytes 0

1 SELECT
2 /*+
3 MONITOR
4 */
5 *
6 FROM
7 m1
8 WHERE
9 id <= 'C090000'
10 UNION ALL
11 SELECT *
12 FROM
13 m1 m12
14 WHERE
15 id <= 'C090000'
16 UNION ALL
17 SELECT *
18 FROM
19 m1 m13
20 WHERE
21 id <= 'C090000'
22 UNION ALL
23 SELECT *
24 FROM
25 m1 m14
26 WHERE
27 id <= 'C090000'
28 ORDER BY
29* 1, 2
old 1: select dbms_sqltune.report_sql_monitor(sql_id=>'&1', type=>'text') from dual
new 1: select dbms_sqltune.report_sql_monitor(sql_id=>'', type=>'text') from dual

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

・・・中略・・・

SQL Plan Monitoring Details (Plan Hash Value=946172832)
=========================================================================================================================================================================================
| Id | Operation | Name | Rows | Cost | Time | Start | Execs | Rows | Read | Read | Write | Write | Mem | Temp | Activity | Activity Detail |
| | | | (Estim) | | Active(s) | Active | | (Actual) | Reqs | Bytes | Reqs | Bytes | (Max) | (Max) | (%) | (# samples) |
=========================================================================================================================================================================================
| 0 | SELECT STATEMENT | | | | 279 | +2 | 1 | 4M | | | | | . | . | 5.79 | Cpu (6) |
| | | | | | | | | | | | | | | | | PGA memory operation (1) |
| | | | | | | | | | | | | | | | | local write wait (7) |
| 1 | SORT ORDER BY | | 4M | 363K | 279 | +2 | 1 | 4M | 38603 | 8GB | 32072 | 8GB | 4GB | 8GB | 84.30 | Cpu (49) |
| | | | | | | | | | | | | | | | | PGA memory operation (1) |
| | | | | | | | | | | | | | | | | direct path read temp (28) |
| | | | | | | | | | | | | | | | | direct path write temp (126) |
| 2 | UNION-ALL | | | | 176 | +2 | 1 | 4M | | | | | . | . | | |
| 3 | TABLE ACCESS FULL | M1 | 907K | 90828 | 16 | +1 | 1 | 900K | 2633 | 3GB | | | . | . | 4.55 | Cpu (2) |
| | | | | | | | | | | | | | | | | direct path read (9) |
| 4 | TABLE ACCESS FULL | M1 | 907K | 90828 | 8 | +17 | 1 | 900K | 2633 | 3GB | | | . | . | 2.48 | Cpu (5) |
| | | | | | | | | | | | | | | | | direct path read (1) |
| 5 | TABLE ACCESS FULL | M1 | 907K | 90828 | 79 | +26 | 1 | 900K | 2633 | 3GB | | | . | . | 2.48 | Cpu (2) |
| | | | | | | | | | | | | | | | | direct path read (4) |
| 6 | TABLE ACCESS FULL | M1 | 907K | 90828 | 72 | +106 | 1 | 900K | 2633 | 3GB | | | . | . | 0.41 | Cpu (1) |
=========================================================================================================================================================================================

8GBのハッシュ結合

ORCL@SCOTT> @auto_hashwk8gb_optimal.sql

・・・中略・・・

NAME VALUE UNIT CON_ID
---------------------------------------------------------------- ------------- ------------ ----------
global memory bound 879609302016 bytes 0

1 SELECT
2 /*+
3 MONITOR
4 LEADING(m1 m2)
5 USE_HASH(m2)
6 */
7 *
8 FROM
9 (
10 SELECT * FROM m1 m11
11 UNION ALL
12 SELECT * FROM m1 m12
13 UNION ALL
14 SELECT * FROM m1 m13
15 ) m1
16 INNER JOIN
17 (
18 SELECT * FROM m2 m21
19 UNION ALL
20 SELECT * FROM m2 m22
21 UNION ALL
22 SELECT * FROM m2 m23
23 ) m2
24 ON
25 m1.id = m2.id
26 AND m1.rev# = m2.rev#
27 WHERE
28* m1.id <= 'C075000'
old 1: select dbms_sqltune.report_sql_monitor(sql_id=>'&1', type=>'text') from dual
new 1: select dbms_sqltune.report_sql_monitor(sql_id=>'', type=>'text') from dual

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

・・・中略・・・

SQL Plan Monitoring Details (Plan Hash Value=2506347387)
=========================================================================================================================================================================================
| Id | Operation | Name | Rows | Cost | Time | Start | Execs | Rows | Read | Read | Write | Write | Mem | Temp | Activity | Activity Detail |
| | | | (Estim) | | Active(s) | Active | | (Actual) | Reqs | Bytes | Reqs | Bytes | (Max) | (Max) | (%) | (# samples) |
=========================================================================================================================================================================================
| 0 | SELECT STATEMENT | | | | 350 | +2 | 1 | 7M | | | | | . | . | 9.18 | Cpu (18) |
| | | | | | | | | | | | | | | | | PGA memory operation (1) |
| 1 | HASH JOIN | | 5M | 1M | 350 | +2 | 1 | 7M | 31032 | 7GB | 31032 | 7GB | 3GB | 8GB | 67.15 | Cpu (81) |
| | | | | | | | | | | | | | | | | direct path read temp (36) |
| | | | | | | | | | | | | | | | | direct path write temp (22) |
| 2 | VIEW | | 2M | 272K | 27 | +2 | 1 | 2M | | | | | . | . | | |
| 3 | UNION-ALL | | | | 27 | +2 | 1 | 2M | | | | | . | . | 0.97 | Cpu (2) |
| 4 | TABLE ACCESS FULL | M1 | 752K | 90828 | 16 | +1 | 1 | 750K | 2633 | 3GB | | | . | . | 7.25 | Cpu (3) |
| | | | | | | | | | | | | | | | | direct path read (12) |
| 5 | TABLE ACCESS FULL | M1 | 752K | 90828 | 5 | +18 | 1 | 750K | 2633 | 3GB | | | . | . | 1.45 | Cpu (2) |
| | | | | | | | | | | | | | | | | direct path read (1) |
| 6 | TABLE ACCESS FULL | M1 | 752K | 90828 | 7 | +23 | 1 | 750K | 2633 | 3GB | | | . | . | 1.93 | Cpu (2) |
| | | | | | | | | | | | | | | | | direct path read (2) |
| 7 | VIEW | | 2M | 272K | 130 | +97 | 1 | 2M | | | | | . | . | | |
| 8 | UNION-ALL | | | | 130 | +97 | 1 | 2M | | | | | . | . | 0.48 | Cpu (1) |
| 9 | TABLE ACCESS FULL | M2 | 759K | 90581 | 47 | +88 | 1 | 750K | 2618 | 3GB | | | . | . | 4.83 | Cpu (3) |
| | | | | | | | | | | | | | | | | direct path read (7) |
| 10 | TABLE ACCESS FULL | M2 | 759K | 90581 | 41 | +134 | 1 | 750K | 2618 | 3GB | | | . | . | 4.35 | Cpu (5) |
| | | | | | | | | | | | | | | | | direct path read (4) |
| 11 | TABLE ACCESS FULL | M2 | 759K | 90581 | 53 | +174 | 1 | 750K | 2618 | 3GB | | | . | . | 2.42 | Cpu (1) |
| | | | | | | | | | | | | | | | | direct path read (4) |
=========================================================================================================================================================================================

 

 

これ、Linuxのカーネルパラメータのvm.max_map_count

/proc/sys/vm/max_map_count

65530

が絡んでるよねという話と、隠しパラメータの realfree_heap関連のパラメータでも調整できそうだよね。という話はあるんですが...それはPL/SQLのはなし...で


_realfree_heap_pagesize 65536 TRUE
_use_realfree_heap TRUE TRUE

とりあえず、
vm/max_map_countを196608

にして
_realfree_heap_pagesize=65536 や
_realfree_heap_pagesize=256K

などとして戯れてみましたが

ソートやハッシュ結合で利用可能なサイズは、それらで制御できるものでもありません。いまのところ。

ORCL@SCOTT> @auto_sortwk8gb_optimal.sql

NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
workarea_size_policy string AUTO

NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
pga_aggregate_target big integer 4398046511103

NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
_pga_max_size big integer 4398046511103

NAME VALUE UNIT CON_ID
---------------------------------------------------------------- ------------- ------------ ----------
global memory bound 879609302016 bytes 0

/proc/sys/vm/max_map_count
196608

1 SELECT
2 /*+
3 MONITOR
4 */
5 *
6 FROM
7 m1
8 WHERE
9 id <= 'C090000'
10 UNION ALL
11 SELECT *
12 FROM
13 m1 m12
14 WHERE
15 id <= 'C090000'
16 UNION ALL
17 SELECT *
18 FROM
19 m1 m13
20 WHERE
21 id <= 'C090000'
22 UNION ALL
23 SELECT *
24 FROM
25 m1 m14
26 WHERE
27 id <= 'C090000'
28 ORDER BY
29* 1, 2
old 1: select dbms_sqltune.report_sql_monitor(sql_id=>'&1', type=>'text') from dual
new 1: select dbms_sqltune.report_sql_monitor(sql_id=>'', type=>'text') from dual

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

・・・中略・・・

SQL Plan Monitoring Details (Plan Hash Value=946172832)
=========================================================================================================================================================================================
| Id | Operation | Name | Rows | Cost | Time | Start | Execs | Rows | Read | Read | Write | Write | Mem | Temp | Activity | Activity Detail |
| | | | (Estim) | | Active(s) | Active | | (Actual) | Reqs | Bytes | Reqs | Bytes | (Max) | (Max) | (%) | (# samples) |
=========================================================================================================================================================================================
| 0 | SELECT STATEMENT | | | | 295 | +2 | 1 | 4M | | | | | . | . | 3.38 | Cpu (8) |
| 1 | SORT ORDER BY | | 4M | 363K | 297 | +1 | 1 | 4M | 38603 | 8GB | 38600 | 8GB | 4GB | 8GB | 91.56 | Cpu (43) |
| | | | | | | | | | | | | | | | | direct path read temp (12) |
| | | | | | | | | | | | | | | | | direct path write temp (162) |
| 2 | UNION-ALL | | | | 205 | +2 | 1 | 4M | | | | | . | . | 0.84 | Cpu (2) |
| 3 | TABLE ACCESS FULL | M1 | 907K | 90828 | 6 | +2 | 1 | 900K | 2633 | 3GB | | | . | . | 2.11 | Cpu (1) |
| | | | | | | | | | | | | | | | | direct path read (4) |
| 4 | TABLE ACCESS FULL | M1 | 907K | 90828 | 7 | +8 | 1 | 900K | 2633 | 3GB | | | . | . | 0.42 | Cpu (1) |
| 5 | TABLE ACCESS FULL | M1 | 907K | 90828 | 100 | +14 | 1 | 900K | 2633 | 3GB | | | . | . | 0.84 | Cpu (2) |
| 6 | TABLE ACCESS FULL | M1 | 907K | 90828 | 94 | +113 | 1 | 900K | 2633 | 3GB | | | . | . | 0.84 | Cpu (2) |
=========================================================================================================================================================================================

ちなみに、PL/SQLで巨大なPGAメモリーを利用する場合は、しっかり9GBとか...やばい状態になったら、pga_aggregate_limitで抑えてくれると思いますが.....

[oracle@localhost ˜]$ ulimit -v -m
virtual memory (kbytes, -v) unlimited
max memory size (kbytes, -m) unlimited

 

orcl12c@SYS> @show_param

KSPPINM KSPPSTVL KSPPSTDF
---------------------------------------------- ------------------------------ ------------------------------
_pga_max_size 4398046511103 FALSE
_realfree_heap_pagesize 65536 TRUE
_use_realfree_heap TRUE TRUE
pga_aggregate_limit 0 FALSE
pga_aggregate_target 4398046511103 FALSE


/proc/sys/vm/max_map_count
65530
PGAを大量に消費するスクリプトは以下のブログを参考に
Max PGA Research: Check that a process can allocate a large volume of memory / Yury's Blog

ORCL@SCOTT> @plsql_pga8gb 8192
old 2: c_count number := 1024*&1;
new 2: c_count number := 1024*8192;

PL/SQL procedure successfully completed.
実際に確保されたPGAサイズなど。。。
ORCL@SCOTT> r
1 select
2 vss.value/1024/1024/1024 "GB"
3 ,vsn.name
4 ,vss.sid
5 from
6 v$sesstat vss
7 inner join v$statname vsn
8 on
9 vss.statistic# = vsn.statistic#
10 and vss.con_id = vsn.con_id
11 and (vsn.name like '%pga%' or vsn.name like '%uga%')
12 where
13 sid IN (select sid from v$session where username='SCOTT')
14 order by
15* sid,name

GB NAME SID
---------- ---------------------------------------------------------------- ----------
9.49698084 session pga memory 321
9.49698084 session pga memory max 321
1.48221001 session uga memory 321
3.99991362 session uga memory max 321

[oracle@localhost ˜]$ free -h
total used free shared buff/cache available
Mem: 22G 1.0G 9.6G 11G 11G 10G
Swap: 4.0G 8.7M 4.0G

・・・中略・・・

[oracle@localhost ˜]$ free -h
total used free shared buff/cache available
Mem: 22G 10G 128M 11G 11G 705M
Swap: 4.0G 8.8M 4.0G

ここまでくればおわかりだと思いますが、global memory bound (約839GB)からは巨大なPGAサイズになりそうに思えますが、Temp落ちせずにソート可能なサイズは、隠しパラメータを調整した場合でも最大4GB、ハッシュ結合は、2GBが上限、となっています。いまのところ。。。。

ということは、2014年の以下のプレゼンでも話題になっていましたよね。:)
Overcome Oracle PGA Memory Limits Mar.5.2014 Alex Fatkulin / Enkatic

 

だったら、どのようにして、Temp落ち に立ち向かえばいいんだろう.....次回へ続く :)

 


10gR2(64bit)のころのままなので、以下のシリーズも合わせて読んでおくといいですよ:)


Mac De Oracle なんですが、Windows(32bit)でのOracleな話
Mac De Oracle なんですが、Windows(32bit)でのOracleな話 #2
Mac De Oracle なんですが、Windows(32bit)でのOracleな話 #3
pga_aggregate_targetでPGA?、_pga_max_sizeでPGA? #1
pga_aggregate_targetでPGA?、_pga_max_sizeでPGA? #2
pga_aggregate_targetでPGA?、_pga_max_sizeでPGA? #3
pga_aggregate_targetでPGA?、_pga_max_sizeでPGA? #4
pga_aggregate_targetでPGA?、_pga_max_sizeでPGA? #5
pga_aggregate_targetでPGA?、_pga_max_sizeでPGA? #6
pga_aggregate_targetでPGA?、_pga_max_sizeでPGA? #7
pga_aggregate_targetでPGA?、_pga_max_sizeでPGA? #8
pga_aggregate_targetでPGA?、_pga_max_sizeでPGA? #9
pga_aggregate_targetでPGA?、_pga_max_sizeでPGA? #10
pga_aggregate_targetでPGA?、_pga_max_sizeでPGA? #11
pga_aggregate_targetでPGA?、_pga_max_sizeでPGA? #12
pga_aggregate_targetでPGA?、_pga_max_sizeでPGA? #13
pga_aggregate_targetでPGA?、_pga_max_sizeでPGA? #14
pga_aggregate_targetでPGA?、_pga_max_sizeでPGA? #15
pga_aggregate_targetでPGA?、_pga_max_sizeでPGA? #16
pga_aggregate_targetでPGA?、_pga_max_sizeでPGA? #17
pga_aggregate_targetでPGA?、_pga_max_sizeでPGA? #18
pga_aggregate_targetでPGA?、_pga_max_sizeでPGA? #19
_pga_max_sizeってOracle11gではどうなったっけ? という確認。
_pga_max_sizeってOracle11gではどうなったっけ? という確認。シーズン2
pga_aggregate_targetでPGA?、_pga_max_sizeでPGA? Season2 #1
pga_aggregate_targetでPGA?、_pga_max_sizeでPGA? Season2 #2
pga_aggregate_targetでPGA?、_pga_max_sizeでPGA? Season2 #3
pga_aggregate_targetでPGA?、_pga_max_sizeでPGA? Season2 #4
pga_aggregate_targetでPGA?、_pga_max_sizeでPGA? Season2 #5
pga_aggregate_targetでPGA?、_pga_max_sizeでPGA? Season2 #6
pga_aggregate_targetでPGA?、_pga_max_sizeでPGA? Season2 #7
pga_aggregate_targetでPGA?、_pga_max_sizeでPGA? Season2 #8

 


Temp落ち #1 - "Temp落ち" って?
Temp落ち #2 - PGA (Program Global Area)
Temp落ち #3 - 手動PGA管理で作業領域として指定可能な最大サイズ
Temp落ち #4 - 手動PGA管理で作業領域として指定可能な最大サイズ de Temp落ちの確認
Temp落ち #5 - pga_aggregate_targetでPGA?、_pga_max_sizeでPGA? 12.2.0.1版 (その前に少し脱線)
Temp落ち #6 - pga_aggregate_targetでPGA?、_pga_max_sizeでPGA? 12.2.0.1版
Temp落ち #7 - 自動PGA管理で到達可能な最大サイズ de Temp落ちの確認 12.2.0.1版
Temp落ち #8 - 自動PGA管理でパラメータ上設定可能な最大サイズは?(実際に利用可能なサイズとは限りませんが。意味深) 12.2.0.1版

| | コメント (0) | トラックバック (0)

2018年3月12日 (月)

Temp落ち #8 - 自動PGA管理でパラメータ上設定可能な最大サイズは?(実際に利用可能なサイズとは限りませんが。意味深) 12.2.0.1版

Previously on Mac De Oracle

自動PGA管理下では、SQL Work Areaサイズは、pga_aggregate_targetのサイズに応じて変化し、最大1GBまで調整され、それのサイズ以上のソートやハッシュ結合は、もれなく、"Temp落ち" する。
手動PGA管理下では、最大2GBまで指定できました。。自動だと1GBまでなのか。。。と残念がる声が、昔は海だった方面から聞こえた気がしましたが、たぶん、気のせいw

というところまででした。


今日は、自動PGA管理下ではそれが最大なのか? のか? 自己責任で試してみることにしますw

まずはこれまでの復習。

自動PGA管理で、SQL Work Areaサイズの算出に関わるパラメータは以下の通り

pga_aggregate_target = 10MB 〜 4TB - 1
_pga_max_size = 200MB 〜 2GB
Oracleが動的に値を調整している_pga_max_sizeパラメータへユーザーが値を設定してしまうとOracleの自動調整が無効化され、設定した値で固定されてしまうので注意が必要です。

私の観測範囲だとおおよそ以下のように変化します。最近は大量のメモリーを搭載したサーバーが多いので、pga_aggregate_targetが10GB以上という状況も普通になってきたので、自動PGA管理下のSQL Work Areaサイズは最大1GBとざっくり丸暗記しても困ることは思いますw(ちょっと乱暴かw)

pga_aggregate_target = 10MB〜10GB - 1 :
_pga_max_size = 200MB 〜 2047MB
GREATEST(pga_aggregate_target*0.2 ,200MB)

pga_aggregate_target = 10GB以上〜4TB-1 :
_pga_max_size = 2GB
LEAST(pga_aggregate_target*0.2 ,2GB)


_pga_max_sizeはpga_aggregate_targetの値に応じて動的に変化し、それらを元に _smm_max_size が算出される
LEAST(pga_aggregate_target * 0.2, _pga_max_size * 0.5)

pga_aggregate_target = 10MB〜10GB-1
_pga_max_size = 200MB〜2047MB
_smm_max_size = 2MB〜1023MB


pga_aggregate_target = 10GB〜4TB-1
_pga_max_size = 2048MB
_smm_max_size = 1024MB
_smm_max_sizeは、v$pgastatのglobal memory boundだろうということは確からしいということまでは確認しました。

20180307_143308
20180307_143330
いままでの結果をまとめると
PGAのSQL Work Areaサイズの最大サイズを示す global memory boundは、pga_aggregate_targetが10MB〜10GB-1までは2MB〜1023MBで調整され、pga_aggregate_targetが10GB〜4TB-1では、1024MB (1GB) で固定されている、というのが、Oracle 10GR2〜12cR2まで動きであることは間違いなさそう:)

自動PGA管理下でSQL Work Areaを1GBを超えるサイズにするにはどのパラメータをどのような値に設定すればよいか。。。
その鍵を握るパラメータは

_pga_max_size



(いまいちピンとこないという方は、過去のエントリーを参照していただけるとスッキリすると思います。

ただ、冒頭にも書きましたが(昔それでハマったw)、(Oracleが動的に値を調整している_pga_max_sizeパラメータへユーザーが値を設定してしまうとOracleの自動調整が無効化され、設定した値で固定されてしまうので注意が必要です。
という点はお忘れなく。また、今後も同仕様のままである保証はなく、世界中のOracle使いの方達が調べ上げた結果、現状はこんな感じ。
という状況だと認識しておいたほうが無難だと思っています。

とはいえ、実際どこまで設定可能なのか?  1GBを以上使えるのか? 知りたいですよね...

長い前置きはこれぐらいにして、
実際にSQL Work Areaサイズに対応したメモリーが実際にどの程度割り当てられるのかということの確認は後回しですが、 パラメータの上では、どこまで設定できるのかというところを確認しました。


なお、
以下のエラーメッセージから、_pga_max_sizeに設定可能な値は、pga_aggregate_targetと同様(Big Integer)、10MB〜4TB-1までであると思われます。

orcl12c@SYS> show parameter _pga_max_size

NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
_pga_max_size big integer 2G

orcl12c@SYS> alter system set "_pga_max_size" = 4T scope=memory;
alter system set "_pga_max_size" = 4T scope=memory
*
行1でエラーが発生しました。:
ORA-02097: 指定した値が無効なので、パラメータを変更できません。 ORA-00093:
_pga_max_sizeは、10Mから4096G-1の間に設定する必要があります。

ということで、
_pga_max_sizeを1GB/10GB/100GB/1TB/4T-1のそれぞれに設定したうえで、Temp落ち #6 - pga_aggregate_targetでPGA?、_pga_max_sizeでPGA? 12.2.0.1版 で利用したスクリプトを利用し、global memory boundやその他パラメータの変化を確認しました。

ログの例

orcl12c@SYS> alter system set "_pga_max_size" = 10m scope=both;

システムが変更されました。

orcl12c@SYS> show parameter _pga_max_size

NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
_pga_max_size big integer 10m


orcl12c@SYS> @dotest_auto_workarea
<< 10m >>
接続されました。
1* alter system set pga_aggregate_target=&1 scope=spfile
旧 1: alter system set pga_aggregate_target=&1 scope=spfile
新 1: alter system set pga_aggregate_target=10m scope=spfile

システムが変更されました。

データベースがクローズされました。
データベースがディスマウントされました。
ORACLEインスタンスがシャットダウンされました。
ORACLEインスタンスが起動しました。

Total System Global Area 2147483648 bytes
Fixed Size 8794848 bytes
Variable Size 603983136 bytes
Database Buffers 1526726656 bytes
Redo Buffers 7979008 bytes
データベースがマウントされました。
データベースがオープンされました。
+++ initial parameters +++

KSPPINM KSPPSTVL KSPPSTDF
---------------------------------------------- ------------------------------ ------------------------------
__pga_aggregate_target 16777216 FALSE

・・・中略・・・

pga_aggregate_limit 0 FALSE
pga_aggregate_target 10485760 FALSE

50行が選択されました。

/proc/sys/vm/max_map_count

65530

+++ v$pgastat +++

NAME VALUE UNIT CON_ID
---------------------------------------------------------------- ---------- ------------ ----------
aggregate PGA target parameter 10 MB 0
aggregate PGA auto target 4 MB 0
global memory bound 2 MB 0

・・・中略・・・


結果は以下のグラフと表にまとめたとおり。
_pga_max_size=4TB-1、pga_aggregate_target=4TB-1の時のglobal memory bound (v$pgastat) = _smm_max_size が最大となり、約839GBとなることがわかりました。
パラメータ上は839GB程度まで増加しますが、ほんとうにPGAがそんなサイズまで利用可能なのでしょうか?....(怪しいです。答え、知ってるんですけどねw。。

1g
10g
100g
1t
4t1
Globalmemorybound

ということで、

次回は実際に、そんなに使えんのかよ! という実験をしてみたいと思います :)

つづく。




10gR2(64bit)のころのままなので、以下のシリーズも合わせて読んでおくといいですよ:)
Mac De Oracle なんですが、Windows(32bit)でのOracleな話
Mac De Oracle なんですが、Windows(32bit)でのOracleな話 #2
Mac De Oracle なんですが、Windows(32bit)でのOracleな話 #3
pga_aggregate_targetでPGA?、_pga_max_sizeでPGA? #1
pga_aggregate_targetでPGA?、_pga_max_sizeでPGA? #2
pga_aggregate_targetでPGA?、_pga_max_sizeでPGA? #3
pga_aggregate_targetでPGA?、_pga_max_sizeでPGA? #4
pga_aggregate_targetでPGA?、_pga_max_sizeでPGA? #5
pga_aggregate_targetでPGA?、_pga_max_sizeでPGA? #6
pga_aggregate_targetでPGA?、_pga_max_sizeでPGA? #7
pga_aggregate_targetでPGA?、_pga_max_sizeでPGA? #8
pga_aggregate_targetでPGA?、_pga_max_sizeでPGA? #9
pga_aggregate_targetでPGA?、_pga_max_sizeでPGA? #10
pga_aggregate_targetでPGA?、_pga_max_sizeでPGA? #11
pga_aggregate_targetでPGA?、_pga_max_sizeでPGA? #12
pga_aggregate_targetでPGA?、_pga_max_sizeでPGA? #13
pga_aggregate_targetでPGA?、_pga_max_sizeでPGA? #14
pga_aggregate_targetでPGA?、_pga_max_sizeでPGA? #15
pga_aggregate_targetでPGA?、_pga_max_sizeでPGA? #16
pga_aggregate_targetでPGA?、_pga_max_sizeでPGA? #17
pga_aggregate_targetでPGA?、_pga_max_sizeでPGA? #18
pga_aggregate_targetでPGA?、_pga_max_sizeでPGA? #19
_pga_max_sizeってOracle11gではどうなったっけ? という確認。
_pga_max_sizeってOracle11gではどうなったっけ? という確認。シーズン2
pga_aggregate_targetでPGA?、_pga_max_sizeでPGA? Season2 #1
pga_aggregate_targetでPGA?、_pga_max_sizeでPGA? Season2 #2
pga_aggregate_targetでPGA?、_pga_max_sizeでPGA? Season2 #3
pga_aggregate_targetでPGA?、_pga_max_sizeでPGA? Season2 #4
pga_aggregate_targetでPGA?、_pga_max_sizeでPGA? Season2 #5
pga_aggregate_targetでPGA?、_pga_max_sizeでPGA? Season2 #6
pga_aggregate_targetでPGA?、_pga_max_sizeでPGA? Season2 #7
pga_aggregate_targetでPGA?、_pga_max_sizeでPGA? Season2 #8


Temp落ち #1 - "Temp落ち" って?
Temp落ち #2 - PGA (Program Global Area)
Temp落ち #3 - 手動PGA管理で作業領域として指定可能な最大サイズ
Temp落ち #4 - 手動PGA管理で作業領域として指定可能な最大サイズ de Temp落ちの確認
Temp落ち #5 - pga_aggregate_targetでPGA?、_pga_max_sizeでPGA? 12.2.0.1版 (その前に少し脱線)
Temp落ち #6 - pga_aggregate_targetでPGA?、_pga_max_sizeでPGA? 12.2.0.1版
Temp落ち #7 - 自動PGA管理で到達可能な最大サイズ de Temp落ちの確認 12.2.0.1版


| | コメント (0) | トラックバック (0)

2018年3月 8日 (木)

Temp落ち #7 - 自動PGA管理で到達可能な最大サイズ de Temp落ちの確認 12.2.0.1版

Previously on Mac De Oracle

自動PGA管理で利用可能なSQL Work Areaサイズはいくつなのか?の確認でした。
これまで同様、隠しパラメータ等の変更をしないデフォルトの設定では最大1GBまで到達することを確認しました。
また、手動PGA管理で利用可能な最大サイズより小さいことも再確認しました。


今日は自動PGA管理下ではオンメモリーで処理可能なサイズは1GBまでなのか、それを超えた場合はもれなく "Temp落ち" なのか確認することにします。

 

確認用データおよび方法は前々回のエントリーを参照ください。

自動PGA管理でGlobal Memory Bound = 1GB(自動PGA管理での最大 Sort作業領域サイズ)

メモリーソートで1GBぐらいまで利用していることが確認できます。(ソートされるデータ量は1GB以下程度に制限しています。)
ORCL@SCOTT> @auto_sortwk1gb_optimal

NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
workarea_size_policy string AUTO

NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
pga_aggregate_target big integer 4398046511103

NAME VALUE UNIT CON_ID
---------------------------------------------------------------- ---------- ------------ ----------
global memory bound 1073741824 bytes 0

1 SELECT
2 /*+
3 MONITOR
4 */
5 *
6 FROM
7 m1
8 WHERE
9 id <= 'C045000'
10 ORDER BY
11 id
12* ,rev#
old 1: select dbms_sqltune.report_sql_monitor(sql_id=>'&1', type=>'text') from dual
new 1: select dbms_sqltune.report_sql_monitor(sql_id=>'', type=>'text') from dual

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

・・・中略・・・

Global Stats
===========================================================================
| Elapsed | Cpu | IO | Other | Fetch | Buffer | Read | Read |
| Time(s) | Time(s) | Waits(s) | Waits(s) | Calls | Gets | Reqs | Bytes |
===========================================================================
| 4.78 | 3.85 | 0.34 | 0.59 | 30001 | 334K | 2633 | 3GB |
===========================================================================

SQL Plan Monitoring Details (Plan Hash Value=3534657201)
==================================================================================================================================================
| Id | Operation | Name | Rows | Cost | Time | Start | Execs | Rows | Read | Read | Mem | Activity | Activity Detail |
| | | | (Estim) | | Active(s) | Active | | (Actual) | Reqs | Bytes | (Max) | (%) | (# samples) |
==================================================================================================================================================
| 0 | SELECT STATEMENT | | | | 10 | +2 | 1 | 450K | | | . | 33.33 | Cpu (2) |
| 1 | SORT ORDER BY | | 456K | 302K | 11 | +1 | 1 | 450K | | | 1GB | 33.33 | Cpu (2) |
| 2 | TABLE ACCESS FULL | M1 | 456K | 90827 | 3 | +2 | 1 | 450K | 2633 | 3GB | . | 33.33 | Cpu (2) |
==================================================================================================================================================

 

Temp落ちする程度のデータ量でソートさせた場合も、PGAの作業領域は最大1GBまで利用されていたことが確認できます。
ORCL@SCOTT> @auto_sortwk1gb_mpass    

NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
workarea_size_policy string AUTO

NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
pga_aggregate_target big integer 4398046511103

NAME VALUE UNIT CON_ID
---------------------------------------------------------------- ---------- ------------ ----------
global memory bound 1073741824 bytes 0

1 SELECT
2 /*+
3 MONITOR
4 */
5 *
6 FROM
7 m1
8 WHERE
9 id <= 'C050000'
10 ORDER BY
11 id
12* ,rev#
old 1: select dbms_sqltune.report_sql_monitor(sql_id=>'&1', type=>'text') from dual
new 1: select dbms_sqltune.report_sql_monitor(sql_id=>'', type=>'text') from dual

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

・・・中略・・・

Global Stats
===========================================================================================
| Elapsed | Cpu | IO | Other | Fetch | Buffer | Read | Read | Write | Write |
| Time(s) | Time(s) | Waits(s) | Waits(s) | Calls | Gets | Reqs | Bytes | Reqs | Bytes |
===========================================================================================
| 16 | 6.91 | 7.91 | 0.71 | 33335 | 334K | 7996 | 4GB | 4431 | 1GB |
===========================================================================================

SQL Plan Monitoring Details (Plan Hash Value=3534657201)
=====================================================================================================================================================================================
| Id | Operation | Name | Rows | Cost | Time | Start | Execs | Rows | Read | Read | Write | Write | Mem | Temp | Activity | Activity Detail |
| | | | (Estim) | | Active(s) | Active | | (Actual) | Reqs | Bytes | Reqs | Bytes | (Max) | (Max) | (%) | (# samples) |
=====================================================================================================================================================================================
| 0 | SELECT STATEMENT | | | | 22 | +2 | 1 | 500K | | | | | . | . | 6.25 | Cpu (1) |
| 1 | SORT ORDER BY | | 507K | 326K | 22 | +2 | 1 | 500K | 5363 | 1GB | 4431 | 1GB | 1GB | 1GB | 68.75 | Cpu (4) |
| | | | | | | | | | | | | | | | | direct path read temp (1) |
| | | | | | | | | | | | | | | | | direct path write temp (6) |
| 2 | TABLE ACCESS FULL | M1 | 507K | 90828 | 13 | +1 | 1 | 500K | 2633 | 3GB | | | . | . | 25.00 | Cpu (3) |
| | | | | | | | | | | | | | | | | direct path read (1) |
=====================================================================================================================================================================================

自動PGA管理でGlobal Memory Bound = 1GB(自動PGA管理での最大 Hash作業領域サイズ)

Hash Joinの場合も、自動PGA管理の最大サイズ程度まで利用されていることが確認できます。(Temp落ちしない程度のデータ量にしています。)
ORCL@SCOTT> @auto_hashwk1gb_optimal

NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
workarea_size_policy string AUTO

NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
pga_aggregate_target big integer 4398046511103

NAME VALUE UNIT CON_ID
---------------------------------------------------------------- ---------- ------------ ----------
global memory bound 1073741824 bytes 0

1 SELECT
2 /*+
3 MONITOR
4 LEADING(m1 m2)
5 USE_HASH(m2)
6 */
7 *
8 FROM
9 m1
10 INNER JOIN m2
11 ON
12 m1.id = m2.id
13 AND m1.rev# = m2.rev#
14 WHERE
15* m1.id <= 'C042000'
old 1: select dbms_sqltune.report_sql_monitor(sql_id=>'&1', type=>'text') from dual
new 1: select dbms_sqltune.report_sql_monitor(sql_id=>'', type=>'text') from dual

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

・・・中略・・・

Global Stats
===========================================================================
| Elapsed | Cpu | IO | Other | Fetch | Buffer | Read | Read |
| Time(s) | Time(s) | Waits(s) | Waits(s) | Calls | Gets | Reqs | Bytes |
===========================================================================
| 7.29 | 5.05 | 0.68 | 1.55 | 28001 | 695K | 5251 | 5GB |
===========================================================================

SQL Plan Monitoring Details (Plan Hash Value=1822065247)
==================================================================================================================================================
| Id | Operation | Name | Rows | Cost | Time | Start | Execs | Rows | Read | Read | Mem | Activity | Activity Detail |
| | | | (Estim) | | Active(s) | Active | | (Actual) | Reqs | Bytes | (Max) | (%) | (# samples) |
==================================================================================================================================================
| 0 | SELECT STATEMENT | | | | 14 | +2 | 1 | 420K | | | . | 22.22 | Cpu (2) |
| 1 | HASH JOIN | | 423K | 268K | 15 | +1 | 1 | 420K | | | 1GB | 22.22 | Cpu (2) |
| 2 | TABLE ACCESS FULL | M1 | 432K | 90827 | 2 | +2 | 1 | 420K | 2633 | 3GB | . | 11.11 | Cpu (1) |
| 3 | TABLE ACCESS FULL | M2 | 423K | 90580 | 13 | +3 | 1 | 420K | 2618 | 3GB | . | 44.44 | Cpu (4) |
==================================================================================================================================================
Hash Joinの場合もSort時と同じように、一時表領域も利用が必要となるデータ量になると、一旦、自動PGA管理の最大サイズ程度まで利用したうえでTemp落ちしていることが確認できます。
ORCL@SCOTT> @auto_hashwk1gb_mpass

NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
workarea_size_policy string AUTO

NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
pga_aggregate_target big integer 4398046511103

NAME VALUE UNIT CON_ID
---------------------------------------------------------------- ---------- ------------ ----------
global memory bound 1073741824 bytes 0

1 SELECT
2 /*+
3 MONITOR
4 LEADING(m1 m2)
5 USE_HASH(m2)
6 */
7 *
8 FROM
9 m1
10 INNER JOIN m2
11 ON
12 m1.id = m2.id
13 AND m1.rev# = m2.rev#
14 WHERE
15* m1.id <= 'C055000'
old 1: select dbms_sqltune.report_sql_monitor(sql_id=>'&1', type=>>'text') from dual
new 1: select dbms_sqltune.report_sql_monitor(sql_id=>'', type=>'text') from dual

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

・・・中略・・・

Global Stats
============================================================================================
| Elapsed | Cpu | IO | Other | Fetch | Buffer | Read | Read | Write | Write |
| Time(s) | Time(s) | Waits(s) | Waits(s) | Calls | Gets | Reqs | Bytes | Reqs | Bytes |
============================================================================================
| 24 | 7.18 | 15 | 1.99 | 36668 | 687K | 10829 | 6GB | 5578 | 1GB |
============================================================================================

SQL Plan Monitoring Details (Plan Hash Value=1822065247)
======================================================================================================================================================================================
| Id | Operation | Name | Rows | Cost | Time | Start | Execs | Rows | Read | Read | Write | Write | Mem | Temp | Activity | Activity Detail |
| | | | (Estim) | | Active(s) | Active | | (Actual) | Reqs | Bytes | Reqs | Bytes | (Max) | (Max) | (%) | (# samples) |
======================================================================================================================================================================================
| 0 | SELECT STATEMENT | | | | 33 | +2 | 1 | 550K | | | | | . | . | 14.29 | Cpu (4) |
| 1 | HASH JOIN | | 551K | 293K | 33 | +2 | 1 | 550K | 5578 | 1GB | 5578 | 1GB | 1GB | 1GB | 67.86 | Cpu (8) |
| | | | | | | | | | | | | | | | | direct path read temp (1) |
| | | | | | | | | | | | | | | | | direct path write temp (10) |
| 2 | TABLE ACCESS FULL | M1 | 551K | 90828 | 16 | +1 | 1 | 550K | 2633 | 3GB | | | . | . | 7.14 | Cpu (1) |
| | | | | | | | | | | | | | | | | direct path read (1) |
| 3 | TABLE ACCESS FULL | M2 | 557K | 90580 | 16 | +16 | 1 | 550K | 2618 | 3GB | | | . | . | 10.71 | Cpu (3) |
======================================================================================================================================================================================

PGAの最大サイズは異なりますが、自動PGA管理、手動PGA管理いずれでの場合でも制限値を超えた場合は、もれなく "Temp落ち" するということはご理解いただけたのではないかと思います。

では、次回は恒例?w の隠しパラメータと戯れた場合、自動PGA管理下ではどこまで増加させることができるのか?。。。。確認してみたいと思います。


Temp落ち #1 - "Temp落ち" って?
Temp落ち #2 - PGA (Program Global Area)
Temp落ち #3 - 手動PGA管理で作業領域として指定可能な最大サイズ
Temp落ち #4 - 手動PGA管理で作業領域として指定可能な最大サイズ de Temp落ちの確認
Temp落ち #5 - pga_aggregate_targetでPGA?、_pga_max_sizeでPGA? 12.2.0.1版 (その前に少し脱線)
Temp落ち #6 - pga_aggregate_targetでPGA?、_pga_max_sizeでPGA? 12.2.0.1版

 

| | コメント (0) | トラックバック (0)

2018年3月 7日 (水)

Temp落ち #6 - pga_aggregate_targetでPGA?、_pga_max_sizeでPGA? 12.2.0.1版

Previously on Mac De Oracle
pga_aggregate_target scope=memory or bothでそれまでとはことなる動きとエラーは発生するところの話でした。


きょうは、自動PGA管理下ではどうなるか確認しておきます。
以前、簡単に確認した範囲結果から、これまでの仕様と大きな違いはないとみています。(変わっていないと思っていたのでブログでも書いていなかったのですが、"Temp落ち"ネタの準備運動も兼ね現状を確認しながら進めてみたいと思います)


まず環境情報から、
確認に利用するインスタンスのPGA以外のパラメータは以下の通りです。
(隠しパラメータは必要がある場合には適宜変更します。また、いくつかのパラメータは確認の都合上物理メモリーサイズ以上に設定することがあります。それらの変更が必要な場合には事前に解説する予定です。)

OS等の情報は以前のエントリーを参照のこと。

NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
sga_max_size big integer 12G
sga_min_size big integer 0
sga_target big integer 12G

今回の主役である自動PGA管理のパラメータの初期設定は以下の通り(隠しパラメータを除く)
pga_aggregate_limit = 0 に設定し、pga_aggregate_targetの上限値制限を仕様上のサイズ4096GB - 1まで利用できるようにしておきます。(以前と同様の手順で確認するために、pga_aggregate_limitによる制限を無効化しています。なお、pga_aggregate_limitを0以外に設定して行う場合には、pga_aggregate_targetを4TB - 1まで設定することを考慮すると、pga_aggregate_limitは、8TB以上に設定する必要があります。)

orcl12c@SYS> show parameter pga_aggregate

NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
pga_aggregate_limit big integer 0
pga_aggregate_target big integer 10M

上記設定からスタートして、pga_aggregate_targetを10MB/50MB/100MB/500MB/1GB/5GB/10GB/50GB/100GB/500GB/1T/4TB - 1と増加させながら、pgaサイズおよび、関連する隠しパラメータ(_pga_max_sizeや_smm_*など)がどのように変化するか、pga_aggregate_targetでPGA?、_pga_max_sizeでPGA? Season2 #8の手順で確認します。

昔のように実行ログをペタペタ貼っていると長くなるので、確認結果を表とグラフにしました。
想定通り以前と変わっていませんでした:)

デフォルト設定のままであれば、pga_aggregate_targetを限界値まで大きく増やしたとしても、10GB以降、個々のソート操作やハッシュ結合操作で利用できるPGAのSQL work areaサイズはv$pgastatのglobal memory boundの示す通り、1GB(シリアル実行時)が最大であることが確認できます。 えーーー。手動PGA管理より最大サイズ小さいじゃんと、今更驚かないようにしましょうねw (以前からそうなのですからw)
つまり、自動PGA管理の場合、特定の隠しパラメータを変更しない限り、1GBを超えるソート処理やハッシュ結合操作は全て、"Temp落ち" する宿命にあるわけです。12cR2であっても。
え"〜〜〜〜〜っ! と一応、驚いておきましょうw。 メモリーを沢山積んでるマシンは最近多いわけですが、このあたりはなぜか変わってません。
20180307_143101

ちなみに、v$pgastatの示すglobal memory boundは、どこから? という確認がしたくて、 _smm_max_sizeの変化と比較しているグラグも作成しておきました。
_smm_max_sizeパラメータはpga_aggregate_targetのサイズ変化に伴い変化する隠しパラメータですが、このパラメータがglobal memory boundの元になっているのは確からしいですね。
20180307_143308

最後のグラフは、pga_aggregate_targetの値とv$pgastatのglobal memory boundの変化をまとめたグラフです。
global memory boundで示されるPGAのSQL Work Areaサイズの最大サイズには上限があることがわかります:)
20180307_143330

次回は、自動PGA管理では、1GBを超えるソートやハッシュ結合はもれなく"Temp落ち"するのか確認してみることにします。


参考:このエントリーで利用したスクリプト
(今後の確認も兼ねてw このエントリーでネタにしている以外で関連しそうなパラメータも取得して変化を確認できるようにしてあります。)

orcl12c@SYS> !cat show_param.sql
set linesize 200
col ksppinm for a46
col ksppstvl for a30
col ksppstdf for a30
select
a.ksppinm
,b.ksppstvl
,b.ksppstdf
from
x$ksppi a join x$ksppcv b
on a.indx = b.indx
where
a.ksppinm in (
'pga_aggregate_target'
,'pga_aggregate_limit'
,'_use_realfree_heap'
,'_realfree_heap_pagesize'
)
or a.ksppinm like '%\_smm%' escape '\'
or a.ksppinm like '%\_pga%' escape '\'
order by
a.ksppinm
/

!echo /proc/sys/vm/max_map_count
!more /proc/sys/vm/max_map_count

orcl12c@SYS> !cat show_pgstat.sql
select
name
,case
when unit='bytes' then
value/1024/1024
else value
end "VALUE"
,case
when unit='bytes' then
'MB'
else unit
end "UNIT"
,con_id
from
v$pgastat
where
name in (
'aggregate PGA target parameter'
,'aggregate PGA auto target'
,'global memory bound'
,'total PGA used for auto workareas'
,'maximum PGA used for auto workareas'
,'total PGA used for manual workareas'
,'maximum PGA used for manual workareas'
)
;
orcl12c@SYS> !cat auto_workarea.sql
conn sys/oracle@orcl12c as sysdba
alter system set pga_aggregate_target=&1 scope=spfile
.
r
shutdown immediate
startup

prompt +++ initial parameters +++
@show_param

prompt +++ v$pgastat +++
@show_pgstatå
orcl12c@SYS> !cat doTest_auto_workarea.sql
prompt << 10m >>
@auto_workarea 10m

prompt << 50m >>
@auto_workarea 50m

prompt << 100m >>
@auto_workarea 100m

prompt << 500m >>
@auto_workarea 500m

prompt << 1g >>
@auto_workarea 1g

prompt << 5g >>
@auto_workarea 5g

prompt << 10g >>
@auto_workarea 10g

prompt << 50g >>
@auto_workarea 50g

prompt << 100g >>
@auto_workarea 100g

prompt << 500g >>
@auto_workarea 500g

prompt << 1t >>
@auto_workarea 1t

prompt << 4t - 1 >>
@auto_workarea 4398046511103


実行例

orcl12c@SYS> @doTest_auto_workarea.sql
<< 10m >>
Connected.
1* alter system set pga_aggregate_target=&1 scope=spfile
old 1: alter system set pga_aggregate_target=&1 scope=spfile
new 1: alter system set pga_aggregate_target=10m scope=spfile

System altered.

Database closed.
Database dismounted.
ORACLE instance shut down.
ORACLE instance started.

Total System Global Area 1.2885E+10 bytes
Fixed Size 8807168 bytes
Variable Size 1375735040 bytes
Database Buffers 5033164800 bytes
Redo Buffers 24743936 bytes
In-Memory Area 6442450944 bytes
Database mounted.
Database opened.
+++ initial parameters +++

KSPPINM KSPPSTVL KSPPSTDF
---------------------------------------------- ------------------------------ ------------------------------
__pga_aggregate_target 33554432 FALSE

・・・略・・・

pga_aggregate_limit 0 FALSE
pga_aggregate_target 10485760 FALSE

50 rows selected.

/proc/sys/vm/max_map_count

65530

+++ v$pgastat +++

NAME VALUE UNIT CON_ID
---------------------------------------------------------------- ---------- ------------ ----------
aggregate PGA target parameter 10 MB 0
aggregate PGA auto target 4 MB 0
global memory bound 2 MB 0
total PGA used for auto workareas .106445313 MB 0
maximum PGA used for auto workareas .106445313 MB 0
total PGA used for manual workareas 0 MB 0
maximum PGA used for manual workareas 0 MB 0

7 rows selected.

・・・略・・・


Temp落ち #1 - "Temp落ち" って?
Temp落ち #2 - PGA (Program Global Area)
Temp落ち #3 - 手動PGA管理で作業領域として指定可能な最大サイズ
Temp落ち #4 - 手動PGA管理で作業領域として指定可能な最大サイズ de Temp落ちの確認
Temp落ち #5 - pga_aggregate_targetでPGA?、_pga_max_sizeでPGA? 12.2.0.1版 (その前に少し脱線)

| | コメント (0) | トラックバック (0)

2018年2月24日 (土)

Temp落ち #5 - pga_aggregate_targetでPGA?、_pga_max_sizeでPGA? 12.2.0.1版 (その前に少し脱線)



Previously on Mac De Oracle

手動PGA管理下で利用される4つのパラメータ(HASH_AREA_SIZE / SORT_AREA_SIZE / BITMAP_MERGE_AREA_SIZE / CREATE_BITMAP_AREA_SIZE)は、Integer型であり2,147,483,647バイト(つまり2GB - 1)までは指定可能、かつ、個々の作業領域は同程度確保されること。そのサイズを超えるデータ量の場合は一時表領域が利用される。つまり"Temp落ち"が発生するというところまでした。

SQL> show parameter _area_size

NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
bitmap_merge_area_size integer 2147483647
create_bitmap_area_size integer 2147483647
hash_area_size integer 2147483647
sort_area_size integer 2147483647

64bit環境でInteger型なので、そんなもんでしょうね。 仕様ですからね、こればっかりはどうにもならない。


で、自動PGA管理で確認しようとパタパタ準備していたところ、12.1.0.2まではなかった12.2.0.1での変更点に気付いたので、そちらを先に。
(少し脱線)

pga_aggregate_targetをscope=memoryで設定する際、物理メモリーの空きサイズ以上に設定しようとするとORA-00855エラーなり設定できないよう動作が変更されたようです。

また、spfileにのみ設定する場合には動作が異なり、設定時には、ORA-00855は発生しません。
アラートログファイルには、起動時のワーニングとして記録され、アラートログにもなにも記録されれず、正常起動しpga_aggregate_targetには指定したサイズで設定されるという、
少々分かりづらい仕様に変わったようです。 (今頃気づくとは、遅い!w

(18cではどうなるんだろう。。なんとなく、Autonomousを意識してるようなアトモスフィアを感じます..が、どうなんでしょうw?)

以下、動作確認の記録。
Guest OSのメモリーサイズは以下の通り。空いているメモリーサイズは500MB〜600MB程度です。

Oracle Database 12c Enterprise Edition Release 12.2.0.1.0 - 64bit Production
に接続されました。
orcl12c@SYS> !cat /proc/meminfo | grep Mem
MemTotal: 3781732 kB
MemFree: 43300 kB
MemAvailable: 559076 kB


orcl12c@SYS> 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 2G
sga_min_size big integer 0
sga_target big integer 2G
unified_audit_sga_queue_size integer 1048576

orcl12c@SYS> show parameter pga_agg

NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
pga_aggregate_limit big integer 2G
pga_aggregate_target big integer 200M


この状態で、pga_aggregate_limitの50%のサイズでpga_aggregate_limitの制限内、pga_aggregate_target=1g としてメモリー上でのみ変更してみると

orcl12c@SYS> alter system set pga_aggregate_target=1g scope=memory;
alter system set pga_aggregate_target=1g scope=memory
*
行1でエラーが発生しました。:
ORA-02097: 指定した値が無効なので、パラメータを変更できません。
ORA-00855: PGA_AGGREGATE_TARGET cannot be set because of insufficient physical memory.


空きメモリーサイズ以下ならどうなるか試して見ます。

orcl12c@SYS> alter system set pga_aggregate_target=500m scope=memory;

システムが変更されました。


空きメモリーサイズを多少上回るサイズでは。。。(やはり、ORA-00855となります)

orcl12c@SYS> alter system set pga_aggregate_target=700m scope=memory;
alter system set pga_aggregate_target=700m scope=memory
*
行1でエラーが発生しました。:
ORA-02097: 指定した値が無効なので、パラメータを変更できません。
ORA-00855: PGA_AGGREGATE_TARGET cannot be set because of insufficient physical memory.


scope=bothとなる状態で、空きメモリー以上のサイズを設定しようとしても同様のエラーになりますが.....

orcl12c@SYS> alter system set pga_aggregate_target=1g;
alter system set pga_aggregate_target=1g
*
行1でエラーが発生しました。:
ORA-02097: 指定した値が無効なので、パラメータを変更できません。
ORA-00855: PGA_AGGREGATE_TARGET cannot be set because of insufficient physical memory.


scope=spfileとした場合には、エラーにならず変更可能です。このあたりの動きは、他のパラメータと同様、起動時にエラーで起動しないという動きになるのかな??? と思いきや.....
なんと、正常起動し、pga_aggregate_targetにはしっかり、1GBが設定されています。!!!!! (動きが違う!!!)

orcl12c@SYS> alter system set pga_aggregate_target=1g scope=spfile;

システムが変更されました。

orcl12c@SYS> shutdown immediate
データベースがクローズされました。
データベースがディスマウントされました。
ORACLEインスタンスがシャットダウンされました。
orcl12c@SYS> startup
ORACLEインスタンスが起動しました。

Total System Global Area 2147483648 bytes
Fixed Size 8794848 bytes
Variable Size 603983136 bytes
Database Buffers 1526726656 bytes
Redo Buffers 7979008 bytes
データベースがマウントされました。
データベースがオープンされました。
orcl12c@SYS>
orcl12c@SYS> show parameter pga_agg

NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
pga_aggregate_limit big integer 2G
pga_aggregate_target big integer 1G

なぜ、動作が違うんだろう........


2018/2/25訂正
以下のメッセージよくよく見たら、pga_aggregate_limitパラメータへの警告でpga_aggregate_targetのORA-00855とは無関係なワーニングでした。orz.

pga_aggregate_limitの下限値は2G、sea_max_size=2Gなのに、Guest OSへのメモリー割り当て4Gなのでそりゃでるわね。というこでした。

とはいえ、 pga_aggreagte_target scope=memoryとspfileではORA-00855エラーの有無の違いはあるようで、spfileに設定した場合にはORA-00855は発生せず、アラートログファイルには何も記録されていない(謎


なお、起動時のアラートログファイルには以下の"WARNING"メッセージが記録されます。しかも、メッセージを見る限り、pga_aggregate_limit へのワーニングと読めるが....

2018-02-24T22:16:38.907017+09:00
WARNING: pga_aggregate_limit value is too high for the
amount of physical memory on the system
PGA_AGGREGATE_LIMIT is 2048 MB
PGA_AGGREGATE_TARGET is 1024 MB.
physical memory size is 3693 MB
limit based on physical memory and SGA usage is 1275 MB
SGA_TARGET is 2048 MB

おまけ


12.1.0.2までは該当するメッセージはありません。
[oracle@vbgeneric ˜]$ sqlplus -version

SQL*Plus: Release 12.1.0.2.0 Production

[oracle@vbgeneric ˜]$ oerr ORA 855
[oracle@vbgeneric ˜]$



12.2.0.1で実装されたメッセージと機能だということがわかります。
[oracle@localhost ˜]$ sqlplus -version

SQL*Plus: Release 12.2.0.1.0 Production

[oracle@localhost ˜]$ oerr ORA 855
00855, 00000, "PGA_AGGREGATE_TARGET cannot be set because of insufficient physical memory."
// *Cause: PGA_AGGREGATE_TARGET value was too high for the current system global area (SGA) size and amount of physical memory available.
// *Action: Reduce the SGA size or increase the physical memory size.

ということで、次回こそw 自動PGA管理下での確認へ

続く。


Temp落ち #1 - "Temp落ち" って?
Temp落ち #2 - PGA (Program Global Area)
Temp落ち #3 - 手動PGA管理で作業領域として指定可能な最大サイズ
Temp落ち #4 - 手動PGA管理で作業領域として指定可能な最大サイズ de Temp落ちの確認

| | コメント (0) | トラックバック (0)

2018年2月22日 (木)

Temp落ち #4 - 手動PGA管理で作業領域として指定可能な最大サイズ de Temp落ちの確認


Previously on Mac De Oracle
手動PGA管理で作業領域として指定可能な最大サイズは、2GB - 1までということの確認でした。
本当に、その程度のサイズまでPGAの作業領域が利用されるのでしょうか?。 念のために確認しておきましょう。 実は、それより少ないサイズで頭打ちなんてことは、ないかな〜 と わざとらしく言ってみたりして(意味深w

その前に、指定した作業領域を使い切れるぐらい(つまり、Temp落ちさせられる程度)のデータ量の表を準備しておきます。
今回は、Nested Loop Join(NLJ)やソート回避などのための索引は作成しません。Temp落ちのネタなので。

M1とM2の2表を作成し、それぞれ、2.5GB程度のセグメントサイズにしておきます。 なお、以下の無名PL/SQLブロックでは、FORALLを利用して1000行単位でバルク処理しています。配列を利用するのでメモリー使用量にはそれなりに配慮が必要ですが。:)
単純なぐるぐる系INSERTにしてしまうとデータ量が多い場合、性能的に辛くなってしまうので、ここ重要!

ORCL@SCOTT> l
1 CREATE TABLE m1
2 (
3 id CHAR(7) NOT NULL
4 ,rev# NUMBER NOT NULL
5 ,value NUMBER NOT NULL
6 ,description VARCHAR2(4000)
7 ,additional_info CHAR(200)
8* ) NOLOGGING
ORCL@SCOTT> /

Table created.

ORCL@SCOTT> l
1 DECLARE
2 TYPE IDS_t IS TABLE OF m1.id%TYPE INDEX BY PLS_INTEGER;
3 TYPE REV#S_t IS TABLE OF m1.rev#%TYPE INDEX BY PLS_INTEGER;
4 TYPE VALS_t IS TABLE OF m1.value%TYPE INDEX BY PLS_INTEGER;
5 IDs IDS_t;
6 REV#s REV#S_t;
7 VALs VALS_t;
8 k PLS_INTEGER := 1;
9 BEGIN
10 FOR i IN 1..100000 LOOP
11 FOR j IN 1..10 LOOP
12 IDs(k) := 'C' || TO_CHAR(i, 'FM000000');
13 REV#s(k) := j;
14 VALs(k) := i + j;
15 k := k + 1;
16 END LOOP;
17 IF MOD(i, 100) = 0 THEN
18 FORALL l in 1..1000 EXECUTE IMMEDIATE
19 'INSERT /*+ APPEND_VALUE NO_GATHER_OPTIMIZER_STATISTICS */ INTO m1 '
20 || 'VALUES(:1, :2, :3, LPAD(''X'',2000, ''X''), LPAD(''9'',200,''9''))'
21 USING IDs(l), REV#s(l), VALs(l);
22 COMMIT;
23 k := 1;
24 END IF;
25 END LOOP;
26* END;
ORCL@SCOTT> /

PL/SQL procedure successfully completed.

Elapsed: 00:01:22.45
ORCL@SCOTT> select count(1) from m1;

COUNT(1)
----------
1000000

ORCL@SCOTT> select segment_name,sum(bytes)/1024/1024/1024 "GB" from user_segments where segment_name='M1' group by segment_name;

SEGMENT_NAME GB
------------------------------ ----------
M1 2.5625

ORCL@SCOTT> l
1 CREATE TABLE m2
2 (
3 id CHAR(7) NOT NULL
4 ,rev# NUMBER NOT NULL
5 ,value NUMBER NOT NULL
6 ,description VARCHAR2(4000)
7* ) NOLOGGING
ORCL@SCOTT> /

Table created.

ORCL@SCOTT> l
1 INSERT /*+ APPEND NO_GATHER_OPTIMIZER_STATISTICS */ INTO m2
2* SELECT id,rev#,value,description FROM m1
ORCL@SCOTT> /

1000000 rows created.

Elapsed: 00:00:40.22
ORCL@SCOTT> commit;

Commit complete.

ORCL@SCOTT> exec dbms_stats.gather_table_stats(ownname=>'SCOTT',tabname=>'M1',no_invalidate=>false,method_opt=>'FOR ALL COLUMNS SIZE SKEWONLY');

PL/SQL procedure successfully completed.

ORCL@SCOTT> exec dbms_stats.gather_table_stats(ownname=>'SCOTT',tabname=>'M2',no_invalidate=>false,method_opt=>'FOR ALL COLUMNS SIZE SKEWONLY');

PL/SQL procedure successfully completed.

これで、準備完了。
ちなみに、NO_GATHER_OPTIMIZER_STATISTICSヒントを利用していますが、データ登録後に、ヒストグラムも含めて取得したかったため、バルクロード時のオンラインオプティマイザ統計収集を行わないようにするためのヒントです。
データ登録後オプティマイザ統計を取得するため、データ登録時のオンラインオプティマイザ統計のオーバーヘッドは無駄となるためです。利用できるなら利用したほうがよいとは思いますが、制限もあるのでご一読を(バルク・ロードのためのオンライン統計収集


 

手動PGA管理で2GB - 1(手動PGA管理での最大 Sort作業領域サイズ)

メモリーソートで2GBぐらいまで利用していることが確認できます。(ソートされるデータ量が2GB以下程度に制限しています。)
ORCL@SCOTT> @manual_sortwk2gb_optimal    
1* alter session set workarea_size_policy=manual

Session altered.

1* alter session set sort_area_size = 2147483647

Session altered.

1 SELECT
2 /*+
3 MONITOR
4 */
5 *
6 FROM
7 m1
8 WHERE
9 id <= 'C075000'
10 ORDER BY
11 id
12* ,rev#
old 1: select dbms_sqltune.report_sql_monitor(sql_id=>'&1', type=>'text') from dual
new 1: select dbms_sqltune.report_sql_monitor(sql_id=>'', type=>'text') from dual

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

・・・中略・・・

Global Stats
=================================================
| Elapsed | Cpu | Other | Fetch | Buffer |
| Time(s) | Time(s) | Waits(s) | Calls | Gets |
=================================================
| 5.42 | 4.13 | 1.29 | 50001 | 334K |
=================================================

SQL Plan Monitoring Details (Plan Hash Value=3534657201)
===================================================================================================================================
| Id | Operation | Name | Rows | Cost | Time | Start | Execs | Rows | Mem | Activity | Activity Detail |
| | | | (Estim) | | Active(s) | Active | | (Actual) | (Max) | (%) | (# samples) |
===================================================================================================================================
| 0 | SELECT STATEMENT | | | | 15 | +2 | 1 | 750K | . | 20.00 | Cpu (1) |
| 1 | SORT ORDER BY | | 752K | 439K | 16 | +1 | 1 | 750K | 2GB | 60.00 | Cpu (3) |
| 2 | TABLE ACCESS FULL | M1 | 752K | 90828 | 3 | +2 | 1 | 750K | . | 20.00 | Cpu (1) |
===================================================================================================================================

 

Temp落ちする程度のデータ量でソートさせた場合も、PGAの作業領域は一旦、2GBまで利用されていることが確認できます。
ORCL@SCOTT> @manual_sortwk2gb
1* alter session set workarea_size_policy=manual

Session altered.

1* alter session set sort_area_size = 2147483647

Session altered.

1 SELECT
2 /*+
3 MONITOR
4 */
5 *
6 FROM
7 m1
8 ORDER BY
9 id
10* ,rev#
old 1: select dbms_sqltune.report_sql_monitor(sql_id=>'&1', type=>'text') from dual
new 1: select dbms_sqltune.report_sql_monitor(sql_id=>'', type=>'text') from dual

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

・・・中略・・・

Global Stats
===========================================================================================
| Elapsed | Cpu | IO | Other | Fetch | Buffer | Read | Read | Write | Write |
| Time(s) | Time(s) | Waits(s) | Waits(s) | Calls | Gets | Reqs | Bytes | Reqs | Bytes |
===========================================================================================
| 46 | 11 | 15 | 20 | 66668 | 334K | 2148 | 2GB | 2146 | 2GB |
===========================================================================================

SQL Plan Monitoring Details (Plan Hash Value=3534657201)
=====================================================================================================================================================================================
| Id | Operation | Name | Rows | Cost | Time | Start | Execs | Rows | Read | Read | Write | Write | Mem | Temp | Activity | Activity Detail |
| | | | (Estim) | | Active(s) | Active | | (Actual) | Reqs | Bytes | Reqs | Bytes | (Max) | (Max) | (%) | (# samples) |
=====================================================================================================================================================================================
| 0 | SELECT STATEMENT | | | | 60 | +2 | 1 | 1M | | | | | . | . | 6.38 | Cpu (2) |
| | | | | | | | | | | | | | | | | PGA memory operation (1) |
| 1 | SORT ORDER BY | | 1M | 553K | 61 | +1 | 1 | 1M | 2148 | 2GB | 2146 | 2GB | 2GB | 2GB | 91.49 | Cpu (32) |
| | | | | | | | | | | | | | | | | direct path read temp (10) |
| | | | | | | | | | | | | | | | | direct path write temp (1) |
| 2 | TABLE ACCESS FULL | M1 | 1M | 90822 | 27 | +2 | 1 | 1M | | | | | . | . | 2.13 | Cpu (1) |
=====================================================================================================================================================================================

 

手動PGA管理で2GB - 1(手動PGA管理での最大 Hash作業領域サイズ) Hash Joinの場合も、手動PGA管理で設定可能な最大サイズ程度まで利用されていることが確認できます。(Temp落ちしない程度のデータ量にしています。)

ORCL@SCOTT> @manual_hashwk2gb_optimal
1* alter session set workarea_size_policy = manual

Session altered.

1* alter session set hash_area_size = 2147483647

Session altered.

1 SELECT
2 /*+
3 MONITOR
4 LEADING(m1 m2)
5 USE_HASH(m2)
6 */
7 *
8 FROM
9 m1
10 INNER JOIN m2
11 ON
12 m1.id = m2.id
13 AND m1.rev# = m2.rev#
14 WHERE
15* m1.id <= 'C075000'
old 1: select dbms_sqltune.report_sql_monitor(sql_id=>'&1', type=>'text') from dual
new 1: select dbms_sqltune.report_sql_monitor(sql_id=>'', type=>'text') from dual

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

・・・中略・・・

Global Stats
===========================================================================
| Elapsed | Cpu | IO | Other | Fetch | Buffer | Read | Read |
| Time(s) | Time(s) | Waits(s) | Waits(s) | Calls | Gets | Reqs | Bytes |
===========================================================================
| 8.05 | 4.66 | 0.16 | 3.23 | 50001 | 717K | 2618 | 3GB |
===========================================================================

SQL Plan Monitoring Details (Plan Hash Value=1822065247)
==================================================================================================================================================
| Id | Operation | Name | Rows | Cost | Time | Start | Execs | Rows | Read | Read | Mem | Activity | Activity Detail |
| | | | (Estim) | | Active(s) | Active | | (Actual) | Reqs | Bytes | (Max) | (%) | (# samples) |
==================================================================================================================================================
| 0 | SELECT STATEMENT | | | | 21 | +2 | 1 | 750K | | | . | 12.50 | Cpu (1) |
| 1 | HASH JOIN | | 752K | 181K | 22 | +1 | 1 | 750K | | | 2GB | 25.00 | Cpu (2) |
| 2 | TABLE ACCESS FULL | M1 | 752K | 90828 | 2 | +2 | 1 | 750K | | | . | 25.00 | Cpu (2) |
| 3 | TABLE ACCESS FULL | M2 | 759K | 90581 | 20 | +3 | 1 | 750K | 2618 | 3GB | . | 37.50 | Cpu (3) |
==================================================================================================================================================

 

Hash Joinの場合もSort時と同じように、一時表領域も利用させる程度のデータ量になると、一旦、手動PGA管理で設定可能な最大サイズ程度まで利用したうえでTemp落ちしていることが確認できます。

ORCL@SCOTT> @manual_hashwk2gb
1* alter session set workarea_size_policy = manual

Session altered.

1* alter session set hash_area_size = 2147483647

Session altered.

1 SELECT
2 /*+
3 MONITOR
4 LEADING(m1 m2)
5 USE_HASH(m2)
6 */
7 *
8 FROM
9 m1
10 INNER JOIN m2
11 ON
12 m1.id = m2.id
13* AND m1.rev# = m2.rev#
old 1: select dbms_sqltune.report_sql_monitor(sql_id=>'&1', type=>'text') from dual
new 1: select dbms_sqltune.report_sql_monitor(sql_id=>'', type=>'text') from dual

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

・・・中略・・・

Global Stats
===========================================================================================
| Elapsed | Cpu | IO | Other | Fetch | Buffer | Read | Read | Write | Write |
| Time(s) | Time(s) | Waits(s) | Waits(s) | Calls | Gets | Reqs | Bytes | Reqs | Bytes |
===========================================================================================
| 12 | 5.68 | 2.17 | 4.59 | 66668 | 706K | 3133 | 3GB | 515 | 511MB |
===========================================================================================

SQL Plan Monitoring Details (Plan Hash Value=1822065247)
=====================================================================================================================================================================================
| Id | Operation | Name | Rows | Cost | Time | Start | Execs | Rows | Read | Read | Write | Write | Mem | Temp | Activity | Activity Detail |
| | | | (Estim) | | Active(s) | Active | | (Actual) | Reqs | Bytes | Reqs | Bytes | (Max) | (Max) | (%) | (# samples) |
=====================================================================================================================================================================================
| 0 | SELECT STATEMENT | | | | 30 | +2 | 1 | 1M | | | | | . | . | 25.00 | Cpu (4) |
| 1 | HASH JOIN | | 1M | 189K | 31 | +1 | 1 | 1M | 515 | 511MB | 515 | 511MB | 2GB | 515MB | 43.75 | Cpu (5) |
| | | | | | | | | | | | | | | | | direct path read temp (1) |
| | | | | | | | | | | | | | | | | direct path write temp (1) |
| 2 | TABLE ACCESS FULL | M1 | 1M | 90822 | 6 | +0 | 1 | 1M | | | | | . | . | 12.50 | Cpu (2) |
| 3 | TABLE ACCESS FULL | M2 | 1M | 90574 | 24 | +5 | 1 | 1M | 2618 | 3GB | | | . | . | 18.75 | Cpu (2) |
| | | | | | | | | | | | | | | | | direct path read (1) |
=====================================================================================================================================================================================

おまけ 1つのSQLの実行で利用されるPGAの作業領域は1つだけではないということも確認しておきましょうかね。(知ってる方はスルーしてよいですよ:)
以下の例では、MERGE JOINさせていますが、表M1と表M2それぞれのSort作業領域は、Merge Join終了時まで保持されることになるため、最大3GBのSort作業領域が利用されています。(SQLモニターの結果ではわかりにくいのですが。。。)
なお、手動PGA管理、自動PGA管理に関係なく、実行される操作により複数の作業領域が同時に確保されることがあります。
(ちなみに、自動PGA管理で利用されるPGA_AGGREGATE_LIMITがPGA_AGGREGATE_TARGETの2倍とされるのも、このような動きが考慮された結果だと知っていると、納得感はあるかもしれません。)

 

前回使った図で朱色で示したSQL Work Areaが複数ありますが、Hash/Sort/Bitmap系など複数のタイプおよび同一タイプの作業領域が同時に確保されることも意図した図になっているのは、これが理由なんです。

Structure_of_pga
ORCL@SCOTT> @manual_sortwk2gb2_optimal
1* alter session set workarea_size_policy = manual

Session altered.

1* alter session set sort_area_size = 2147483647

Session altered.

1 SELECT
2 /*+
3 MONITOR
4 USE_MERGE(m1 m2)
5 */
6 *
7 FROM
8 m1
9 INNER JOIN m2
10 ON
11 m1.id = m2.id
12 AND m1.rev# = m2.rev#
13 WHERE
14* m1.id <= 'C075000'
old 1: select dbms_sqltune.report_sql_monitor(sql_id=>'&1', type=>'text') from dual
new 1: select dbms_sqltune.report_sql_monitor(sql_id=>'', type=>'text') from dual

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

・・・中略・・・

Global Stats
===========================================================================
| Elapsed | Cpu | IO | Other | Fetch | Buffer | Read | Read |
| Time(s) | Time(s) | Waits(s) | Waits(s) | Calls | Gets | Reqs | Bytes |
===========================================================================
| 17 | 10 | 4.75 | 2.19 | 50001 | 667K | 5251 | 5GB |
===========================================================================

SQL Plan Monitoring Details (Plan Hash Value=1391069689)
========================================================================================================================================================
| Id | Operation | Name | Rows | Cost | Time | Start | Execs | Rows | Read | Read | Mem | Activity | Activity Detail |
| | | | (Estim) | | Active(s) | Active | | (Actual) | Reqs | Bytes | (Max) | (%) | (# samples) |
========================================================================================================================================================
| 0 | SELECT STATEMENT | | | | 23 | +10 | 1 | 750K | | | . | 14.29 | Cpu (2) |
| 1 | MERGE JOIN | | 752K | 849K | 23 | +10 | 1 | 750K | | | . | | |
| 2 | SORT JOIN | | 752K | 439K | 32 | +1 | 1 | 750K | | | 2GB | 21.43 | Cpu (3) |
| 3 | TABLE ACCESS FULL | M1 | 752K | 90828 | 8 | +2 | 1 | 750K | 2633 | 3GB | . | 35.71 | Cpu (3) |
| | | | | | | | | | | | | | direct path read (2) |
| 4 | SORT JOIN | | 759K | 410K | 23 | +10 | 750K | 750K | | | 1GB | 14.29 | Cpu (2) |
| 5 | TABLE ACCESS FULL | M2 | 759K | 90581 | 5 | +10 | 1 | 750K | 2618 | 3GB | . | 14.29 | Cpu (2) |
========================================================================================================================================================

SQLモニターの結果ではわかりにくいわけですが、v$sesstatをから眺めれば状況がよくわかります!
2つのソート作業領域が同時に確保されたことで、2GB + 1GB = 3GB程度のサイズにまで達していることが確認できます。

ORCL@SYSTEM> r
1 select
2 vss.value/1024/1024/1024 "GB"
3 ,vsn.name
4 ,vss.sid
5 from
6 v$sesstat vss
7 inner join v$statname vsn
8 on
9 vss.statistic# = vsn.statistic#
10 and vss.con_id = vsn.con_id
11 and vsn.name like '%pga%'
12 where
13 sid IN (select sid from v$session where username='SCOTT')
14 order by
15* sid,name

GB NAME SID
---------- ---------------------------------------------------------------- ----------
3.04611414 session pga memory 203
3.04611414 session pga memory max 203

では、次回はやっとw、真打、自動PGA管理下での確認。(引っ張り過ぎかもしれないw)
つづく。


Temp落ち #1 - "Temp落ち" って?
Temp落ち #2 - PGA (Program Global Area)
Temp落ち #3 - 手動PGA管理で作業領域として指定可能な最大サイズ

 

| | コメント (0) | トラックバック (0)

2018年2月20日 (火)

Temp落ち #3 - 手動PGA管理で作業領域として指定可能な最大サイズ

自動PGA管理は12cでどうなんだっけ?という確認の前に、
いままで何度か質問されたことがあり、FAQだと思っているので

手動PGA管理で利用する以下パラメータの最大サイズはいくつ? 

HASH_AREA_SIZE
SORT_AREA_SIZE
BITMAP_MERGE_AREA_SIZE
CREATE_BITMAP_AREA_SIZE

ということを書いておきたいと思います。

これからしばらく続く Temp落ち ネタで利用する環境で固定部分は以下のとおり
(初期化パラメータ等は必要に応じて載せるつもりです。)


環境は以下のとおり。
host osとguest osのバージョンやメモリーサイズなど

discus:˜ oracle$ sw_vers
ProductName: Mac OS X
ProductVersion: 10.13.3
BuildVersion: 17D47

discus:˜ oracle$ system_profiler SPHardwareDataType | grep -E 'Processor Name|Cores|Memory'
Processor Name: 6-Core Intel Xeon
Total Number of Cores: 12
Memory: 32 GB

discus:˜ oracle$ VBoxManage -v
5.2.6r120293

discus:˜ oracle$ VBoxManage showvminfo e3d4f948-b2e6-4db3-a89d-df637d87a372 | grep -E 'Memory size|OS type|Number of CPUs'
Memory size: 23569MB
Number of CPUs: 12
OS type: Linux26_64


orcl12c@SYS> select * from v$version;

BANNER CON_ID
-------------------------------------------------------------------------------- ----------
Oracle Database 12c Enterprise Edition Release 12.2.0.1.0 - 64bit Production 0
PL/SQL Release 12.2.0.1.0 - Production 0
CORE 12.2.0.1.0 Production 0
TNS for Linux: Version 12.2.0.1.0 - Production 0
NLSRTL Version 12.2.0.1.0 - Production 0


orcl12c@SYS> show pdbs

CON_ID CON_NAME OPEN MODE RESTRICTED
---------- ------------------------------ ---------- ----------
2 PDB$SEED READ ONLY NO
3 ORCL READ WRITE NO

さて、今日の本題

手動PGA管理で各SQL Work Area Sizeを決定する以下の初期化パラメータの最大サイズは? いくつでしょう? 
すでにご存知のかたはスキップしていいですよ:)

マニュアルを読んでみるときづくのですが、手動PGA管理で各SQL Work Area Sizeを決定する4パラメータとも、「0以上、上限はOS依存」のような記述になっています。

そう、マニュアルを読んだだけではまったく参考にならないわけです。(え〜〜っ!)

そこで、みなさんサポートを頼るなり、ご自分でMOSを検索するなり、そこそこの苦労をして入手することになります。
私みたいな性格だと、どのマニュアルでもいいからまとめて載せてよーめんどくさいから。と、めんどくさい病の発作がでたりしますw

なので、環境があるのなら、you 試しちゃいなよー。が手っ取り早いかなーと(最終的にMOSとかサポートを頼るにしてもw)

上限はOS依存とだけしか記載されていませんが、私の観測範囲では、2GB - 1 が上限 となっています。
以下、Linux/Solaris/Windowsでの検証ログ。

Oracle® Databaseリファレンス 12cリリース2 (12.2) E72905-03より

HASH_AREA_SIZE
https://docs.oracle.com/cd/E82638_01/REFRN/HASH_AREA_SIZE.htm

SORT_AREA_SIZE
https://docs.oracle.com/cd/E82638_01/REFRN/SORT_AREA_SIZE.htm

BITMAP_MERGE_AREA_SIZE
https://docs.oracle.com/cd/E82638_01/REFRN/BITMAP_MERGE_AREA_SIZE.htm

CREATE_BITMAP_AREA_SIZE
https://docs.oracle.com/cd/E82638_01/REFRN/CREATE_BITMAP_AREA_SIZE.htm


Linux

orcl12c@SYS> !uname -r; cat /etc/redhat-release /etc/oracle-release
4.1.12-94.3.6.el7uek.x86_64
Red Hat Enterprise Linux Server release 7.3 (Maipo)
Oracle Linux Server release 7.3

orcl12c@SYS> create pfile from spfile;

File created.

orcl12c@SYS> --2GB
orcl12c@SYS> select 2*1024*1024*1024 from dual;

2*1024*1024*1024
----------------
2147483648

orcl12c@SYS> alter system set hash_area_size = 2147483648 scope=spfile;
alter system set hash_area_size = 2147483648 scope=spfile
*
ERROR at line 1:
ORA-02017: integer value required

orcl12c@SYS> alter system set sort_area_size = 2147483648 scope=spfile;
alter system set sort_area_size = 2147483648 scope=spfile
*
ERROR at line 1:
ORA-02017: integer value required

orcl12c@SYS> alter system set bitmap_merge_area_size = 2147483648 scope=spfile;
alter system set bitmap_merge_area_size = 2147483648 scope=spfile
*
ERROR at line 1:
ORA-02017: integer value required

orcl12c@SYS> alter system set create_bitmap_area_size = 2147483648 scope=spfile;
alter system set create_bitmap_area_size = 2147483648 scope=spfile
*
ERROR at line 1:
ORA-02017: integer value required

orcl12c@SYS> --2GB - 1
orcl12c@SYS> select 2*1024*1024*1024-1 from dual;

2*1024*1024*1024-1
------------------
2147483647

orcl12c@SYS> alter system set hash_area_size = 2147483647 scope=spfile;

System altered.

orcl12c@SYS> alter system set sort_area_size = 2147483647 scope=spfile;

System altered.

orcl12c@SYS> alter system set bitmap_merge_area_size = 2147483647 scope=spfile;

System altered.

orcl12c@SYS> alter system set create_bitmap_area_size = 2147483647 scope=spfile;

System altered.

orcl12c@SYS> shutdown immediate
Database closed.
Database dismounted.
ORACLE instance shut down.
orcl12c@SYS> create spfile from pfile;

File created.

orcl12c@SYS>


Solaris 11 (x86)

SQL> !uname -r; cat /etc/release
5.11
Oracle Solaris 11.3 X86
Copyright (c) 1983, 2015, Oracle and/or its affiliates. All rights reserved.
Assembled 06 October 2015

SQL>
SQL> create pfile from spfile;

ファイルが作成されました。

SQL> --2GB
SQL> select 2*1024*1024*1024 from dual;

2*1024*1024*1024
----------------
2147483648

SQL> alter system set hash_area_size = 2147483648 scope=spfile;
alter system set hash_area_size = 2147483648 scope=spfile
*
行1でエラーが発生しました。:
ORA-02017: 整数値が必要です。


SQL> alter system set sort_area_size = 2147483648 scope=spfile;
alter system set sort_area_size = 2147483648 scope=spfile
*
行1でエラーが発生しました。:
ORA-02017: 整数値が必要です。


SQL> alter system set bitmap_merge_area_size = 2147483648 scope=spfile;
alter system set bitmap_merge_area_size = 2147483648 scope=spfile
*
行1でエラーが発生しました。:
ORA-02017: 整数値が必要です。


SQL> alter system set create_bitmap_area_size = 2147483648 scope=spfile;
alter system set create_bitmap_area_size = 2147483648 scope=spfile
*
行1でエラーが発生しました。:
ORA-02017: 整数値が必要です。


SQL> --2GB - 1
SQL> select 2*1024*1024*1024-1 from dual;

2*1024*1024*1024-1
------------------
2147483647

SQL> alter system set hash_area_size = 2147483647 scope=spfile;

システムが変更されました。

SQL> alter system set sort_area_size = 2147483647 scope=spfile;

システムが変更されました。

SQL> alter system set bitmap_merge_area_size = 2147483647 scope=spfile;

システムが変更されました。

SQL> alter system set create_bitmap_area_size = 2147483647 scope=spfile;

システムが変更されました。

SQL> shutdown immediate
データベースがクローズされました。
データベースがディスマウントされました。
ORACLEインスタンスがシャットダウンされました。
ERROR:
ORA-12514: TNS:
リスナーは接続記述子でリクエストされたサービスを現在認識していません


警告: Oracleにはもう接続されていません。
SQL> conn sys/oracle@orcl122 as sysdba
ERROR:
ORA-12514: TNS:
リスナーは接続記述子でリクエストされたサービスを現在認識していません


SQL> exit
bash-4.1$ export ORACLE_SID=orcl122
bash-4.1$ sqlplus / as sysdba

SQL*Plus: Release 12.2.0.1.0 Production on 月 2月 19 22:44:47 2018

Copyright (c) 1982, 2016, Oracle. All rights reserved.

アイドル・インスタンスに接続しました。

SQL> startup
ORACLEインスタンスが起動しました。

Total System Global Area 838860800 bytes
Fixed Size 8790120 bytes
Variable Size 356519832 bytes
Database Buffers 465567744 bytes
Redo Buffers 7983104 bytes
データベースがマウントされました。
データベースがオープンされました。
SQL> show parameter _area_size

NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
bitmap_merge_area_size integer 2147483647
create_bitmap_area_size integer 2147483647
hash_area_size integer 2147483647
sort_area_size integer 2147483647
workarea_size_policy string AUTO
SQL>
SQL> shutdown immediate
データベースがクローズされました。
データベースがディスマウントされました。
ORACLEインスタンスがシャットダウンされました。
SQL>
SQL> create spfile from pfile;

File created.


Microsoft Windows

Oracle Database 12c Enterprise Edition Release 12.2.0.1.0 - 64bit Production
に接続されました。
SQL>
SQL> $ver

Microsoft Windows [Version 10.0.16299.125]

SQL> create pfile from spfile;

ファイルが作成されました。

SQL> --2GB
SQL> select 2*1024*1024*1024 from dual;

2*1024*1024*1024
----------------
2147483648

SQL> alter system set hash_area_size = 2147483648 scope=spfile;
alter system set hash_area_size = 2147483648 scope=spfile
*
行1でエラーが発生しました。:
ORA-02017: 整数値が必要です。

SQL> alter system set sort_area_size = 2147483648 scope=spfile;
alter system set sort_area_size = 2147483648 scope=spfile
*
行1でエラーが発生しました。:
ORA-02017: 整数値が必要です。

SQL> alter system set bitmap_merge_area_size = 2147483648 scope=spfile;
alter system set bitmap_merge_area_size = 2147483648 scope=spfile
*
行1でエラーが発生しました。:
ORA-02017: 整数値が必要です。

SQL> alter system set create_bitmap_area_size = 2147483648 scope=spfile;
alter system set create_bitmap_area_size = 2147483648 scope=spfile
*
行1でエラーが発生しました。:
ORA-02017: 整数値が必要です。


SQL> --2GB - 1
SQL> select 2*1024*1024*1024-1 from dual;

2*1024*1024*1024-1
------------------
2147483647

SQL> alter system set hash_area_size = 2147483647 scope=spfile;

システムが変更されました。

SQL> alter system set sort_area_size = 2147483647 scope=spfile;

システムが変更されました。

SQL> alter system set bitmap_merge_area_size = 2147483647 scope=spfile;

システムが変更されました。

SQL> alter system set create_bitmap_area_size = 2147483647 scope=spfile;

システムが変更されました。

SQL> shutdown immediate
データベースがクローズされました。
データベースがディスマウントされました。
ORACLEインスタンスがシャットダウンされました。
ERROR:ORA-12514: TNSリスナーは接続記述子でリクエストされたサービスを現在認識していません
SQL> 警告: Oracleにはもう接続されていません。
SQL> exit
Disconnected
C:\Users\discus>set ORACLE_SID=orcl122SQL>
C:\Users\discus>sqlplus / as sysdba
SQL*Plus: Release 12.2.0.1.0 Production on 月 2月 19 22:28:45 2018
Copyright (c) 1982, 2016, Oracle. All rights reserved.
SQL>
アイドル・インスタンスに接続しました。
SQL> create spfile from pfile;
SQL>
File created.
SQL> exit
Disconnected

C:\Users\discus>


ということで、

手動PGA管理でSQL Work Area Sizeを制御する初期化パラメータで指定可能な最大サイズは

2GB -1

ということになります。(HP-UXやAIXは未確認なので情報いただけたら、ここに追記しまーす。:)

次回へつづく。




Temp落ち #1 - "Temp落ち" って?
Temp落ち #2 - PGA (Program Global Area)

| | コメント (0) | トラックバック (0)

2018年2月18日 (日)

Temp落ち #2 - PGA (Program Global Area)

Previously on Mac De Oracle
”Temp落ち”ってなに? 
という話と、それを確認できるツールをいくつか紹介したところまででした。



余談
このネタを書きながら、"Temp落ち"とは異なる理由で今回ネタにするメモリー領域の事を調べていた事を思い出しました。(懐かしい)

当時、自動PGA管理に関する情報があまりなく、新・ソートに関する検証 その1 ペンネーム グリーンペペを隅から隅まで読み試していました:)。その何年か後に、グリーンペペさんが、だれなのかを知ることに。。業界狭いですw

むか〜し、Windows(32bit)環境のOracleで、」ORA-12518が頻発していたトラブルの原因は今回のネタで取り上げるメモリー領域だった!なんてこともあるので、構造等、知ってて損はないですよ:)


では、今回のお話。

"Hash JoinやSortなどの処理をできる限りメモリー上で行う"という、そのメモリー領域とは???
PGA (Program Global Area)と呼ばれるメモリー領域のSQL Work Areaに確保されます。
また、それらのサイズを制御する初期化パラメータがあります。(後述)
PGAは、おおよそ以下のような構造で、サーバープロセスやバックグランドプロセス毎に確保されます。”ここ大切"
Pga

Pgas_processes2_2

Structure_of_pga




参考)
PGAのメモリーサイズを制御するパラメータは、以下の通り(隠しパラメータもありますが、とりあえずデフォルト前提で:)

以下の4パラメータは、手動PGA管理で利用されるパラメータで、自動PGA管理が主流となった今ではあまり利用されることはありません。(たま〜〜に使いたくなるときはありますが、結局使わなかったり、それは別の機会にでも書くことにします)

HASH_AREA_SIZE
https://docs.oracle.com/cd/E82638_01/REFRN/HASH_AREA_SIZE.htm

SORT_AREA_SIZE
https://docs.oracle.com/cd/E82638_01/REFRN/SORT_AREA_SIZE.htm

BITMAP_MERGE_AREA_SIZE
https://docs.oracle.com/cd/E82638_01/REFRN/BITMAP_MERGE_AREA_SIZE.htm

CREATE_BITMAP_AREA_SIZE
https://docs.oracle.com/cd/E82638_01/REFRN/CREATE_BITMAP_AREA_SIZE.htm

Oracle database 9.2.0以降、自動PGA管理が登場し、上記4パラメータで個別にサイズを管理する必要がなくなりました。
PGA_AGGREGATE_TARGET/PGA_AGGREATE_LIMITの2つのパラメータで自動PGA管理で行う方法に慣れておいた方が良いと思います。

余談
ちなみに、10gR1〜11gR2までは、PGA_AGGREGATE_TARGETパラメータだけだったのですが、その頃、自動PGA管理で割り当てられるサイズを検証していたネタは以下:) pga_aggregate_targetでPGA?、_pga_max_sizeでPGA? Season2 #8 http://discus-hamburg.cocolog-nifty.com/mac_de_oracle/2010/09/pga_aggregate-7.html

ところで、ひさびさに以下マニュアルを読んで見たのですが、何度見てもモヤモヤは消えない感じのままなのがつらいです。もう少しなんとかならんかなー。
と思わなくもないです...w 作業領域の割り当てルールを明記しないのは、何故なんだろうと、ズーーーーっと考えてる。書いてくれてれば楽なのにな〜と。

Oracle® Databaseパフォーマンス・チューニング・ガイド 12cリリース2 (12.2) E72901-03
16 プログラム・グローバル領域のチューニング
https://docs.oracle.com/cd/E82638_01/TGDBA/tuning-program-global-area.htm


Oracle® Databaseリファレンス 12cリリース2 (12.2) E72905-03
PGA_AGGREGATE_LIMIT
https://docs.oracle.com/cd/E82638_01/REFRN/PGA_AGGREGATE_LIMIT.htm

12.2からResource Managerを利用して特定のコンシューマ・グループ内の各セッションに割り当てられるようになったようで、 PGAメモリー使用量に絶対制限を設定し、超過した場合にはORA-10260エラーとさせることができるようになったようですね。(まだ試したことはないのですが)

16.3.2 リソース・マネージャを使用したプログラム・グローバル領域のサイズ設定
https://docs.oracle.com/cd/E82638_01/TGDBA/tuning-program-global-area.htm

PGA_AGGREGATE_TARGET
https://docs.oracle.com/cd/E82638_01/REFRN/PGA_AGGREGATE_TARGET.htm


12cの自動PGA管理について軽く確認した感触だと、12cR2でPDB毎の制御ができるようになった事以外、大きな変化ないんじゃないかと思っているのですが、そういえばちゃんと確認したことないな。。。
次回は、昔試した方法で、12cでもPGA割り当てルールに変化はないのか確認しておきますか。。。18cはどうなるんだろ:)


続く。



Temp落ち #1 - "Temp落ち" って?

| | コメント (0) | トラックバック (0)

2017年12月 4日 (月)

”utl_file I/O” - この症状はあれの可能性が高いですね。

JPOUG Advent Calendar 2017の4日目のエントリーです。

さて、最近あまりお目にかかってなかったUTL_FILEパッケージで表データをcsvに書きだすネタにしました。

先日、UTL_FILEパッケージを利用した処理が想定以上に遅いという相談をうけました。
AWRレポートをみると、上位の待機イベントは、”utl_file I/O"。

!!!!おーーーこれは、珍しいというか、久々にみた病気w

UTL_FILEパッケージを利用したI/Oをグルグルしているとか、でかいファイル読み書きしているかの、どちらかですよねw
ということで、この症状の治療法を考えてみます。


<参考 - 環境>

MacBook:˜ system_profiler SPHardwareDataType | grep -E 'Model|Processor|Cores|Memory'
Model Name: MacBook
Model Identifier: MacBook9,1
Processor Name: Intel Core m5
Processor Speed: 1.2 GHz
Number of Processors: 1
Total Number of Cores: 2
Memory: 8 GB

ホストOS
MacBook:˜ discus$ sw_vers
ProductName: Mac OS X
ProductVersion: 10.13.1
BuildVersion: 17B1003

MacBook:˜ discus$ VBoxManage -version
5.1.30r118389


ゲストOSとOracle Database
orcl@SYS> !uname -a
Linux localhost.localdomain 4.1.12-94.3.6.el7uek.x86_64 #2 SMP Tue May 30 19:25:15 PDT 2017 x86_64 x86_64 x86_64 GNU/Linux

orcl@SYS> !cat /etc/oracle-release
Oracle Linux Server release 7.3

orcl@SYS>
orcl@SYS> select * from v$version;

BANNER CON_ID
-------------------------------------------------------------------------------- ----------
Oracle Database 12c Enterprise Edition Release 12.2.0.1.0 - 64bit Production 0
PL/SQL Release 12.2.0.1.0 - Production 0
CORE 12.2.0.1.0 Production 0
TNS for Linux: Version 12.2.0.1.0 - Production 0
NLSRTL Version 12.2.0.1.0 - Production 0

UTL_FILEでファイル出力する際、ちょっとした手順の漏れが性能差として現れてしまうことがあります。
表の行長は数百バイト程度ですが、行数は数千万〜数億行なんていう状況だと、性能差が顕著に現れてしまうので注意が必要です。

以下の表、セグメントサイズは1GB程度ですが、行数は1千万行以上あります。
この表データをUTL_FILEパッケージを利用してcsvに出力してみます。

ORCL@SCOTT> select segment_name,sum(bytes)/1024/1024/1024 "GB" from user_segments group by segment_name;

SEGMENT_NAME GB
------------------------------ ----------
ABOUT_100BYTES_ROWS .9140625
PK_ABOUT_100BYTES_ROWS .171875


ORCL@SCOTT> select count(1) from about_100bytes_rows;

COUNT(1)
----------
10737420

表の1行は100bytes(改行コード含)です。

ORCL@SCOTT%gt; r
1 SELECT
2 LENGTH(
3 TO_CHAR(id,'FM000000000000000000000000000009')
4 ||','||FOO
5 ) row_length
6 FROM
7 about_100bytes_rows
8 WHERE
9* rownum <= 1

ROW_LENGTH
----------
99

次の2つのコードの赤太文字部分に着目してください。
その部分が異なるだけで処理時間に大きな差が出ます。

DECLARE
cDIR_NAME CONSTANT VARCHAR2(30) := 'FILES_DIR';
cFILE_NAME CONSTANT VARCHAR2(128) := 'no_writebuffering_'||TO_CHAR(systimestamp, 'rrmmddhh24miss.ff')||'.txt';
cBufferSize CONSTANT BINARY_INTEGER := 32767;
cOpenMode CONSTANT VARCHAR2(2) := 'w';
fileHandle UTL_FILE.FILE_TYPE;

cBulkReadLimit CONSTANT PLS_INTEGER := 324;
TYPE tBulkReadArray IS TABLE OF VARCHAR2(8192) INDEX BY BINARY_INTEGER;
bulkReadArray tBulkReadArray;
CURSOR cur_about100bytesRow IS
SELECT
TO_CHAR(id,'FM000000000000000000000000000009')
||','||FOO
AS csvrow
FROM
about_100bytes_rows
;
BEGIN
OPEN cur_about100bytesRow;
fileHandle := UTL_FILE.FOPEN(cDIR_NAME, cFILE_NAME, cOpenMode, cBufferSize);
LOOP
FETCH cur_about100bytesRow
BULK COLLECT INTO bulkReadArray
LIMIT cBulkReadLimit;

EXIT WHEN bulkReadArray.COUNT = 0;

FOR i IN bulkReadArray.FIRST..bulkReadArray.LAST LOOP
UTL_FILE.PUT_LINE(
file => fileHandle
, buffer => bulkReadArray(i)
, autoflush => true
);
END LOOP;
END LOOP;
UTL_FILE.FFLUSH(fileHandle);
UTL_FILE.FCLOSE(fileHandle);
CLOSE cur_about100bytesRow;
EXCEPTION
WHEN OTHERS THEN
IF UTL_FILE.IS_OPEN(fileHandle) THEN
UTL_FILE.FCLOSE(fileHandle);
END IF;

IF cur_about100bytesRow%ISOPEN THEN
CLOSE cur_about100bytesRow;
END IF;
RAISE;
END;
/


PL/SQLプロシージャが正常に完了しました。

経過: 00:02:27.05


DECLARE
cDIR_NAME CONSTANT VARCHAR2(30) := 'FILES_DIR';
cFILE_NAME CONSTANT VARCHAR2(128) := 'writebuffering_'||TO_CHAR(systimestamp, 'rrmmddhh24miss.ff')||'.txt';
cBufferSize CONSTANT BINARY_INTEGER := 32767;
cOpenMode CONSTANT VARCHAR2(2) := 'w';
fileHandle UTL_FILE.FILE_TYPE;
buffer VARCHAR2(32767);

cBulkReadLimit CONSTANT PLS_INTEGER := 324;
TYPE tBulkReadArray IS TABLE OF VARCHAR2(8192) INDEX BY BINARY_INTEGER;
bulkReadArray tBulkReadArray;
CURSOR cur_about100bytesRow IS
SELECT
TO_CHAR(id,'FM000000000000000000000000000009')
||','||FOO
AS csvrow
FROM
about_100bytes_rows
;
BEGIN
OPEN cur_about100bytesRow;
fileHandle := UTL_FILE.FOPEN(cDIR_NAME, cFILE_NAME, cOpenMode, cBufferSize);
LOOP
FETCH cur_about100bytesRow
BULK COLLECT INTO bulkReadArray
LIMIT cBulkReadLimit;

EXIT WHEN bulkReadArray.COUNT = 0;

buffer := NULL;
FOR i IN bulkReadArray.FIRST..bulkReadArray.LAST LOOP
buffer := buffer || bulkReadArray(i) || UTL_TCP.CRLF;
END LOOP;
UTL_FILE.PUT(fileHandle, buffer);
UTL_FILE.FFLUSH(fileHandle);
END LOOP;
UTL_FILE.FFLUSH(fileHandle);
UTL_FILE.FCLOSE(fileHandle);
CLOSE cur_about100bytesRow;
EXCEPTION
WHEN OTHERS THEN
IF UTL_FILE.IS_OPEN(fileHandle) THEN
UTL_FILE.FCLOSE(fileHandle);
END IF;

IF cur_about100bytesRow%ISOPEN THEN
CLOSE cur_about100bytesRow;
END IF;
RAISE;
END;
/


PL/SQLプロシージャが正常に完了しました。

経過: 00:00:43.96


何が違うかお分ですよね!
UTL_FILE.PUT_LINE/UTL_FILE.PUTが違う!!w
その部分は重要ではなく、100Bytes単位に書き込んでいるか、約32KB単位で書き込んでいるかが重要なんです。

UTL_FILEは最大32767バイトのバッファを利用できますが、前者はバッファを有効利用せず、100Bytes毎に書き出しています。後者は約32KB単位で書き出しています。

その差はAWRレポートからも見えてきます。


AWRレポート(一部抜粋)
UTL_FILEパッケージによるI/Oの待機は、”utl_file I/O”という待機イベントで現れます。

Avg Waitは短いですが、理由は100バイト単位の小さいなサイズの書き込みを繰り返しているわけなので、そんなとこでしょう。

Top 10 Foreground Events by Total Wait Time

Total Wait Avg % DB Wait
Event Waits Time (sec) Wait time Class
------------------------------ ----------- ---------- --------- ------ --------
DB CPU 147.4 99.3
utl_file I/O 32,212,266 49.5 1.54us 33.3 User I/O
direct path read 1,881 1.2 620.61us .8 User I/O
resmgr:cpu quantum 1 .1 85.85ms .1 Schedule
db file sequential read 17 0 .98ms .0 User I/O
PGA memory operation 90 0 35.13us .0 Other
latch: shared pool 1 0 1.05ms .0 Concurre
control file sequential read 80 0 12.83us .0 System I
Disk file operations I/O 6 0 73.67us .0 User I/O
SQL*Net message to client 2 0 9.00us .0 Network


一方、約32KB単位でバッファリングして書き出している場合、Waits回数が激減しています。
Avg Waitsは大きくなっていますが、書き出しサイズにほぼ比例しているので想定通りというところ。

Top 10 Foreground Events by Total Wait Time

Total Wait Avg % DB Wait
Event Waits Time (sec) Wait time Class
------------------------------ ----------- ---------- --------- ------ --------
DB CPU 45 98.5
utl_file I/O 66,288 27.4 413.54us 60.1 User I/O
direct path read 1,881 1 550.71us 2.3 User I/O
db file sequential read 88 0 443.38us .1 User I/O
direct path write 2 0 4.69ms .0 User I/O
control file sequential read 80 0 33.25us .0 System I
latch: shared pool 1 0 2.38ms .0 Concurre
Disk file operations I/O 4 0 323.50us .0 User I/O
PGA memory operation 79 0 15.73us .0 Other
SQL*Net message to client 4 0 20.25us .0 Network

utl_file.put/put_lineでcsvを出力しているdeviceのiostat(util%)
まだまだ余裕があるのでI/Oで詰まっているのではなく、UTL_FILE.PUT/PUT_LINEの使い方の影響が大きいということですね。
20171203_202342


最後に、
UTL_FILEパッケージの入出力時にはバッファの有効利用をお忘れなく。(つい忘れちゃうこともあるので、急いでるときとかw)
扱うデータが多い場合は得に。

そして、みなさま、
メリークリスマス(まだエントリーを書くかもしれませんがw)
#JPOUG

| | コメント (0) | トラックバック (0)

2017年11月11日 (土)

SDCLI Error Out "Failed to create the processor for command format"

昨日 Windowsの SQL Developer 17.2のsdcliコマンドで整形しようと思ったらハマったので、備忘録


SDCLI Error Out "Failed to create the processor for command format" (Doc ID 2297353.1)

Oracle SQL Developer - Version 17.2 and later
と記載されているようですが、Version4.2で発生していたのでそのまま新版でも引き続き発生してるという感じですね。
改善されるまでの間、面倒くさいので、Version 4.0.2〜4.1.5あたりをインストールしてSQLを整形したほうがイライラしなくてよいと思います。

discus-mother:bin oracle$ cat version.properties
COMPANY=Oracle
PRODUCT=SQL Developer
VERSION=4.2000170891709f
VER=4.2.0
VER_FULL=4.2.0.17.089.1709
BUILD_LABEL=17.089.1709
BUILD_NUM=17.089.1709
EDITION=
discus-mother:bin oracle$
discus-mother:bin oracle$ sdcli format intput=sample.sql output=sample_fmt.sql

Oracle SQL Developer
Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.

Failed to create the processor for command format

私の場合、SQL Developer 4.0.3をインストールしてSQL文整形オンリー使いで回避しました。



参考
SQL Developer 4の素敵なコマンドライン de SQL整形 :)

Note:
ディレクトリ指定の一括変換も動作が怪しいことがあるので、単一のSQL文整形を繰り返すようなshell作ったほうがいいかもしれません。

| | コメント (0) | トラックバック (0)

2017年11月 7日 (火)

DBMS_ADVISOR.CREATE_FILE()プロシージャは、Diagnostic/Tuning Pack不要らしいということの確認

Previously on Mac De Oracle



余談

DBMS_ADVISOR.CREATE_FILEとなっているがライセンス上、diagnostic/tuning packライセンスはなくてもアクセスしてできるように読み取れるのだけと、もしかすると、この影響で、DBMS_ADVISOR.CREATE_FILEの存在は知っていても使ってないのかあるのかな??

以下のマニュアルを読む限り、Diagnostic/Tuning Packでは、DBMS_ADVISORパッケージ全体ではなく、Diagnostic/Tuning Packに関連するパラメータを与える必要のある機能についての制限であることしか記載されていない。
つまり、DBMS_ADVISOR.CREATE_FILE()に関して言えば、Diagnostic/Tuning Pack特有の機能ではないから利用可能なはず。 ←間違ってたらツッコミ希望w

Oracle® Databaseライセンス情報 12cリリース1 (12.1) 2 オプションおよびパック
https://docs.oracle.com/cd/E49329_01/license.121/b71334/options.htm



なんてことを書いたところ、

control_management_pack_access=none

でも使えるとなら間違いなくないんじゃないの?
というコメントがあったので試してみました。 マニュアルの通りだと思われます。ということですね。FAQ!

orcl@SYS> show parameter control_management_pack_access

NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
control_management_pack_access string NONE
orcl@SYS>
orcl@SYS> l
1 DECLARE
2 reportClob CLOB := EMPTY_CLOB();
3 BEGIN
4 reportClob := 'test test test';
5 DBMS_ADVISOR.CREATE_FILE(
6 buffer => reportClob
7 ,location => 'REP_DIR'
8 ,filename => 'test.txt'
9 );
10* END;
orcl@SYS> /

PL/SQLプロシージャが正常に完了しました。

経過: 00:00:00.23
orcl@SYS> !ls report
test.txt

orcl@SYS> !cat report/test.txt
test test test



DBMS_SQLTUNE.PACK_STGTAB_SQLSETって、例外投げんのかよw
SQL Tuning Setのキャプチャから退避までのスクリプト(やっつけ)
SQL Tuning Set (STS)のフィルタリング
DBMS_SQLTUNE.REPORT_ANALYSIS_TASK()ファンクションで生成されるCLOB型のレポートをファイルに保存する簡単な方法

| | コメント (0) | トラックバック (0)

2017年9月 1日 (金)

ORA-12034 #2

前回の通り、高速リフレッシュの間にdata pump export / importを完了させれば、ORA-12034なんて起きないはず。

VirtualBoxの環境は試験開始前のスナップショットで戻してあります
20170415_14044_2

SQL*Plus: Release 12.1.0.2.0 Production on Mon Aug 28 20:57:49 2017

Copyright (c) 1982, 2014, Oracle. All rights reserved.

Connected to:
Oracle Database 12c Enterprise Edition Release 12.1.0.2.0 - 64bit Production
With the Partitioning, OLAP, Advanced Analytics and Real Application Testing options

orcl@MVIEW_SCHEMA1> @mview_info_c
Connected.

¥Session altered.

ROWNER RNAME REFGROUP JOB B INTERVAL NEXT_DATE CON_ID
-------------------- -------------------- ---------- ---------- - -------------------- ------------------- ----------
MVIEW_SCHEMA1 MV_MASTER 61 81 N sysdate+5/1440 2017/08/28 21:00:54 3

MVIEW_NAME REFRES REFRESH_ LAST_REF AFTER_FAST_REFRESH COMPILE_STATE
------------------------------ ------ -------- -------- ------------------- -------------------
MV_MASTER DEMAND FAST FAST UNDEFINED VALID

JOB LOG_USER SCHEMA_USER LAST_DATE NEXT_DATE INTERVAL FAILURES WHAT
---------- -------------------- -------------------- ------------------- ------------------- -------------------- ---------- ------------------------------------------------------------
81 MVIEW_SCHEMA1 MVIEW_SCHEMA1 2017/08/28 20:55:54 2017/08/28 21:00:54 sysdate+5/1440 0 dbms_refresh.refresh('"MVIEW_SCHEMA1"."MV_MASTER"');

前回は5分間隔だったので、余裕をもたせて30分にしてあります。
本番環境で5分間隔の高速リフレッシュを30分にしたり、止めたりってことはかなり敷居が高いとは思いますが、そのあたりは空気を読んで対応する必要があるかと。 :)

orcl12c@SYS> conn mview_schema1@orcl
Connected.
orcl@MVIEW_SCHEMA1> alter materialized view mv_master refresh next sysdate+30/1440;

Materialized view altered.

orcl@MVIEW_SCHEMA1> @mview_info_c
Connected.

Session altered.


ROWNER RNAME REFGROUP JOB B INTERVAL NEXT_DATE CON_ID
-------------------- -------------------- ---------- ---------- - -------------------- ------------------- ----------
MVIEW_SCHEMA1 MV_MASTER 61 81 N sysdate+30/1440 2017/08/28 21:30:36 3

MVIEW_NAME REFRES REFRESH_ LAST_REF AFTER_FAST_REFRESH COMPILE_STATE
------------------------------ ------ -------- -------- ------------------- -------------------
MV_MASTER DEMAND FAST FAST UNDEFINED VALID

JOB LOG_USER SCHEMA_USER LAST_DATE NEXT_DATE INTERVAL FAILURES WHAT
---------- -------------------- -------------------- ------------------- ------------------- -------------------- ---------- ------------------------------------------------------------
81 MVIEW_SCHEMA1 MVIEW_SCHEMA1 2017/08/28 20:55:54 2017/08/28 21:30:36 sysdate+30/1440 0 dbms_refresh.refresh('"MVIEW_SCHEMA1"."MV_MASTER"');

準備は整ったので、高速リフレッシュが終わったタイミングでexportからimportまでをやっつけちゃいます!
まずはエクスポート

Connected to: Oracle Database 12c Enterprise Edition Release 12.1.0.2.0 - 64bit Production
With the Partitioning, OLAP, Advanced Analytics and Real Application Testing options
Starting "SYSTEM"."SYS_EXPORT_SCHEMA_01": system/********@orcl directory=workdir dumpfile=mview_schema1.dmp logfile=exp_mview_schema1.log schemas=mview_schema1
Estimate in progress using BLOCKS method...
Processing object type SCHEMA_EXPORT/TABLE/TABLE_DATA
Total estimation using BLOCKS method: 64 KB
Processing object type SCHEMA_EXPORT/USER
Processing object type SCHEMA_EXPORT/SYSTEM_GRANT
Processing object type SCHEMA_EXPORT/DEFAULT_ROLE
Processing object type SCHEMA_EXPORT/TABLESPACE_QUOTA
Processing object type SCHEMA_EXPORT/PRE_SCHEMA/PROCACT_SCHEMA
Processing object type SCHEMA_EXPORT/DB_LINK
Processing object type SCHEMA_EXPORT/TABLE/TABLE
Processing object type SCHEMA_EXPORT/TABLE/COMMENT
Processing object type SCHEMA_EXPORT/TABLE/CONSTRAINT/CONSTRAINT
Processing object type SCHEMA_EXPORT/TABLE/INDEX/STATISTICS/INDEX_STATISTICS
Processing object type SCHEMA_EXPORT/TABLE/STATISTICS/TABLE_STATISTICS
Processing object type SCHEMA_EXPORT/STATISTICS/MARKER
Processing object type SCHEMA_EXPORT/MATERIALIZED_VIEW
Processing object type SCHEMA_EXPORT/JOB
Processing object type SCHEMA_EXPORT/REFRESH_GROUP
. . exported "MVIEW_SCHEMA1"."MV_MASTER" 5.5 KB 2 rows
Master table "SYSTEM"."SYS_EXPORT_SCHEMA_01" successfully loaded/unloaded
******************************************************************************
Dump file set for SYSTEM.SYS_EXPORT_SCHEMA_01 is:
/u01/userhome/oracle/mview_schema1.dmp
Job "SYSTEM"."SYS_EXPORT_SCHEMA_01" successfully completed at Mon Aug 28 21:05:00 2017 elapsed 0 00:00:56

[oracle@vbgeneric ˜]$ sqlplus master_schema@orcl

SQL*Plus: Release 12.1.0.2.0 Production on Mon Aug 28 21:05:19 2017

Copyright (c) 1982, 2014, Oracle. All rights reserved.


Connected to:
Oracle Database 12c Enterprise Edition Release 12.1.0.2.0 - 64bit Production
With the Partitioning, OLAP, Advanced Analytics and Real Application Testing options

orcl@MASTER_SCHEMA> select count(*) from mlog$_master;

COUNT(*)
----------
0

orcl@MASTER_SCHEMA> conn mview_schema1@orcl
Connected.

orcl@MVIEW_SCHEMA1> @mview_info_c
Connected.

Session altered.


ROWNER RNAME REFGROUP JOB B INTERVAL NEXT_DATE CON_ID
-------------------- -------------------- ---------- ---------- - -------------------- ------------------- ----------
MVIEW_SCHEMA1 MV_MASTER 61 81 N sysdate+30/1440 2017/08/28 21:30:36 3

MVIEW_NAME REFRES REFRESH_ LAST_REF AFTER_FAST_REFRESH COMPILE_STATE
------------------------------ ------ -------- -------- ------------------- -------------------
MV_MASTER DEMAND FAST FAST UNDEFINED VALID

JOB LOG_USER SCHEMA_USER LAST_DATE NEXT_DATE INTERVAL FAILURES WHAT
---------- -------------------- -------------------- ------------------- ------------------- -------------------- ---------- ------------------------------------------------------------
81 MVIEW_SCHEMA1 MVIEW_SCHEMA1 2017/08/28 20:55:54 2017/08/28 21:30:36 sysdate+30/1440 0 dbms_refresh.refresh('"MVIEW_SCHEMA1"."MV_MASTER"');

次にインポートしてMviewを複製! 

orcl12c@SYS> conn system@orcl2
Connected.
orcl2@SYSTEM> create directory workdir as '/u01/userhome/oracle';

Directory created.

orcl2@SYSTEM> exit
Disconnected from Oracle Database 12c Enterprise Edition Release 12.1.0.2.0 - 64bit Production
With the Partitioning, OLAP, Advanced Analytics and Real Application Testing options
[oracle@vbgeneric ˜]$ impdp system@orcl2 directory=workdir dumpfile=mview_schema1.dmp logfile=imp_mview_schema1.dmp

Import: Release 12.1.0.2.0 - Production on Mon Aug 28 21:07:13 2017

Copyright (c) 1982, 2014, Oracle and/or its affiliates. All rights reserved.

Connected to: Oracle Database 12c Enterprise Edition Release 12.1.0.2.0 - 64bit Production
With the Partitioning, OLAP, Advanced Analytics and Real Application Testing options
Master table "SYSTEM"."SYS_IMPORT_FULL_01" successfully loaded/unloaded
Starting "SYSTEM"."SYS_IMPORT_FULL_01": system/********@orcl2 directory=workdir dumpfile=mview_schema1.dmp logfile=imp_mview_schema1.dmp
Processing object type SCHEMA_EXPORT/USER
Processing object type SCHEMA_EXPORT/SYSTEM_GRANT
Processing object type SCHEMA_EXPORT/DEFAULT_ROLE
Processing object type SCHEMA_EXPORT/TABLESPACE_QUOTA
Processing object type SCHEMA_EXPORT/PRE_SCHEMA/PROCACT_SCHEMA
Processing object type SCHEMA_EXPORT/DB_LINK
Processing object type SCHEMA_EXPORT/TABLE/TABLE
Processing object type SCHEMA_EXPORT/TABLE/TABLE_DATA
. . imported "MVIEW_SCHEMA1"."MV_MASTER" 5.5 KB 2 rows
Processing object type SCHEMA_EXPORT/TABLE/COMMENT
Processing object type SCHEMA_EXPORT/TABLE/CONSTRAINT/CONSTRAINT
Processing object type SCHEMA_EXPORT/TABLE/INDEX/STATISTICS/INDEX_STATISTICS
Processing object type SCHEMA_EXPORT/TABLE/STATISTICS/TABLE_STATISTICS
Processing object type SCHEMA_EXPORT/STATISTICS/MARKER
Processing object type SCHEMA_EXPORT/MATERIALIZED_VIEW
Processing object type SCHEMA_EXPORT/JOB
Processing object type SCHEMA_EXPORT/REFRESH_GROUP
Job "SYSTEM"."SYS_IMPORT_FULL_01" successfully completed at Mon Aug 28 21:07:40 2017 elapsed 0 00:00:23

複製完了!!!!
結果はいかに...

[oracle@vbgeneric ˜]$ sqlplus mview_schema1@orcl2

SQL*Plus: Release 12.1.0.2.0 Production on Mon Aug 28 21:08:09 2017

Copyright (c) 1982, 2014, Oracle. All rights reserved.


Connected to:
Oracle Database 12c Enterprise Edition Release 12.1.0.2.0 - 64bit Production
With the Partitioning, OLAP, Advanced Analytics and Real Application Testing options

orcl2@MVIEW_SCHEMA1> @mview_info_c
Connected.

Session altered.

ROWNER RNAME REFGROUP JOB B INTERVAL NEXT_DATE CON_ID
-------------------- -------------------- ---------- ---------- - -------------------- ------------------- ----------
MVIEW_SCHEMA1 MV_MASTER 61 81 N sysdate+30/1440 2017/08/28 22:00:46 5
MVIEW_SCHEMA1 MV_MASTER 61 81 N sysdate+30/1440 2017/08/28 22:00:46 3

MVIEW_NAME REFRES REFRESH_ LAST_REF AFTER_FAST_REFRESH COMPILE_STATE
------------------------------ ------ -------- -------- ------------------- -------------------
MV_MASTER DEMAND FAST FAST UNDEFINED VALID
MV_MASTER DEMAND FAST FAST UNDEFINED VALID

JOB LOG_USER SCHEMA_USER LAST_DATE NEXT_DATE INTERVAL FAILURES WHAT
---------- -------------------- -------------------- ------------------- ------------------- -------------------- ---------- ------------------------------------------------------------
81 MVIEW_SCHEMA1 MVIEW_SCHEMA1 2017/08/28 21:30:46 2017/08/28 22:00:46 sysdate+30/1440 0 dbms_refresh.refresh('"MVIEW_SCHEMA1"."MV_MASTER"');
81 MVIEW_SCHEMA1 MVIEW_SCHEMA1 2017/08/28 21:30:46 2017/08/28 22:00:46 sysdate+30/1440 0 dbms_refresh.refresh('"MVIEW_SCHEMA1"."MV_MASTER"');

予想通り成功しました!

エクスポート〜インポートによるMVIEW複製までを高速リフレッシュの間に行うことが可能ならば例のエラーは回避できることが確認できました。
が、
小さなMViewならまだしも、巨大なMView、巨大なMViewが複数あるリフレッシュグループだったりすると、それはもう大変な作業になることは想像できます。
大人の事情でMViewの高速リフレッシュを止められない、とか高速リフレッシュ間隔が非常短い場合には無理しないで、ほかの手を考えた方が良いと思います。
ただし、他の手を進めるにも時間には余裕を持った方がいいですよね。なんでギリギリなんだろうねと、よく思います。
夏休みの最後の1週間で宿題全部やりきるみたいなのは嫌ですよねw
20170802_140801




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へ複製(オプジェクトパスが不足すると...)
ORA-12034

| | コメント (0) | トラックバック (0)

2017年8月31日 (木)

ORA-12034

一ヶ月の家庭内、ワンオペも無事終了したので、ブログも今年前半のペースで再開か!?w

ということで、
以前ちょっとだけ書いた高速リフレッシュを止めてないと完全リフレッシュが必要になってしまう。タイミングの問題にフォーカスしてみようと思います。

どのようなタイミングの問題かというと、

ORA-12034: materialized view log on "xxxxxx"."xxxxxxx" younger than last refresh

出会った方も意外と多かったりしてw 

前述のエラーは、materialized view logが絡んいるので、”高速リフレッシュ”時に発生するエラーです!
高速リフレッシュを行なっている環境でこの状態になってしまうと、”高速リフレッシュ”の再開には”完全リフレッシュ”が必須となってしまうところが怖いというか面倒くさいところ。
マスターサイトも含めて同期するサイズが小さければ完全リフレッシュも面倒なことにならない場合もありますが、数十GB以上の巨大なマテビューだったら、どうします???
マテリアライズドビューのリフレッシュ間隔が短いシステムだと、完全リフレッシュに要する時間が大問題になることも... (色々な状況が想定されていない構成だと、そうなりやすい.....なw

もう少し簡単に言うと、
materialized view logの伝播が必要なデータ有無に関係なく、リフレッシュ時刻を跨いてしまうかどうか! なんですよね、これ。

実際にどうなるか、materialized view logは空の状態で、Data Pumpも癖モノだよね〜w その2 - Materialized ViewをTableとして移行する
の環境を利用して再現させてみます。環境の詳細は、Data Pumpも癖モノだよね〜w その4 - schemaモードでMviewを他のPDBへ複製参照のこと。


VirtualBoxのスナップショットから基本レプリケーション環境構築済みの状態(以前いろいろ行った試験前の状態)に戻してあります。
20170415_14044

まず、高速リフレッシュの状態がどうなっているか確認してみると....5分間隔(INTERVAL列)で動作中であることがわかりますよね!(DBMS_JOBのINTERVALの指定方法っ非直感的わかりづらいので早くなくなってほしいw)
直近の高速リフレッシュが終わり、MLOGも0件。つまりマテリアライズドビューに反映する必要のあるデータは存在しない状態にしてあります。


orcl@MVIEW_SCHEMA1> select job,log_user,schema_user,last_date,next_date,interval,failures,what from user_jobs;

JOB LOG_USER SCHEMA_USER LAST_DATE NEXT_DATE INTERVAL FAILURES WHAT
---------- -------------------- -------------------- ------------------- ------------------- -------------------- ---------- ------------------------------------------------------------
81 MVIEW_SCHEMA1 MVIEW_SCHEMA1 2017/08/28 09:00:44 2017/08/28 09:05:44 sysdate+5/1440 0 dbms_refresh.refresh('"MVIEW_SCHEMA1"."MV_MASTER"');

前述の状態(5分間隔の高速リフレッシュが動作中の状態)で、次の高速リフレッシュが実行されるまでの間にマテリアライズドビュー関連オブジェクトを含むschemaを丸ごとエクスポートします(他のデータベースへ複製するために)
エラーを再現するData Pump Export、Importと高速リフレッシュ間隔との間合いは下図の通り
20170802_140338

上図の通りの流れでData Pump ExportからImportまでを行い、ORA-12034の発生状況を確認

Connected to: Oracle Database 12c Enterprise Edition Release 12.1.0.2.0 - 64bit Production
With the Partitioning, OLAP, Advanced Analytics and Real Application Testing options
Starting "SYSTEM"."SYS_EXPORT_SCHEMA_01": system/********@orcl directory=workdir dumpfile=mview_schema1.dmp logfile=exp_mview_schema1.log schemas=mview_schema1
Estimate in progress using BLOCKS method...
Processing object type SCHEMA_EXPORT/TABLE/TABLE_DATA
Total estimation using BLOCKS method: 64 KB
Processing object type SCHEMA_EXPORT/USER
Processing object type SCHEMA_EXPORT/SYSTEM_GRANT
Processing object type SCHEMA_EXPORT/DEFAULT_ROLE
Processing object type SCHEMA_EXPORT/TABLESPACE_QUOTA
Processing object type SCHEMA_EXPORT/PRE_SCHEMA/PROCACT_SCHEMA
Processing object type SCHEMA_EXPORT/DB_LINK
Processing object type SCHEMA_EXPORT/TABLE/TABLE
Processing object type SCHEMA_EXPORT/TABLE/COMMENT
Processing object type SCHEMA_EXPORT/TABLE/CONSTRAINT/CONSTRAINT
Processing object type SCHEMA_EXPORT/TABLE/INDEX/STATISTICS/INDEX_STATISTICS
Processing object type SCHEMA_EXPORT/TABLE/STATISTICS/TABLE_STATISTICS
Processing object type SCHEMA_EXPORT/STATISTICS/MARKER
Processing object type SCHEMA_EXPORT/MATERIALIZED_VIEW
Processing object type SCHEMA_EXPORT/JOB
Processing object type SCHEMA_EXPORT/REFRESH_GROUP
. . exported "MVIEW_SCHEMA1"."MV_MASTER" 5.5 KB 2 rows
Master table "SYSTEM"."SYS_EXPORT_SCHEMA_01" successfully loaded/unloaded
******************************************************************************
Dump file set for SYSTEM.SYS_EXPORT_SCHEMA_01 is:
/u01/userhome/oracle/mview_schema1.dmp
Job "SYSTEM"."SYS_EXPORT_SCHEMA_01" successfully completed at Mon Aug 28 09:02:48 2017 elapsed 0 00:00:54


念のためマスターサイトでMLOGの件数を確認しておきます。
マテビューサイトと同期する必要のあるデータはないことが確認できます。

orcl@MASTER_SCHEMA> select count(*) from mlog$_master;

COUNT(*)
----------
0


という確認を行なっている間いに高速リフレッシュが実行されました! (LAST_DATE列、NEXT_DATE列、FAILURES列から正常にリフレッシュされたことを確認できます)

orcl@MVIEW_SCHEMA1> select job,log_user,schema_user,last_date,next_date,interval,failures,what from user_jobs;
JOB LOG_USER SCHEMA_USER LAST_DATE NEXT_DATE INTERVAL FAILURES WHAT
---------- -------------------- -------------------- ------------------- ------------------- -------------------- ---------- ------------------------------------------------------------
81 MVIEW_SCHEMA1 MVIEW_SCHEMA1 2017/08/28 09:05:48 2017/08/28 09:10:48 sysdate+5/1440 0 dbms_refresh.refresh('"MVIEW_SCHEMA1"."MV_MASTER"');

まず、異なるPDBにディレクトリオブジェクトを作成して、schemaごとインポートします。
この時点で以前のエントリにもあるようにORCL:master_schema.masterをマスターサイトするmviewが、ORCL:mview_schema1.mview_masterとORCL2:mview_schema1.mview_masterという構成になります。


orcl2@SYSTEM> create directory workdir as '/u01/userhome/oracle';

Directory created.


Starting "SYSTEM"."SYS_IMPORT_FULL_01": system/********@orcl2 directory=workdir dumpfile=mview_schema1.dmp logfile=imp_mview_schema1.dmp
Processing object type SCHEMA_EXPORT/USER
Processing object type SCHEMA_EXPORT/SYSTEM_GRANT
Processing object type SCHEMA_EXPORT/DEFAULT_ROLE
Processing object type SCHEMA_EXPORT/TABLESPACE_QUOTA
Processing object type SCHEMA_EXPORT/PRE_SCHEMA/PROCACT_SCHEMA
Processing object type SCHEMA_EXPORT/DB_LINK
Processing object type SCHEMA_EXPORT/TABLE/TABLE
Processing object type SCHEMA_EXPORT/TABLE/TABLE_DATA
. . imported "MVIEW_SCHEMA1"."MV_MASTER" 5.5 KB 2 rows
Processing object type SCHEMA_EXPORT/TABLE/COMMENT
Processing object type SCHEMA_EXPORT/TABLE/CONSTRAINT/CONSTRAINT
Processing object type SCHEMA_EXPORT/TABLE/INDEX/STATISTICS/INDEX_STATISTICS
Processing object type SCHEMA_EXPORT/TABLE/STATISTICS/TABLE_STATISTICS
Processing object type SCHEMA_EXPORT/STATISTICS/MARKER
Processing object type SCHEMA_EXPORT/MATERIALIZED_VIEW
Processing object type SCHEMA_EXPORT/JOB
Processing object type SCHEMA_EXPORT/REFRESH_GROUP
Job "SYSTEM"."SYS_IMPORT_FULL_01" successfully completed at Mon Aug 28 10:02:09 2017 elapsed 0 00:00:22


インポートが無事終わったので、高速リフレッシュの状態を確認!!

おおおおおおおお〜〜、インポートしたschemaに含まれるMVIEWは高速リフレッシュに失敗しています。
なんということでしょうw(狙い通りなので、わざとらしいですねw)

なお、LAST_REF列がCOMPLETEという完全リフレッシュを示すステータスになっていますが、これはで確認下通り、昔からこんな動作だった曖昧な記憶があるので仕様だと思われますが、
インポート時に完全リフレッシュしているわけでもないのに、完全リフレッシュ扱いとされている紛らわしい状態になります。(このステータスが影響している可能性もありそうな...)

orcl2@MVIEW_SCHEMA1> @mview_info_c
Connected.

Session altered.

ROWNER RNAME REFGROUP JOB B INTERVAL NEXT_DATE CON_ID
-------------------- -------------------- ---------- ---------- - -------------------- ------------------- ----------
MVIEW_SCHEMA1 MV_MASTER 61 81 N sysdate+5/1440 2017/08/28 10:06:46 3
MVIEW_SCHEMA1 MV_MASTER 61 81 N sysdate+5/1440 2017/08/28 10:04:22 5


MVIEW_NAME REFRES REFRESH_ LAST_REF AFTER_FAST_REFRESH COMPILE_STATE
------------------------------ ------ -------- -------- ------------------- -------------------
MV_MASTER DEMAND FAST FAST UNDEFINED VALID
MV_MASTER DEMAND FAST COMPLETE UNDEFINED VALID


JOB LOG_USER SCHEMA_USER LAST_DATE NEXT_DATE INTERVAL FAILURES WHAT
---------- -------------------- -------------------- ------------------- ------------------- -------------------- ---------- ------------------------------------------------------------
81 MVIEW_SCHEMA1 MVIEW_SCHEMA1 2017/08/28 10:01:46 2017/08/28 10:06:46 sysdate+5/1440 0 dbms_refresh.refresh('"MVIEW_SCHEMA1"."MV_MASTER"');
81 MVIEW_SCHEMA1 MVIEW_SCHEMA1 2017/08/28 10:04:22 sysdate+5/1440 1 dbms_refresh.refresh('"MVIEW_SCHEMA1"."MV_MASTER"');


高速リフレッシュのが実行され2度目の失敗、failusers列が2になっています。いずれ高速リフレッシュジョブは自動的に停止されます。
(自動停止される前に問題に対処すればそのまま継続されます)

orcl2@MVIEW_SCHEMA1> @mview_info_c
Connected.

Session altered.

ROWNER RNAME REFGROUP JOB B INTERVAL NEXT_DATE CON_ID
-------------------- -------------------- ---------- ---------- - -------------------- ------------------- ----------
MVIEW_SCHEMA1 MV_MASTER 61 81 N sysdate+5/1440 2017/08/28 10:08:26 5
MVIEW_SCHEMA1 MV_MASTER 61 81 N sysdate+5/1440 2017/08/28 10:06:46 3


MVIEW_NAME REFRES REFRESH_ LAST_REF AFTER_FAST_REFRESH COMPILE_STATE
------------------------------ ------ -------- -------- ------------------- -------------------
MV_MASTER DEMAND FAST FAST UNDEFINED VALID
MV_MASTER DEMAND FAST COMPLETE UNDEFINED VALID


JOB LOG_USER SCHEMA_USER LAST_DATE NEXT_DATE INTERVAL FAILURES WHAT
---------- -------------------- -------------------- ------------------- ------------------- -------------------- ---------- ------------------------------------------------------------
81 MVIEW_SCHEMA1 MVIEW_SCHEMA1 2017/08/28 10:01:46 2017/08/28 10:06:46 sysdate+5/1440 0 dbms_refresh.refresh('"MVIEW_SCHEMA1"."MV_MASTER"');
81 MVIEW_SCHEMA1 MVIEW_SCHEMA1 2017/08/28 10:08:26 sysdate+5/1440 2 dbms_refresh.refresh('"MVIEW_SCHEMA1"."MV_MASTER"');

では、原因を調査してみましょう!


P列(POSSIBLE列)の REFRESH_FAST行がNになっていて高速リフレッシュできない状態になっています。
コメントにはmv log is newer than last full refresh 記載されています。 このメッセージ冒頭で書いたメッセージと微妙に違うのですが、

orcl2@MVIEW_SCHEMA1> @?/rdbms/admin/utlxmv

Table created.

orcl2@MVIEW_SCHEMA1> exec dbms_mview.explain_mview('MV_MASTER','TEST01');

PL/SQL procedure successfully completed.

orcl2@MVIEW_SCHEMA1> SELECT mvname,capability_name,related_text,related_num,msgno,possible,msgtxt,seq FROM mv_capabilities_table;

MVNAME CAPABILITY_NAME RELATED_TEXT RELATED_NUM MSGNO P MSGTXT SEQ
------------------------------ ------------------------------ -------------------- ----------- ---------- - ------------------------------------------------------------------------------------------ ----------
MV_MASTER PCT N 1
MV_MASTER REFRESH_COMPLETE Y 1002
MV_MASTER REFRESH_FAST N 2003
MV_MASTER REWRITE N 3004
MV_MASTER PCT_TABLE MASTER 52 2068 N relation is not a partitioned table 4005
MV_MASTER REFRESH_FAST_AFTER_INSERT MASTER_SCHEMA.MASTER 2077 N mv log is newer than last full refresh 5006
MV_MASTER REFRESH_FAST_AFTER_ONETAB_DML 2146 N see the reason why REFRESH_FAST_AFTER_INSERT is disabled 6007
MV_MASTER REFRESH_FAST_AFTER_ANY_DML 2161 N see the reason why REFRESH_FAST_AFTER_ONETAB_DML is disabled 7008
MV_MASTER REFRESH_FAST_PCT 2197 N PCT FAST REFRESH is not possible if query contains a remote table 8009
MV_MASTER REWRITE_FULL_TEXT_MATCH MASTER 52 2099 N mv references a remote table or view in the FROM list 9010
MV_MASTER REWRITE_FULL_TEXT_MATCH 2159 N query rewrite is disabled on the materialized view 9011
MV_MASTER REWRITE_PARTIAL_TEXT_MATCH 2159 N query rewrite is disabled on the materialized view 10012
MV_MASTER REWRITE_GENERAL 2159 N query rewrite is disabled on the materialized view 11013
MV_MASTER REWRITE_PCT 2158 N general rewrite is not possible or PCT is not possible on any of the detail tables 12014
MV_MASTER PCT_TABLE_REWRITE MASTER 52 2068 N relation is not a partitioned table 13015

15 rows selected.


試しに手動で高速リフレッシュさせてみます。

orcl2@MVIEW_SCHEMA1> exec dbms_refresh.refresh('"MVIEW_SCHEMA1"."MV_MASTER"');
BEGIN dbms_refresh.refresh('"MVIEW_SCHEMA1"."MV_MASTER"'); END;

*
ERROR at line 1:
ORA-12034: materialized view log on "MASTER_SCHEMA"."MASTER" younger than last refresh
ORA-06512: at "SYS.DBMS_SNAPSHOT", line 2821
ORA-06512: at "SYS.DBMS_SNAPSHOT", line 3058
ORA-06512: at "SYS.DBMS_IREFRESH", line 687
ORA-06512: at "SYS.DBMS_REFRESH", line 195
ORA-06512: at line 1


冒頭で説明した高速リフレッシュ時のエラーが発生していることがわかります。
そして、.......
このエラーが発生してしまうと、完全リフレッシュで回復させるしかありません!!!!! 


参考:
新規マテリアライズド・ビュー・サイトでの高速リフレッシュ・エラー

"新規マテリアライズド・ビュー・サイトでマテリアライズド・ビュー作成中に、マスター表またはマスター・マテリアライズド・ビューのマテリアライズド・ビュー・ログがパージされる場合があります。これが発生すると、次のエラーが検出される場合があります。

ORA-12004 REFRESH FAST cannot be used for materialized view materialized_view_name
ORA-12034 materialized view log on materialized_view_name younger than last refresh"


回避策として使えそうな方法は....
高速リフレッシュを停止して行う方法もあります(止められないシステムもあるので大人の事情しだいでしょうけど)
デプロイメントテンプレートで対応できそうな要件か十分検討、検証した上でやる必要があると思います。(完全リフレッシュするマテビューが巨大すぎて完全リフレッシュだけで作業時間オーバーなんてこともありえますから)

マニュアルに記載されている回避方法ってのもあるけど、手順がめんどくさい>< な。 可能なら止めちゃった方が楽そうだが、大人の事情が絡んでるとそうもいかないだろうし、結局めんどくさいw
めんどくさいの嫌いなので試したこともないんだけど、時間があったら回避できるか試してみるか....な。

新規マテリアライズド・ビュー・サイトを追加するときの問題の回避


次回は、高速リフレッシュを跨がないように、したら回避できるよね。と言うお話へつづく
リフレッシュの間に終わらないとNGだけどw 、高速リフレッシュの間にexport/importが終わればこの問題は発生しない。。わけで。
次回のネタのイメージ(リフレッシュをまた跨らなければ例のエラーは発生しないという確認:)
20170802_140351




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へ複製(オプジェクトパスが不足すると...)