JDBC로 일괄 INSERTS를 수행하는 효율적인 방법
내 앱에서 INSERTS를 많이해야합니다. Java 앱이고 일반 JDBC를 사용하여 쿼리를 실행하고 있습니다. DB는 Oracle입니다. 그래도 일괄 처리를 활성화했기 때문에 쿼리를 실행하는 데 필요한 네트워크 대기 시간이 절약됩니다. 그러나 쿼리는 별도의 INSERT로 직렬로 실행됩니다.
insert into some_table (col1, col2) values (val1, val2)
insert into some_table (col1, col2) values (val3, val4)
insert into some_table (col1, col2) values (val5, val6)
다음 형식의 INSERT가 더 효율적인지 궁금합니다.
insert into some_table (col1, col2) values (val1, val2), (val3, val4), (val5, val6)
즉, 여러 INSERT를 하나로 축소합니다.
일괄 INSERT를 더 빠르게 만들기위한 다른 팁이 있습니까?
이것은 이전 두 가지 답변을 혼합 한 것입니다.
PreparedStatement ps = c.prepareStatement("INSERT INTO employees VALUES (?, ?)");
ps.setString(1, "John");
ps.setString(2,"Doe");
ps.addBatch();
ps.clearParameters();
ps.setString(1, "Dave");
ps.setString(2,"Smith");
ps.addBatch();
ps.clearParameters();
int[] results = ps.executeBatch();
질문은 JDBC를 사용하여 Oracle에 효율적으로 삽입하는 것을 요구하지만 현재 DB2 (IBM 메인 프레임에서)를 사용하고 있습니다. 개념적으로 삽입하는 것이 비슷하므로 다음 사이의 메트릭을 보는 것이 도움이 될 것이라고 생각했습니다.
한 번에 하나의 레코드 삽입
레코드 배치 삽입 (매우 효율적)
여기에 통계가 있습니다.
1) 한 번에 하나의 레코드 삽입
public void writeWithCompileQuery(int records) {
PreparedStatement statement;
try {
Connection connection = getDatabaseConnection();
connection.setAutoCommit(true);
String compiledQuery = "INSERT INTO TESTDB.EMPLOYEE(EMPNO, EMPNM, DEPT, RANK, USERNAME)" +
" VALUES" + "(?, ?, ?, ?, ?)";
statement = connection.prepareStatement(compiledQuery);
long start = System.currentTimeMillis();
for(int index = 1; index < records; index++) {
statement.setInt(1, index);
statement.setString(2, "emp number-"+index);
statement.setInt(3, index);
statement.setInt(4, index);
statement.setString(5, "username");
long startInternal = System.currentTimeMillis();
statement.executeUpdate();
System.out.println("each transaction time taken = " + (System.currentTimeMillis() - startInternal) + " ms");
}
long end = System.currentTimeMillis();
System.out.println("total time taken = " + (end - start) + " ms");
System.out.println("avg total time taken = " + (end - start)/ records + " ms");
statement.close();
connection.close();
} catch (SQLException ex) {
System.err.println("SQLException information");
while (ex != null) {
System.err.println("Error msg: " + ex.getMessage());
ex = ex.getNextException();
}
}
}
100 건의 거래에 대한 측정 항목 :
each transaction time taken = 123 ms
each transaction time taken = 53 ms
each transaction time taken = 48 ms
each transaction time taken = 48 ms
each transaction time taken = 49 ms
each transaction time taken = 49 ms
...
..
.
each transaction time taken = 49 ms
each transaction time taken = 49 ms
total time taken = 4935 ms
avg total time taken = 49 ms
첫 번째 트랜잭션이 약 복용 120-150ms
에 대한 어떤 쿼리 구문 분석 , 후속 트랜잭션이 단지 약 복용 후 실행 50ms
. (아직 높지만 내 데이터베이스가 다른 서버에 있습니다 (네트워크 문제를 해결해야 함))
2) 배치에 삽입 (효율적) -preparedStatement.executeBatch()
public int[] writeInABatchWithCompiledQuery(int records) {
PreparedStatement preparedStatement;
try {
Connection connection = getDatabaseConnection();
connection.setAutoCommit(true);
String compiledQuery = "INSERT INTO TESTDB.EMPLOYEE(EMPNO, EMPNM, DEPT, RANK, USERNAME)" +
" VALUES" + "(?, ?, ?, ?, ?)";
preparedStatement = connection.prepareStatement(compiledQuery);
for(int index = 1; index <= records; index++) {
preparedStatement.setInt(1, index);
preparedStatement.setString(2, "empo number-"+index);
preparedStatement.setInt(3, index+100);
preparedStatement.setInt(4, index+200);
preparedStatement.setString(5, "usernames");
preparedStatement.addBatch();
}
long start = System.currentTimeMillis();
int[] inserted = preparedStatement.executeBatch();
long end = System.currentTimeMillis();
System.out.println("total time taken to insert the batch = " + (end - start) + " ms");
System.out.println("total time taken = " + (end - start)/records + " s");
preparedStatement.close();
connection.close();
return inserted;
} catch (SQLException ex) {
System.err.println("SQLException information");
while (ex != null) {
System.err.println("Error msg: " + ex.getMessage());
ex = ex.getNextException();
}
throw new RuntimeException("Error");
}
}
100 개의 트랜잭션 배치에 대한 메트릭은 다음과 같습니다.
total time taken to insert the batch = 127 ms
1000 건의 거래
total time taken to insert the batch = 341 ms
따라서 ~5000ms
(한 번에 하나의 trxn으로) 100 개의 트랜잭션을 만드는 것이 ~150ms
(100 개의 레코드 배치로 ) 감소합니다 .
참고-매우 느린 내 네트워크는 무시하지만 메트릭 값은 상대적입니다.
는 Statement
당신에게 다음과 같은 옵션을 제공합니다 :
Statement stmt = con.createStatement();
stmt.addBatch("INSERT INTO employees VALUES (1000, 'Joe Jones')");
stmt.addBatch("INSERT INTO departments VALUES (260, 'Shoe')");
stmt.addBatch("INSERT INTO emp_dept VALUES (1000, 260)");
// submit a batch of update commands for execution
int[] updateCounts = stmt.executeBatch();
You'll have to benchmark, obviously, but over JDBC issuing multiple inserts will be much faster if you use a PreparedStatement rather than a Statement.
You can use this rewriteBatchedStatements
parameter to make the batch insert even faster.
you can read here about the param: MySQL and JDBC with rewriteBatchedStatements=true
How about using the INSERT ALL statement ?
INSERT ALL
INTO table_name VALUES ()
INTO table_name VALUES ()
...
SELECT Statement;
I remember that the last select statement is mandatory in order to make this request succeed. Don't remember why though. You might consider using PreparedStatement instead as well. lots of advantages !
Farid
You can use addBatch and executeBatch for batch insert in java See the Example : Batch Insert In Java
In my code I have no direct access to the 'preparedStatement' so I cannot use batch, I just pass it the query and a list of parameters. The trick however is to create a variable length insert statement, and a LinkedList of parameters. The effect is the same as the top example, with variable parameter input length.See below (error checking omitted). Assuming 'myTable' has 3 updatable fields: f1, f2 and f3
String []args={"A","B","C", "X","Y","Z" }; // etc, input list of triplets
final String QUERY="INSERT INTO [myTable] (f1,f2,f3) values ";
LinkedList params=new LinkedList();
String comma="";
StringBuilder q=QUERY;
for(int nl=0; nl< args.length; nl+=3 ) { // args is a list of triplets values
params.add(args[nl]);
params.add(args[nl+1]);
params.add(args[nl+2]);
q.append(comma+"(?,?,?)");
comma=",";
}
int nr=insertIntoDB(q, params);
in my DBInterface class I have:
int insertIntoDB(String query, LinkedList <String>params) {
preparedUPDStmt = connectionSQL.prepareStatement(query);
int n=1;
for(String x:params) {
preparedUPDStmt.setString(n++, x);
}
int updates=preparedUPDStmt.executeUpdate();
return updates;
}
Using PreparedStatements will be MUCH slower than Statements if you have low iterations. To gain a performance benefit from using a PrepareStatement over a statement, you need to be using it in a loop where iterations are at least 50 or higher.
Batch insert using statement
int a= 100;
try {
for (int i = 0; i < 10; i++) {
String insert = "insert into usermaster"
+ "("
+ "userid"
+ ")"
+ "values("
+ "'" + a + "'"
+ ");";
statement.addBatch(insert);
System.out.println(insert);
a++;
}
dbConnection.commit();
} catch (SQLException e) {
System.out.println(" Insert Failed");
System.out.println(e.getMessage());
} finally {
if (statement != null) {
statement.close();
}
if (dbConnection != null) {
dbConnection.close();
}
}
참고URL : https://stackoverflow.com/questions/3784197/efficient-way-to-do-batch-inserts-with-jdbc
'IT Share you' 카테고리의 다른 글
데이터 프레임의 각 그룹 내에서 최대 값 추출 (0) | 2020.12.10 |
---|---|
git pull 및 git push에 대한 다른 기본 원격 (추적 분기) (0) | 2020.12.10 |
C # Random.Next-상한을 반환하지 않습니까? (0) | 2020.12.10 |
jquery로 Enter 키를 눌렀는지 감지 (0) | 2020.12.10 |
Backbone에서 뷰 믹스 인을 수행하는 적절한 방법 (0) | 2020.12.10 |