![](/img/trans.png)
[英]Hibernate JPA EntityManager.createQuery() performance
[英]entityManager.createQuery() taking lot of time to build query and bind the parameters. Performance affected
我們使用 Spring JPA 標准查詢 (javax.persistence.criteria.CriteriaQuery) 從數據庫中獲取數據。 我們使用 javax.persistence.criteria.Predicate 來構建謂詞。 我們在一個查詢中有 1500 個“OR”謂詞。 每個謂詞都有 6 個“與”謂詞。
SELECT (*) FROM TABLE_ABC as T1 WHERE (t1.column1 = 'c11' AND
t1.column2 = 'c12' AND t1.column3 = 'c13' AND t1.column4 = 'c14' AND
t1.column5 = 'c15')
OR
(t1.column1 = 'c21' AND t1.column2 = 'c22'
AND t1.column3 = 'c23' AND t1.column4 = 'c24' AND t1.column5 = 'c25')
OR
(t1.column1 = 'c31' AND t1.column2 = 'c32'
AND t1.column3 = 'c33' AND t1.column4 = 'c34' AND t1.column5 = 'c35').....
早些時候,我們使用“org.hibernate.Criteria”並使用“Conjuction”和“Disjunction”來構建相同的查詢。 這種方法行之有效。 隨着“org.hibernate.Criteria”被棄用,我們將轉向 javax-criteriaquery 包。 我們正面臨着性能的大幅下降。 日志的向下鑽取表明步驟中消耗的時間更多
=> entityManager.createQuery(),它執行以下操作
這些操作比較耗時。
是否有任何解決方案可以使這些執行速度更快? 'javax.persistence.criteria.CriteriaQuery' 是前進的方向嗎?
請在這里幫忙!
請看下面的代碼:
@Transactional(propagation = Propagation.REQUIRES_NEW, isolation = Isolation.READ_COMMITTED)
public getData(List<DataDAO> dataReqList) {
{
CriteriaBuilder builder = em.getCriteriaBuilder();
CriteriaQuery<DataReq> criteriaQuery = builder.createQuery(DataReq.class);
Root<DataReq> dataReqRoot = criteriaQuery.from(DataReq.class);
Predicate[] predicateArr = new Predicate[dataReqList.size()];
for (DataDAO dataReq : dataReqList) {
predicateArr[i] = builder.and(
builder.equal(dataReqRoot.get(TEST_S), dataReq.getS()),
builder.equal(dataReqRoot.get(TEST_T2), dataReq.getT2()),
builder.equal(dataReqRoot.get(K1), dataReq.getK1()),
builder.equal(dataReqRoot.get(K2), dataReq.getK2()),
builder.equal(dataReqRoot.get(TEST_P), dataReq.getP()),
builder.equal(dataReqRoot.get(TEST_T1),
dataReq.getT1(),
builder.equal(dataReqRoot.get(TEST_I), dataReq.getI()));
i++;
}
List<Data> dataResultList = getResultList(builder, criteriaQuery, predicateArr);
}
private List<Data> getResultList(CriteriaBuilder builder,
CriteriaQuery<DataReq> criteriaQuery, Predicate[] predicateArr) {
criteriaQuery.where(builder.or(predicateArr));
TypedQuery<DataReq> query = entityManager.createQuery(criteriaQuery);
List<DataReq> dataReqList = null;
try {
dataReqList = query.getResultList();
} catch(Exception e) {
...
}
return convertToData(dataReqList);
}
使用“org.hibernate.Criteria”並使用“Conjuction”和“Disjunction”的相同查詢在幾毫秒內非常有效。
對於上下文,根據您使用的數據庫,這就像帶有行值表達式的動態IN
謂詞。 如果支持,您還可以編寫:
WHERE (t1.column1, t1.column2, t1.column3, t1.column4, t1.column5, t1.column6) IN (
('c11', 'c12', 'c13', 'c14', 'c15', 'c16'),
('c21', 'c22', 'c23', 'c24', 'c25', 'c26'),
...
)
如此長的IN
列表不僅會在生成動態 SQL 的客戶端庫中變成問題,還會在服務器端變成問題。 您提到了綁定變量,也許您使用的舊 API 根本沒有使用綁定變量,而是將所有值內聯到查詢中。 我已經看到在 Oracle 中對於大量參數的性能要好得多,所以這是內聯值可能比綁定變量更好的情況之一。
由於您使用的是 Hibernate,您可以嘗試啟用
<property name="hibernate.criteria.literal_handling_mode" value="bind"/>
以上將(也許)有助於恢復您之前體驗過的性能,但根據您的IN
列表大小,可能會有更好的解決方案。 我在博客中介紹了一種替代方法,您可以使用數組代替單個綁定值,以防您使用 Oracle 或 PostgreSQL 。
我經常看到的另一個選項是使用以下形式的臨時表(假設為 Oracle):
CREATE GLOBAL TEMPORARY TABLE predicates (
column1 VARCHAR2(100),
column2 VARCHAR2(100),
column3 VARCHAR2(100),
column4 VARCHAR2(100),
column5 VARCHAR2(100),
column6 VARCHAR2(100)
)
然后,在運行查詢之前,將所有各種謂詞值批量插入該表中,然后半連接它:
WHERE (t1.column1, t1.column2, t1.column3, t1.column4, t1.column5, t1.column6) IN (
SELECT column1, column2, column3, column4, column5, column6
FROM predicates
)
如果您沒有臨時表,您可以嘗試使用普通表,並在其中添加一個 transaction_id 列,在查詢后手動清理其內容。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.