为什么我的查询性能急剧下降?

Why does my query performance drastically drop?

当我有 1 或 2 个条目的映射时,使用以下 CriteriaBuilder returns 在 1 秒内产生结果,但是当它达到 3 时,查询性能下降。然后添加第 4 个条目会使性能进一步下降,以至于我实际上没有看到它 return 结果集。

我曾尝试改用子查询,但似乎遇到了类似的问题,其中 2 个 EXISTS 子查询将在合理时间内 return 获取数据,但 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 

这里有一个 table 结构的例子:

我想要实现的目标是 select 一项研究,其中字段的值包含 'james' 并且 xml 标记为“1”(1 是名称, 2 是性别)。我使用地图的原因是因为您可能还想搜索其他字段,例如性别。我认为唯一可行的方法是使用现有的子查询或连接,就像我在上面所做的那样。

不幸的是,这个数据结构非常糟糕,但它是从以前的数据库设计中继承而来的,所以我有点坚持使用它。

如果我正确理解你在做什么,那么你就是在为每个地图条目添加到查询中。这意味着,您将查询必须处理的数据量乘以每个地图元素的巨大数字。这势必会产生糟糕的可扩展性。

要验证这是否真的是问题所在,请执行以下操作:

运行 (sql) 针对数据库的 2 和 3 个映射条目的语句并测量它们的性能。确保获取所有条目,而不仅仅是第一个条目。

如果我的猜测是正确的,您会看到大致相同的性能下降,所以这不是 JPA/eclipse-link 问题。

解决方案可能是切换到不同的数据模型,可能是星型模式。但这会影响您的应用程序中的很多事情,我们对此知之甚少。