ねら~ITエンジニア雑記

やきうのお兄ちゃんが綴るOracle Databaseメインのブログ

CLOB型の(文字数ではなく)バイト数を返却するファンクションを自作(Oracle Database)

昔の記事(https://gonsuke777.hatenablog.com/entry/20150129/1422535354)が間違っていたので、訂正を兼ねた記事を作成彡(゚)(゚)

CLOB型の(文字数ではなく)バイト数を返却するファンクションを自作してみます。

CONVERTTOBLOBプロシージャでCLOB型をBLOB型に変換して、 そのバイト数をDBMS_LOB.GETLENGTHを変換するやで彡(゚)(゚)

1. ファイルのバイト数と中身

下記のUTF-8エンコードのテキストファイル(2057850バイト)をOracle Databaseにロードして検証します。ASCII文字とひらがなと4バイトの文字を混ぜています。

ls -la clob_test2.txt
-rw-r--r--. 1 oracle oinstall 2057850 Aug 19 22:29 clob_test2.txt

cat clob_test2.txt

aaabbbcccあああいいいううう𡚴𡸴𣇄𣗄𣜿𣝣𣳾aaabbbcccあああいいいううう𡚴𡸴𣇄𣗄𣜿𣝣𣳾…
aaabbbcccあああいいいううう𡚴𡸴𣇄𣗄𣜿𣝣𣳾aaabbbcccあああいいいううう𡚴𡸴𣇄𣗄𣜿𣝣𣳾…
:
aaabbbcccあああいいいううう𡚴𡸴𣇄𣗄𣜿𣝣𣳾aaabbbcccあああいいいううう𡚴𡸴𣇄𣗄𣜿𣝣𣳾…
aaabbbcccあああいいいううう𡚴𡸴𣇄𣗄𣜿𣝣𣳾aaabbbcccあああいいいううう𡚴𡸴𣇄𣗄𣜿𣝣𣳾…

テキストファイルのロードは下記記事を参照彡(゚)(゚)

DBMS_LOB.LoadClobFromFileプロシージャを使って
テキストファイルを Oracle Database の CLOB型列 に ロードする。
https://gonsuke777.hatenablog.com/entry/20160815/1471259132

2. 自作ファンクションFNC_CLOB_LENBの作成

自作ファンクションの作成、前述した通りCONVERTTOBLOBプロシージャで CLOB型をBLOB型に変換して、そのバイト数をDBMS_LOB.GETLENGTHを変換してます。

CREATE OR REPLACE FUNCTION FNC_CLOB_LENB(
  clob_in IN CLOB
)
RETURN NUMBER
IS
  blob_tmp BLOB;
  i_d_offset INTEGER;
  i_s_offset INTEGER;
  i_l_contxt INTEGER;
  i_warning  INTEGER;
BEGIN
  -- Initialize
  DBMS_LOB.CREATETEMPORARY(blob_tmp, FALSE, DBMS_LOB.CALL);
  i_d_offset := 1;
  i_s_offset := 1;
  i_l_contxt := 0;
  -- CONVERT CLOB to BLOB
  DBMS_LOB.CONVERTTOBLOB(
      blob_tmp                   -- dest_lob
    , clob_in                    -- src_blob
    , DBMS_LOB.LOBMAXSIZE        -- amount
    , i_d_offset                 -- dest_offset
    , i_s_offset                 -- src_offset
    , NLS_CHARSET_ID('AL32UTF8') -- blob_csid
    , i_l_contxt                 -- lang_context
    , i_warning                  -- warning
  );
  RETURN DBMS_LOB.GETLENGTH(blob_tmp);
END;
/

Function created.

3. 検証結果

結果は下記の通り、自作ファンクションの方は ls の結果と一致してるやで!彡(^)(^)

SELECT DBMS_LOB.GETLENGTH(C2), FNC_CLOB_LENB(C2) FROM TEST_CLOB;

DBMS_LOB.GETLENGTH(C2) FNC_CLOB_LENB(C2)
---------------------- -----------------
               1033498           2057850

4. 参考

以下のマニュアルと記事を参考にしました彡(゚)(゚)

Oracle Database PL/SQLパッケージおよびタイプ・リファレンス 18c
93 DBMS_LOB
https://docs.oracle.com/cd/E96517_01/arpls/DBMS_LOB.html#GUID-A35DE03B-41A6-4E55-8CDE-77737FED9306
 
oracle CLOBの項目のバイト数を計算するテクニック
https://qiita.com/wagase/items/39c29d3720901e6ef331
 
Oracle Database SQL言語リファレンス 18c
NLS_CHARSET_ID
https://docs.oracle.com/cd/E96517_01/sqlrf/NLS_CHARSET_ID.html#GUID-733B03A0-CD66-4645-A323-401A176499E3

LOCALTIMESTAMP, CURRENT_TIMESTAMP, SYSTIMESTAMP の各組み込み関数の挙動を検証してみる。(Oracle Database)

ワイの中で今サマータイムがアツい彡(゚)(゚) サマータイムに絡んで、Oracle Database の組み込み関数の LOCALTIMESTAMP, CURRENT_TIMESTAMP, SYSTIMESTAMP の挙動を検証してみる。

1. Case1. OSタイムゾーンが日本(JST)の状態で検証

まずOSのタイムゾーンが日本(JST)の状態で検証彡(゚)(゚)

date
Thu Aug 16 14:40:09 JST 2018
-- Initialize
SET LINESIZE 300;
SET PAGESIZE 100;
COLUMN SESSIONTIMEZONE   FORMAT A15;
COLUMN LOCALTIMESTAMP    FORMAT A30;
COLUMN CURRENT_TIMESTAMP FORMAT A42;
COLUMN SYSTIMESTAMP      FORMAT A42;
ALTER SESSION SET NLS_TIMESTAMP_FORMAT    = 'YYYY/MM/DD HH24:MI:SS.FF';
ALTER SESSION SET NLS_TIMESTAMP_TZ_FORMAT = 'YYYY/MM/DD HH24:MI:SS.FF TZR TZD';

ALTER SESSION SET TIME_ZONE = 'UCT';
SELECT SESSIONTIMEZONE, LOCALTIMESTAMP, CURRENT_TIMESTAMP, SYSTIMESTAMP FROM DUAL;

ALTER SESSION SET TIME_ZONE = 'Asia/Tokyo';
SELECT SESSIONTIMEZONE, LOCALTIMESTAMP, CURRENT_TIMESTAMP, SYSTIMESTAMP FROM DUAL;

ALTER SESSION SET TIME_ZONE = 'US/Pacific';
SELECT SESSIONTIMEZONE, LOCALTIMESTAMP, CURRENT_TIMESTAMP, SYSTIMESTAMP FROM DUAL;

SESSIONTIMEZONE LOCALTIMESTAMP                 CURRENT_TIMESTAMP                          SYSTIMESTAMP
--------------- ------------------------------ ------------------------------------------ ------------------------------------------
UCT             2018/08/16 05:43:35.927468     2018/08/16 05:43:35.927468 UCT UCT         2018/08/16 14:43:35.927370 +09:00

SESSIONTIMEZONE LOCALTIMESTAMP                 CURRENT_TIMESTAMP                          SYSTIMESTAMP
--------------- ------------------------------ ------------------------------------------ ------------------------------------------
Asia/Tokyo      2018/08/16 14:43:35.973241     2018/08/16 14:43:35.973241 ASIA/TOKYO JST  2018/08/16 14:43:35.973227 +09:00

SESSIONTIMEZONE LOCALTIMESTAMP                 CURRENT_TIMESTAMP                          SYSTIMESTAMP
--------------- ------------------------------ ------------------------------------------ ------------------------------------------
US/Pacific      2018/08/15 22:43:36.026801     2018/08/15 22:43:36.026801 US/PACIFIC PDT  2018/08/16 14:43:36.026789 +09:00

LOCALTIMESTAMP と CURRENT_TIMESTAMP は SESSION の TIME_ZONE の影響を受けてるけど、SYSTIMESTAMPは無影響やね彡(゚)(゚)。

2. Case2. OSタイムゾーンをロサンゼルスに変更して検証

次にOSタイムゾーンをロサンゼルスに変更して検証してみる。 ロスは2018/8/16現在、太平洋夏時間(PDT)やね彡(゚)(゚)

cp -p /usr/share/zoneinfo/America/Los_Angeles /etc/localtime
date
Thu Aug 16 23:04:25 PDT 2018
-- Initialize
SET LINESIZE 300;
SET PAGESIZE 100;
COLUMN SESSIONTIMEZONE   FORMAT A15;
COLUMN LOCALTIMESTAMP    FORMAT A30;
COLUMN CURRENT_TIMESTAMP FORMAT A42;
COLUMN SYSTIMESTAMP      FORMAT A42;
ALTER SESSION SET NLS_TIMESTAMP_FORMAT    = 'YYYY/MM/DD HH24:MI:SS.FF';
ALTER SESSION SET NLS_TIMESTAMP_TZ_FORMAT = 'YYYY/MM/DD HH24:MI:SS.FF TZR TZD';

ALTER SESSION SET TIME_ZONE = 'UCT';
SELECT SESSIONTIMEZONE, LOCALTIMESTAMP, CURRENT_TIMESTAMP, SYSTIMESTAMP FROM DUAL;

ALTER SESSION SET TIME_ZONE = 'Asia/Tokyo';
SELECT SESSIONTIMEZONE, LOCALTIMESTAMP, CURRENT_TIMESTAMP, SYSTIMESTAMP FROM DUAL;

ALTER SESSION SET TIME_ZONE = 'US/Pacific';
SELECT SESSIONTIMEZONE, LOCALTIMESTAMP, CURRENT_TIMESTAMP, SYSTIMESTAMP FROM DUAL;

SESSIONTIMEZONE LOCALTIMESTAMP                 CURRENT_TIMESTAMP                          SYSTIMESTAMP
--------------- ------------------------------ ------------------------------------------ ------------------------------------------
UCT             2018/08/16 05:45:19.484222     2018/08/16 05:45:19.484222 UCT UCT         2018/08/15 22:45:19.484217 -07:00

SESSIONTIMEZONE LOCALTIMESTAMP                 CURRENT_TIMESTAMP                          SYSTIMESTAMP
--------------- ------------------------------ ------------------------------------------ ------------------------------------------
Asia/Tokyo      2018/08/16 14:45:19.526919     2018/08/16 14:45:19.526919 ASIA/TOKYO JST  2018/08/15 22:45:19.526914 -07:00

SESSIONTIMEZONE LOCALTIMESTAMP                 CURRENT_TIMESTAMP                          SYSTIMESTAMP
--------------- ------------------------------ ------------------------------------------ ------------------------------------------
US/Pacific      2018/08/15 22:45:19.572191     2018/08/15 22:45:19.572191 US/PACIFIC PDT  2018/08/15 22:45:19.572185 -07:00

LOCALTIMESTAMP と CURRENT_TIMESTAMP は Case 1 と同じ動作やけど、SYSTIMESTAMPの値が変わってるやね彡(゚)(゚)

3. まとめ

上記の挙動をまとめると、以下の通りとなります。

組み込み関数 データ型 DB SESSIONのTIME_ZONE値 OSのtimezone
LOCALTIMESTAMP TIMESTAMP 影響する 影響しない
CURRENT_TIMESTAMP TIMESTAMP WITH TIME ZONE 影響する 影響しない
SYSTIMESTAMP TIMESTAMP WITH TIME ZONE 影響しない 影響する

「OSのtimezone」と「DB SESSIONのTIME_ZONE値」を一致させられる環境なら、 各組み込み関数で取れてくる値に違いは無いので影響はほぼ無いと思うんやけど、 それが異なるケースではその違いを意識して実装する必要が有りそうやね彡(゚)(゚)

SYSTIMESTAMPの返り値をAT TIME ZONE書式で変換する、SESSIONTIMEZONEを任意のTIME_ZONEに変更してCURRENT_TIMESTAMPを使う、など

SELECT SYSTIMESTAMP, SYSTIMESTAMP AT TIME ZONE 'Japan' FROM DUAL;

SYSTIMESTAMP                               SYSTIMESTAMPATTIMEZONE'JAPAN'
------------------------------------------ ---------------------------------------------------------------------------
2018/08/16 01:14:47.217209 -07:00          2018/08/16 17:14:47.217209 JAPAN JST
ALTER SESSION SET TIME_ZONE = 'Japan';
SELECT SESSIONTIMEZONE, CURRENT_TIMESTAMP FROM DUAL;

セッションが変更されました。

SESSIONTIMEZONE CURRENT_TIMESTAMP
--------------- ------------------------------------------
Japan           2018/08/16 17:15:18.966717 JAPAN JST

4. マニュアル

マニュアルも参考や!彡(゚)(゚)

LOCALTIMESTAMP
https://docs.oracle.com/cd/E96517_01/sqlrf/LOCALTIMESTAMP.html#GUID-3C3D1F29-5F53-41F2-B2D6-A3767DFB22CA
LOCALTIMESTAMPは、セッションのタイムゾーンの現在の日付および時刻をTIMESTAMPデータ型の値で戻します。
 
CURRENT_TIMESTAMP
https://docs.oracle.com/cd/E96517_01/sqlrf/CURRENT_TIMESTAMP.html#GUID-CBD42B84-869D-45C7-9FFC-001DD7712097
CURRENT_TIMESTAMPは、セッション・タイムゾーンの現在の日付および時刻をTIMESTAMP WITH TIME ZONEデータ型の値で戻します。
 
SYSTIMESTAMP
https://docs.oracle.com/cd/E96517_01/sqlrf/SYSTIMESTAMP.html#GUID-FCED18CE-A875-4D5D-9178-3DE4FA956516
SYSTIMESTAMPは、データベースが存在するシステムの、秒の小数部とタイムゾーンを含む日付を戻します。戻り値の型は、TIMESTAMP WITH TIME ZONEです。
 
ALTER SESSION
https://docs.oracle.com/cd/E96517_01/sqlrf/ALTER-SESSION.html#GUID-27186B28-7EFC-4998-B1ED-2B905CC0211B
TIME_ZONEパラメータには、現行のSQLセッションのデフォルトのローカル・タイムゾーン・オフセットまたは地域名を指定します。

サマータイム(夏時間, Daylight Saving)を理解するためにTIMESTAMP WITH TIME ZONE型と戯れてみる。(Oracle Database)

サマータイムが話題ですやね彡(゚)(゚) ワイら日本人には馴染みの薄いサマータイムですが、これを理解するために Oracle Database のTIMESTAMP WITH TIME ZONE型と戯れてみます。

1. TZR書式/TZD書式に使用可能な文字列を確認して、サマータイムを使用するタイムゾーンを選択

TZR書式/TZD書式に使用可能な文字列を確認します。V$TIMEZONE_NAMESビューから確認可能です。

-- TZR書式/TZD書式に使用可能な文字列を確認
SET LINESIZE 300;
SET PAGESIZE 1000;
SELECT * FROM V$TIMEZONE_NAMES;

TZNAME                             TZABBREV        CON_ID
---------------------------------- ----------- ----------
Africa/Abidjan                     LMT                  0
Africa/Abidjan                     GMT                  0
Africa/Accra                       LMT                  0
Africa/Accra                       GMT                  0
Africa/Accra                       GHST                 0
:
US/Mountain                        MPT                  0
US/Pacific ★                      LMT                  0
US/Pacific ★                      PST ★               0
US/Pacific ★                      PDT ★               0
US/Pacific ★                      PWT                  0
US/Pacific ★                      PPT                  0
US/Pacific-New                     LMT                  0

本エントリでは、サマータイムを使用するタイムゾーンのTZR書式として'US/Pacific'、
TZD書式としてPSTとPDTを使ってを検証しますやで彡(゚)(゚)

2. サマータイム開始近辺の日付を生成

サマータイム開始近辺の日付を生成してみます。UTCと比較したいので【1.UTC(TZR)】【2.US/Pacific(TZR)】【3.US/Pacific(TZD)】【4.US/Pacific(TZR)をDATE型にキャスト】の4種類の値を生成してみます。

-- 日付書式の設定
ALTER SESSION SET NLS_DATE_FORMAT         = 'YYYY-MM-DD HH24:MI:SS';
ALTER SESSION SET NLS_TIMESTAMP_FORMAT    = 'YYYY-MM-DD HH24:MI:SS';
ALTER SESSION SET NLS_TIMESTAMP_TZ_FORMAT = 'YYYY-MM-DD HH24:MI:SS TZR';

-- 日付リテラルを格納する変数
VAR v_ts_char VARCHAR2(100);

-- 表示設定
SET LINESIZE 200;
SET PAGESIZE 100;
COLUMN UTC_TZR         FORMAT A26;
COLUMN US_Pacific_TZR  FORMAT A36;
COLUMN US_Pacific_TZD  FORMAT A28;
COLUMN US_Pacific_DATE FORMAT A20;

-- 日付リテラル代入(サマータイム開始近辺)
EXEC :v_ts_char := '2018-03-11 00:00:00';

-- 日付生成
WITH TS_TMP AS (
   SELECT TO_TIMESTAMP_TZ(TO_TIMESTAMP(:v_ts_char) + (LEVEL-1)/48 || ' UTC')                           AS UTC_TZR
        , TO_TIMESTAMP_TZ(TO_TIMESTAMP(:v_ts_char) + (LEVEL-1)/48 || ' UTC') AT TIME ZONE 'US/Pacific' AS US_Pacific_TZR
     FROM DUAL
  CONNECT BY LEVEL <= 30
)
SELECT TS_TMP.*
     , TO_CHAR(TS_TMP.US_Pacific_TZR, 'YYYY-MM-DD HH24:MI:SS TZD') AS US_Pacific_TZD
     , CAST(TS_TMP.US_Pacific_TZR AS DATE)                         AS US_Pacific_DATE
  FROM TS_TMP;

UTC_TZR                    US_PACIFIC_TZR                       US_PACIFIC_TZD               US_PACIFIC_DATE
-------------------------- ------------------------------------ ---------------------------- --------------------
2018-03-11 00:00:00 UTC    2018-03-10 16:00:00 US/PACIFIC       2018-03-10 16:00:00 PST      2018-03-10 16:00:00
2018-03-11 00:30:00 UTC    2018-03-10 16:30:00 US/PACIFIC       2018-03-10 16:30:00 PST      2018-03-10 16:30:00
:
2018-03-11 08:30:00 UTC    2018-03-11 00:30:00 US/PACIFIC       2018-03-11 00:30:00 PST      2018-03-11 00:30:00
2018-03-11 09:00:00 UTC    2018-03-11 01:00:00 US/PACIFIC       2018-03-11 01:00:00 PST      2018-03-11 01:00:00
2018-03-11 09:30:00 UTC    2018-03-11 01:30:00 US/PACIFIC ★    2018-03-11 01:30:00 PST ★   2018-03-11 01:30:002018-03-11 10:00:00 UTC    2018-03-11 03:00:00 US/PACIFIC ★    2018-03-11 03:00:00 PDT ★   2018-03-11 03:00:002018-03-11 10:30:00 UTC    2018-03-11 03:30:00 US/PACIFIC       2018-03-11 03:30:00 PDT      2018-03-11 03:30:00
2018-03-11 11:00:00 UTC    2018-03-11 04:00:00 US/PACIFIC       2018-03-11 04:00:00 PDT      2018-03-11 04:00:00
:

UTC の '2018-03-11 10:00:00 UTC' のタイミングで、US/Pacificの日付については1時間進んでるのが解りますやね彡(゚)(゚)

3. サマータイム終了近辺の日付を生成

同様にサマータイム終了近辺の日付を生成してみます。

-- 日付リテラル代入(サマータイム終了近辺)
EXEC :v_ts_char := '2018-11-04 00:00:00';

-- 日付生成
WITH TS_TMP AS (
   SELECT TO_TIMESTAMP_TZ(TO_TIMESTAMP(:v_ts_char) + (LEVEL-1)/48 || ' UTC')                           AS UTC_TZR
        , TO_TIMESTAMP_TZ(TO_TIMESTAMP(:v_ts_char) + (LEVEL-1)/48 || ' UTC') AT TIME ZONE 'US/Pacific' AS US_Pacific_TZR
     FROM DUAL
  CONNECT BY LEVEL <= 30
)
SELECT TS_TMP.*
     , TO_CHAR(TS_TMP.US_Pacific_TZR, 'YYYY-MM-DD HH24:MI:SS TZD') AS US_Pacific_TZD
     , CAST(TS_TMP.US_Pacific_TZR AS DATE)                         AS US_Pacific_DATE
  FROM TS_TMP;

UTC_TZR                    US_PACIFIC_TZR                       US_PACIFIC_TZD               US_PACIFIC_DATE
-------------------------- ------------------------------------ ---------------------------- --------------------
2018-11-04 00:00:00 UTC    2018-11-03 17:00:00 US/PACIFIC       2018-11-03 17:00:00 PDT      2018-11-03 17:00:00
2018-11-04 00:30:00 UTC    2018-11-03 17:30:00 US/PACIFIC       2018-11-03 17:30:00 PDT      2018-11-03 17:30:00
:
2018-11-04 07:30:00 UTC    2018-11-04 00:30:00 US/PACIFIC       2018-11-04 00:30:00 PDT      2018-11-04 00:30:00
2018-11-04 08:00:00 UTC    2018-11-04 01:00:00 US/PACIFIC ★    2018-11-04 01:00:00 PDT ★   2018-11-04 01:00:002018-11-04 08:30:00 UTC    2018-11-04 01:30:00 US/PACIFIC ★    2018-11-04 01:30:00 PDT ★   2018-11-04 01:30:002018-11-04 09:00:00 UTC    2018-11-04 01:00:00 US/PACIFIC ★    2018-11-04 01:00:00 PST ★   2018-11-04 01:00:002018-11-04 09:30:00 UTC    2018-11-04 01:30:00 US/PACIFIC ★    2018-11-04 01:30:00 PST ★   2018-11-04 01:30:002018-11-04 10:00:00 UTC    2018-11-04 02:00:00 US/PACIFIC       2018-11-04 02:00:00 PST      2018-11-04 02:00:00
:

UTC の '2018-11-04 09:00:00 UTC'から1時間については、US/Pacificの日付で同じ時間が現れているのが解りますやね彡(゚)(゚)

4. サマータイム終了日付のデータを、現地時間の時刻で絞り込むとどうなるか?

下記にUS/Pacificの現地時間で2018/11/04の日付のデータを抽出した結果を出してみる。

-- 日付リテラル代入(サマータイム終了近辺)
EXEC :v_ts_char := '2018-11-03 00:00:00';

-- 日付生成
WITH TS_TMP AS (
   SELECT TO_TIMESTAMP_TZ(TO_TIMESTAMP(:v_ts_char) + (LEVEL-1)/48 || ' UTC')                           AS UTC_TZR
        , TO_TIMESTAMP_TZ(TO_TIMESTAMP(:v_ts_char) + (LEVEL-1)/48 || ' UTC') AT TIME ZONE 'US/Pacific' AS US_Pacific_TZR
     FROM DUAL
  CONNECT BY LEVEL <= 200
)
SELECT TS_TMP.*
     , TO_CHAR(TS_TMP.US_Pacific_TZR, 'YYYY-MM-DD HH24:MI:SS TZD') AS US_Pacific_TZD
     , CAST(TS_TMP.US_Pacific_TZR AS DATE)                         AS US_Pacific_DATE
  FROM TS_TMP
 WHERE UTC_TZR >= TO_TIMESTAMP_TZ('2018-11-04 00:00:00 US/Pacific', 'YYYY-MM-DD HH24:MI:SS TZR') AT TIME ZONE 'UTC'
   AND UTC_TZR <  TO_TIMESTAMP_TZ('2018-11-05 00:00:00 US/Pacific', 'YYYY-MM-DD HH24:MI:SS TZR') AT TIME ZONE 'UTC';

UTC_TZR                    US_PACIFIC_TZR                       US_PACIFIC_TZD               US_PACIFIC_DATE
-------------------------- ------------------------------------ ---------------------------- --------------------
2018-11-04 07:00:00 UTC    2018-11-04 00:00:00 US/PACIFIC       2018-11-04 00:00:00 PDT      2018-11-04 00:00:00
2018-11-04 07:30:00 UTC    2018-11-04 00:30:00 US/PACIFIC       2018-11-04 00:30:00 PDT      2018-11-04 00:30:00
2018-11-04 08:00:00 UTC    2018-11-04 01:00:00 US/PACIFIC ★    2018-11-04 01:00:00 PDT ★   2018-11-04 01:00:00
2018-11-04 08:30:00 UTC    2018-11-04 01:30:00 US/PACIFIC ★    2018-11-04 01:30:00 PDT ★   2018-11-04 01:30:00
2018-11-04 09:00:00 UTC    2018-11-04 01:00:00 US/PACIFIC ★    2018-11-04 01:00:00 PST ★   2018-11-04 01:00:00
2018-11-04 09:30:00 UTC    2018-11-04 01:30:00 US/PACIFIC ★    2018-11-04 01:30:00 PST ★   2018-11-04 01:30:00
2018-11-04 10:00:00 UTC    2018-11-04 02:00:00 US/PACIFIC       2018-11-04 02:00:00 PST      2018-11-04 02:00:002018-11-05 07:00:00 UTC    2018-11-04 23:00:00 US/PACIFIC       2018-11-04 23:00:00 PST      2018-11-04 23:00:00
2018-11-05 07:30:00 UTC    2018-11-04 23:30:00 US/PACIFIC       2018-11-04 23:30:00 PST      2018-11-04 23:30:00

50 rows selected.

うーん、UTC違いの同じ時刻が2重に取れてくるやね彡(゚)(゚)

5. 日本式サマータイムに関する所感

Oracle Database としてのサマータイムの挙動はざっくりとは理解したので、
今話題の日本式サマータイムでの対応を考察してみる。

日本式サマータイムOracle Database できっちり対応しようとすると

  • 日付データについてはTIMESTAMP WITH TIME ZONE型の列に
    UTC形式 または TZR/TZD併用形式で記述した時刻を変換して格納
    ※最初は「UTC形式で格納」と表記したが「TZR/TZD併用形式」でも夏時間境界を判別可能なため。
  • 該当列を表示する時には【AT TIME ZONE 'Japan'】を付与して日本時間に変換
  • 絞り込み条件は日本時刻をUTC形式に変換して、UTC形式の列に絞込みを掛ける。 ただしサマータイム開始日や終了日については、1日の長さが22時間 or 26時間で変動するため、 24時間決め打ちでロジックを組むことはできない。

てな感じになるのかと彡(゚)(゚)

Oracle Database はサマータイムに対応しているものの、日付データを
TIMESTAMP WITH TIME ZONE型で夏時間を意識して格納しているシステムは、
少なくとも日本企業がスクラッチで組んだシステムでは相当レアなんじゃなかろうかと。

大半のシステムはDATE型やTIMESTAMP型で、あるいは文字列型日付データを保持していると
認識していて、これをデータの持ち方を変えて、更にプログラムまで変更して対応するのは、
まあ事実上不可能なんやろうなぁ……と考えざるを得ない彡(-)(-)

6. マニュアル、ほか追加検証

マニュアルは下記の通り彡(゚)(゚)

Oracle Database SQL言語リファレンス
18cバージョン 18.1 E93948-01
日時書式モデル
https://docs.oracle.com/cd/E96517_01/sqlrf/Format-Models.html#GUID-49B32A81-0904-433E-B7FE-51606672183A
 
TIMESTAMP WITH TIME ZONEデータ型
https://docs.oracle.com/cd/E96517_01/sqlrf/Data-Types.html#GUID-BE23545B-469A-4A57-8D13-505F2F5DB706
 
TO_TIMESTAMP_TZ
https://docs.oracle.com/cd/E96517_01/sqlrf/TO_TIMESTAMP_TZ.html#GUID-3999303B-89CA-4AA3-9817-458F36ADC9DC
 
CAST
https://docs.oracle.com/cd/E96517_01/sqlrf/CAST.html#GUID-5A70235E-1209-4281-8521-B94497AAEF75
 
Oracle Database
Databaseグローバリゼーション・サポート・ガイド 18c E94646-01
4.12 夏時間のサポート
https://docs.oracle.com/cd/E96517_01/nlspg/datetime-data-types-and-time-zone-support.html#GUID-E5171DEF-74D7-482A-B4E9-1EE3403E18BC
Oracle Databaseは、指定のタイム・ゾーンで夏時間が有効かどうかを自動的に判別し、
対応するローカル時間を返します。Oracle Databaseで夏時間が特定のタイム・ゾーンで有効かどうかを判別するには、
通常、日時値で十分です。夏時間の開始期間または終了期間は境界事例です。たとえば、米国東部では、
夏時間が有効になる時点で、時刻が午前1時59分59秒から午前3時0分0秒に変わります。
午前2時0分0秒~午前2時59分59秒の時間隔は存在しません。その時間隔に該当する値は無効です。
夏時間の終了時には、時刻が午前2時0分0秒から午前1時0分1秒に変わります。
午前1時0分1秒~午前2時0分0秒の時間隔が繰り返されます。この時間隔に含まれる値は、2回発生するため不明確となります。
 
このような境界事例を解決するために、Oracle DatabaseではTZRおよびTZD書式要素を使用します。
TZRは、日時入力文字列でのタイム・ゾーン・リージョンを表します。たとえば、'Australia/North'、'UTC'および'Singapore'などです。
TZDは、夏時間情報を含むタイム・ゾーン・リージョンの略称を表します。たとえば、米国太平洋標準時間の場合は'PST'、
米国太平洋夏時間の場合は'PDT'です。TZRおよびTZD書式要素に対して有効な値のリストを表示するには、
V$TIMEZONE_NAMES動的パフォーマンス・ビューのTZNAME列とTZABBREV列を問い合せます。
 
4.2.1.3 TIMESTAMP WITH TIME ZONEデータ型
https://docs.oracle.com/cd/E96517_01/nlspg/datetime-data-types-and-time-zone-support.html#GUID-5BC5D2C1-6506-49BE-8177-F743A46FDC09
標準時間から夏時間への切替時に境界を明確にするには、TZR書式要素および対応するTZD書式要素の両方を使用します。
TZD書式要素は、夏時間情報を含むタイム・ゾーン・リージョンの略称です。たとえば、米国太平洋標準時間の場合はPST、
米国太平洋夏時間の場合はPDTです。次のように指定すると、確実に夏時間の値が戻されます。

上記マニュアルの記述に基づいて、夏時間終了時の現地時間について 繰り返される現地時刻をUTCに変換した結果を下記に示します。

-- TZR書式の時間をUTCに変換
SELECT TIMESTAMP '2018-11-04 01:30:00 US/Pacific'     AT TIME ZONE 'UTC' AS TZR_FORMAT FROM DUAL;

-- TZR書式+TZD書式(PDT)の時間をUTCに変換
SELECT TIMESTAMP '2018-11-04 01:30:00 US/Pacific PDT' AT TIME ZONE 'UTC' AS TZR_WITH_PDT FROM DUAL;

-- TZR書式+TZD書式(PST)の時間をUTCに変換
SELECT TIMESTAMP '2018-11-04 01:30:00 US/Pacific PST' AT TIME ZONE 'UTC' AS TZR_WITH_PST FROM DUAL;

TZR_FORMAT
---------------------------------------------------------------------------
2018-11-04 09:30:00 UTC

TZR_WITH_PDT
---------------------------------------------------------------------------
2018-11-04 08:30:00 UTC

TZR_WITH_PST
---------------------------------------------------------------------------
2018-11-04 09:30:00 UTC

TZR書式とTZD書式を併用すると、同じ時刻でもUTC相当の時刻を判別できるんやね彡(゚)(゚)

TIMESTAMP WITH TIME ZONE型のデータをテーブルに格納した場合の検証結果も残しときます。

CREATE TABLE TBL_TZ (
    C1 NUMBER
  , C2 TIMESTAMP WITH TIME ZONE
);
INSERT INTO TBL_TZ VALUES(1, TO_TIMESTAMP_TZ('2018-11-04 08:30:00 UTC', 'YYYY-MM-DD HH24:MI:SS TZR'));
INSERT INTO TBL_TZ VALUES(2, TO_TIMESTAMP_TZ('2018-11-04 09:30:00 UTC', 'YYYY-MM-DD HH24:MI:SS TZR'));
INSERT INTO TBL_TZ VALUES(3, TO_TIMESTAMP_TZ('2018-11-04 01:30:00 US/Pacific PDT', 'YYYY-MM-DD HH24:MI:SS TZR TZD'));
INSERT INTO TBL_TZ VALUES(4, TO_TIMESTAMP_TZ('2018-11-04 01:30:00 US/Pacific PST', 'YYYY-MM-DD HH24:MI:SS TZR TZD'));
COMMIT;

ALTER SESSION SET NLS_TIMESTAMP_TZ_FORMAT = 'YYYY-MM-DD HH24:MI:SS TZR:TZD';
SET LINESIZE 300;
SET PAGESIZE 100;
COLUMN C1            FORMAT 999;
COLUMN C2            FORMAT A36;
COLUMN C2_UTC        FORMAT A30;
COLUMN C2_US_Pacific FORMAT A36;
COLUMN C2_Japan      FORMAT A32;
SELECT C1
     , C2
     , C2 AT TIME ZONE 'UTC'        AS C2_UTC
     , C2 AT TIME ZONE 'US/Pacific' AS C2_US_Pacific
     , C2 AT TIME ZONE 'Japan'      AS C2_Japan
  FROM TBL_TZ;

  C1 C2                                   C2_UTC                         C2_US_PACIFIC                        C2_JAPAN
---- ------------------------------------ ------------------------------ ------------------------------------ --------------------------------
   1 2018-11-04 08:30:00 UTC:GMT          2018-11-04 08:30:00 UTC:GMT    2018-11-04 01:30:00 US/PACIFIC:PDT   2018-11-04 17:30:00 JAPAN:JST
   2 2018-11-04 09:30:00 UTC:GMT          2018-11-04 09:30:00 UTC:GMT    2018-11-04 01:30:00 US/PACIFIC:PST   2018-11-04 18:30:00 JAPAN:JST
   3 2018-11-04 01:30:00 US/PACIFIC:PDT   2018-11-04 08:30:00 UTC:GMT    2018-11-04 01:30:00 US/PACIFIC:PDT   2018-11-04 17:30:00 JAPAN:JST
   4 2018-11-04 01:30:00 US/PACIFIC:PST   2018-11-04 09:30:00 UTC:GMT    2018-11-04 01:30:00 US/PACIFIC:PST   2018-11-04 18:30:00 JAPAN:JST

なるほど、同じ時刻でもPDTとPSTとでUTC時刻やJST時刻が異なる。
あまり馴染みが無かったけど TIMESTAMP WITH TIME ZONE型 は
サマータイムを処理するための色々な機能を備えてるんやね。彡(゚)(゚)

はてなブログの横幅を調整する。(デザインCSSのカスタマイズ)

テーマは「bordeaux」を使用。

デザイン ⇒ (スパナのアイコン) ⇒ デザインCSS と辿って、元の設定を残しつつ下記を貼り付ける。

/* 全体の横幅 */
#content {
width: 1000px;
}

