こんにちは、私は本当に助けを必要としており、私はかなり不満です。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);
}
}
}
'insertScript'はどこから来たのですか?また、明示的な(または暗黙的な)変換はどこにありますか?飛び出したテーブルの唯一の違いは、2番目のタイムスタンプです。彼らはすべての遅いものに存在していますか?また、データ・ポンプを使用して、Javaから制御したい場合は、API経由でデータベース・リンクを介して転送することを検討しましたか? –
私は動的に挿入スクリプトを構築します。私は "ターゲットテーブル(cols)の値(?)に挿入する"です。私は変換をしません。そして私はタイムスタンプ以外の遅いテーブルから20列を選択しましたが、それはまだ遅かったです。 異なるDBプラットフォーム間でデータをコピーするようにします。また、定義されている場合はデータマスキングも行います.Javaを使用している理由、分散したコピーを行う理由 – Bren
低速テーブルにインデックスまたは制約がありますか? –