为什么我的查询性能急剧下降?
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 问题。
解决方案可能是切换到不同的数据模型,可能是星型模式。但这会影响您的应用程序中的很多事情,我们对此知之甚少。
当我有 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 问题。
解决方案可能是切换到不同的数据模型,可能是星型模式。但这会影响您的应用程序中的很多事情,我们对此知之甚少。