/* 記事の横幅 */
#main {
width: 800px;
}

参考:はてなブログ 横幅などカスタマイズ
http://kachua.hatenablog.com/entry/2018/02/03/210645

SQLNET.COMPRESSIONによる圧縮がDBMS_FILE_TRANSFERパッケージのファイル転送(コピー)に効くかを確かめる。(Oracle Database)

SQLNET.COMPRESSIONは12cR1の新機能で、
Oracle Net Servicesによる通信を圧縮する効果が期待されるパラメータです。

Oracle Database Net Servicesリファレンス 12cリリース1 (12.1) B71289-04
SQLNET.COMPRESSION
https://docs.oracle.com/cd/E57425_01/121/NETRF/sqlnet.htm#CIHJIBBI
データ圧縮を有効または無効にします。サーバー、クライアントの両方とも
このパラメータをONに設定している場合、接続に圧縮が使用されます。

※2018/7/30追記:このパラメータは Advanced Compressionのオプション機能となります。

Oracle Databaseライセンス情報ユーザー・マニュアル 12cリリース1 (12.1)
Oracle Advanced Compression
https://docs.oracle.com/cd/E57425_01/121/DBLIC/options.htm#CJACCDBA
高度なネットワーク圧縮

An Oracle White Paper
Advanced Network Compression
http://www.oracle.com/technetwork/database/enterprise-edition/advancednetworkcompression-2141325.pdf

