2016-05-26 11 views
1

Ich benutze Oracle 11g. Ich habe 3 Tabellen (A,B,C) in meiner Datenbank Ich habe ein Stück Code, der drei Einsätze führt: zuerst in A und C, danach in B. Dieses Stück Code wird oft ausgeführt (200000) und macht 200000 Operationen in jede Tabelle einfügen.Spring jdbcTemplate vs PreparedStatement. Leistungsunterschied

Ich habe zwei Möglichkeiten, um eine Einführung zu machen:

  1. jdbc PreparedStatement:

    DataSource ds = jdbcTemplate.getDataSource(); 
    
    try (Connection connection = ds.getConnection(); 
        PreparedStatement statement = connection.prepareStatement(sql1); 
        PreparedStatement statement2 = connection.prepareStatement(sql2); 
        PreparedStatement statement3 = connection.prepareStatement(sql3);) { 
    
        connection.setAutoCommit(false); 
        final int batchSize = 20; 
        int count = 0; 
    
        for (int i=1; i<= total; i++) { 
    
         // Define sql parameters 
    
         statement.setString(1, p1); 
    
         statement2.setString(1, p2); 
         statement2.setString(2, p3); 
    
         statement3.setInt(1, p4); 
         statement3.setString(2, p5); 
    
         statement.addBatch(); 
         statement2.addBatch(); 
         statement3.addBatch(); 
    
         if (++count % batchSize == 0) { 
            statement.executeBatch(); 
            statement.clearBatch(); 
            statement2.executeBatch(); 
            statement2.clearBatch(); 
            statement3.executeBatch(); 
            statement3.clearBatch(); 
            connection.commit(); 
            System.out.println(i); 
         } 
         } 
    
         statement.executeBatch(); 
         statement.clearBatch(); 
         statement2.executeBatch(); 
         statement2.clearBatch(); 
         statement3.executeBatch(); 
         statement3.clearBatch(); 
         connection.commit(); 
        } 
        catch (SQLException e) { 
         e.printStackTrace(); 
        } 
    } 
    
  2. Frühling jdbcTemplate:

    List<String> bulkLoadRegistrationSql = new ArrayList<String>(20); 
    
    for (int i=1; i<= total; i++) { 
    
        // 1. Define sql parameters p1,p2,p,3p4,p5 
    
        // 2. Prepare sql using parameters from 1 
        String sql1String = ... 
        String sql2String = ... 
        String sql3String = ... 
    
        bulkLoadRegistrationSql.add(sql1String); 
        bulkLoadRegistrationSql.add(sql2String); 
        bulkLoadRegistrationSql.add(sql3String); 
    
        if (i % 20 == 0) { 
          jdbcTemplate.batchUpdate(bulkLoadRegistrationSql 
           .toArray(new String[bulkLoadRegistrationSql.size()])); 
          //Clear inserted batch 
          bulkLoadRegistrationSql = new ArrayList<String>(20);  
        } 
    
    } 
    

I Ausführungszeit gemessen für total = 200000 und die Ergebnisse sind sehr verwirrend für mich. Frühling jdbcTemplate wird in 1480 Sekunden ausgeführt, jdbc PreparedStatement in 200 Sekunden

ich in jdbcTemplate Quelle gesucht und gefunden, dass es Statement unter verwendet, die weniger effizient sein sollte als PreparedStatement. Allerdings ist der Unterschied in den Ergebnissen zu groß und ich bin mir nicht sicher, ob dies nur wegen des Unterschieds zwischen Statement und PreparedStatement geschieht. Was sind deine Ideen dazu? Sollten die Ergebnisse theoretisch gleich sein, wenn jdbcTemplate auf namedParameterJdbcTemplate ersetzt wird?

Antwort

1

Ja, es sollte viel näher sein, vorausgesetzt, dass die meiste Zeit damit verbracht wurde, auf die Antworten aus der Datenbank zu warten. Spring hat einen eigenen Overhead, sodass Sie auf der Clientseite mehr Ressourcenverbrauch haben.

In einer vorbereiteten Anweisung, die Platzhalter verwendet, analysiert Oracle das SQL nur einmal und generiert den Plan einmal. Es speichert dann die Parse-Ergebnisse zusammen mit dem Plan für SQL. In Ihrem JDBCTemplate-Beispiel sieht jede SQL-Anweisung anders als der Parser aus und erfordert daher eine vollständige Syntaxanalyse und Plangenerierung durch den Server. Abhängig von der Leistung Ihres Oracle-Servers führt dies zu einer erhöhten Antwortzeit für jede SQL-Anweisung. Bei 200.000 SQL-Anweisungen bedeutet eine Nettoerhöhung von 1280 Sekunden zusätzliche 6,4 Millisekunden pro Anruf. Das scheint für mich aufgrund des zusätzlichen Parsens eine vernünftige Steigerung zu sein.

Ich empfehle, den Datenbankaufrufen einige Timing-Informationen hinzuzufügen, damit Sie bestätigen können, dass die SQL-Antwortzeit in der verbesserten Version niedriger ist.

0

Für jedes gegebene SQL werden 50 bis 80 Prozent der Zeit eines Datenbankmoduls für die Berechnung von Zugriffspfaden aufgewendet.

Wenn Sie PreparedStatement direkt verwenden, berechnet das Datenbankmodul den Zugriffspfad einmal und gibt ein Handle an den bereits berechneten Zugriffspfad zurück (in der Phase "Vorbereitung"). Wenn die vorbereitete Anweisung aufgerufen wird, muss die Datenbank-Engine nur die Parameter auf den bereits vorbereiteten Zugriffspfad anwenden und den Cursor zurückgeben.

0

Spring JDBCTemplate verfügt auch über Methoden, die vorbereitete Anweisungen verwenden. Bitte beachten Sie diese link Ihre Testergebnisse sinnvoll - Sie können die Ausführung nicht mit vorbereiteten Anweisung und gewöhnlichem SQL vergleichen.

Es gibt überladene batchUpdate-Methoden in Spring JDBCTemplate, die vorbereitete Anweisungen verwenden, z. B. die folgende Funktion.

int [] [] batchupdate (String sql, final Sammlung batchArgs, final int batchsize, final ParameterizedPreparedStatementSetter pss)

Verwandte Themen