【问题标题】:Performance issue with Projection投影的性能问题
【发布时间】:2024-05-16 19:00:02
【问题描述】:

我在休眠时遇到了投影问题,完成一个简单的查询需要很长时间。 我的道法:

@Override  
@Transactional  
public List<String> getSourcePaths(List<Integer> sourceIds) {  
    @SuppressWarnings("unchecked")  
    List<String> list = getSession()  
         .createCriteria(AnaFileDB.class)
         .setProjection(Projections.property("sourcePath"))
         .add(Restrictions.in("source.id", sourceIds))
         .list();

    return list;
}

AnaFileDB 类是这样的:

@Entity
@Table(name = "ANA_FILE")
public class AnaFileDB {
...
private String sourcePath;
private AnaFileSourceDB source;
...
}

日志:

2014-01-15 17:31:36,227 [http-8080-5] 调试 org.hibernate.jdbc.AbstractBatcher - 即将打开 PreparedStatement(打开 PreparedStatements:0,全局:0)
休眠:
/* 条件查询 */ select
this_.FILE_SOURCE_PATH 作为 y0_
来自
ANA_FILE 这个_
在哪里
this_.FILE_SOURCE_ID (
?
)
2014-01-15 17:31:36,227 [http-8080-5] TRACE org.hibernate.type.IntegerType - 将“2”绑定到参数:1
2014-01-15 18:17:43,569 [http-8080-5] 调试 org.hibernate.jdbc.AbstractBatcher - 即将打开 ResultSet(打开 ResultSets:0,全局:0)
2014-01-15 18:17:43,569 [http-8080-5] 调试 org.hibernate.loader.Loader - 结果行:
2014-01-15 18:17:43,569 [http-8080-5] TRACE org.hibernate.type.StringType - 返回 '2013.03.01_Tom Januario/01_CTG1203401_CTG.csv' 作为列:y0_
2014-01-15 18:17:43,570 [http-8080-5] 调试 org.hibernate.loader.Loader - 结果行:
2014-01-15 18:17:43,570 [http-8080-5] TRACE org.hibernate.type.StringType - 返回 '2013.03.01_Tom Januario/02_CTG2203539_CTG.csv' 作为列:y0_
2014-01-15 18:17:43,570 [http-8080-5] 调试 org.hibernate.loader.Loader - 结果行:
2014-01-15 18:17:43,570 [http-8080-5] TRACE org.hibernate.type.StringType - 返回 '2013.03.01_Tom Januario/03_CTG3203718_CTG.csv' 作为列:y0_

由于有很多行(数万行),我得到了一大堆这样的日志文件

2014-01-15 17:13:40,462 [http-8080-1] 调试 org.hibernate.loader.Loader - 结果行:
2014-01-15 17:13:40,462 [http-8080-1] TRACE org.hibernate.type.StringType - 返回 'project2/screen4/run4/CTG/CSI000000447_CTG.csv' 作为列:y0_

如何解决?

【问题讨论】:

  • hibernate 有什么特别之处呢?仅使用 JDBC 加载“数万”行的速度是否显着加快?

标签: java sql hibernate


【解决方案1】:

如果您的表有大量记录,那么IN 将需要很长时间才能执行。尝试EXPLAIN 查询并在该表上添加INDEX 可能会得到一些提升。

更新

你可以这样试试:

Disjunction orConditions = Restrctions.disjunction();
orConditions.add(Restrictions.in("source.id", sourceIds));

List<String> list = session.createCriteria(AnaFileDB.class)
                   .add(orConditions)
                   .list();

【讨论】:

  • 问题是当我使用hibernate登录返回的sql查询时,例如Sql Developer效率没有问题,只有hibernate在这种情况下比较慢。从日志来看,hibernate 获取数据的速度似乎很快,但在从 ResultSet 检索数据时却很慢(这是我的猜测)。
  • 首先尝试EXPLAIN 查询和INDEX 在该列上,否则您可以使用for loop 传递id 但这是另一个开销,其中大量select 查询被触发数据库
  • 通过答案中的更新代码,我认为查询不会改变,是@Alinoe 吗?
  • 我什至尝试了 .add(Restrictions.eq("source.id", 2) 并没有任何改变。正如我所说,我认为 Hibernate 生成的查询没有问题,但从 ResultSet 检索数据. 你可以在我的帖子中看到像 StringType 这样的例子 - 返回 'dir/subdir/file_name.csv' 我看到了数百个这样的日志语句(当然是逐个文件),我认为这意味着数据被获取但有一些问题从结果集中创建字符串列表。
  • 好吧,通过保持.add(Restrictions.eq("source.id", 2),您可以将您的记录器设置为ERROR 级别吗,可能您遗漏了一些错误,因为您说有数百个这样的日志语句。