【发布时间】:2018-01-02 12:50:08
【问题描述】:
我将 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执行的生成语句如下:
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 时才会发生,更大的值会按预期工作。很奇怪。
【问题讨论】:
-
如何调用查询?你把它当作原生的吗?
-
没有。我使用 Criteria Query 生成规范并将其传递给 JPA 存储库方法
-
您的 Spring 应用程序中的事务隔离级别是什么?如果驱动程序等待数据库,您能否添加有关它在那一分钟内所做的事情的 JDBC 驱动程序调试日志以及可能的 Postgres 日志?
标签: spring hibernate spring-data