Hibernate如何降低JDBC语句预编译环节的耗时开销?
你观察到的1465946 nanoseconds开销来自JDBC层面每次创建PreparedStatement的预编译成本,同批次重复查询场景下可通过以下可落地的方案直接优化:
开启Hibernate层面的PreparedStatement缓存
这是最直接的适配调整,添加如下配置即可:# 匹配当前批次查询量级配置批量大小 spring.jpa.properties.hibernate.jdbc.batch_size=20 # 开启预编译语句缓存 spring.jpa.properties.hibernate.jdbc.cache_prepared_statements=true # 缓存容量调整为不小于业务常用查询语句数即可 spring.jpa.properties.hibernate.jdbc.prepared_statement_cache_size=100如果使用第三方数据库连接池,连接池层面的语句缓存优先级高于Hibernate自带缓存,优先配置连接池参数
连接池层面开启PreparedStatement缓存
以主流的HikariCP连接池为例,添加如下配置:spring.datasource.hikari.data-source-properties.cachePrepStmts=true spring.datasource.hikari.data-source-properties.prepStmtCacheSize=250 spring.datasource.hikari.data-source-properties.prepStmtCacheSqlLimit=2048 # MySQL5.1+、PostgreSQL等支持服务端预编译的数据库可开启该参数,进一步降低开销 spring.datasource.hikari.data-source-properties.useServerPrepStmts=true开启后同连接内相同SQL的预编译结果会被直接复用,同批次重复查询场景下可消除90%以上的预编译耗时。
合并同逻辑批量查询
如果当前17条查询属于同表同逻辑的单条查询,可合并为IN查询、批量查询,将原本需要预编译N次的语句压缩为1次,从根源上减少预编译次数。比如将多条select * from user where id = ?合并为select * from user where id in (?, ?, ... ?)。规范SQL编写逻辑
检查同逻辑查询是否存在SQL文本不一致的问题,比如同一逻辑的SQL有的写where id=?有的写where id = ?(多了空格)、或者存在参数硬拼接而非占位符绑定的情况,这类问题会导致相同逻辑的SQL被识别为不同语句,无法命中预编译缓存。确保同逻辑SQL文本完全一致即可正常复用预编译结果。
调整配置后重新查看Hibernate统计的preparing JDBC statements指标,即可验证优化效果。
内容的提问来源于stack exchange,提问作者Ajay Kumar

