kagamihogeの日記

kagamihogeの日記です。

SQL*Loaderで1億件(1.6GB)ロードしてみる

ここんとこSQL*Loaderで遊んでるんで、もうちょい大きいデータファイルでもロードしてみるか、ってだけのエントリです。

環境

準備

ロードのテスト用に表領域を別につくる。

CREATE BIGFILE TABLESPACE TABLESPACE1 
    DATAFILE 
        'C:\oraclexe\app\oracle\oradata\XE\USERS2.DBF' SIZE 10G
    DEFAULT NOCOMPRESS 
    ONLINE 
    EXTENT MANAGEMENT LOCAL;

ちなみに、XEなのでSIZE 11Gとかやると下記のエラーが出ます。

ORA-12953: リクエストが、最大許容データベース・サイズの11GBを超えています

制限事項
・利用可能なユーザデータは11GByteまで
Oracle Database 11g Express Edition(XE)の使い方 - オラクルエンジニア通信 - 技術資料、マニュアル、セミナー

入力データはこんな感じ。ゼロ埋め16バイトで数値が昇順に並んだものを1億件。16バイト * 1億で、データファイルのサイズは1.6GBです。

0000000000000001
0000000000000002
0000000000000003
(以下略。実際には改行無し)

ロード先のテーブル。あらかじめスピードアップのためにアレコレやっています。詳しい事はこちら→ SQL*Loaderリファレンスのダイレクト・パス・ロードのパフォーマンスの最適化に書いてあることやる - kagamihogeのblog

DROP TABLE DEST PURGE;
CREATE TABLE DEST (
  COLUMN1 VARCHAR2(16) ,
  CONSTRAINT DEST_PK PRIMARY KEY(COLUMN1) 
    USING INDEX 
    TABLESPACE "TABLESPACE1"
    PCTFREE 0
    STORAGE(
      INITIAL 2818572288
    )
)
TABLESPACE "TABLESPACE1"
PCTFREE 0
STORAGE (
  INITIAL 2281701376
);

SQL*Loader用の制御ファイル。

OPTIONS (DIRECT=true)
UNRECOVERABLE
load data 
infile 'data_1_6g.dat' "fix 16"
insert
into table DEST
SORTED INDEXES (DEST_PK)
(COLUMN1 CHAR(16))

結果

とりあえず実行時間。さすがにたるいんで1回しか試行してません。

  1
SORTED INDEXES有り 03: 31.93
SORTED INDEXES無し 15: 33.24
同一マシン 08: 31.25

100万件で約2.5秒だったんで、2.5 * 100 = 250秒 → 4分ちょいってことで、まぁそんなもんかなって感じです。

上記の3:31って時間は、SQL*Loaderを動かすマシンとOracleが動いてるマシンは物理的に異なるマシンでやってます。なので、同一マシン上で動かしたらどうなるか? ってことでやったのが「同一マシン」のところです。この環境では、それぞれ別マシンでやったほうがネットワークを越すよりも有利なようです。同一マシンってのは、単一の物理ディスクの上に入力データファイルもOracleのデータファイルも載ってます。そんなに良いディスクではないとはいえ、ディスク上をリードとライトで交互に行ったり来たりするような動作になるのが不利っぽいです。

あと、SORTED INDEXESを無しにすると格段にスピードが落ちる。ついでに一時表領域もインデックス作成に必要な分だけ食うようになる。なので、大量のデータをロードするとき気をつけないといけないのは、データ量はもとよりインデックスをいつ・どのように作るのか、と言ってよいかと。ダイレクトパスロードをするとき、PKすら無いテーブルにロードするってのはほぼ有りえないと思うんで、SORTED INDEXESを指定するに越したことはない。あとは、ロードと同時にインデックス作成するかどうか。これは実行時間にも影響するし、一時表領域もデータ量に応じて確保する必要が出てくる。