バッチ挿入操作に一括コピー API を使用する

JDBC ドライバーのダウンロード

Microsoft JDBC Driver for SQL Server バージョン 9.2 以降では、バッチ挿入操作に一括コピー API を使用することがサポートされています。 この機能を使用すると、ユーザーはバッチ挿入操作の実行時に、ドライバーで一括コピー操作をバックグラウンドで行うことができます。 このドライバーは、通常のバッチ挿入操作で行われるのと同じデータを挿入したときのパフォーマンスを向上させることを目的としています。 ドライバーでは、通常のバッチ挿入操作の代わりに、一括コピー API を使用して、ユーザーの SQL クエリが解析されます。 次の設定は、バッチ挿入機能に対して一括コピー API を有効にするためのさまざまな方法であり、その制限事項の一覧が示されています。 このページには、使用とパフォーマンスの向上を示す小さなサンプル コードも含まれています。

この機能は、PreparedStatement および CallableStatement の executeBatch() および executeLargeBatch() API にのみ適用できます。

前提条件

バッチ挿入に対して一括コピー API を有効にするための前提条件。

  • クエリは挿入クエリであること (クエリにコメントを含めることはできますが、この機能を有効にするには、クエリの先頭に INSERT キーワードを使用する必要があります)。

バッチ挿入に一括コピー API を有効にする

バッチ挿入に一括コピー API を有効にするには、次の 3 つの方法があります。

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 はドライバーで管理されません。 挿入ステートメントに ID 列を含めないか、またはバッチ挿入ステートメント間でテーブルの IDENTITY_INSERT 状態を手動で設定するか、INSERT ステートメントで ID 列の明示的な値を手動で渡します。 詳細については、「SET IDENTITY_INSERT」を参照してください。
  • 一括コピー API の制限により、MONEYSMALLMONEYDATEDATETIMEDATETIMEOFFSETSMALLDATETIMETIMEGEOMETRYGEOGRAPHY の各データ型は、現在、この機能ではサポートされていません。

"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 ドライバーによるパフォーマンスと信頼性の強化