簡體   English   中英

entityManager.createQuery() 花費大量時間來構建查詢和綁定參數。 性能受到影響

[英]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(),它執行以下操作


  1. CriteriaCompiler.compile
  2. CriteriaQueryImpl$1.buildCompiledQuery
  3. CriteriaCompiler$1$1.bind

這些操作比較耗時。

是否有任何解決方案可以使這些執行速度更快? '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"/>

HHH-9576這個答案

使用數組的可能更好的解決方案

以上將(也許)有助於恢復您之前體驗過的性能,但根據您的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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM