복붙노트

[SQL] JDBC와 일괄 삽입 할 수있는 효율적인 방법

SQL

JDBC와 일괄 삽입 할 수있는 효율적인 방법

내 응용 프로그램에서 나는 인서트를 많이 할 필요가있다. 그것의 자바 애플 리케이션과 나는 쿼리를 실행하기 위해 일반 JDBC를 사용하고 있습니다. DB를 오라클 서비스를 제공합니다. 그것은 나를 쿼리를 실행하기 위해 대기 시간을 네트워크에 저장 그래서 나는, 그러나 일괄 처리를 사용할 수있다. 그러나 쿼리는 별도의 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들을 만들기위한 다른 팁?

해결법

  1. ==============================

    1.이것은 이전의 두 답변의 혼합이다 :

    이것은 이전의 두 답변의 혼합이다 :

      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();
    
  2. ==============================

    2.문제는 JDBC를 사용하여 Oracle에 효율적으로 삽입 묻습니다 만, 나는 현재 개념적으로 유사한 그래서 그것을 사이에 내 통계를 참조하는 것이 도움이 될 거라고 생각 될 것 삽입, DB2 (에 IBM 메인 프레임)와 함께 연주 해요

    문제는 JDBC를 사용하여 Oracle에 효율적으로 삽입 묻습니다 만, 나는 현재 개념적으로 유사한 그래서 그것을 사이에 내 통계를 참조하는 것이 도움이 될 거라고 생각 될 것 삽입, DB2 (에 IBM 메인 프레임)와 함께 연주 해요

    여기에 메트릭을 이동

    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가 약 복용하고있다. (고 여전히,하지만 내 데이터베이스가 다른 서버에있는 어떤 (I)는 네트워크 문제를 해결하기 위해 필요)

    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
    

    그래서, (100 개 기록의 배치와) 5000ms가 (한 번에 하나의 trxn로) ~ 150ms의 감소됩니다 ~ 100 거래를.

    참고 - 슈퍼 슬로우 내 네트워크를 무시하지만 측정 값은 상대적인 것입니다.

  3. ==============================

    3.성명은 당신에게 다음과 같은 옵션을 제공합니다 :

    성명은 당신에게 다음과 같은 옵션을 제공합니다 :

    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();
    
  4. ==============================

    4.당신은 분명, 벤치 마크해야합니다,하지만 당신은 문보다는 된 PreparedStatement를 사용하는 경우 JDBC를 통해 다수의 삽입을 실행하면 훨씬 더 빨리 될 것입니다.

    당신은 분명, 벤치 마크해야합니다,하지만 당신은 문보다는 된 PreparedStatement를 사용하는 경우 JDBC를 통해 다수의 삽입을 실행하면 훨씬 더 빨리 될 것입니다.

  5. ==============================

    5.당신은 더 빨리 삽입 배치를 만들기 위해이 rewriteBatchedStatements 매개 변수를 사용할 수 있습니다.

    당신은 더 빨리 삽입 배치를 만들기 위해이 rewriteBatchedStatements 매개 변수를 사용할 수 있습니다.

    당신은 PARAM 여기에 대해 읽을 수 있습니다 : MySQL과 JDBC를 rewriteBatchedStatements = 사실로

  6. ==============================

    6.어떻게 INSERT ALL 문을 사용하는 방법에 대해?

    어떻게 INSERT ALL 문을 사용하는 방법에 대해?

    INSERT ALL
    
    INTO table_name VALUES ()
    
    INTO table_name VALUES ()
    
    ...
    
    SELECT Statement;
    

    나는 마지막 선택 문이 요청이 성공하기 위해 필수입니다 기억 해요. 왜하지만 기억하지 마십시오. 대신뿐만 아니라 PreparedStatement의 사용을 고려할 수 있습니다. 많은 장점!

    파리 드

  7. ==============================

    7.일괄 삽입에서 자바 : 당신은 예를 참조 자바 일괄 삽입에 대한 addBatch 및 executeBatch에 사용할 수 있습니다

    일괄 삽입에서 자바 : 당신은 예를 참조 자바 일괄 삽입에 대한 addBatch 및 executeBatch에 사용할 수 있습니다

  8. ==============================

    8.내 코드에서 나는 배치를 사용할 수 없습니다, 그래서 난 그냥 그것을 쿼리 및 매개 변수의 목록을 전달하는 'PreparedStatement의'에 직접 액세스 할 수 없습니다. 트릭은 그러나 문 삽입 가변 길이 및 매개 변수의 LinkedList의를 만드는 것입니다. 효과는 (에러 체크를 생략) 이하로 가변 파라미터 입력 length.See와 상단 예와 동일하다. F1, F2 및 F3 : 가정 'myTable에'는 3 필드가 갱신

    내 코드에서 나는 배치를 사용할 수 없습니다, 그래서 난 그냥 그것을 쿼리 및 매개 변수의 목록을 전달하는 'PreparedStatement의'에 직접 액세스 할 수 없습니다. 트릭은 그러나 문 삽입 가변 길이 및 매개 변수의 LinkedList의를 만드는 것입니다. 효과는 (에러 체크를 생략) 이하로 가변 파라미터 입력 length.See와 상단 예와 동일하다. F1, F2 및 F3 : 가정 'myTable에'는 3 필드가 갱신

    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);
    

    내 DBInterface 클래스에서 내가 가진 :

    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;
    }
    
  9. ==============================

    9.당신이 저 반복이있는 경우자는 PreparedStatements를 사용하면 문보다 훨씬 느립니다. 성명을 통해의 prepareStatement를 사용에서 성능 이점을 얻으려면, 당신은 반복 적어도 50 이상이있는 루프에서 사용해야합니다.

    당신이 저 반복이있는 경우자는 PreparedStatements를 사용하면 문보다 훨씬 느립니다. 성명을 통해의 prepareStatement를 사용에서 성능 이점을 얻으려면, 당신은 반복 적어도 50 이상이있는 루프에서 사용해야합니다.

  10. ==============================

    10.

    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();
                            }
                        }
    
  11. from https://stackoverflow.com/questions/3784197/efficient-way-to-do-batch-inserts-with-jdbc by cc-by-sa and MIT license