2012-03-03 40 views
0

こんにちは、私は本当に助けを必要としており、私はかなり不満です。Jdbc Oracleバッチ更新で一部のテーブルのパフォーマンスが低下する

私は、データベースから別のデータベースにデータを移行することについて、このプロジェクトに取り組んでいます。どちらもOracleです。私がやっていることは、ソースデータベースからテーブルを取得し、ターゲットデータベースにテーブルを作成することです。次に、ソース表からデータをフェッチして、ターゲット・データベースにバッチ挿入します。

もう少し詳しく説明します。

ソース・テーブルから16個のROWID範囲を取得し、データ・コピー用の選択照会を8個のサーバー(それぞれ2個)に配布することで、これを並列に実行します。 (実際にテストサーバーでは、4台のマシンにそれぞれ4台ずつ配布しています)。そして、私はテーブルに挿入する各スレッドでデータを選択します。

ターゲットにテーブルを作成し、他のマシン上で動作するスレーブモジュールにタスクを送信するためのROWID範囲を決定する、1つのサーバー上で動作するマスターモジュールを持つこと。しかし、いくつかのテーブルでは本当に遅いです。そしてなぜ私は知らない。今私は2つのテーブルを持っています。もう一つは劇的に遅いです。同じdbと同じ表領域とデータファイル、別のdb、同じ表領域および同じデータファイルの両方

私は107,910.833行でサイズ13936.4375 MBを高速でコピーでき、5分で終了します。これは、テーブル

-- Create table 
create table CMP_SUBS_RESPONSE_INS 
(
    RESPONSE_TP_SK   NUMBER(16), 
    CHURN_REASON_TP_SK  NUMBER(16), 
    CONTRACT_SK    NUMBER(16), 
    OFFER_SK     NUMBER(16), 
    CHANNEL_SK    NUMBER(16), 
    CMP_RUN_SK    NUMBER(16), 
    CAMPAIGN_CELLS_SK   NUMBER(16), 
    SUBS_RESPONSE_SK   NUMBER(16), 
    SUBS_RESPONSE_NK   VARCHAR2(50), 
    SUBS_RESPONSE_NK2   NUMBER, 
    CRC_CALCULATION_FLAG  VARCHAR2(2), 
    SOURCE_SYSTEM_SK   NUMBER(16), 
    INITIAL_ETL_DATE   DATE, 
    MODIFICATION_SYSTIME  DATE, 
    UPDATE_ETL_DATE   DATE, 
    START_DATE    DATE, 
    END_DATE     DATE, 
    FULFILLMENT_FLAG   VARCHAR2(1), 
    CHURN_SUBREASON_TP_SK  NUMBER(16), 
    LMC_REASON_CATEGORY_SK NUMBER(16), 
    LMC_REASON_TIMEPERIOD_SK NUMBER(16), 
    LMC_REASON_PAYMENTTYPE_SK NUMBER(16) 
) 
tablespace USERS_BTS 
    pctfree 10 
    initrans 1 
    maxtrans 255 
    storage 
    (
    initial 64K 
    next 1M 
    minextents 1 
    maxextents unlimited 
);  

---target 

create table BR_TEST2 
(
    RESPONSE_TP_SK   NUMBER(16), 
    CHURN_REASON_TP_SK  NUMBER(16), 
    CONTRACT_SK    NUMBER(16), 
    OFFER_SK     NUMBER(16), 
    CHANNEL_SK    NUMBER(16), 
    CMP_RUN_SK    NUMBER(16), 
    CAMPAIGN_CELLS_SK   NUMBER(16), 
    SUBS_RESPONSE_SK   NUMBER(16), 
    SUBS_RESPONSE_NK   VARCHAR2(50), 
    SUBS_RESPONSE_NK2   NUMBER, 
    CRC_CALCULATION_FLAG  VARCHAR2(2), 
    SOURCE_SYSTEM_SK   NUMBER(16), 
    INITIAL_ETL_DATE   DATE, 
    MODIFICATION_SYSTIME  DATE, 
    UPDATE_ETL_DATE   DATE, 
    START_DATE    DATE, 
    END_DATE     DATE, 
    FULFILLMENT_FLAG   VARCHAR2(1), 
    CHURN_SUBREASON_TP_SK  NUMBER(16), 
    LMC_REASON_CATEGORY_SK NUMBER(16), 
    LMC_REASON_TIMEPERIOD_SK NUMBER(16), 
    LMC_REASON_PAYMENTTYPE_SK NUMBER(16) 
) 
tablespace PUB_A_BTS 
    pctfree 10 
    initrans 1 
    maxtrans 255 
    storage 
    (
    initial 64K 
    next 1M 
    minextents 1 
    maxextents unlimited 
); 