今回はDBMS_FILE_TRANSFERパッケージによるファイル転送(コピー)の通信が、
SQLNET.COMPRESSIONで圧縮されるかどうかを確認してみるやで彡(゚)(゚)

接続トポロジは以下の通り。

12cR1(データファイルのコピー元) ⇒ DBLINK ⇒ 12cR2(コピー先、DBMS_FILE_TRANSFERを実行)

下記のファイル(users.273.877103105, 約1GB)をコピーして検証してみます。

-- 12cR1
COLUMN FILE_NAME FORMAT A80
SELECT FILE_NAME, BYTES FROM DBA_DATA_FILES;

FILE_NAME                                                                             BYTES
-------------------------------------------------------------------------------- ----------
+DATA/ORCL/13BEADB8DEA01985E0536538A8C0D6E9/DATAFILE/system.270.877103077         272629760
+DATA/ORCL/13BEADB8DEA01985E0536538A8C0D6E9/DATAFILE/sysaux.271.877103077         608174080
+DATA/ORCL/13BEADB8DEA01985E0536538A8C0D6E9/DATAFILE/users.273.877103105         1073741824
                 ★コピー対象(約1GB)^^^^^^^^^^^^^^^^^^^

1. ファイルコピー前のifconfig ethx TX/RX bytes値(SQLNET.COMPRESSION未設定)

