Condividi tramite


Uso dell'API di copia bulk per un'operazione di inserimento batch

Scaricare il driver JDBC

Microsoft JDBC Driver per SQL Server versione 9.2 e successive supporta l'uso dell'API di copia bulk per le operazioni di inserimento batch. Con questa funzionalità gli utenti possono consentire al driver di eseguire operazioni di copia bulk sottostanti durante l'esecuzione di operazioni di inserimento batch. Il driver cerca di migliorare le prestazioni inserendo gli stessi dati che si avrebbero con una normale operazione di inserimento batch. Il driver analizza la query SQL dell'utente usando l'API di copia bulk invece della normale operazione di inserimento batch. Di seguito sono illustrati diversi modi per abilitare l'API di copia bulk per la funzionalità di inserimento batch e sono elencate le relative limitazioni. Questa pagina contiene un piccolo codice di esempio che illustra un utilizzo e anche l'aumento delle prestazioni.

Questa funzionalità è applicabile solo alle API executeBatch() e executeLargeBatch() di PreparedStatement e CallableStatement.

Prerequisiti

Prerequisito per l'abilitazione dell'API di copia bulk per l'inserimento batch.

  • La query deve essere una query di inserimento (la query può contenere commenti, ma deve iniziare con la parola chiave INSERT perché questa funzionalità venga applicata).

Abilitazione dell'API di copia bulk per l'inserimento batch

Sono disponibili tre modi per abilitare l'API di copia bulk per l'inserimento batch.

1. Abilitazione con proprietà di connessione

L'aggiunta di useBulkCopyForBatchInsert=true; alla stringa di connessione abilita questa funzionalità.

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

2. Abilitazione con il metodo setUseBulkCopyForBatchInsert() dall'oggetto SQLServerConnection

La chiamata di SQLServerConnection. setUseBulkCopyForBatchInsert (true) consente di abilitare questa funzionalità.

SQLServerConnection.getUseBulkCopyForBatchInsert() consente di recuperare il valore corrente per la proprietà di connessione useBulkCopyForBatchInsert.

Il valore per useBulkCopyForBatchInsert rimane costante per ogni PreparedStatement al momento della sua inizializzazione. Qualsiasi chiamata successiva a SQLServerConnection.setUseBulkCopyForBatchInsert() non influirà sul valore di PreparedStatement già creato.

3. Abilitazione con il metodo setUseBulkCopyForBatchInsert() dall'oggetto SQLServerDataSource

Simile a quanto descritto sopra, ma con l'uso di SQLServerDataSource per creare un oggetto SQLServerConnection. Entrambi i metodi ottengono lo stesso risultato.

Limitazioni note

Al momento, questa funzionalità è soggetta alle limitazioni seguenti.

  • Le query di inserimento contenenti valori senza parametri, ad esempio INSERT INTO TABLE VALUES (?, 2), non sono supportate. I caratteri jolly (?) sono gli unici parametri supportati per questa funzione.
  • Le query di inserimento contenenti espressioni INSERT-SELECT, ad esempio INSERT INTO TABLE SELECT * FROM TABLE2, non sono supportate.
  • Le query di inserimento contenenti più espressioni VALUE, ad esempio INSERT INTO TABLE VALUES (1, 2) (3, 4), non sono supportate.
  • Le query di inserimento seguite dalla clausola OPTION, unite a più tabelle o seguite da un'altra query, non sono supportate.
  • IDENTIY_INSERT non è gestito nel driver. Non includere colonne Identity nelle istruzioni di inserimento, impostare manualmente lo stato IDENTITY_INSERT delle tabelle tra istruzioni di inserimento batch o passare manualmente il valore esplicito per una colonna Identity con l'istruzione di inserimento. Per altre informazioni, vedere SET IDENTITY_INSERT.
  • A causa delle limitazioni dell'API di copia bulk, i tipi di dati MONEY, SMALLMONEY, DATE, DATETIME, DATETIMEOFFSET, SMALLDATETIME, TIME, GEOMETRY e GEOGRAPHY non sono al momento supportati per questa funzionalità.

Se la query ha esito negativo a causa di errori non correlati all'istanza di SQL Server, il driver registra il messaggio di errore e torna alla logica originale per l'inserimento batch.

Esempio

Di seguito è riportato un esempio che illustra il caso d'uso per un'operazione di inserimento batch di un migliaio di righe, per entrambi gli scenari, normali e con API di copia bulk.

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

Risultato:

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.

Vedi anche

Uso del driver JDBC per il miglioramento di prestazioni e affidabilità