のDDLで、(成し遂げるためにtooo多くの時間を要する1は、約37万行のサイズは11519メガバイト、であり、それ以上2-3かかり、時間多分もっと実際に私はいつも不満を持っていないとプロセスを殺し、最後に見たことがない)テーブルのいずれかで

create table DGG1 
(
    YEAR_MONTH    VARCHAR2(250), 
    SUBSCRIBER_ID   NUMBER, 
    EXT_DATE    TIMESTAMP(6), 
    CALC_MONTHS   VARCHAR2(250), 
    LAST_3_MONTH_FLAG  VARCHAR2(250), 
    AVEA1_YTL    NUMBER, 
    AVEA1_SAVING_YTL  NUMBER, 
    AVEA1_SAVING_PER  NUMBER, 
    AVEA2_YTL    NUMBER, 
    AVEA2_SAVING_YTL  NUMBER, 
    AVEA2_SAVING_PER  NUMBER, 
    AVEA3_YTL    NUMBER, 
    AVEA3_SAVING_YTL  NUMBER, 
    AVEA3_SAVING_PER  NUMBER, 
    AVEA4_YTL    NUMBER, 
    AVEA4_SAVING_YTL  NUMBER, 
    AVEA4_SAVING_PER  NUMBER, 
    AVEA5_YTL    NUMBER, 
    AVEA5_SAVING_YTL  NUMBER, 
    AVEA5_SAVING_PER  NUMBER, 
    AVEA6_YTL    NUMBER, 
    AVEA6_SAVING_YTL  NUMBER, 
    AVEA6_SAVING_PER  NUMBER, 
    AVEA7_YTL    NUMBER, 
    AVEA7_SAVING_YTL  NUMBER, 
    AVEA7_SAVING_PER  NUMBER, 
    AVEA8_YTL    NUMBER, 
    AVEA8_SAVING_YTL  NUMBER, 
    AVEA8_SAVING_PER  NUMBER, 
    AVEA9_YTL    NUMBER, 
    AVEA9_SAVING_YTL  NUMBER, 
    AVEA9_SAVING_PER  NUMBER, 
    AVEA10_YTL    NUMBER, 
    AVEA10_SAVING_YTL  NUMBER, 
    AVEA10_SAVING_PER  NUMBER, 
    TELSIM1_YTL   NUMBER, 
    TELSIM1_SAVING_YTL  NUMBER, 
    TELSIM1_SAVING_PER  NUMBER, 
    TELSIM2_YTL   NUMBER, 
    TELSIM2_SAVING_YTL  NUMBER, 
    TELSIM2_SAVING_PER  NUMBER, 
    TELSIM3_YTL   NUMBER, 
    TELSIM3_SAVING_YTL  NUMBER, 
    TELSIM3_SAVING_PER  NUMBER, 
    TELSIM4_YTL   NUMBER, 
    TELSIM4_SAVING_YTL  NUMBER, 
    TELSIM4_SAVING_PER  NUMBER, 
    TELSIM5_YTL   NUMBER, 
    TELSIM5_SAVING_YTL  NUMBER, 
    TELSIM5_SAVING_PER  NUMBER, 
    TELSIM6_YTL   NUMBER, 
    TELSIM6_SAVING_YTL  NUMBER, 
    TELSIM6_SAVING_PER  NUMBER, 
    TELSIM7_YTL   NUMBER, 
    TELSIM7_SAVING_YTL  NUMBER, 
    TELSIM7_SAVING_PER  NUMBER, 
    TELSIM8_YTL   NUMBER, 
    TELSIM8_SAVING_YTL  NUMBER, 
    TELSIM8_SAVING_PER  NUMBER, 
    TELSIM9_YTL   NUMBER, 
    TELSIM9_SAVING_YTL  NUMBER, 
    TELSIM9_SAVING_PER  NUMBER, 
    TELSIM10_YTL   NUMBER, 
    TELSIM10_SAVING_YTL NUMBER, 
    TELSIM10_SAVING_PER NUMBER, 
    ETT_DATE    TIMESTAMP(6), 
    RUN_ID     VARCHAR2(250), 
    CO_ID     NUMBER, 
    UNIQUE_PARTY_ID  NUMBER, 
    UNOPTIMISEABLE_CHARGES NUMBER, 
    OTHER_CHARGES   NUMBER 
) 
tablespace USERS_BTS 
    pctfree 10 
    initrans 1 
    maxtrans 255 
    storage 
    (
    initial 64k 
    next 1m 
    minextents 1 
    maxextents unlimited 
); 

