Verwenden der Massenkopierungs-API für den Batcheinfügungsvorgang

JDBC-Treiber herunterladen

Der Microsoft JDBC-Treiber 9.2 für SQL Server unterstützt die API für das Massenkopieren für Batcheinfügevorgänge. Mit diesem Feature können Benutzer dem Treiber bei der Ausführung von Batcheinfügevorgängen das Massenkopieren im Hintergrund ermöglichen. Der Treiber strebt beim Einfügen derselben Daten eine bessere Leistung an, als der Treiber bei einem regulären Batcheinfügevorgang erzielen könnte. Der Treiber analysiert die SQL-Abfrage des Benutzers und nutzt anstelle des üblichen Batcheinfügevorgangs die API für das Massenkopieren. Im Folgenden werden verschiedene Einstellungen zum Aktivieren des Features für die API für Masseneinfügevorgänge sowie die geltenden Einschränkungen aufgeführt. Diese Seite enthält außerdem ein kleines Codebeispiel, das eine Verwendung und die Leistungssteigerung veranschaulicht.

Dieses Feature ist nur auf die executeBatch() und executeLargeBatch()-APIs von PreparedStatement und CallableStatement anwendbar.

Voraussetzungen

Voraussetzung für die Aktivierung der API für das Massenkopieren für Batcheinfügevorgänge

  • Die Abfrage muss eine Einfügeabfrage sein (die Abfrage darf Kommentare enthalten, aber muss mit dem INSERT-Schlüsselwort beginnen, damit dieses Feature wirksam ist).

Aktivieren der API für das Massenkopieren für Batcheinfügevorgänge

Es gibt drei Möglichkeiten, die API für das Massenkopieren für Batcheinfügevorgänge zu aktivieren.

1. Aktivierung mit der Verbindungseigenschaft

Durch das Hinzufügen von useBulkCopyForBatchInsert=true; zur Verbindungszeichenfolge wird dieses Feature aktiviert.

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

2. Aktivierung mit der setUseBulkCopyForBatchInsert()-Methode aus dem SQLServerConnection-Objekt

Durch den Aufruf von SQLServerConnection.setUseBulkCopyForBatchInsert(true) wird dieses Feature aktiviert.

SQLServerConnection.getUseBulkCopyForBatchInsert() ruft den aktuellen Wert für die Verbindungseigenschaft useBulkCopyForBatchInsert ab.

Der Wert für useBulkCopyForBatchInsert bleibt für jede PreparedStatement zum Zeitpunkt der Initialisierung konstant. Nachfolgende Aufrufe von SQLServerConnection.setUseBulkCopyForBatchInsert() haben keine Auswirkung auf den Wert des bereits erstellten PreparedStatement-Objekts.

3. Aktivierung mit der setUseBulkCopyForBatchInsert()-Methode aus dem SQLServerDataSource-Objekt

Die Vorgehensweise ähnelt der oben beschriebenen Option, zum Erstellen eines SQLServerConnection-Objekts wird jedoch SQLServerDataSource verwendet. Mit beiden Methoden werden die gleichen Ergebnisse erzielt.

Bekannte Einschränkungen

Für dieses Feature gelten aktuell die folgenden Einschränkungen.

  • Einfügeabfragen, die nicht parametrisierte Werte enthalten (z. B. INSERT INTO TABLE VALUES (?, 2), werden nicht unterstützt. Platzhalter (?) sind die einzigen unterstützten Parameter für diese Funktion.
  • Einfügeabfragen, die INSERT-SELECT-Ausdrücke enthalten (z. B. INSERT INTO TABLE SELECT * FROM TABLE2), werden nicht unterstützt.
  • Einfügeabfragen, die mehrere VALUE-Ausdrücke enthalten (z. B. INSERT INTO TABLE VALUES (1, 2) (3, 4)), werden nicht unterstützt.
  • Einfügeabfragen, auf die eine OPTION-Klausel und mehrere Tabellen oder eine andere Abfrage folgt, werden nicht unterstützt.
  • IDENTIY_INSERT wird nicht im Treiber verwaltet. Schließen Sie entweder keine Identitätsspalten in INSERT-Anweisungen ein, oder legen Sie den IDENTITY_INSERT-Zustand Ihrer Tabellen zwischen Anweisungen für Masseneinfügevorgänge manuell fest, oder übergeben Sie den expliziten Wert für eine Identitätsspalte manuell mit der Einfügeanweisung. Weitere Informationen finden Sie unter SET IDENTITY_INSERT.
  • Aufgrund der Einschränkungen der API für das Massenkopieren werden die Datentypen MONEY, SMALLMONEY, DATE, DATETIME, DATETIMEOFFSET, SMALLDATETIME, TIME, GEOMETRY und GEOGRAPHY für dieses Feature aktuell nicht unterstützt.

Wenn die Abfrage aufgrund von nicht SQL-Server-Instance-bezogenen Fehlern fehlschlägt, protokolliert der Treiber die Fehlermeldung und führt ein Fallback auf die ursprüngliche Logik für Masseneinfügevorgänge durch.

Beispiel

Das folgende Beispiel zeigt einen Anwendungsfall für einen Masseneinfügevorgang mit tausend Zeilen für beide Szenarien – regulär im Vergleich zur API für das Massenkopieren).

    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.");
        }
    }

Ergebnis:

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.

Weitere Informationen

Verbessern von Leistung und Zuverlässigkeit mit dem JDBC-Treiber