web-dev-qa-db-fra.com

pourquoi spring jdbcTemplate batchUpdate insérer ligne par ligne

J'ai 200K lignes à insérer dans une seule table de base de données. J'ai essayé d'utiliser jdbcTemplate.batchUpdate au printemps afin de faire une insertion 10 000 par lot. Cependant, ce processus consomme trop de temps (7 minutes pour 200 000 lignes). Donc, côté base de données, je vérifie le nombre de lignes insérées par select count(*) from table_X. J'ai trouvé le nombre de lignes légèrement augmenté au lieu de 10K attendu. Quelqu'un peut-il expliquer quelle est la raison ou est-ce quelque chose qui devrait être configuré sur la base de données? 

PS: J'utilise sybase ....

6
Ensom Hodder

Il existe de nombreuses approches disponibles sur le Web. Les performances dépendent directement de la 

  1. Code que vous avez écrit
  2. Le pilote JDBC que vous utilisez
  3. serveur de base de données et nombre de connexions que vous utilisez
  4. les index de table conduisent à une lenteur d'insertion

Sans regarder votre code, personne ne peut deviner, mais personne ne peut trouver la solution exacte. 

Approche 1

//insert batch example
public void insertBatch(final List<Customer> customers){

  String sql = "INSERT INTO CUSTOMER " +
    "(CUST_ID, NAME, AGE) VALUES (?, ?, ?)";

  getJdbcTemplate().batchUpdate(sql, new BatchPreparedStatementSetter() {

    @Override
    public void setValues(PreparedStatement ps, int i) throws SQLException {
        Customer customer = customers.get(i);
        ps.setLong(1, customer.getCustId());
        ps.setString(2, customer.getName());
        ps.setInt(3, customer.getAge() );
    }

    @Override
    public int getBatchSize() {
        return customers.size();
    }
  });
}

référence 

https://www.mkyong.com/spring/spring-jdbctemplate-batchupdate-example/

http://docs.spring.io/spring-framework/docs/3.0.0.M4/reference/html/ch12s04.html

Approche 2.1

//insert batch example
public void insertBatch(final List<Customer> customers){
    String sql = "INSERT INTO CUSTOMER " +
        "(CUST_ID, NAME, AGE) VALUES (?, ?, ?)";

    List<Object[]> parameters = new ArrayList<Object[]>();

    for (Customer cust : customers) {
        parameters.add(new Object[] {cust.getCustId(),
            cust.getName(), cust.getAge()}
        );
    }
    getSimpleJdbcTemplate().batchUpdate(sql, parameters);
}

Alternativement, vous pouvez exécuter le code SQL directement.

//insert batch example with SQL
public void insertBatchSQL(final String sql){

    getJdbcTemplate().batchUpdate(new String[]{sql});

}

se référer 

https://www.mkyong.com/spring/spring-simplejdbctemplate-batchupdate-example/

Approche 2.2

public class JdbcActorDao implements ActorDao {
    private SimpleJdbcTemplate simpleJdbcTemplate;

    public void setDataSource(DataSource dataSource) {
        this.simpleJdbcTemplate = new SimpleJdbcTemplate(dataSource);
    }

    public int[] batchUpdate(final List<Actor> actors) {
        SqlParameterSource[] batch = SqlParameterSourceUtils.createBatch(actors.toArray());
        int[] updateCounts = simpleJdbcTemplate.batchUpdate(
            "update t_actor set first_name = :firstName, last_name = :lastName where id = :id",
            batch);
        return updateCounts;
    }

    //  ... additional methods
}

Approche 2.3

public class JdbcActorDao implements ActorDao {
    private SimpleJdbcTemplate simpleJdbcTemplate;

    public void setDataSource(DataSource dataSource) {
        this.simpleJdbcTemplate = new SimpleJdbcTemplate(dataSource);
    }

    public int[] batchUpdate(final List<Actor> actors) {
        List<Object[]> batch = new ArrayList<Object[]>();
        for (Actor actor : actors) {
            Object[] values = new Object[] {
                    actor.getFirstName(),
                    actor.getLastName(),
                    actor.getId()};
            batch.add(values);
        }
        int[] updateCounts = simpleJdbcTemplate.batchUpdate(
                "update t_actor set first_name = ?, last_name = ? where id = ?",
                batch);
        return updateCounts;
    }

    //  ... additional methods
}

Approche 3: JDBC

dbConnection.setAutoCommit(false);//commit trasaction manually

String insertTableSQL = "INSERT INTO DBUSER"
            + "(USER_ID, USERNAME, CREATED_BY, CREATED_DATE) VALUES"
            + "(?,?,?,?)";
PreparedStatement = dbConnection.prepareStatement(insertTableSQL);

preparedStatement.setInt(1, 101);
preparedStatement.setString(2, "mkyong101");
preparedStatement.setString(3, "system");
preparedStatement.setTimestamp(4, getCurrentTimeStamp());
preparedStatement.addBatch();

preparedStatement.setInt(1, 102);
preparedStatement.setString(2, "mkyong102");
preparedStatement.setString(3, "system");
preparedStatement.setTimestamp(4, getCurrentTimeStamp());
preparedStatement.addBatch();
preparedStatement.executeBatch();

dbConnection.commit();

se référer

https://www.mkyong.com/jdbc/jdbc-preparedstatement-example-batch-update/

/*Happy Coding*/
15
Sanka

Essayez le réglage ci-dessous pour la chaîne de connexion - useServerPrepStmts=false&rewriteBatchedStatements=true. Je n'ai pas essayé mais ça fait partie de mes favoris. Vous pouvez rechercher sur ces lignes ..

Connection c = DriverManager.getConnection("jdbc:<db>://Host:<port>/db?useServerPrepStmts=false&rewriteBatchedStatements=true", "username", "password");
1