- PR -

JDBCで30万件を登録

1
投稿者投稿内容
Tanaka
会議室デビュー日: 2003/01/26
投稿数: 7
お住まい・勤務地: 神奈川・新宿
投稿日時: 2003-03-19 20:18
Tanakaと申します。

Javaで、
・タブ区切りテキストファイルを1レコードずつ読み込む。
・読み込んだレコードでデータベースをSELECTし、同一キーを持つ
 レコードがなければINSERT、あればUPDATEする。
というようなプログラムを作成しました。
SELECT、INSERT、UPDATEなどのSQL文は、それぞれ個別にPreparedして
使用しています。

JDBCドライバはType4(Thin)で、JDKのバージョンは1.4.1_01です。
ORACLEのバージョンは9iになります。

このJavaプログラムをLinuxで実行し、LAN内のWindows2000サーバの
ORACLEデータベースにネットワークを介してデータを登録する処理を
実行しました。

データの件数は30万件で、最初の1時間で5万件ほど登録できたので、
6,7時間で終了すると思っていましたが、5万件ほど登録したあとに、
パフォーマンスが落ちて、10時間経過しても10万件ほどしか登録
できませんでした。

サーバとその負荷状況、ネットーワークなどの環境により
一概には言えないと思いますが、ネットワークを介して
Type4ドライバで30万件ものデータを登録するとなると、
このくらいの時間はかかってしまうものなのでしょうか?

このような経験をして対処されたことのある方、
またJDBCプログラミングで気をつけなければならない点など
ありましたら、ご教授してください。

よろしくお願いします。

_________________
--
Tanaka
へげもん
ベテラン
会議室デビュー日: 2002/04/14
投稿数: 87
お住まい・勤務地: 埼玉県
投稿日時: 2003-03-19 21:04
おっしゃるとおり、一概には言えません。
データ量が増えるにつれ遅くなる原因としては、Oracleサーバ側とJavaクライアント側の両方が考えられます。まずは、それぞれのリソース消費量などを調べて、切り分けてみましょう。

Oracle側だとすると、追加・更新しているテーブルのスキーマやインデックスの張り方が気になります。SELECTやUPDATEが毎回動くとなると、インデックスがキーに張られていなければ件数の増加に伴い遅くなるのは当然です。また、余分なインデックスが張られていれば、UPDATEやINSERTが遅くなります。

Javaクライアント側だとすると、メモリのスラッシングなどが考えられます。テキストファイルからレコードを読み込む際に、オブジェクトを大量に作成していませんか? 文字列クラスをStringBufferクラスに置き換えるなどの工夫できる場合があります。
会社員
ベテラン
会議室デビュー日: 2003/01/21
投稿数: 50
投稿日時: 2003-03-19 21:35
sqlldrコマンドは使用できないのでしょうか?
あとは、テーブル構成やselect/update文を見ないとわかりません。
まりり
ぬし
会議室デビュー日: 2001/12/05
投稿数: 329
投稿日時: 2003-03-19 22:20
トランザクションはどうなってます?
1トランザクションで動かしているのならロールバックセグメントが大きくなってパフォーマンスは落ちるかなと思いますが。
Tanaka
会議室デビュー日: 2003/01/26
投稿数: 7
お住まい・勤務地: 神奈川・新宿
投稿日時: 2003-03-19 23:43
みなさん、さっそくの返答ありがとうございます。

まず、トランザクションは未使用です。

この処理は、通常1日1回1000件前後のデータの登録・更新に
使用します。今回の30万件は初期セットアッップ用にと実行
しました。

ORACLE側のインデックスですが、確かにこの処理で発行する
SELECTなどでは使用されないフィールドにもインデックスは
張られています。ですが、他の用途で使用するためこのままに
しておきたいと思っています。

Javaプログラムを実行しているLinuxを調査したところ、空き
メモリ容量が徐々に減っていっています。psコマンドで確認
できるこのJavaプログラムの実メモリ占有率や使用サイズに
変化はありませんが、このプログラム以外、大してプログラムを
実行していないとなると、当然このプログラムの作りが悪いから
なのですね。

そこで、へげもんさんがご指摘して下さった、テキストファイルの
レコード読み込みの部分を見直してみました。
おおまかですが、以下のような感じになっています。

----

private void methodA()
{

String rec;
while ((rec=buff.readLine())!=null) {
methodB(rec);
}

}
private void methodB(String rec)
{
String field[] = rec.split("\t");

[SQL発行->登録・更新処理]

}

----

このmethodBのfield[]は、methodBを抜けるとなくなると思います。
field[]がなくなると、rec.splitで作られたStringオブジェクトの
配列は、どこからも参照されなくなり、GCの対象になると思っている
のですが・・・


_________________
--
Tanaka
maru
ぬし
会議室デビュー日: 2003/01/27
投稿数: 412
投稿日時: 2003-03-20 00:07
こんにちは。
Oracle側なら、表のエクステント、データファイルの初期サイズや増加サイズなどは
どうでしょうか?初期で多めにとっておいたほうがいいと思います。
ま、これが直接の原因で数十時間も処理がかかるとは思えませんが・・・。細かな拡張がない
分、若干処理は上がると思います。
あと、初期セットアップに関係ないインデックスは30万件の初期セットアップ後に作った
ほうがいいのではないでしょうか?

基本的なことなので、すでにやってたらごめんなさい。
Tanaka
会議室デビュー日: 2003/01/26
投稿数: 7
お住まい・勤務地: 神奈川・新宿
投稿日時: 2003-03-20 17:39
こんにちは。

maruさんのアドバイスをもとに、Oracleの該当テーブルを確認
してみると、初期サイスが64Kバイトの設定になっており、
60回以上ものエクステントが発生していました。

おそらく、最初の5万件までは初期サイズ内で収まっていたので、
1時間程度で済み、その後はエクステントにつぐエクステントで
パフォーマンスが落ちていたのだと思われます。

実は、このOracleはあるWebシステム・パッケージとともに導入
されたもので、パッケージ販売会社のSEに設定してもらっています。
まだ仮設定の状態ですが、ある程度の容量は確保されていると思い
当処理を実行してみたのです。
実行する前に確認してみるべきでした。

今すぐ、容量拡張して再度実行してみたいところですが、
私にはそのような権限はない(立場的に)ので、
来週パッケージ販売会社のSEが来るまでお預けとなります。

ご返答してくださったみなさま、ありがとうございました。
_________________
--
Tanaka
katsum
大ベテラン
会議室デビュー日: 2002/02/27
投稿数: 119
お住まい・勤務地: 東京都
投稿日時: 2003-03-21 14:41
> Javaで、
> ・タブ区切りテキストファイルを1レコードずつ読み込む。
> ・読み込んだレコードでデータベースをSELECTし、同一キーを持つ
>  レコードがなければINSERT、あればUPDATEする。
> というようなプログラムを作成しました。
これだけのプログラムなら、Java 以外の言語で作成するのもひとつの方法だと思います。

P.S.
最近の「とにかくJava」風潮に疑問を感じ始めている katsum でした(笑)。
1

スキルアップ/キャリアアップ(JOB@IT)