MTU lab

CSVをzipで圧縮しながら出力

概要

CSVや固定長データ形式など、テキストファイルは扱いやすい反面、ファイルサイズが大きくなりがちです。テキストファイルを zip 等の書庫形式ファイルで保存出来れば、高い圧縮率が期待できるので、場所をとらず論理バックアップやアーカイブにとても便利です。しかし、テキストファイルを一旦出力してから zipへ圧縮するのは二度手間ですし一時的な領域を必要とします。

MTU v4.1 から登場した「並列化可能なパイプ処理」と言う機能は、上記のように他のユーティリティーを使って、テキストファイルを直接何か他のものへ変換する用途にぴったりです。例えば zip アーカイバーと組み合わせてこの機能を使うとダイレクトに zip ファイルへ圧縮されたCSVデータを作ることができます。

処理はとてもスピーディーで弊社の実証実験では1.44ギガバイト分のCSVデータを844メガバイト(圧縮率58パーセント)のzipファイルへ直接圧縮して出力するのに277秒で完了しました。対象が複数あれば、並列実行により更にスピードアップ可能です。

このトピックでは、サンプルなどを挟みながらデータ圧縮の方法を説明したいと思います。

準備

  1. 説明にあたり、次のものを準備してください。
  2. 準備するもの 入手先 摘要
    MTU v4.1 サンプル版 こちらから入手 64-bit版、32-bit版どちらでも可
    Zip Oracle Database Client ORACLE_HOMEのbinにあります
    7-Zip こちらから入手 64-bit x64版、32-bit x86版どちらでも可

    MTU は取扱説明書(4.28MB)に解説された方法に従ってインストールしてください。

    Zipあるいは7-Zipのいずれを使う場合においても、それぞれの実行形式のあるフォルダを環境変数PATHの指し示す場所に含めてください。

  3. SQL*Plus を使ってSCOTTスキーマを作成します。SYSかSYSTEMユーザでログインしプロンプトで@?/rdbms/admin/utlsampl.sqlを実行して作成しておきます。
  4. [スタートメニュー] – [PLUMSIX] – [MTU v4.1 xx-bit xxxx版] にある [環境変数の編集]というショートカットを選択します。
  5. メモ帳により env.bat というファイルが開きますので、下記の編集をした後保存してください。
  6. 環境変数名 出荷時初期値 書き換える値
    USERID SYSTEM/MANAGER SYSTEM/パスワード@DB別名
    LISTTABLE   EMP,DEPT,SALGRADE
    STDOUT 0x0000 0x0001
    STREAM_LOCATOR   zipを使う場合
    ipc_pipe://zip “{O}\{C}” -v –
    7-Zipを使う場合
    ipc_pipe://7z a -t7z -mx1 -si{C}.{X} “{O}/{C}”
    SKIPSCR   true
    EMBED_COLUMN_NAME   ,:”:

    MTUはSTREAM_LOCATORに与えられたipc_pipe://というスキーム文字列の後に続くコマンドを子プロセスとして実行します。
    子プロセスは標準入力に対応していなければなりません。また、上記の文字列中にコマンドを与えるとき、標準入力を扱う指定が選択されていなければなりません。
    zip の場合、コマンド末尾の’-‘ ハイフンが、7-Zip の場合は -si というスイッチが標準入力を扱う指定となります。
    子プロセスが同時に起動される数は環境変数PARALLELISMの値を上限とします。
    1つ以上の名無しパイプを使ってMTUと各子プロセスがプロセス間通信を行います。この時、各プロセスは並列に動作します。
    中括弧で囲まれたアルファベット文字は、子プロセスへ引き渡される文字列のプレースフォルダを示しており、{O}は出力先フォルダ名、{C}はテーブル名+パーティション名、{X}は拡張子名へそれぞれ変換されます。
     

  7. [スタートメニュー] – [PLUMSIX] – [MTU v4.1 xx-bit xxxx版] にある [コマンド・プロンプト]というショートカットを選択します。

実行

