2016-06-29 23 views
1

次のCriteriaBuilderを使用すると、1または2のエントリのマップがあるときに1秒以内に結果が返されますが、3に達するとクエリのパフォーマンスが低下します。その後、4番目のエントリを追加すると、結果セットを返すのを実際に見たことのないポイントにパフォーマンスがさらに低下します。クエリのパフォーマンスが大幅に低下するのはなぜですか?

代わりにサブクエリを使用しようとしましたが、2 EXISTSサブクエリが妥当な時間内にデータを返しますが、3つ以上の場合はパフォーマンスが大幅に低下するという同様の問題が発生しているようです。

ORDER BYを指定しないと、3つのエントリ(1秒以下)でもクエリがうまく動作することに気付きましたが、同じ3つのエントリに追加するとすぐに30秒以上かかることになります。ここで

はビルダーです:

CriteriaBuilder builder = em.getCriteriaBuilder(); 
CriteriaQuery<Study> q = builder.createQuery(Study.class); 
Root<Study> rootStudy = q.from(Study.class); 

List<Predicate> pList = new ArrayList<Predicate>(searchMap.size()); 
q.select(rootStudy); 

Join<Study, Demographics> dem = rootStudy.join("demographics"); 
Join<Study, MetaData> met = rootStudy.join("metadata"); 

// add all conditions 
for (Map.Entry<XmlTagHashKey, String> entry : searchMap.entrySet()) { 

    MapJoin< Demographics, XmlTagHashKey, Field2 > mapJoin = demJoin.joinMap("fields"); 

    Path<String> attributePath = mapJoin.get("value"); 
    Predicate p = builder.and(builder.equal(mapJoin.key(), entry.getKey()), 
          builder.like(attributePath, "%" + entry.getValue() + "%")); 

    pList.add(p); 
} 

q.where(pList.toArray(new Predicate[]{})); 
q.orderBy(builder.desc( met.<String>get(XMLTagEnum.bbrad_status_updated.name()))); 

TypedQuery<Study> typedQuery = em.createQuery(q); 
typedQuery.setMaxResults(100); 
return getResultsList(typedQuery); 

ここで私は3つのマップエントリ持っている時には、上記ビルダーから作成されたSQLされます。ここでは

SELECT t1.id, 
     t1.study_id, 
     t1.demographics_id, 
     t1.metadata_id 
FROM demographics_has_fields t8, 
     field t7, 
     demographics_has_fields t6, 
     field t5, 
     demographics_has_fields t4, 
     field t3, 
     demographics t2, 
     study t1, 
     metadata t0 
WHERE (((((t6.xmltag = ?) 
       AND t5.value LIKE ?) 
      AND ((t4.xmltag = ?) 
        AND t3.value LIKE ?)) 
      AND ((t8.xmltag = ?) 
       AND t7.value LIKE ?)) 
     AND (((((t2.id = t1.demographics_id) 
        AND ((t6.demographics_id = t2.id) 
          AND (t5.id = t6.field_id))) 
        AND ((t4.demographics_id = t2.id) 
         AND (t3.id = t4.field_id))) 
       AND ((t8.demographics_id = t2.id) 
         AND (t7.id = t8.field_id))) 
       AND (t0.id = t1.metadata_id))) 
ORDER BY t0.bbradstatusupdated DESC 

は、テーブル構造の例を示します。私はACHしようとしています何

Table Structure

ieveは、フィールドの値に 'james'が含まれ、xmlタグが '1'(1は名前、2は性別)のStudyを選択することです。私が地図を使用するのは、ジェンダーのような追加のフィールドを検索したいからです。私はこれが動作する唯一の方法は、上記のようにサブクエリまたはジョインが存在することだと思います。

残念ながら、このデータ構造はかなり悪いですが、以前のデータベース設計から継承されたので、私はそれに固執しています。

+0

こんにちは、ここでは、マップするクエリのパフォーマンスについての素晴らしい記事です。多分それはあなたを助けるでしょうhttp://www.javaworld.com/article/2076240/build-ci-sdlc/optimize-a-query-on-a -map.html – Hrabosch

+0

これは超低速でなければなりません。テーブル構造、サンプルデータ、期待される出力を追加すると、うまくいくクエリを見つけるのに役立つかもしれません –

答えて

2

あなたが行っていることを正しく理解している場合は、すべてのマップエントリのクエリへの結合に追加します。これは、クエリーが処理するデータの量にマップ要素ごとに膨大な数を掛けることを意味します。これは、スケーラビリティに悪影響を与えるために縛られますこれは本当に問題であれば

は以下を実行し、検証するには:

は、データベースに対して2と3のマップエントリの(SQL)ステートメントを実行し、そのパフォーマンスを測定します。最初のエントリだけでなく、すべてのエントリを取得するようにしてください。

私の推測が正しいとすれば、多かれ少なかれ同じパフォーマンス低下が見られるでしょう。したがって、これはJPA/eclipse-linkの問題ではありません。

解決策は、別のデータモデル、おそらくスタースキーマに切り替えることがあります。しかし、これはあなたのアプリケーションでは多くのことに影響を与えます。

+0

あなたは100%正しいです。私は乗算の問題に関して多くの疑念を抱いています。私は、テーブル構造の例といくつかのサンプルデータを含めて、より多くの情報が必要であるかどうかを教えてください! – james4563

関連する問題