----target 

create table dds_etl.br_test 
(
    YEAR_MONTH    VARCHAR2(250), 
    SUBSCRIBER_ID   NUMBER, 
    EXT_DATE    TIMESTAMP(6), 
    CALC_MONTHS   VARCHAR2(250), 
    LAST_3_MONTH_FLAG  VARCHAR2(250), 
    AVEA1_YTL    NUMBER, 
    AVEA1_SAVING_YTL  NUMBER, 
    AVEA1_SAVING_PER  NUMBER, 
    AVEA2_YTL    NUMBER, 
    AVEA2_SAVING_YTL  NUMBER, 
    AVEA2_SAVING_PER  NUMBER, 
    AVEA3_YTL    NUMBER, 
    AVEA3_SAVING_YTL  NUMBER, 
    AVEA3_SAVING_PER  NUMBER, 
    AVEA4_YTL    NUMBER, 
    AVEA4_SAVING_YTL  NUMBER, 
    AVEA4_SAVING_PER  NUMBER, 
    AVEA5_YTL    NUMBER, 
    AVEA5_SAVING_YTL  NUMBER, 
    AVEA5_SAVING_PER  NUMBER, 
    AVEA6_YTL    NUMBER, 
    AVEA6_SAVING_YTL  NUMBER, 
    AVEA6_SAVING_PER  NUMBER, 
    AVEA7_YTL    NUMBER, 
    AVEA7_SAVING_YTL  NUMBER, 
    AVEA7_SAVING_PER  NUMBER, 
    AVEA8_YTL    NUMBER, 
    AVEA8_SAVING_YTL  NUMBER, 
    AVEA8_SAVING_PER  NUMBER, 
    AVEA9_YTL    NUMBER, 
    AVEA9_SAVING_YTL  NUMBER, 
    AVEA9_SAVING_PER  NUMBER, 
    AVEA10_YTL    NUMBER, 
    AVEA10_SAVING_YTL  NUMBER, 
    AVEA10_SAVING_PER  NUMBER, 
    TELSIM1_YTL   NUMBER, 
    TELSIM1_SAVING_YTL  NUMBER, 
    TELSIM1_SAVING_PER  NUMBER, 
    TELSIM2_YTL   NUMBER, 
    TELSIM2_SAVING_YTL  NUMBER, 
    TELSIM2_SAVING_PER  NUMBER, 
    TELSIM3_YTL   NUMBER, 
    TELSIM3_SAVING_YTL  NUMBER, 
    TELSIM3_SAVING_PER  NUMBER, 
    TELSIM4_YTL   NUMBER, 
    TELSIM4_SAVING_YTL  NUMBER, 
    TELSIM4_SAVING_PER  NUMBER, 
    TELSIM5_YTL   NUMBER, 
    TELSIM5_SAVING_YTL  NUMBER, 
    TELSIM5_SAVING_PER  NUMBER, 
    TELSIM6_YTL   NUMBER, 
    TELSIM6_SAVING_YTL  NUMBER, 
    TELSIM6_SAVING_PER  NUMBER, 
    TELSIM7_YTL   NUMBER, 
    TELSIM7_SAVING_YTL  NUMBER, 
    TELSIM7_SAVING_PER  NUMBER, 
    TELSIM8_YTL   NUMBER, 
    TELSIM8_SAVING_YTL  NUMBER, 
    TELSIM8_SAVING_PER  NUMBER, 
    TELSIM9_YTL   NUMBER, 
    TELSIM9_SAVING_YTL  NUMBER, 
    TELSIM9_SAVING_PER  NUMBER, 
    TELSIM10_YTL   NUMBER, 
    TELSIM10_SAVING_YTL NUMBER, 
    TELSIM10_SAVING_PER NUMBER, 
    ETT_DATE    TIMESTAMP(6), 
    RUN_ID     VARCHAR2(250), 
    CO_ID     NUMBER, 
    UNIQUE_PARTY_ID  NUMBER, 
    UNOPTIMISEABLE_CHARGES NUMBER, 
    OTHER_CHARGES   NUMBER 
) 
tablespace PUB_A_BTS 
    pctfree 10 
    initrans 1 
    maxtrans 255 
    storage 
    (
    initial 64k 
    next 1m 
    minextents 1 
    maxextents unlimited 
); 

ませ制約やインデックス。あなたが見ることができるようにヌルチェックでもありません。

