You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Data JPA复合主键免查插入及不存在则插入性能优化咨询

问题解答

一、场景1(全新数据批量插入)方案合理性判断

你当前通过重写isNew()返回true的方案是符合场景1需求的最优实现之一。
该方案的核心逻辑是强制Spring Data JPA将所有实体识别为新实例,完全跳过select before save的查询步骤,没有额外的查询开销,匹配你场景1中所有数据都是全新无重复的特性。
可补充以下配置进一步优化批量插入性能,确保达到单分钟100万条的吞吐量要求:

# Hibernate批量插入配置
spring.jpa.properties.hibernate.jdbc.batch_size=1000
spring.jpa.properties.hibernate.order_inserts=true
spring.jpa.properties.hibernate.order_updates=true
spring.jpa.properties.hibernate.jdbc.batch_versioned_data=true
# JDBC连接参数,开启批量语句重写
jdbc:postgresql://xxxx:xxxx/db?rewriteBatchedStatements=true

如果数据量过大,可替换为Hibernate StatelessSession 或者原生JDBC批量操作,避免JPA一级缓存累积带来的内存开销,性能可再提升30%以上。

二、场景2(旧数据补全,insert if not exists)高性能方案

你之前的写法性能极差的核心原因是:用CONCAT拼接主键列后做IN查询,完全无法命中(datetime,data)的联合主键索引,数十亿条记录的表全表扫描必然无法满足性能要求。
推荐直接使用PostgreSQL原生的UPSERT(INSERT ... ON CONFLICT DO NOTHING) 实现,不需要提前查询数据存在性,直接批量插入时自动跳过主键重复的记录,全程走主键索引,性能和纯批量插入几乎持平,完全满足吞吐量要求。

具体实现方案

方案1:Spring Data JPA原生查询实现

// 仓库接口方法
@Modifying
@Query(nativeQuery = true, value = "INSERT INTO \"A\" (datetime, data, value) VALUES (:datetime, :data, :value) ON CONFLICT (datetime, data) DO NOTHING")
void batchUpsert(@Param("datetime") List<OffsetDateTime> datetimes, @Param("data") List<String> datas, @Param("value") List<Double> values);

使用时每次传入1000~5000条数据为一个批次提交即可。

方案2:JdbcTemplate批量实现(性能更高)

如果追求极致性能,直接用JDBC批量操作跳过JPA的上下文开销:

public void batchUpsertA(List<AEntity> entities) {
    String sql = "INSERT INTO \"A\" (datetime, data, value) VALUES (?, ?, ?) ON CONFLICT (datetime, data) DO NOTHING";
    jdbcTemplate.batchUpdate(sql, new BatchPreparedStatementSetter() {
        @Override
        public void setValues(PreparedStatement ps, int i) throws SQLException {
            AEntity entity = entities.get(i);
            ps.setObject(1, entity.getId().getDatetime());
            ps.setString(2, entity.getId().getData());
            ps.setDouble(3, entity.getValue());
        }
        @Override
        public int getBatchSize() {
            return entities.size();
        }
    });
}

注意事项

  • 该方案是原子操作,不存在并发插入的冲突问题,不需要额外加锁
  • 批次大小控制在1000~5000条最佳,过大容易引发数据库锁等待,过小会导致频繁提交的开销过高
  • 不需要修改表结构、不需要新增字段,完全匹配你的限制要求

内容的提问来源于stack exchange,提问作者Khalil Bouzekri

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.26 04:24:00