namedParameterJdbcTemplate batchUpdate vs INSERT INTO SELECT

时间:2017-03-16 16:24:25

标签: java postgresql jdbc performance-testing jsonb

我正在进行一项实验,我希望看到将多个记录插入PostgreSQL数据库的方法将为我提供最佳的速度性能。我正在使用" PostgreSQL 9.5.3,由Visual C ++ build 1800,64位"编译。 + Java 1.8 + Postgres JDBC驱动程序9.4.1207。

此实验的表定义如下:

CREATE TABLE mytable (ea VARCHAR(256) NOT NULL, ehv CHAR(60) NOT NULL);

ALTER TABLE mytable ADD CONSTRAINT pk_mytable_ea PRIMARY KEY (ea);

第一种方法是执行executeBatch,我在其中创建参数映射列表。代码如下所示:

public void executeBatch(List<MyObject> myObjects) {
        final String sql = "INSERT INTO mytable(" +
                "    ea, ehv) " +
                "    VALUES (:ea, :ehv) ";

        MapSqlParameterSource[] params = new MapSqlParameterSource[myObjects.size()];
        for (int i = 0; i < myObjects.size(); i++) {
            params[i] = new MapSqlParameterSource()
                    .addValue("ea", myObjects.get(i).getEa())
                    .addValue("ehv", myObjects.get(i).getEhv());
        }

        jdbcTemplate.batchUpdate(sql, params);
    }

第二种方法更具异国情调,它使用Jackson将对象序列化为jsonb,然后使用jsonb_to_recordset我扩展此{{ {1}}字符串到记录行,然后我将其插入JSON

mytable

我使用以下测试对这两种方法进行了比较,其中我创建了10,000个MyObjects。

public void insertFromString(List<MyObject> myObjects) throws RepositoryException {
        final String sql = "INSERT INTO mytable(ea, ehv)\n" +
                "select ea, ehv\n" +
                "from jsonb_to_recordset(:myObjectsJson) as x(ea text, ehv text)\n" +
                "ON CONFLICT DO NOTHING";

        ObjectMapper jsonObjectMapper = new ObjectMapper();
        String myObjectsJson = null;
        try {
            myObjectsJson = jsonObjectMapper.writeValueAsString(myObjects);
        } catch (JsonProcessingException ex) {
            throw new RepositoryException("Error while transforming myObjects to json.", ex);
        }

        PGobject jsonObject = new PGobject();
        jsonObject.setType("jsonb");
        try {
            jsonObject.setValue(myObjectsJson);
        } catch (SQLException ex) {
            throw new RepositoryException("Error while building jsonb object.", ex);
        }

        jdbcTemplate.update(sql, new MapSqlParameterSource().addValue("myObjectsJson", jsonObject));
    }

运行测试我发现第二种方法表现更好:

@Test
    public void test() throws JsonProcessingException, RepositoryException {
        List<MyObject> myObjects = new ArrayList(10000);
        for(int i = 0; i < 10000; i++) {
            myObjects.add(new MyObject(i + "ea", i + "ehv"));
        }

        long before = System.currentTimeMillis();
        censusRepository.executeBatch(myObjects);
        long after = System.currentTimeMillis();
        System.out.println("executeBatch Took - " + (after-before));

        namedParameterJdbcTemplate.update("delete from mytable", new MapSqlParameterSource());

        before = System.currentTimeMillis();
        censusRepository.insertFromString(myObjects);
        after = System.currentTimeMillis();
        System.out.println("insertFromString Took - " + (after-before));

        namedParameterJdbcTemplate.update("delete from mytable", new MapSqlParameterSource());
    }

是什么导致第二种方法的表现比executeBatch Took - 464ms insertFromString Took - 253ms 好得多?根据您的经验,我应采取哪种方法。你能建议另一个,这可以给我更好的表现吗?我有以下约束 - 我将在数据库中插入1000个MyObjects批次,每个MyObject包含两个String值。

0 个答案:

没有答案