我正在使用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
所有A
和B
字段均为数字。
如果我复制该查询并直接在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时发生,更大的值全部按预期工作。怪异。
答案 0 :(得分:0)
有多种可能的原因。
JPA会在返回结果之前获取所有行。在停止计时器之前,请确保PGAdmin通过滚动到结果的最后来做同样的事情。
JPA(在某些情况下是Spring)会将您从数据库获取的ResultSet
转换为实体或其他一些Java对象。如果你在构造函数或getter中做了非常重要的事情,这可能会导致性能下降。此外,如果您的会话非常大,这可能会导致性能问题。一旦你附上了一个分析器,这些就会变得很明显。
查询必须从规范(在您的情况下)创建,这可能还需要一些时间。再次:附上一个分析器来识别它。