Hibernate生成的查询在应用程序中很慢但在手动执行时很快

时间:2018-01-02 12:50:08

标签: spring hibernate spring-data

我正在使用Spring DATA JPA和Hibernate + PostgreSQL,我生成这样的q查询:

SELECT A.field1 AS field1_10_,
       A.field2 AS field2_10_,
       A.field3 AS field3_10_,
       ...
       A.field10 as field10_10_
FROM mytable A
WHERE (A.field1 BETWEEN 1 AND 2)
  AND ((cast(A.field1 AS varchar(255))||cast(A.field2 AS varchar(255))) IN
         (SELECT (cast(B.field1 AS varchar(255))||cast(max(B.field2) AS varchar(255)))
          FROM mytable B
          WHERE B.field1 BETWEEN 1 AND 2
          GROUP BY B.field2))
LIMIT 20

所有AB字段均为数字。

如果我复制该查询并直接在Postgres中执行(使用Pgadmin),结果将在不到一秒的时间内完成。但在我的应用程序中,Hibernate需要大约一分钟来检索结果。我已激活Hibernate统计信息,并且大部分时间都在运行JDBC语句。

我正在使用Spring分页,使用相同的规范生成计数查询。此查询运行速度快(少于一秒):

SELECT count(*) AS col_0_0_
FROM mytable A
WHERE (A.field1 BETWEEN 1 AND 2)
  AND ((cast(A.field1 AS varchar(255))||cast(A.field2 AS varchar(255))) IN
         (SELECT (cast(B.field1 AS varchar(255))||cast(max(B.field2) AS varchar(255)))
          FROM mytable B
          WHERE B.field1 BETWEEN 1 AND 2
          GROUP BY B.field2))

有什么想法吗?

更新:我刚刚发现PostgreSQL执行的generatestatement如下:

SELECT A.field1 AS field1_10_,
       A.field2 AS field2_10_,
       A.field3 AS field3_10_,
       ...
       A.field10 as field10_10_
FROM mytable A
WHERE (A.field1 BETWEEN ? AND ?)
  AND ((cast(A.field1 AS varchar(255))||cast(A.field2 AS varchar(255))) IN
         (SELECT (cast(B.field1 AS varchar(255))||cast(max(B.field2) AS varchar(255)))
          FROM mytable B
          WHERE B.field1 BETWEEN ? AND ?
          GROUP BY B.field2))
LIMIT $1

请注意,BETWEEN条件中的替换字符是问号?,但限制是美元以及参数顺序$1。 Spring分页会自动添加限制,如果删除它,查询速度很快。

更新2 :我刚刚发现问题仅在指定限制为1时发生,更大的值全部按预期工作。怪异。

1 个答案:

答案 0 :(得分:0)

有多种可能的原因。

  1. JPA会在返回结果之前获取所有行。在停止计时器之前,请确保PGAdmin通过滚动到结果的最后来做同样的事情。

  2. JPA(在某些情况下是Spring)会将您从数据库获取的ResultSet转换为实体或其他一些Java对象。如果你在构造函数或getter中做了非常重要的事情,这可能会导致性能下降。此外,如果您的会话非常大,这可能会导致性能问题。一旦你附上了一个分析器,这些就会变得很明显。

  3. 查询必须从规范(在您的情况下)创建,这可能还需要一些时间。再次:附上一个分析器来识别它。