ここで私が書いたJavaコードは、jvisualvmをサンプリングに使用しました。遅いもののようですが、CPU時間の99%がexecuteBatchメソッドで費やされています。oracle.net.ns.Packet.receive ()メソッドはexecuteBatchのサブツリーにあります。速いものについてはまだ時間がかかるものの、約45%です。

私は書き込み機構をコメントアウトしてgetObjectメソッドを実行し、100秒でテーブルのロードを終了します。ソースDBからの読み込みは、問題が私にとってどこにあるかのようには見えません。

だから、DBはバッチインサートを実行するのに時間がかかりすぎると思っていました。私は、列数が増えると処理速度が遅くなると思っていましたが、遅くコピーされた表から20列しか選択されませんでしたが、それはまだ遅くてexecuteBatchでぶら下がっていました。それから、私はそれが私が適切なgetXXX()メソッドを列型に使用しなかったためだと思って、コードをgetObjectから適切に変更してメソッドを取得する必要がありました。

私はdbが新しい領域を割り当てるのに時間がかかりすぎると思っていました。だから、私はバッチを実行中にスペースを割り当てる時間を費やさないことを確認するために、最初のエクステント15ギガバイトのテーブルを作成しました。それから、もう一度動作しませんでした。

テーブルのコピーが遅すぎると、サーバーのCPUアクティビティがスレーブモジュールを実行していることがわかります(実際のデータコピーを行うコードは以下のとおりです)。そして、それは高速です、CPU使用量の多く。

私はさまざまなバッチサイズとフェッチサイズで試してみましたが、あまり役に立ちませんでした。

誰も私がここで間違っていることを教えてもらえますか?私は、ファンタスetlツールで同じテーブルをコピーし、それは約10分ですぐに仕事をします。

明らかに、特定のタイプのテーブルについてです。しかし、私はちょうどここで間違っているものを見つけることができません。私は最新のjdbcドライバ(ojdbc6)を入手して問題ではないことを確認しましたが、それでも同じでした。

は私がターゲット接続が自動私はにデータを書き込む

OraclePreparedStatement preparedStatement = null; 
preparedStatement = connection.prepareStatement(insertScript); 

、ここで、インサートを準備する方法偽

targetConnection.setAutoCommit(false); 

をコミットしている

public ResultSet getQueryResultset(Connection con, String query) throws SQLException { 
     OraclePreparedStatement preparedStatement = null; 
     preparedStatement = con.prepareStatement(query); 
     preparedStatement.setRowPrefetch(DTSConstants.FETCH_SIZE);//1000 
     return preparedStatement.executeQuery(); 
    } 

ソースDBからクエリ結果を取得しますターゲット

private int write(ResultSet resultSet, OraclePreparedStatement preparedStatement, long taskID) throws SQLException, 
      DTSException, MLException, ParseException { 
     int statementCounter = 0; 
     int rowsAffected = 0; 
     int columnCount = columnNames.length; 
     while (resultSet.next()) { 
      setColumnsAndAddBatch(resultSet, preparedStatement, columnCount); 
      statementCounter++; 
      rowsAffected++; 
      if (statementCounter >= DTSConstants.BATCH_SIZE) { /1000 
       preparedStatement.executeBatch(); 
       statementCounter = 0; 
       controllerUtil.performTaskSanityCheck(taskID); 
      } 
     } 
     preparedStatement.executeBatch(); 
     return rowsAffected; 
    } 


private void setColumnsAndAddBatch(ResultSet resultSet, OraclePreparedStatement preparedStatement, int columnCount) 
      throws SQLException, MLException, ParseException { 
     for (int i = 0; i < columnCount; i++) { 
      Object object = resultSet.getObject(i + 1);//Changed this to Object object = OracleDataHandler.getData(resultSet, i + 1, columntypes[i]); 

      if (maskingLibGateway != null) { 
       String columnName = columnNames[i]; 
       if (maskFields.containsKey(columnName) == true) { // never true for my examples, so the method never gets called 
        object = maskObject(object, columnName); 
       } 
      } 
      preparedStatement.setObject(i + 1, object); 
     } 
     preparedStatement.addBatch(); 
    } 