ファイルコピー前の Network Interface の RX/TX bytes値を確認します。
TX ⇒ 送信、RX ⇒ 受信となります。

# 12cR1側(コピー元)
$ ifconfig eth0
eth0      Link encap:Ethernet  HWaddr 08:00:27:D0:22:C8
          inet addr:192.168.56.101  Bcast:192.168.56.255  Mask:255.255.255.0
          inet6 addr: fe80::a00:27ff:fed0:22c8/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:23613 errors:0 dropped:0 overruns:0 frame:0
          TX packets:747935 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:1573399 (1.5 MiB)  TX bytes:2112323918 (1.9 GiB)
                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^★
# 12cR2側(コピー先)
$ ifconfig eth2
ifconfig eth2
eth2      Link encap:Ethernet  HWaddr 08:00:27:44:DA:94
          inet addr:192.168.56.201  Bcast:192.168.56.255  Mask:255.255.255.0
          inet6 addr: fe80::a00:27ff:fe44:da94/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:747657 errors:0 dropped:0 overruns:0 frame:0
          TX packets:23654 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:1129696230 (1.0 GiB)  TX bytes:1576027 (1.5 MiB)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^★

2. DBMS_FILE_TRANSFER実行後のifconfig ethx RX/TX bytes値(SQLNET.COMPRESSION未設定)

