バッチ挿入操作に一括コピー API を使用する
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 の制限により、
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.