パブリッククラスOracleDataHandler {

public static Object getData(ResultSet resultSet, int columnIndex, int columnType) throws SQLException { 

    switch (columnType) { 
    case Types.NUMERIC: 
    case Types.DECIMAL: 
     return resultSet.getBigDecimal(columnIndex); 
    case Types.CHAR: 
    case Types.VARCHAR: 
    case Types.LONGNVARCHAR: 
     return resultSet.getString(columnIndex); 
    case Types.INTEGER: 
     return resultSet.getInt(columnIndex); 
    case Types.DATE: 
     return resultSet.getDate(columnIndex); 
    case Types.TIMESTAMP: 
     return resultSet.getTimestamp(columnIndex); 
    case Types.TIME: 
     return resultSet.getTime(columnIndex); 
    case Types.BIGINT: 
     return resultSet.getLong(columnIndex); 
    case Types.DOUBLE: 
    case Types.FLOAT: 
     return resultSet.getDouble(columnIndex); 
    case Types.SMALLINT: 
     return resultSet.getShort(columnIndex); 
    case Types.TINYINT: 
     return resultSet.getByte(columnIndex); 
    case Types.BINARY: 
    case Types.VARBINARY: 
     return resultSet.getBytes(columnIndex); 
    case Types.CLOB: 
     return resultSet.getClob(columnIndex); 
    case Types.ARRAY: 
     return resultSet.getArray(columnIndex); 
    case Types.BLOB: 
     return resultSet.getBlob(columnIndex); 
    case Types.REAL: 
     return resultSet.getFloat(columnIndex); 
    case Types.BIT: 
    case Types.BOOLEAN: 
     return resultSet.getBoolean(columnIndex); 
    case Types.REF: 
     return resultSet.getRef(columnIndex); 
    case Types.DATALINK: 
     return resultSet.getURL(columnIndex); 
    case Types.LONGVARBINARY: 
     return resultSet.getBinaryStream(columnIndex); 
    default: 
     return resultSet.getObject(columnIndex); 
    } 

} 

}

+1

'insertScript'はどこから来たのですか?また、明示的な(または暗黙的な)変換はどこにありますか?飛び出したテーブルの唯一の違いは、2番目のタイムスタンプです。彼らはすべての遅いものに存在していますか?また、データ・ポンプを使用して、Javaから制御したい場合は、API経由でデータベース・リンクを介して転送することを検討しましたか? –

+0

私は動的に挿入スクリプトを構築します。私は "ターゲットテーブル(cols)の値(?)に挿入する"です。私は変換をしません。そして私はタイムスタンプ以外の遅いテーブルから20列を選択しましたが、それはまだ遅かったです。 異なるDBプラットフォーム間でデータをコピーするようにします。また、定義されている場合はデータマスキングも行います.Javaを使用している理由、分散したコピーを行う理由 – Bren

+0

低速テーブルにインデックスまたは制約がありますか? –

答えて

0

私は問題を解決しgetXXXメソッドを決定するために、このクラスを使用しました。

私がしたすべては、私は方法

もののを取得する使用方法type.Just各データのために適切なJDBC setXXXメソッドへのsetObjectメソッドを変更することでした、私はかなり正確に問題だったか理解していませんでした。そして、なぜいくつかのテーブルだけで、他のテーブルではありません。私はタイムスタンプ以外の列を選択したので、タイムスタンプのデータ型にすることはできません。

誰かが私に本当に問題が何であるか教えてもらえれば、私は本当にそれを飾ります。私はそれはターゲットのデータベースはいくつかのデータ型(いずれかの1つの変換?)または私はJava側のメモリでより大きなデータを作成していたと仮定して、ネットワークを介してsetXXXメソッドを使用してそれはあまりにも多くの時間がかかりましたか?これらはまさに前提です。 (非常によく愚かなものかもしれません)

とにかく私は問題を解決して嬉しいです。返事をくれたすべての人に感謝します。

+0

まだ分かりませんが、私は今も同じ問題があります。実際には、まだ解決していません。私はここに市長に直面しています。単純なフィールドは10個の制約なしのテーブルを想像しています.DBへのシンボリックリンクを使用し、自動コミットオフ、プリペアドステートメント、パラメータの設定、バッチと地獄の追加、51秒の実行時間25,000データの場合... DB側ではボトルネックは見られませんが、問題はありません。また、私は、実際の取引の前にojdbcのトレースレベルをFINESTに設定すると、多大な変換が発生していることに気付きました。 – newhouse

+0

"oracle.jdbc.driver.DBConversion javaCharsToCHARBytes"を何千回も実行しています。また、giglingの効果は、私がjarの_gデバッグバージョンを使用すると実行時間が半分になりますが、FINESTをトレースしなければSLOWが実行されます。私はちょうど今、激怒しています。 – newhouse

+0

@ n3whous3:dbサーバーまたはマシンでJavaを実行しているときに、遅いものがありますか? dbリンクを介してデータをコピーするにはどれぐらいかかりますか? ボトルネックの原因となっているコードには、Jvisuamvmなどを使用して試したことがあります。 – Bren

関連する問題