일괄 삽입 작업에 대량 복사 API 사용

JDBC 드라이버 다운로드

Microsoft JDBC Driver for SQL Server 버전 9.2 이상에서는 일괄 삽입 작업에 대량 복사 API를 사용할 수 있습니다. 일괄 삽입 작업을 실행할 때 사용자는 이 기능으로 그 아래에서 대량 복사 작업을 수행할 수 있습니다. 드라이버의 일반적인 일괄 삽입 작업과 같이, 동일한 데이터를 삽입하면서 성능을 향상하는 것이 드라이버의 목표입니다. 드라이버는 일반적인 일괄 삽입 작업 대신 대량 복사 API를 사용하여 사용자의 SQL 쿼리를 구문 분석합니다. 다음 설정은 일괄 삽입 기능에 대량 복사 API를 사용하도록 설정하는 다양한 방법이며 제한 사항을 나열합니다. 이 페이지에는 사용 방법과 성능 향상까지 시연하는 간단한 샘플 코드도 포함되어 있습니다.

이 기능은 PreparedStatement 및 CallableStatement의 executeBatch() & executeLargeBatch() API에만 적용됩니다.

필수 조건

일괄 삽입에 대량 복사 API를 사용하기 위한 필수 조건입니다.

  • 쿼리는 삽입 쿼리여야 합니다. 쿼리에는 주석이 포함될 수 있지만, 이 기능을 적용하려면 쿼리가 INSERT 키워드로 시작해야 합니다.

일괄 삽입에 대량 복사 API 사용

일괄 삽입에 대량 복사 API를 사용하는 방법은 세 가지입니다.

1. 연결 속성 사용 설정

연결 문자열에 useBulkCopyForBatchInsert=true;를 추가하면 이 기능을 사용할 수 있습니다.

Connection connection = DriverManager.getConnection("jdbc:sqlserver://<server>:<port>;userName=<user>;password=<password>;database=<database>;encrypt=true;useBulkCopyForBatchInsert=true;");

2. SQLServerConnection 개체의 setUseBulkCopyForBatchInsert() 메서드 사용 설정

SQLServerConnection.setUseBulkCopyForBatchInsert(true)를 호출하면 이 기능이 사용 설정됩니다.

SQLServerConnection.getUseBulkCopyForBatchInsert()useBulkCopyForBatchInsert 연결 속성의 현재 값을 검색합니다.

useBulkCopyForBatchInsert의 값은 초기화 시 각 PreparedStatement에 일정하게 유지됩니다. SQLServerConnection.setUseBulkCopyForBatchInsert()에 대한 후속 호출은 이미 생성된 PreparedStatement 값에 영향을 주지 않습니다.

3. SQLServerDataSource 개체의 setUseBulkCopyForBatchInsert() 메서드 사용 설정

이전 옵션과 비슷하지만 SQLServerDataSource를 사용하여 SQLServerConnection 개체를 만듭니다. 두 방법 모두 동일한 결과를 얻을 수 있습니다.

알려진 제한 사항

현재는 다음의 제한 사항이 이 기능에 적용됩니다.

  • 매개 변수화하지 않은 값이 포함된 삽입 쿼리(예: INSERT INTO TABLE VALUES (?, 2)는 지원되지 않습니다. 와일드카드(?)는 이 함수에 유일하게 지원되는 매개 변수입니다.
  • INSERT-SELECT 식이 포함된 삽입 쿼리(예: INSERT INTO TABLE SELECT * FROM TABLE2)는 지원되지 않습니다.
  • 여러 VALUE 식이 포함된 삽입 쿼리(예: INSERT INTO TABLE VALUES (1, 2) (3, 4))는 지원되지 않습니다.
  • OPTION 절 뒤에 오거나, 여러 테이블과 조인되거나, 그 다음에 다른 쿼리가 이어지는 삽입 쿼리는 것은 지원되지 않습니다.
  • IDENTIY_INSERT는 드라이버에서 관리되지 않습니다. insert 문에 ID 열을 포함하지 않거나, 일괄 삽입 문 사이에서 테이블의 IDENTITY_INSERT 상태를 수동으로 설정하거나, insert 문으로 ID 열에 대한 명시적 값을 수동으로 전달하세요. 자세한 내용은 SET IDENTITY_INSERT를 참조하세요.
  • 대량 복사 API의 제한 사항으로 인해 MONEY, SMALLMONEY, DATE, DATETIME, DATETIMEOFFSET, SMALLDATETIME, TIME, GEOMETRY, GEOGRAPHY 데이터 형식은 현재 이 기능에 지원되지 않습니다.

SQL Server 인스턴스와 관련이 없는 오류로 인해 쿼리가 실패하면 드라이버는 오류 메시지를 기록하고 일괄 삽입을 위해 기존의 논리로 돌아갑니다.

예시

이 예제에서는 일반 및 대량 복사 API 시나리오를 비교하여 두 가지 모두에 대해 1,000개 행의 일괄 삽입 작업 사용 사례를 보여줍니다.

    public static void main(String[] args) throws Exception
    {
        String tableName = "batchTest";
        String tableNameBulkCopyAPI = "batchTestBulk";

        String connectionUrl = "jdbc:sqlserver://<server>:<port>;encrypt=true;databaseName=<database>;user=<user>;password=<password>";

        try (Connection con = DriverManager.getConnection(connectionUrl);
                Statement stmt = con.createStatement();
                PreparedStatement pstmt = con.prepareStatement("insert into " + tableName + " values (?, ?)");) {

            String dropSql = "if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[" + tableName + "]') and OBJECTPROPERTY(id, N'IsUserTable') = 1) DROP TABLE [" + tableName + "]";
            stmt.execute(dropSql);

            String createSql = "create table " + tableName + " (c1 int, c2 varchar(20))";
            stmt.execute(createSql);

            System.out.println("Starting batch operation using regular batch insert operation.");
            long start = System.currentTimeMillis();
            for (int i = 0; i < 1000; i++) {
                pstmt.setInt(1, i);
                pstmt.setString(2, "test" + i);
                pstmt.addBatch();
            }
            pstmt.executeBatch();

            long end = System.currentTimeMillis();

            System.out.println("Finished. Time taken : " + (end - start) + " milliseconds.");
        }

        try (Connection con = DriverManager.getConnection(connectionUrl + ";useBulkCopyForBatchInsert=true");
                Statement stmt = con.createStatement();
                PreparedStatement pstmt = con.prepareStatement("insert into " + tableNameBulkCopyAPI + " values (?, ?)");) {

            String dropSql = "if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[" + tableNameBulkCopyAPI + "]') and OBJECTPROPERTY(id, N'IsUserTable') = 1) DROP TABLE [" + tableNameBulkCopyAPI + "]";
            stmt.execute(dropSql);

            String createSql = "create table " + tableNameBulkCopyAPI + " (c1 int, c2 varchar(20))";
            stmt.execute(createSql);

            System.out.println("Starting batch operation using Bulk Copy API.");
            long start = System.currentTimeMillis();
            for (int i = 0; i < 1000; i++) {
                pstmt.setInt(1, i);
                pstmt.setString(2, "test" + i);
                pstmt.addBatch();
            }
            pstmt.executeBatch();

            long end = System.currentTimeMillis();

            System.out.println("Finished. Time taken : " + (end - start) + " milliseconds.");
        }
    }

결과:

Starting batch operation using regular batch insert operation.
Finished. Time taken : 104132 milliseconds.
Starting batch operation using Bulk Copy API.
Finished. Time taken : 1058 milliseconds.

참고 항목

JDBC 드라이버로 성능 및 안정성 개선