我有一个像这样的实体模型:
class Article {
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
public Set<UserPropertyValue<?>> getUserPropertyValues() {
return userPropertyValues;
}
}
@Entity
@Inheritance(strategy = InheritanceType.JOINED)
public abstract class UserPropertyValue<T> {
}
@Entity
public class IntegerUserPropertyValue extends UserPropertyValue<Integer> {
}
@Entity
public class StringUserPropertyValue extends UserPropertyValue<String> {
}
// about 10 more inheritors like this, removed for clarity
现在,当我在 Hibernate 5 中运行
article.getUserPropertyValues()
时,我得到这个 PostgreSQL 查询(为了清晰起见,进行了删减):
select long_list_of_fields
from Article_UserPropertyValue userproper0_
inner join
UserPropertyValue userproper1_ on userproper0_.userPropertyValues_id = userproper1_.id
left outer join
IntegerUserPropertyValue userproper1_2_ on userproper1_.id = userproper1_2_.id
left outer join
StringUserPropertyValue userproper1_10_ on userproper1_.id = userproper1_10_.id
where userproper0_.Article_id = ?
在具有大约 2M UserPropertyValue 记录的数据库上,运行时间为 50 毫秒,并使用索引扫描。
现在我们正在升级到 Hibernate 6,我收到以下查询:
select long_list_of_fields
from Article_UserPropertyValue upv1_0
join
(
UserPropertyValue upv1_1
left join
IntegerUserPropertyValue upv1_3 on upv1_1.id = upv1_3.id
left join
StringUserPropertyValue upv1_11 on upv1_1.id = upv1_11.id
)
on upv1_1.id = upv1_0.userPropertyValues_id
where upv1_0.Article_id = ?
注意 Hibernate 现在如何连接子查询,而不是直接将所有子表连接到主表。
PostgreSQL 查询规划器中的某些内容决定对表 UserPropertyValue 进行顺序扫描。
有人知道有一些神奇的设置可以恢复到旧的行为吗?
回答我自己的问题;我没有找到改变 Hibernate 查询的方法,但我确实在 PostgreSQL 中找到了一个设置来修复新连接语法的性能。
将
join_collapse_limit
从默认值 8 增加到 50,使执行时间与旧语法保持一致。我有 12 个连接表(为简洁起见编辑了示例),我认为这导致优化器使用顺序扫描。