DBMS_FILE_TRANSFERでファイル転送(コピー)を実行して、
実行後の Network Interface の RX/TX bytes値を確認します。

-- 12cR2側でDBMS_FILE_TRANSFERを実行
CONNECT AYSHIBAT/xxxxxxxx@PDB01
BEGIN
  DBMS_FILE_TRANSFER.GET_FILE(
      'DIR_DATAFILE'        -- 12cR1側のディレクトリ・オブジェクト
    , 'users.273.877103105' -- 12cR1側のデータファイル名
    , 'DBL_PDB1_12cR1'      -- 12cR1 ⇒ 12cR2 の DBLINK名
    , 'DIR_DATAFILE_PDB01'  -- 12cR2側のディレクトリ・オブジェクト
    , 'users.273.877103105' -- 12cR2側のデータファイル名
  );
END;
/

Connected.

PL/SQL procedure successfully completed.
# 12cR1側(コピー元)
$ ifconfig eth0
eth0      Link encap:Ethernet  HWaddr 08:00:27:D0:22:C8
          inet addr:192.168.56.101  Bcast:192.168.56.255  Mask:255.255.255.0
          inet6 addr: fe80::a00:27ff:fed0:22c8/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:45875 errors:0 dropped:0 overruns:0 frame:0
          TX packets:1491835 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:3043561 (2.9 MiB)  TX bytes:4234449971 (3.9 GiB)
                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^★
# 12cR2側(コピー先)
$ ifconfig eth2
eth2      Link encap:Ethernet  HWaddr 08:00:27:44:DA:94
          inet addr:192.168.56.201  Bcast:192.168.56.255  Mask:255.255.255.0
          inet6 addr: fe80::a00:27ff:fe44:da94/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:1491332 errors:0 dropped:0 overruns:0 frame:0
          TX packets:45916 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:2253854289 (2.0 GiB)  TX bytes:3046189 (2.9 MiB)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^★

送受信のバイト数を計算すると、以下の結果になりました。
12cR1側は約1.97GBを送信、12cR2側では約1.05GBを受信してるやね彡(゚)(゚)

# 12cR1側(コピー元)
TX bytes数 … 4,234,449,971(コピー後) - 2,112,323,918(コピー前)
= 2,122,126,053bytes(約1.97GB) を送信

# 12cR2側(コピー先)
RX bytes数 … 2,253,854,289(コピー後) - 1,129,696,230(コピー前)
= 1,124,158,059bytes(約1.05GB) を受信

3. sqlnet.ora設定(SQLNET.COMPRESSION=on)

送信側(12cR1)と受信側(12cR2)のsqlnet.oraに、
それぞれSQLNET.COMPRESSION=onを設定します。
設定後に両方のDBを再起動しています。

# 12cR1側(コピー元)
cat $ORACLE_HOME/network/admin/sqlnet.ora
SQLNET.COMPRESSION=on ★
# 12cR2側(コピー先)
cat $ORACLE_HOME/network/admin/sqlnet.ora
# sqlnet.ora Network Configuration File: /u01/app/oracle/product/12.2.0/dbhome_1/network/admin/sqlnet.ora
# Generated by Oracle configuration tools.

NAMES.DIRECTORY_PATH= (TNSNAMES, ONAMES, HOSTNAME)
SQLNET.COMPRESSION=on ★

#SQLNET.OUTBOUND_CONNECT_TIMEOUT=5
#SQLNET.INBOUND_CONNECT_TIMEOUT=5

4. ファイルコピー前のifconfig ethx RX/TX bytes値(SQLNET.COMPRESSION=on設定済み)

再度ファイルコピー前の Network Interface の RX/TX bytes値を確認します。

# 12cR1側(コピー元)
$ ifconfig eth0
eth0      Link encap:Ethernet  HWaddr 08:00:27:D0:22:C8
          inet addr:192.168.56.101  Bcast:192.168.56.255  Mask:255.255.255.0
          inet6 addr: fe80::a00:27ff:fed0:22c8/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:45887 errors:0 dropped:0 overruns:0 frame:0
          TX packets:1491865 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:3044569 (2.9 MiB)  TX bytes:4234451867 (3.9 GiB)
                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^★
# 12cR2側(コピー先)
$ ifconfig eth2
eth2      Link encap:Ethernet  HWaddr 08:00:27:44:DA:94
          inet addr:192.168.56.201  Bcast:192.168.56.255  Mask:255.255.255.0
          inet6 addr: fe80::a00:27ff:fe44:da94/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:1491362 errors:0 dropped:0 overruns:0 frame:0
          TX packets:45928 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:2253856185 (2.0 GiB)  TX bytes:3047197 (2.9 MiB)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^★

5. DBMS_FILE_TRANSFER実行後のifconfig ethx RX/TX bytes値(SQLNET.COMPRESSION=on設定済)

SQLNET.COMPRESSION=onの状態で、DBMS_FILE_TRANSFERで
ファイル転送(コピー)を実行してみます。
実行後の Network Interface の RX/TX bytes値を確認します。

CONNECT AYSHIBAT/xxxxxxxx@PDB01
BEGIN
  DBMS_FILE_TRANSFER.GET_FILE(
      'DIR_DATAFILE'        -- 12cR1側のディレクトリ・オブジェクト
    , 'users.273.877103105' -- 12cR1側のデータファイル名
    , 'DBL_PDB1_12cR1'      -- 12cR1 ⇒ 12cR2 の DBLINK名
    , 'DIR_DATAFILE_PDB01'  -- 12cR2側のディレクトリ・オブジェクト
    , 'users.273.877103105' -- 12cR2側のデータファイル名
  );
END;
/

Connected.

PL/SQL procedure successfully completed.
# 12cR1側(コピー元)
$ ifconfig eth0
eth0      Link encap:Ethernet  HWaddr 08:00:27:D0:22:C8
          inet addr:192.168.56.101  Bcast:192.168.56.255  Mask:255.255.255.0
          inet6 addr: fe80::a00:27ff:fed0:22c8/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:58625 errors:0 dropped:0 overruns:0 frame:0
          TX packets:1556074 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:3888437 (3.7 MiB)  TX bytes:4251723023 (3.9 GiB)
                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^★