これで準備が整いました。それでは実行してみましょう。STREAM_LOCATOR へ zip を使う設定をした場合の事例です。

  1. コマンドプロンプトでカレントディレクトリにあるunload.batスクリプトを実行します。次のようなメッセージが表示され、MTU が開始します。
  2. C:\ProgramData\PLUMSIX\mtu_4.1\x64>unload
    Multi-threaded Unloader version 4.11
    (c) 2003 Plumsix Co.,Ltd. All rights reserved.
    Windows 7 Professional Service Pack 1 (build 7601), 64-bit native
    Number of NUMA nodes: 1
    Number of physical processor packages: 1
    Number of processor cores: 2
    Number of logical processors: 2
    Number of processor L1/L2/L3 caches: 4/1/0
    表データファイル出力を実行します...
    
    #### 途中略 ####
    
    空領域サイズチェックの閾値は 1024Mバイトです。
    データファイルと制御ファイルを出力中です。[5280M] C:\ProgramData\PLUMSIX\mtu_4.1\x64\output
    ストリームの位置:ipc_pipe://zip "{O}\{C}" -v -
    TableName                     :      NumRows:  Elapse:Rows/s:Bytes:  B/s:   Len
    EMP                           :           12:    0.09:  127.: 774.:8234.:   64.
    DEPT                          :            4:    0.10:   41.: 219.:2257.:   54.
    SALGRADE                      :            5:    0.12:   43.: 245.:2112.:   49.
    処理対象となった表の総数      :            3
    ラウンドトリップ(回)        :          137
    出力バイト総数(kbytes)      :         3.88
    所要時間(秒)                :         2.68
    処理速度(kbytes/秒)         :         1.45
    正常終了しました。
    
    

  3. データの出力先である、output フォルダを確認して見てください。zipという拡張子のファイルが出力されています。この中にCSVデータが圧縮して保存されています。
  4. C:\ProgramData\PLUMSIX\mtu_4.1\x64>dir output
     ドライブ C のボリューム ラベルがありません。
     ボリューム シリアル番号は 5CDE-F5D3 です
    
     C:\ProgramData\PLUMSIX\mtu_4.1\x64\output のディレクトリ
    
    2012/10/30  17:24              .
    2012/10/30  17:24              ..
    2012/10/30  17:24               298 DEPT.ctl
    2012/10/30  17:24               296 DEPT.zip
    2012/10/30  17:24               618 EMP.ctl
    2012/10/30  17:24               510 EMP.zip
    2012/10/30  17:24               299 SALGRADE.ctl
    2012/10/30  17:24               283 SALGRADE.zip
    2012/10/30  17:24               594 _stderr.log
    2012/10/30  17:24               877 _stdout.log
                   8 個のファイル               3,775 バイト
                   2 個のディレクトリ   5,536,919,552 バイトの空き領域
    

  5. _stderr.log というファイルには、zip が戻したエラーメッセージが格納されます。確認してみましょう。
  6. C:\ProgramData\PLUMSIX\mtu_4.1\x64> type output\_stderr.log
    Information - [B:2012-10-30 17:24:37:zip "C:\ProgramData\PLUMSIX\mtu_4.1\x64\output\SALGRADE" -v -]
    Information - [E:2012-10-30 17:24:37:zip "C:\ProgramData\PLUMSIX\mtu_4.1\x64\output\SALGRADE" -v -]
    
    Information - [B:2012-10-30 17:24:37:zip "C:\ProgramData\PLUMSIX\mtu_4.1\x64\output\EMP" -v -]
    Information - [E:2012-10-30 17:24:37:zip "C:\ProgramData\PLUMSIX\mtu_4.1\x64\output\EMP" -v -]
    
    Information - [B:2012-10-30 17:24:37:zip "C:\ProgramData\PLUMSIX\mtu_4.1\x64\output\DEPT" -v -]
    Information - [E:2012-10-30 17:24:37:zip "C:\ProgramData\PLUMSIX\mtu_4.1\x64\output\DEPT" -v -]
    

    Information という接頭辞で始まる行はMTUが出力したものです。今回はエラーが発生しなかったので zip が出力したエラーメッセージは何もありません。

  7. _stdout.log というファイルには、zip が戻した標準出力が格納されます。確認してみましょう。
  8. C:\ProgramData\PLUMSIX\mtu_4.1\x64> type output\_stdout.log
    Information - [B:2012-10-30 17:24:37:zip "C:\ProgramData\PLUMSIX\mtu_4.1\x64\output\SALGRADE" -v -]
      adding: -     (in=152) (out=87) (deflated 43%)
    total bytes=152, compressed=87 -> 43% savings
    Information - [E:2012-10-30 17:24:37:zip "C:\ProgramData\PLUMSIX\mtu_4.1\x64\output\SALGRADE" -v -]
    
    Information - [B:2012-10-30 17:24:37:zip "C:\ProgramData\PLUMSIX\mtu_4.1\x64\output\EMP" -v -]
      adding: -     (in=679) (out=314) (deflated 54%)
    total bytes=679, compressed=314 -> 54% savings
    Information - [E:2012-10-30 17:24:37:zip "C:\ProgramData\PLUMSIX\mtu_4.1\x64\output\EMP" -v -]
    
    Information - [B:2012-10-30 17:24:37:zip "C:\ProgramData\PLUMSIX\mtu_4.1\x64\output\DEPT" -v -]
      adding: -     (in=124) (out=100) (deflated 19%)
    total bytes=124, compressed=100 -> 19% savings
    Information - [E:2012-10-30 17:24:37:zip "C:\ProgramData\PLUMSIX\mtu_4.1\x64\output\DEPT" -v -]
    

    こちらには zip のメッセージが各表ごとに2行分ずつ記録されていました。

  9. 次にzip ファイルの内容を見て行きます。例えば output\EMP.zip のヘッダを見るには unzip ユーティリティーを使います。
  10. C:\ProgramData\PLUMSIX\mtu_4.1\x64> unzip -l output\EMP.zip
    Archive:  output/EMP.zip
      Length      Date    Time    Name
    ---------  ---------- -----   ----
          679  2012/10/30 17:24   -
    ---------                     -------
          679                     1 file
    

  11. ファイル名が’-‘(半角ハイフン)となっていますがこれは、zip を実行したときの引数によるものです。zip では標準入力から圧縮対象データを導入する場合ハイフンを使用します。この zip ファイルを普通に unzip してしまうと’-‘という名前のファイルに解凍されてしまいます。
    適切な名前を与えたい場合は、次のようにスイッチ’-p’を指定して標準出力へ一旦出力させた後。リダイレクトによりファイル名を与えるようにすると良いでしょう。
  12. C:\ProgramData\PLUMSIX\mtu_4.1\x64> unzip -p output\EMP.zip > output\EMP.dat
    
    C:\ProgramData\PLUMSIX\mtu_4.1\x64> type output\EMP.dat
    "EMPNO","ENAME","JOB","MGR","HIREDATE","SAL","COMM","DEPTNO"
    7369,"SMITH","CLERK",7902,"1980/12/17",800,,20
    7499,"ALLEN","SALESMAN",7698,"1981/02/20",1600,300,30
    7521,"WARD","SALESMAN",7698,"1981/02/22",1250,500,30
    7566,"JONES","MANAGER",7839,"1981/04/02",2975,,20
    7654,"MARTIN","SALESMAN",7698,"1981/09/28",1250,1400,30
    7698,"BLAKE","MANAGER",7839,"1981/05/01",2850,,30
    7782,"CLARK","MANAGER",7839,"1981/06/09",2450,,10
    7839,"KING","PRESIDENT",,"1981/11/17",5000,,10
    7844,"TURNER","SALESMAN",7698,"1981/09/08",1500,0,30
    7900,"JAMES","CLERK",7698,"1981/12/03",950,,30
    7902,"FORD","ANALYST",7566,"1981/12/03",3000,,20
    7934,"MILLER","CLERK",7782,"1982/01/23",1300,,10
    

  13. for コマンドを併用すると解凍を1度で行うことが出来ます。次の例をご覧ください。
  14. C:\ProgramData\PLUMSIX\mtu_4.1\x64> for /F %I in ('dir /b /s output\*.zip') do (unzip -p %~dpnI > %~dpnI.dat)
    
    C:\ProgramData\PLUMSIX\mtu_4.1\x64>dir output\*.dat
     ドライブ C のボリューム ラベルがありません。
     ボリューム シリアル番号は 5CDE-F5D3 です
    
     C:\ProgramData\PLUMSIX\mtu_4.1\x64\output のディレクトリ
    
    2012/10/31  13:37               124 DEPT.dat
    2012/10/31  13:37               679 EMP.dat
    2012/10/31  13:37               152 SALGRADE.dat
                   3 個のファイル                 955 バイト
                   0 個のディレクトリ   5,529,391,104 バイトの空き領域
    

  15. zip には最大4ギガバイトまでの容量制限があるため、大きなボリュームのCSVを扱うには適していません。このようなケースでは 7-Zip を使うと良いでしょう。

