- ベストアンサー
oo4oを使ったOracleへのデータ処理を高速化したい
タブ区切りのtsvファイルの1項目目に並んでいるデータをDBのプライマリーキーとみなして、DB上に既にあればupdate、なければinsertします。 下のPGは、DBに30万件のデータが入った状態で実行すると、遅すぎて使えません。もっと速くすることはできませんでしょうか。 Public Const OraSQL_01 = "INSERT INTO CUSTOMER (COMPANY_CODE, TEST1) Values (:データ0, :データ1)" Public Const OraSQL_02 = "UPDATE CUSTOMER SET COMPANY_CODE = :データ0, TEST1 = :データ1 WHERE COMPANY_CODE = :データ0" wkFile1 = "c:\test\test.csv" Open wkFile1 For Input As #1 OraSession.BeginTrans Set rs = OraDatabase.CreateDynaset("SELECT COMPANY_CODE FROM CUSTOMER", ORADYN_DEFAULT) OraDatabase.Parameters.Add "データ0", 0, ORAPARM_INPUT OraDatabase.Parameters("データ0").ServerType = ORATYPE_NUMBER OraDatabase.Parameters.Add "データ1", 0, ORAPARM_INPUT OraDatabase.Parameters("データ1").ServerType = ORATYPE_VARCHAR2 Do Until EOF(1) Line Input #1, Text sec = Split(Text, vbTab) OraDatabase.Parameters("データ0").Value = sec(0) OraDatabase.Parameters("データ1").Value = sec(1) Dim flg As Boolean Do Until rs.EOF flg = False If rs("COMPANY_CODE") = sec(0) Then OraDatabase.ExecuteSQL OraSQL_02 flg = True Exit Do Else rs.MoveNext End If Loop If flg = False Then OraDatabase.ExecuteSQL OraSQL_01 End If rs.MoveFirst Loop OraSession.CommitTrans
- みんなの回答 (4)
- 専門家の回答
質問者が選んだベストアンサー
ざっと眺めただけだが確かに遅すぎて使えそうにないな。 アプローチ1.tsvから1行読み込んだら、1列目(顧客コード)をキーにselectして引っかかればupdate、引っかからなければinsertを実行するように変更する。 これはあれなのかな? ひょっとしたらtsvに同じ顧客コードが2行以上あった時に、毎回selectするとエラーが発生せずに1回目に出てきたの餡餅商事はinsert→2回目以降に出てきた餡餅商事はupdateでエラーが発生せずに終わってしまうからダメなのかな? それならこのアプローチを取らなかった理由は分かる。 アプローチ2.顧客コード一覧をダイナセットで取る時に顧客コードを昇順でソートし、バイナリサーチを使うように変更する。 これは説明の必要もないだろう。シーケンシャルサーチはありえんだろう。30万行やし。
その他の回答 (3)
- taka_tetsu
- ベストアンサー率65% (1020/1553)
こんな手も。 1.空のテンポラリの表を作成。主キーもつけておく。 2.テキストファイルの内容をテンポラリ表にSQL*Loaderでロード 3.更新対象のデータをCUSTOMERから削除 delete from CUSTOMER where COMPANY_CODE in (select COMPANY_CODE from テンポラリ表); 4.テンポラリ表の内容をCUSTOMERに追加 insert into CUSTOMER select * from テンポラリ表; 5.テンポラリ表の削除。 #CUSTOMERテーブルの行数だけではなく、テキストファイルの行数も多ければ、下手にロジック組むよりこの方が高速です。
- tsukasa-12r
- ベストアンサー率65% (358/549)
Oracle のバージョンはいくつでしょうか? 9i 以降だったら MERGE が使えますけど。
- taka_tetsu
- ベストアンサー率65% (1020/1553)
selectというか、Dynaset不要。insertして一意制約違反だったらupdateすればいいだけ。 updateの際は、主キーの項目はsetに含めない。
お礼
コードの記述方法がわかりました。 Set rs = OraDatabase.CreateDynaset("SELECT COMPANY_CODE FROM CUSTOMER WHERE COMPANY_CODE = :データ0", ORADYN_DEFAULT) If rs("COMPANY_CODE") = sec2(0) Then OraDatabase.ExecuteSQL OraSQL_02 Else OraDatabase.ExecuteSQL OraSQL_01 End If でできました。 有難うございました。
補足
anmochiさんご回答有難うございます。 恐縮ですが、アプローチ1をとる場合の書き方がわかりません。 1列目をキーにSELECTしてダイナセットで取るには Set rs = OraDatabase.CreateDynaset("SELECT COMPANY_CODE FROM CUSTOMER WHERE COMPANY_CODE = :データ0", ORADYN_DEFAULT) でよいかと思いますが、ひっかかっる、ひっかからないのコードはどのように記述すれば宜しいのでしょうか、わかれば教えて頂けませんでしょうか。 宜しくお願いします。