我目前正在尝试优化从数据库加载大量数据的小型应用程序的性能。 我使用标准JPA与Hibernate和Oracle作为数据库。
我有一个ServiceClass
,其getAllData
方法只执行命名查询loadAllData
。 FirstResult和MaxResult也可以设置为限制数据。
Oracle JDBC驱动程序中fetchSize
的默认值为10
,因此我通过
q.setHint(“org.hibernate.fetchSize”,100)
在处理ResultSet时提高性能。
问题是该提示仅适用于由此查询直接加载的实体,但不适用于已解决的渴望或懒惰的关系(ManyToMany
/ OneToMany
)!
服务类:
public class ServiceClass {
@Inject
EntityManager entityManager;
public List<Data> getAllData(Integer limit, Integer offset) {
Query q = entityManager.createNamedQuery("loadAllData", Data.class);
if (limit != null && offset != null) {
q.setFirstResult(offset);
q.setMaxResults(limit);
}
q.setHint("org.hibernate.fetchSize", 100);
List<Data> result = q.getResultList();
return result;
}
}
数据实体:
@Entity
@Table(name="DATA")
@NamedQuery(name = "loadAllData",
//hints=@QueryHint(name=QueryHints.FETCH_SIZE, value="100"),
query = "SELECT d FROM Data d LEFT JOIN FETCH d.dataA ORDER BY d.dataId")
public class Data {
@Id
@Column(name="DATA_ID")
private String dataId;
@ManyToOne
@JoinColumn(name = "A_ID")
@BatchSize(size = 100)
private A dataA;
@OneToMany
@JoinColumn(name = "DATA_ID")
@BatchSize(size = 100)
private Set<B> dataSetB;
@ManyToMany
@JoinTable(name = "DATA_C", joinColumns = { @JoinColumn(name = "DATA_ID") }, inverseJoinColumns = { @JoinColumn(name = "C_ID") })
@BatchSize(size = 100)
private Set<C> dataSetC;
}
如果加载了Data
对象+ A
对象,则调试输出显示提示正常工作:
15:55:11.337 [http-bio-8080-exec-3] DEBUG org.hibernate.loader.Loader - Result set row: 0
15:55:11.342 [http-bio-8080-exec-3] DEBUG org.hibernate.loader.Loader - Result row: EntityKey[Data#1], EntityKey[A#5]
15:55:11.348 [http-bio-8080-exec-3] DEBUG org.hibernate.loader.Loader - Result set row: 1
15:55:11.348 [http-bio-8080-exec-3] DEBUG org.hibernate.loader.Loader - Result row: EntityKey[Data#2], EntityKey[A#5]
15:55:11.349 [http-bio-8080-exec-3] DEBUG org.hibernate.loader.Loader - Result set row: 2
15:55:11.349 [http-bio-8080-exec-3] DEBUG org.hibernate.loader.Loader - Result row: EntityKey[Data#3], EntityKey[A#5]
15:55:11.350 [http-bio-8080-exec-3] DEBUG org.hibernate.loader.Loader - Result set row: 3
15:55:11.350 [http-bio-8080-exec-3] DEBUG org.hibernate.loader.Loader - Result row: EntityKey[Data#4], EntityKey[A#5]
15:55:11.351 [http-bio-8080-exec-3] DEBUG org.hibernate.loader.Loader - Result set row: 4
15:55:11.351 [http-bio-8080-exec-3] DEBUG org.hibernate.loader.Loader - Result row: EntityKey[Data#5], EntityKey[A#5]
15:55:11.351 [http-bio-8080-exec-3] DEBUG org.hibernate.loader.Loader - Result set row: 5
15:55:11.351 [http-bio-8080-exec-3] DEBUG org.hibernate.loader.Loader - Result row: EntityKey[Data#6], EntityKey[A#5]
15:55:11.352 [http-bio-8080-exec-3] DEBUG org.hibernate.loader.Loader - Result set row: 6
15:55:11.352 [http-bio-8080-exec-3] DEBUG org.hibernate.loader.Loader - Result row: EntityKey[Data#7], EntityKey[A#5]
15:55:11.353 [http-bio-8080-exec-3] DEBUG org.hibernate.loader.Loader - Result set row: 7
15:55:11.353 [http-bio-8080-exec-3] DEBUG org.hibernate.loader.Loader - Result row: EntityKey[Data#8], EntityKey[A#5]
15:55:11.354 [http-bio-8080-exec-3] DEBUG org.hibernate.loader.Loader - Result set row: 8
15:55:11.354 [http-bio-8080-exec-3] DEBUG org.hibernate.loader.Loader - Result row: EntityKey[Data#9], EntityKey[A#5]
15:55:11.354 [http-bio-8080-exec-3] DEBUG org.hibernate.loader.Loader - Result set row: 9
15:55:11.354 [http-bio-8080-exec-3] DEBUG org.hibernate.loader.Loader - Result row: EntityKey[Data#10], EntityKey[A#5]
15:55:11.355 [http-bio-8080-exec-3] DEBUG org.hibernate.loader.Loader - Result set row: 10
15:55:11.355 [http-bio-8080-exec-3] DEBUG org.hibernate.loader.Loader - Result row: EntityKey[Data#11], EntityKey[A#5]
15:55:11.356 [http-bio-8080-exec-3] DEBUG org.hibernate.loader.Loader - Result set row: 11
15:55:11.356 [http-bio-8080-exec-3] DEBUG org.hibernate.loader.Loader - Result row: EntityKey[Data#12], EntityKey[A#5]
15:55:11.357 [http-bio-8080-exec-3] DEBUG org.hibernate.loader.Loader - Result set row: 12
15:55:11.357 [http-bio-8080-exec-3] DEBUG org.hibernate.loader.Loader - Result row: EntityKey[Data#13], EntityKey[A#5]
15:55:11.357 [http-bio-8080-exec-3] DEBUG org.hibernate.loader.Loader - Result set row: 13
15:55:11.357 [http-bio-8080-exec-3] DEBUG org.hibernate.loader.Loader - Result row: EntityKey[Data#14], EntityKey[A#5]
15:55:11.358 [http-bio-8080-exec-3] DEBUG org.hibernate.loader.Loader - Result set row: 14
15:55:11.358 [http-bio-8080-exec-3] DEBUG org.hibernate.loader.Loader - Result row: EntityKey[Data#15], EntityKey[A#5]
15:55:11.359 [http-bio-8080-exec-3] DEBUG org.hibernate.loader.Loader - Result set row: 15
15:55:11.359 [http-bio-8080-exec-3] DEBUG org.hibernate.loader.Loader - Result row: EntityKey[Data#16], EntityKey[A#5]
如果我没有设置fetchSize
提示,处理结果第9行和第10行之间会有一个小差距~100ms(因为默认fetchSize
是10)。
OneToMany以及ManyToMany关系稍后会解决,但fetchSize
提示不起作用,如您所见:
15:55:11.627 [http-bio-8080-exec-3] DEBUG org.hibernate.loader.Loader - Result set row: 0
15:55:11.627 [http-bio-8080-exec-3] DEBUG org.hibernate.loader.Loader - Result row: EntityKey[B#1109]
15:55:11.627 [http-bio-8080-exec-3] DEBUG org.hibernate.loader.Loader - Result set row: 1
15:55:11.628 [http-bio-8080-exec-3] DEBUG org.hibernate.loader.Loader - Result row: EntityKey[B#1141]
15:55:11.628 [http-bio-8080-exec-3] DEBUG org.hibernate.loader.Loader - Result set row: 2
15:55:11.628 [http-bio-8080-exec-3] DEBUG org.hibernate.loader.Loader - Result row: EntityKey[B#1135]
15:55:11.628 [http-bio-8080-exec-3] DEBUG org.hibernate.loader.Loader - Result set row: 3
15:55:11.629 [http-bio-8080-exec-3] DEBUG org.hibernate.loader.Loader - Result row: EntityKey[B#1172]
15:55:11.629 [http-bio-8080-exec-3] DEBUG org.hibernate.loader.Loader - Result set row: 4
15:55:11.629 [http-bio-8080-exec-3] DEBUG org.hibernate.loader.Loader - Result row: EntityKey[B#1172]
15:55:11.629 [http-bio-8080-exec-3] DEBUG org.hibernate.loader.Loader - Result set row: 5
15:55:11.629 [http-bio-8080-exec-3] DEBUG org.hibernate.loader.Loader - Result row: EntityKey[B#1172]
15:55:11.630 [http-bio-8080-exec-3] DEBUG org.hibernate.loader.Loader - Result set row: 6
15:55:11.630 [http-bio-8080-exec-3] DEBUG org.hibernate.loader.Loader - Result row: EntityKey[B#1192]
15:55:11.630 [http-bio-8080-exec-3] DEBUG org.hibernate.loader.Loader - Result set row: 7
15:55:11.630 [http-bio-8080-exec-3] DEBUG org.hibernate.loader.Loader - Result row: EntityKey[B#1189]
15:55:11.631 [http-bio-8080-exec-3] DEBUG org.hibernate.loader.Loader - Result set row: 8
15:55:11.631 [http-bio-8080-exec-3] DEBUG org.hibernate.loader.Loader - Result row: EntityKey[B#1181]
15:55:11.631 [http-bio-8080-exec-3] DEBUG org.hibernate.loader.Loader - Result set row: 9
15:55:11.631 [http-bio-8080-exec-3] DEBUG org.hibernate.loader.Loader - Result row: EntityKey[B#1181]
15:55:11.730 [http-bio-8080-exec-3] DEBUG org.hibernate.loader.Loader - Result set row: 10
15:55:11.731 [http-bio-8080-exec-3] DEBUG org.hibernate.loader.Loader - Result row: EntityKey[B#1237]
15:55:11.731 [http-bio-8080-exec-3] DEBUG org.hibernate.loader.Loader - Result set row: 11
15:55:11.731 [http-bio-8080-exec-3] DEBUG org.hibernate.loader.Loader - Result row: EntityKey[B#1237]
15:55:11.732 [http-bio-8080-exec-3] DEBUG org.hibernate.loader.Loader - Result set row: 12
15:55:11.732 [http-bio-8080-exec-3] DEBUG org.hibernate.loader.Loader - Result row: EntityKey[B#1237]
15:55:11.733 [http-bio-8080-exec-3] DEBUG org.hibernate.loader.Loader - Result set row: 13
15:55:11.733 [http-bio-8080-exec-3] DEBUG org.hibernate.loader.Loader - Result row: EntityKey[B#1237]
15:55:11.735 [http-bio-8080-exec-3] DEBUG org.hibernate.loader.Loader - Result set row: 14
15:55:11.735 [http-bio-8080-exec-3] DEBUG org.hibernate.loader.Loader - Result row: EntityKey[B#1237]
15:55:11.736 [http-bio-8080-exec-3] DEBUG org.hibernate.loader.Loader - Result set row: 15
15:55:11.736 [http-bio-8080-exec-3] DEBUG org.hibernate.loader.Loader - Result row: EntityKey[B#1235]
15:55:11.736 [http-bio-8080-exec-3] DEBUG org.hibernate.loader.Loader - Result set row: 16
您可以看到,由于数据库的网络延迟,结果行9和10之间需要约100毫秒。因此使用的默认fetchSize
为10,而不是我在查询中设置的提示。
我还尝试直接在命名查询中设置提示(注释行)或将fetchType
设置为EAGER
,但效果相同。
这是一个错误还是设计?有谁知道如何解决这个问题?
修改
我到目前为止唯一的解决方案是将fetchSize
设置为persistence.xml
中的属性,但我不想将其指定为全局设置。
<property name="hibernate.jdbc.fetch_size" value="100"/>