如何避免Hibernate Envers产生交叉连接(Cross Join)?
将Hibernate Envers查询的交叉连接改为左连接
你的问题核心是默认的forRevisionsOfEntity方法生成的SQL采用了交叉连接+where关联条件的写法(本质等价于内连接),如果要显式改为左连接,需要放弃默认的快捷查询方法,手动构建关联查询。
原因说明
forRevisionsOfEntity(EntityName.class, false, true)方法的底层实现会自动关联revinfo表,但默认采用隐式内连接的方式(即cross join加where条件)。理论上entity_name_aud的rev字段必然对应revinfo中的有效记录(Envers的审计机制保证),所以这种写法和显式内连接性能差异不大,但如果业务上确实需要左连接,可按以下方式修改。
解决方案:手动构建左连接查询
使用Envers的API手动指定左连接类型,示例代码如下:
AuditQuery query = auditReader.createQuery() // 选择实体和审计revision实体 .select(AuditEntity.entity(), AuditEntity.revisionEntity()) // 从目标审计表查询 .from(EntityName.class) // 左连接revinfo表 .leftJoin(AuditEntity.revisionEntity()) // 添加contract_id过滤条件 .add(filter); return query.getResultList();
也可以通过addJoin方法显式指定连接类型:
AuditQuery query = auditReader.createQuery() .forEntitiesAtRevision(EntityName.class, Integer.class) .addAlias("revision", "r") // 指定左外连接类型 .addJoin("e.rev", "r", JoinType.LEFT_OUTER_JOIN) .add(filter); return query.getResultList();
额外性能优化建议
如果实际查询性能不佳,优先检查以下两点:
- 确保
entity_name_aud.contract_id字段已创建索引 - 确保
entity_name_aud.rev和revinfo.rev字段已创建主键/索引
这两个索引对查询性能的提升远大于连接类型的调整。
内容的提问来源于stack exchange,提问作者ggrigorov
相关产品推荐
相关产品推荐