# 12cR2側(コピー先)
$ ifconfig eth2
eth2      Link encap:Ethernet  HWaddr 08:00:27:44:DA:94
          inet addr:192.168.56.201  Bcast:192.168.56.255  Mask:255.255.255.0
          inet6 addr: fe80::a00:27ff:fe44:da94/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:1555359 errors:0 dropped:0 overruns:0 frame:0
          TX packets:58624 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:2268359561 (2.1 GiB)  TX bytes:3888293 (3.7 MiB)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^★
# 12cR1側(コピー元)
TX bytes数 … 4,251,723,023(コピー後) - 4,234,451,867(コピー前)
= 17,271,156bytes(約0.016GB) を送信

# 12cR2側(コピー先)
RX bytes数 … 2,268,359,561(コピー後) - 2,253,856,185(コピー前)
= 14,503,376bytes(約0.014GB) を受信

12cR1側は約0.016GBを送信、12cR2側では約0.014GBを受信しています彡(゚)(゚)
sqlnet.ora(SQLNET.COMPRESSION=on)設定前と比較して、
少なくなってますやね彡(^)(^)
#圧縮率は格納データの特性に依存する想定なので、実測してみて下さい。

まとめ

SQLNET.COMPRESSION=onによる圧縮は、DBMS_FILE_TRANSFERパッケージによる
ファイル転送(コピー)に効果が有ることが解りました。

下記の記事に書いた TTS(トランスポータブル表領域) で、ネットワーク帯域が
ボトルネックになるケースでは試してみる価値が有りそうですやね彡(^)(^)
#送信元が12cR1(12.1)以降の必要が有りますけど(゚ε゚ )

Oracle Database 11gR2(11.2.0.4)から12cR2(12.2.0.1)のPDBにTTS(トランスポータブル表領域)をしてみる。
http://d.hatena.ne.jp/gonsuke777/20180626/1530009840

ちなこの機能(SQLNET.COMPRESSION=on)は PDB の Clone や Relocate に
効果は有るんですかね?どちらも裏でデータファイルのコピーが
走っているはずなんで、隙を見て検証してみますやで彡(゚)(゚)

DBMS_FILE_TRANSFERパッケージでDB(11gR2) -> DBLINK -> PDB(12cR2)のデータファイルの転送(コピー)を実行する。(Oracle Database)

DBMS_FILE_TRANSFERパッケージで中間ファイルを介さずに、
DB(11gR2) to PDB(12cR2) の直接のファイル転送(コピー)を
実行してみますやで彡(゚)(゚)

Oracle Database PL/SQL Packages and Types Reference 12c Release 2 (12.2)
67 DBMS_FILE_TRANSFER
https://docs.oracle.com/en/database/oracle/oracle-database/12.2/arpls/DBMS_FILE_TRANSFER.html#GUID-9E206058-78CB-4028-8883-7C28B845F86C

今回試すのは以下のような接続トポロジです。

11gR2(データファイルのコピー元) ⇒ DBLINK ⇒ 12cR2(コピー先、DBMS_FILE_TRANSFERを実行)

1. データファイルのコピー元にディレクトリ・オブジェクトを作成

データファイルのパスを参照可能なディレクトリ・オブジェクトを作成して、
READ権限を付与します。下記例では専用ユーザーを作成していますが、必須ではありません。

-- 11gR2(ユーザー作成)
CREATE USER FILETRANS IDENTIFIED BY xxxxxxxx
DEFAULT TABLESPACE USERS
TEMPORARY TABLESPACE TEMP;
GRANT CREATE SESSION TO FILETRANS;

-- 11gR2(ディレクトリ・オブジェクト作成)
CREATE DIRECTORY DIR_DATAFILE as '+DATA/ORCL/DATAFILE';
GRANT READ ON DIRECTORY DIR_DATAFILE TO FILETRANS;

User created.

Grant succeeded.

Directory created.

Grant succeeded.

2. データファイルのコピー先(PDB)にディレクトリ・オブジェクトを作成

データファイルのコピー先(PDB)のパスにアクセス可能なディレクトリ・オブジェクトを
PDB上に作成して、DBMS_FILE_TRANSFERパッケージを実行するユーザーに
ディレクトリ・オブジェクトのWRITE権限を付与します。

-- 12cR2
CONNECT /AS SYSDBA
ALTER SESSION SET CONTAINER = PDB01;
SHOW CON_NAME;
CREATE DIRECTORY DIR_DATAFILE_PDB01 as '/u01/app/oracle/oradata/AYUCDB/6C4B2D3386C20FB8E055000000000001/datafile/';
GRANT WRITE ON DIRECTORY DIR_DATAFILE_PDB01 TO AYSHIBAT;

Connected.

Session altered.

CON_NAME
------------------------------
PDB01

Directory created.

Grant succeeded.

3. データファイルのコピー先(PDB)に、コピー元へ接続するDBLINKを作成

データファイルのコピー先(PDB)に、コピー元(今回は11gR2)へ接続する
DBLINK(DATABASE LINK)を作成します。コピー元の接続ユーザーは、
コピーするデータファイルのディレクトリ・オブジェクトのREAD権限が必要です。

-- 12cR2
CONNECT AYSHIBAT/xxxxxxxx@PDB01
SHOW CON_NAME;
CREATE DATABASE LINK DBL_ORCL_11GR2
CONNECT TO FILETRANS IDENTIFIED BY xxxxxxxx
USING 'ORCL_11GR2';

-- DBLINKの動作確認
SET LINESIZE 170;
SELECT * FROM V$VERSION@DBL_ORCL_11GR2;
SELECT * FROM V$VERSION;

Connected.

CON_NAME
------------------------------
PDB01

Database link created.

BANNER
--------------------------------------------------------------------------------
Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Production
PL/SQL Release 11.2.0.4.0 - Production
CORE    11.2.0.4.0      Production
TNS for Linux: Version 11.2.0.4.0 - Production
NLSRTL Version 11.2.0.4.0 - Production

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

4. DBMS_FILE_TRANSFERパッケージのGET_FILEプロシージャを実行して、データファイルをコピー

コピー先(今回は12cR2側)でDBMS_FILE_TRANSFERパッケージの
GET_FILEプロシージャを実行して、データファイルをコピーします。

-- 12cR2
BEGIN
  DBMS_FILE_TRANSFER.GET_FILE(
      'DIR_DATAFILE'            -- 11gR2側のディレクトリ・オブジェクト
    , 'tbs_tts1.266.979841605'  -- 11gR2側のデータファイル名
    , 'DBL_ORCL_11GR2'          -- 12cR2 ⇒ 11gR2 の DBLINK名
    , 'DIR_DATAFILE_PDB01'      -- 12cR2側のディレクトリ・オブジェクト
    , 'tbs_tts1.266.979841605'  -- 12cR2側のデータファイル名
  );
END;
/

BEGIN
  DBMS_FILE_TRANSFER.GET_FILE(
      'DIR_DATAFILE'            -- 11gR2側のディレクトリ・オブジェクト
    , 'tbs_tts2.267.979841605'  -- 11gR2側のデータファイル名
    , 'DBL_ORCL_11GR2'          -- 12cR2 ⇒ 11gR2 の DBLINK名
    , 'DIR_DATAFILE_PDB01'      -- 12cR2側のディレクトリ・オブジェクト
    , 'tbs_tts2.267.979841605'  -- 12cR2側のデータファイル名
  );
END;
/
# DBMS_FILE_TRANSFER実行前
$ pwd
/u01/app/oracle/oradata/AYUCDB/6C4B2D3386C20FB8E055000000000001/datafile
$ ls -la
total 1133172
drwxr-x---. 2 oracle oinstall      4096 Jun 27 14:26 .
drwxr-x---. 3 oracle oinstall      4096 May 16 12:19 ..
-rw-r-----. 1 oracle oinstall 398467072 Jun 27 14:25 o1_mf_sysaux_fhq8s86l_.dbf
-rw-r-----. 1 oracle oinstall 272637952 Jun 27 14:37 o1_mf_system_fhq8s865_.dbf
-rw-r-----. 1 oracle oinstall 135274496 Jun 26 19:11 o1_mf_temp_fhq8s86n_.dbf
-rw-r-----. 1 oracle oinstall 104865792 Jun 27 14:37 o1_mf_undotbs1_fhq8s86m_.dbf
-rw-r-----. 1 oracle oinstall 259530752 Jun 27 13:47 o1_mf_users_fhq8s86o_.dbf
SQL> BEGIN
  2    DBMS_FILE_TRANSFER.GET_FILE(
  3        'DIR_DATAFILE'            -- 11gR2側のディレクトリ・オブジェクト
  4      , 'tbs_tts1.266.979841605'  -- 11gR2側のデータファイル名
  5      , 'DBL_ORCL_11GR2'          -- 12cR2 ⇒ 11gR2 の DBLINK名
  6      , 'DIR_DATAFILE_PDB01'      -- 12cR2側のディレクトリ・オブジェクト
  7      , 'tbs_tts1.266.979841605'  -- 12cR2側のデータファイル名
  8    );
  9  END;
 10  /

PL/SQL procedure successfully completed.

