Sdílet prostřednictvím


Použití rozhraní API hromadného kopírování pro operaci dávkového vložení

Stáhnout ovladač JDBC

Ovladač Microsoft JDBC pro SQL Server verze 9.2 a vyšší podporuje použití rozhraní API hromadného kopírování pro dávkové operace vložení. Tato funkce umožňuje uživatelům aktivovat provádění operací hromadného kopírování ovladačem na pozadí při provádění dávkového vkládání. Cílem ovladače je dosáhnout zlepšení výkonu při vkládání stejných dat, jako by měl ovladač s běžnou operací dávkového vložení. Ovladač analyzuje dotaz SQL uživatele pomocí rozhraní API hromadného kopírování místo obvyklé dávkové operace vložení. Následující nastavení jsou různé způsoby, jak povolit rozhraní API hromadného kopírování pro funkci dávkového vkládání a uvádí její omezení. Tato stránka obsahuje také malý vzorový kód, který ukazuje využití a zvýšení výkonu.

Tato funkce se vztahuje pouze na API executeBatch() & executeLargeBatch() pro PreparedStatement a CallableStatement.

Požadavky

Předpokladem pro povolení rozhraní API hromadného kopírování pro dávkové vložení

  • Dotaz musí být vložený dotaz (dotaz může obsahovat komentáře, ale musí začínat klíčovým slovem INSERT, aby se tato funkce projevila).

Povolení rozhraní API hromadného kopírování pro dávkové vložení

Existují tři způsoby, jak povolit API pro hromadné kopírování pro dávkové vložení.

1. Povolení pomocí vlastnosti připojení

Přidání useBulkCopyForBatchInsert=true; do připojovacího řetězce tuto funkci povolí.

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

2. Povolení pomocí metody setUseBulkCopyForBatchInsert() z objektu SQLServerConnection

Volání SQLServerConnection.setUseBulkCopyForBatchInsert(true) umožňuje tuto funkci.

SQLServerConnection.getUseBulkCopyForBatchInsert() načte aktuální hodnotu vlastnosti připojení useBulkCopyForBatchInsert.

Hodnota useBulkCopyForBatchInsert zůstává konstantní pro každý PreparedStatement v době inicializace. Následná volání SQLServerConnection.setUseBulkCopyForBatchInsert() nemají vliv na již vytvořenou hodnotu PreparedStatement.

3. Povolení metody setUseBulkCopyForBatchInsert() prostřednictvím objektu SQLServerDataSource

Podobá se předchozí možnosti, ale použití SQLServerDataSource k vytvoření objektu SQLServerConnection. Obě metody dosáhnou stejného výsledku.

Známá omezení

V současné době platí pro tuto funkci tato omezení.

  • Dotazy, které obsahují neparametrizované hodnoty (například INSERT INTO TABLE VALUES (?, 2), nejsou podporovány. Zástupné znaky (?) jsou jedinými podporovanými parametry pro tuto funkci.
  • Vkládání dotazů obsahujících výrazy INSERT-SELECT (například INSERT INTO TABLE SELECT * FROM TABLE2) se nepodporuje.
  • Vkládání dotazů obsahujících více výrazů VALUE (například INSERT INTO TABLE VALUES (1, 2) (3, 4)) se nepodporuje.
  • Vložení dotazů, za kterými následuje klauzule OPTION, spojení s více tabulkami nebo následný jiný dotaz, se nepodporuje.
  • IDENTITY_INSERT se v ovladači neřídí. Do příkazů insert buď nezahrnujte sloupce identity, nebo mezi dávkovými příkazy insert ručně nastavte stav IDENTITY_INSERT svých tabulek, případně ručně předejte explicitní hodnotu pro sloupec identity pomocí příkazu insert. Další informace najdete v části SET IDENTITY_INSERT.
  • Vzhledem k omezením rozhraní API hromadného kopírování, MONEY, SMALLMONEY, DATE, DATETIME, DATETIMEOFFSET, SMALLDATETIME, TIME, GEOMETRYa datových typů GEOGRAPHY se v současné době pro tuto funkci nepodporují.

Pokud dotaz selže kvůli chybám nesouvisejícím s instancí SQL Serveru, ovladač zaprotokoluje chybovou zprávu a vrátí se do původní logiky pro dávkové vložení.

Příklad

Tento příklad ukazuje případ použití dávkové operace vložení tisíc řádků pro běžné scénáře vs. rozhraní API hromadného kopírování.

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

Výsledek:

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.

Viz také

zvýšení výkonu a spolehlivosti pomocí ovladače JDBC