まとめ

如何でしたか。ここまで zip を使った実例を示しながら、ファイルの圧縮方法について説明いたしました。
このトピックで取り上げた「並列化可能なパイプ処理」と言う機能は、zip に限らず標準入力を選択できるプログラムであれば何にでも応用することが出来ます。

最後にこの機能を弊社のテスト環境を使って測定したときの性能データを示します。レコード長は151バイト、件数は1千万件で、並列度は1です。

指標 \ 手段 ノーマル zip 2.1 7-Zip v9.20
ファイルサイズ(MB) 1445 (100%) 844 (58%) 832 (57%)
所要時間(秒) 103 277 274
データ率(MB/秒) 14 3 3

テストに使用したCSVデータの一部を示します。

0000000152"cF6vWw","18640222001321",2472159193122,"aVdvGVF1gKkj3Q6",144531.53,"38570401121539","pVczuj  ","tR0u6NL6AEZc",681023439147420,"PoLEtACubVlRHluCSt8P",
0000000144"fZUnV8Wct","30770602063844",1910787657492,"ldE3lAcAdCp",961432.64,"33430104102212","jjchhNkk","4uM0U7jIG",604006539366843,"fj4dTUWpin1XF4Gm",
0000000140"dvEyofq4t","23420602183330",745431829922,"2Dv5YDgIU4ZjWz",194972.07,"19340131053824","dLcv    ","g1hYDPGjy",785274274473772,"46v3o7YOT3",
0000000146"dZkvpFq","30191030061548",4539188173119,"Vua5uLfUR",302624.1,"25000423200315","4OrYwkG5","y2wRrz7jb9Pp",621299403202238,"fzIqtMNW3NZHCKSNPIAN",
0000000147"X9q3qt6","38440417052938",6169028453271,"isxCj1BFxejQ",39493.22,"28650804021748","aYf1    ","tmWxAa2zWXj",659607368215518,"bX4wjP9Y8RRHy7Pf0SM",
0000000150"bONPzUuwG","28070724103315",1852577489160,"DekdwHPhi9svOG",754542.41,"35201222185540","xxxsoCil","x1mMTsVN0Csn",865734756064736,"u7rwyZIO63UOivc0",
0000000144"adMhv","34220820222923",6006456727601,"IGW1F8ePSOP3Yr",510889.91,"26591028124825","9GqtV   ","PxXx7HCgx",83097569186830,"rA4C1W9e4J6xvbS9yY",
0000000133"aiS4k","25110312221040",2088306807610,"p5U0CyRT0",220063.51,"34891229132924","DsyEq   ","kFDwnc",652425843337974,"eEInEsqSRaVLVK",

乱数表を使用してランダムに生成した文字が続くので、冗長性が低くあまり圧縮率は上がっていません。従って現実的なデータを対象に行った場合は、圧縮率と所要時間はこれよりも良い結果が得られると思われます。

by 開発1号