SQL> BEGIN
  2    DBMS_FILE_TRANSFER.GET_FILE(
  3        'DIR_DATAFILE'            -- 11gR2側のディレクトリ・オブジェクト
  4      , 'tbs_tts2.267.979841605'  -- 11gR2側のデータファイル名
  5      , 'DBL_ORCL_11GR2'          -- 12cR2 ⇒ 11gR2 の DBLINK名
  6      , 'DIR_DATAFILE_PDB01'      -- 12cR2側のディレクトリ・オブジェクト
  7      , 'tbs_tts2.267.979841605'  -- 12cR2側のデータファイル名
  8    );
  9  END;
 10  /

PL/SQL procedure successfully completed.
# DBMS_FILE_TRANSFER実行後
$ pwd
/u01/app/oracle/oradata/AYUCDB/6C4B2D3386C20FB8E055000000000001/datafile
$ ls -la
total 1153668
drwxr-x---. 2 oracle oinstall      4096 Jun 27 14:40 .
drwxr-x---. 3 oracle oinstall      4096 May 16 12:19 ..
-rw-r-----. 1 oracle oinstall 398467072 Jun 27 14:25 o1_mf_sysaux_fhq8s86l_.dbf
-rw-r-----. 1 oracle oinstall 272637952 Jun 27 14:37 o1_mf_system_fhq8s865_.dbf
-rw-r-----. 1 oracle oinstall 135274496 Jun 26 19:11 o1_mf_temp_fhq8s86n_.dbf
-rw-r-----. 1 oracle oinstall 104865792 Jun 27 14:37 o1_mf_undotbs1_fhq8s86m_.dbf
-rw-r-----. 1 oracle oinstall 259530752 Jun 27 13:47 o1_mf_users_fhq8s86o_.dbf
-rw-r-----. 1 oracle oinstall  10493952 Jun 27 14:40 tbs_tts1.266.979841605 ★コピーされたデータファイル
-rw-r-----. 1 oracle oinstall  10493952 Jun 27 14:40 tbs_tts2.267.979841605 ★コピーされたデータファイル
$

見事にデータファイルがコピーされましたやで!彡(^)(^)

5. まとめ

cpやscp等によるファイルシステム(中間ファイル)を介した転送と異なって、
DBMS_FILE_TRANSFERパッケージは DB to DB による直接のファイル転送(コピー)が
実現できるんやで彡(^)(^) #中間ファイルを介さないので理論上は速い。

転送中(転送経路上)の圧縮ができるとより理想的なんやけど、
下記パラメータ(SQLNET.COMPRESSION)を使ったら実現可能なんやろうか……?
彡(゚)(゚)

Oracle Database Net Servicesリファレンス 12cリリース2 (12.2)
5.2.20 SQLNET.COMPRESSION
https://docs.oracle.com/cd/E82638_01/netrf/parameters-for-the-sqlnet-ora-file.html#GUID-61CE4FA9-3ABB-4E9B-B788-FB57E6B56F47
データ圧縮を有効または無効にします。サーバー、クライアントの両方ともこのパラメータをONに設定している場合、接続に圧縮が使用されます。

Oracle Database 11gR2(11.2.0.4)から12cR2(12.2.0.1)のPDBにTTS(トランスポータブル表領域)をしてみる。

表題の通り、Oracle Database 11gR2(11.2.0.4)から12cR2(12.2.0.1)の
PDBにTTS(トランスポータブル表領域)を実行してみるやで彡(゚)(゚)

プラットフォームはどちらも Linux x86 64bitで試します。
特別な手順は必要なくマニュアル通りに粛々と実施するだけです。

Oracle Database管理者ガイド 11gリリース2 (11.2) B56301-08
データベース間で表領域をトランスポートする手順および例
https://docs.oracle.com/cd/E16338_01/server.112/b56301/tspaces.htm#i1007252

Oracle Database データベース管理者ガイド 12c リリース2 (12.2)
15.1.2.2 トランスポータブル表領域またはトランスポータブル表の使用例
https://docs.oracle.com/cd/E82638_01/admin/transporting-data.html#GUID-5158E6EB-591A-4DF0-9A44-BAF1E10338A8

0. 移行対象の表/表領域

移行対象は以下の表(TBL_TEST_TTS1,TBL_TEST_TTS2)/表領域(TBS_TTS1,TBS_TTS2)とします。

-- 11gR2
COLUMN OWNER FORMAT A20;
COLUMN SEGMENT_NAME FORMAT A20;
COLUMN BYTES FORMAT 999,999,999;
COLUMN TABLESPACE_NAME FORMAT A20;
SELECT OWNER, SEGMENT_NAME, BYTES, TABLESPACE_NAME FROM DBA_SEGMENTS WHERE TABLESPACE_NAME IN ('TBS_TTS1', 'TBS_TTS2');

OWNER                SEGMENT_NAME                BYTES TABLESPACE_NAME
-------------------- -------------------- ------------ --------------------
AYSHIBAT             TBL_TEST_TTS1             196,608 TBS_TTS1
AYSHIBAT             TBL_TEST_TTS2             196,608 TBS_TTS2

1. 移行元/移行先のエンディアンを確認

まず移行元/移行先のエンディアンを確認します。
今回はどちらも同じエンディアン彡(゚)(゚)

-- 移行元(11gR2)のエンディアン
COLUMN PLATFORM_NAME FORMAT A30;
COLUMN ENDIAN_FORMAT FORMAT A30;
SELECT d.PLATFORM_NAME, ENDIAN_FORMAT
     FROM V$TRANSPORTABLE_PLATFORM tp, V$DATABASE d
     WHERE tp.PLATFORM_NAME = d.PLATFORM_NAME;

PLATFORM_NAME                  ENDIAN_FORMAT
------------------------------ ------------------------------
Linux x86 64-bit               Little

-- 移行先(12cR2)のエンディアン
COLUMN PLATFORM_NAME FORMAT A30;
COLUMN ENDIAN_FORMAT FORMAT A30;
SELECT d.PLATFORM_NAME, ENDIAN_FORMAT
     FROM V$TRANSPORTABLE_PLATFORM tp, V$DATABASE d
     WHERE tp.PLATFORM_NAME = d.PLATFORM_NAME;

PLATFORM_NAME                  ENDIAN_FORMAT
------------------------------ ------------------------------
Linux x86 64-bit               Little

2. 表領域が自己完結しているかを確認

下記のコマンドで表領域が自己完結しているかを確認します。
TRANSPORT_SET_VIOLATIONSで行が出なければ、自己完結しています。

-- 11gR2
EXECUTE SYS.DBMS_TTS.TRANSPORT_SET_CHECK('TBS_TTS1, TBS_TTS2', TRUE);

SELECT * FROM SYS.TRANSPORT_SET_VIOLATIONS;

PL/SQL procedure successfully completed.

no rows selected

3. 移行対象の表領域を READ ONLY にします。

下記のコマンドで移行対象の表領域を READ ONLY にします。

-- 11gR2
ALTER TABLESPACE TBS_TTS1 READ ONLY;
ALTER TABLESPACE TBS_TTS2 READ ONLY;

Tablespace altered.
Tablespace altered.

4. 表領域の定義情報をエクスポート(expdp)

expdpコマンドで表領域の定義情報をエクスポートします。
定義情報だけのエクスポートなので、時間はそれほど掛かりません。

# 11gR2
expdp AYSHIBAT/xxxxxxxx@orcl dumpfile=tts_users.dmp directory=DIR_AYSHIBAT transport_tablespaces=TBS_TTS1,TBS_TTS2 logfile=exp_tts_users.log

Export: Release 11.2.0.4.0 - Production on Tue Jun 26 18:49:44 2018

Copyright (c) 1982, 2011, Oracle and/or its affiliates.  All rights reserved.

Connected to: Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Production
With the Partitioning, Automatic Storage Management, OLAP, Data Mining
and Real Application Testing options
Starting "AYSHIBAT"."SYS_EXPORT_TRANSPORTABLE_01":  AYSHIBAT/********@orcl dumpfile=tts_users.dmp directory=DIR_AYSHIBAT transport_tablespaces=TBS_TTS1,TBS_TTS2 logfile=exp_tts_users.log
Processing object type TRANSPORTABLE_EXPORT/PLUGTS_BLK
Processing object type TRANSPORTABLE_EXPORT/TABLE
Processing object type TRANSPORTABLE_EXPORT/POST_INSTANCE/PLUGTS_BLK
Master table "AYSHIBAT"."SYS_EXPORT_TRANSPORTABLE_01" successfully loaded/unloaded
******************************************************************************
Dump file set for AYSHIBAT.SYS_EXPORT_TRANSPORTABLE_01 is:
  /home/oracle/work/ayshibat/tts_users.dmp
******************************************************************************
Datafiles required for transportable tablespace TBS_TTS1:
  +DATA/orcl/datafile/tbs_tts1.266.979841605
Datafiles required for transportable tablespace TBS_TTS2:
  +DATA/orcl/datafile/tbs_tts2.267.979841605
Job "AYSHIBAT"."SYS_EXPORT_TRANSPORTABLE_01" successfully completed at Tue Jun 26 18:50:53 2018 elapsed 0 00:01:06

5. dmpファイルとデータファイルの転送(コピー)

dmpファイルとデータファイルを移行先(12cR2)に転送(コピー)します。
データファイルの転送にはcpコマンド/DBMS_FILE_TRANSFER/RMAN等々の手段が有りますが、
今回は 11gR2のASM ⇒ asmcmdでファイルシステムに出力 ⇒ scpで転送 ⇒ 12cR2のファイルシステム とします。

# 11gR2
asmcmd
cd +DATA/ORCL/DATAFILE
ls -l

Type      Redund  Striped  Time             Sys  Name
DATAFILE  MIRROR  COARSE   JUN 26 18:00:00  Y    SYSAUX.257.836897651
DATAFILE  MIRROR  COARSE   JUN 26 18:00:00  Y    SYSTEM.256.836897649
DATAFILE  MIRROR  COARSE   JUN 26 18:00:00  Y    TBS_TTS1.266.979841605
DATAFILE  MIRROR  COARSE   JUN 26 18:00:00  Y    TBS_TTS2.267.979841605
DATAFILE  MIRROR  COARSE   JUN 26 18:00:00  Y    UNDOTBS1.258.836897653
DATAFILE  MIRROR  COARSE   JUN 26 18:00:00  Y    USERS.259.836897653

cp '+DATA/ORCL/DATAFILE/TBS_TTS1.266.979841605' '/home/grid/work/ayshibat/TBS_TTS1.266.979841605'
cp '+DATA/ORCL/DATAFILE/TBS_TTS2.267.979841605' '/home/grid/work/ayshibat/TBS_TTS2.267.979841605'

copying +DATA/ORCL/DATAFILE/TBS_TTS1.266.979841605 -> /home/grid/work/ayshibat/TBS_TTS1.266.979841605
copying +DATA/ORCL/DATAFILE/TBS_TTS2.267.979841605 -> /home/grid/work/ayshibat/TBS_TTS2.267.979841605

↓

【scpでdmpファイルとデータファイルを転送(コピー)】

↓
# 12cR2
cd /u01/app/oracle/oradata/AYUCDB/6C4B2D3386C20FB8E055000000000001/datafile/
ls -la
-rw-r--r--. 1 oracle oinstall  10493952 Jun 26 18:55 TBS_TTS1.266.979841605 ★scpで転送(コピー)したデータファイル
-rw-r--r--. 1 oracle oinstall  10493952 Jun 26 18:56 TBS_TTS2.267.979841605 ★scpで転送(コピー)したデータファイル
-rw-r-----. 1 oracle oinstall 398467072 Jun 26 18:35 o1_mf_sysaux_fhq8s86l_.dbf
-rw-r-----. 1 oracle oinstall 272637952 Jun 26 18:57 o1_mf_system_fhq8s865_.dbf
:
cd /home/oracle/work/ayshibat
ls -la tts_users.dmp
-rw-r--r--. 1 oracle oinstall 94208 Jun 26 18:50 tts_users.dmp ★scpで転送(コピー)したdmpファイル

6. PDBに表領域の定義情報をインポート(impdp)

impdpコマンドで表領域の定義情報をインポートします。
やはり定義情報だけのインポートなので、時間はそれほど掛かりません。

# 12cR2
impdp AYSHIBAT/xxxxxxxx@PDB01 dumpfile=tts_users.dmp directory=DIR_AYSHIBAT \
transport_datafiles=\
'/u01/app/oracle/oradata/AYUCDB/6C4B2D3386C20FB8E055000000000001/datafile/TBS_TTS1.266.979841605',\
'/u01/app/oracle/oradata/AYUCDB/6C4B2D3386C20FB8E055000000000001/datafile/TBS_TTS2.267.979841605' \
logfile=imp_tts_users.log

Import: Release 12.2.0.1.0 - Production on Tue Jun 26 19:10:48 2018

Copyright (c) 1982, 2017, Oracle and/or its affiliates.  All rights reserved.

Connected to: Oracle Database 12c Enterprise Edition Release 12.2.0.1.0 - 64bit Production
Master table "AYSHIBAT"."SYS_IMPORT_TRANSPORTABLE_01" successfully loaded/unloaded
Starting "AYSHIBAT"."SYS_IMPORT_TRANSPORTABLE_01":  AYSHIBAT/********@PDB01 dumpfile=tts_users.dmp directory=DIR_AYSHIBAT transport_datafiles=/u01/app/oracle/oradata/AYUCDB/6C4B2D3386C20FB8E055000000000001/datafile/TBS_TTS1.266.979841605,/u01/app/oracle/oradata/AYUCDB/6C4B2D3386C20FB8E055000000000001/datafile/TBS_TTS2.267.979841605 logfile=imp_tts_users.log
Processing object type TRANSPORTABLE_EXPORT/PLUGTS_BLK
Processing object type TRANSPORTABLE_EXPORT/TABLE
Processing object type TRANSPORTABLE_EXPORT/POST_INSTANCE/PLUGTS_BLK
Job "AYSHIBAT"."SYS_IMPORT_TRANSPORTABLE_01" successfully completed at Tue Jun 26 19:11:05 2018 elapsed 0 00:00:13

7. PDBに接続してデータを確認

PDBに接続してデータを確認します。見事にデータが転送されています。
やったぜ彡(^)(^)

-- 12cR2
sqlplus /nolog
CONNECT AYSHIBAT/xxxxxxxx@PDB01
SHOW CON_NAME;
COLUMN OWNER FORMAT A20;
COLUMN SEGMENT_NAME FORMAT A20;
COLUMN BYTES FORMAT 999,999,999;
COLUMN TABLESPACE_NAME FORMAT A20;
SELECT OWNER, SEGMENT_NAME, BYTES, TABLESPACE_NAME FROM DBA_SEGMENTS WHERE TABLESPACE_NAME IN ('TBS_TTS1', 'TBS_TTS2');
SELECT COUNT(*) FROM TBL_TEST_TTS1;
SELECT COUNT(*) FROM TBL_TEST_TTS2;

SQL*Plus: Release 12.2.0.1.0 Production on Tue Jun 26 19:14:27 2018

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

Connected.

CON_NAME
------------------------------
PDB01

OWNER                SEGMENT_NAME                BYTES TABLESPACE_NAME
-------------------- -------------------- ------------ --------------------
AYSHIBAT             TBL_TEST_TTS2             196,608 TBS_TTS2
AYSHIBAT             TBL_TEST_TTS1             196,608 TBS_TTS1

  COUNT(*)
----------
     10000

  COUNT(*)
----------
     10000

8. 表領域の READ ONLY状態を解除

表領域のREAD ONLY状態を解除します。ちな移行元(今回は11gR2)のREAD ONLY解除は、
データファイル書き出しが終わった時点で実施してOKですやで彡(゚)(゚)

-- 11gR2
SELECT TABLESPACE_NAME, STATUS FROM DBA_TABLESPACES WHERE TABLESPACE_NAME IN ('TBS_TTS1', 'TBS_TTS2');
ALTER TABLESPACE TBS_TTS1 READ WRITE;
ALTER TABLESPACE TBS_TTS2 READ WRITE;
SELECT TABLESPACE_NAME, STATUS FROM DBA_TABLESPACES WHERE TABLESPACE_NAME IN ('TBS_TTS1', 'TBS_TTS2');

TABLESPACE_NAME                STATUS
------------------------------ ---------
TBS_TTS1                       READ ONLY
TBS_TTS2                       READ ONLY

Tablespace altered.
Tablespace altered.

TABLESPACE_NAME                STATUS
------------------------------ ---------
TBS_TTS1                       ONLINE
TBS_TTS2                       ONLINE

-- 12cR2
SELECT TABLESPACE_NAME, STATUS FROM DBA_TABLESPACES WHERE TABLESPACE_NAME IN ('TBS_TTS1', 'TBS_TTS2');
ALTER TABLESPACE TBS_TTS1 READ WRITE;
ALTER TABLESPACE TBS_TTS2 READ WRITE;
SELECT TABLESPACE_NAME, STATUS FROM DBA_TABLESPACES WHERE TABLESPACE_NAME IN ('TBS_TTS1', 'TBS_TTS2');

TABLESPACE_NAME                STATUS
------------------------------ ---------
TBS_TTS1                       READ ONLY
TBS_TTS2                       READ ONLY

Tablespace altered.
Tablespace altered.

TABLESPACE_NAME                STATUS
------------------------------ ---------
TBS_TTS1                       ONLINE
TBS_TTS2                       ONLINE

9. まとめ

特別な手順は無く、11gR2 ⇒ 12cR2(PDB) の
TTS(トランスポータブル表領域)が実行できました彡(^)(^)

リアルな環境を考慮すると、5. のデータファイル転送(コピー)のところで
最も時間が掛かるのですが、一旦中間ファイルに書き出す今回のやり方よりも、
中間ファイルを介さずに直接転送する方法も有るようなので、
詰める余地が有りますやね彡(゚)(゚)

2018/6/27追記

「5. dmpファイルとデータファイルの転送(コピー)」の
データファイル転送部分はDBMS_FILE_TRANSFERパッケージでも行けました。
ファイルシステム(中間ファイル)を介さないので理論上速い。下記記事参照彡(゚)(゚)

DBMS_FILE_TRANSFERパッケージでDB(11gR2) -> DBLINK -> PDB(12cR2)のデータファイルの転送(コピー)を実行する。(Oracle Database)
http://d.hatena.ne.jp/gonsuke777/20180627/1530081386