Spring 启动 JdbcTemplate - 禁用语句缓存?
Spring Boot JdbcTemplate - disable statement cache?
我有一个 Spring 引导后端,我使用 REST-API 与之通信。此后端使用 Spring JdbcTemplate
连接并在 PostgreSQL 数据库上执行查询。
我发现了一个问题,即一个请求在重复恰好 10 次后速度明显变慢。我已将问题缩小到使用 JdbcTemplate
从数据库检索数据的代码部分。更具体地说,问题发生在每个 tomcat worker-thread:
的第二次迭代中
[nio-8080-exec-1] --- GET /myresource - Execution time 400 ms
[nio-8080-exec-2] --- GET /myresource - Execution time 300 ms
[nio-8080-exec-3] --- GET /myresource - Execution time 285 ms
...
[io-8080-exec-10] --- GET /myresource - Execution time 200 ms
现在每个 tomcat worker 都收到并处理了一个请求,下一次这些 worker 中的一个收到相同的请求,使用完全相同的查询,执行时间会长 10-15 倍:
[nio-8080-exec-1] --- GET /myresource - Execution time 6000 ms
[nio-8080-exec-2] --- GET /myresource - Execution time 5500 ms
[nio-8080-exec-3] --- GET /myresource - Execution time 6700 ms
我已经尝试 运行使用 psql 或 pgAdmin 执行相同的查询,没有问题。这让我相信 JdbcTemplate
正在以某种方式为每个工作人员缓存查询,而第二次查询是 运行 缓存启动并且由于某种原因它慢得多,但我不确定.我也尝试将 tomcat 更改为 jetty/undertow 但同样的问题出现在那里所以我相信它一定与 JdbcTemplate
.
有关
有什么方法可以使用 JdbcTemplate
禁用这种类型的缓存,或者我还能做些什么来避免这种行为?
谢谢!
编辑:
我的 application.yaml:
spring:
datasource:
platform: postgres
url: my-jdbc-url
username: my-user
password: my-password
代码根据请求中的参数动态创建带有 WHERE/AND 子句的查询,但相同的请求参数总是创建相同的查询。代码:
public List<MyDatatype> runQuery(MyParams params) {
String sql = createSqlFromParams(params);
List<Object> params = createParamsList(params);
return jdbcTemplate.query(sql, params.toArray(), myDatatypeRowMapper());
}
查询最后看起来像这样(使用 postGIS 函数按坐标之间的距离排序):
SELECT * FROM my_table
WHERE x IN [1,2,3]
AND y BETWEEN 0 AND 1000
AND z BETWEEN 0 AND 500
ORDER BY geom <-> other_geom
LIMIT 1000;
编辑 2:
根据@M.Deinum的建议,添加
spring.datasource.hikari.data-source-properties.preparedStatementCacheQueries=0
问题解决了!
假设您在 Spring 引导中使用默认连接池 HikariCP,您可以使用 spring.datasource.hikari.data-source-properties
来提供额外的、特定于驱动程序的属性。
要禁用 Server Prepared Statements,您需要包含 preparedStatementCacheQueries
属性 并将值设置为 0(默认值为 256)。
spring.datasource.hikari.data-source-properties.preparedStatementCacheQueries=0
这将禁用整个缓存并可能影响应用程序的不同区域。
这些相关问题here and here似乎暗示您可能想要检查磁盘、索引等而不是禁用查询缓存。
我有一个 Spring 引导后端,我使用 REST-API 与之通信。此后端使用 Spring JdbcTemplate
连接并在 PostgreSQL 数据库上执行查询。
我发现了一个问题,即一个请求在重复恰好 10 次后速度明显变慢。我已将问题缩小到使用 JdbcTemplate
从数据库检索数据的代码部分。更具体地说,问题发生在每个 tomcat worker-thread:
[nio-8080-exec-1] --- GET /myresource - Execution time 400 ms
[nio-8080-exec-2] --- GET /myresource - Execution time 300 ms
[nio-8080-exec-3] --- GET /myresource - Execution time 285 ms
...
[io-8080-exec-10] --- GET /myresource - Execution time 200 ms
现在每个 tomcat worker 都收到并处理了一个请求,下一次这些 worker 中的一个收到相同的请求,使用完全相同的查询,执行时间会长 10-15 倍:
[nio-8080-exec-1] --- GET /myresource - Execution time 6000 ms
[nio-8080-exec-2] --- GET /myresource - Execution time 5500 ms
[nio-8080-exec-3] --- GET /myresource - Execution time 6700 ms
我已经尝试 运行使用 psql 或 pgAdmin 执行相同的查询,没有问题。这让我相信 JdbcTemplate
正在以某种方式为每个工作人员缓存查询,而第二次查询是 运行 缓存启动并且由于某种原因它慢得多,但我不确定.我也尝试将 tomcat 更改为 jetty/undertow 但同样的问题出现在那里所以我相信它一定与 JdbcTemplate
.
有什么方法可以使用 JdbcTemplate
禁用这种类型的缓存,或者我还能做些什么来避免这种行为?
谢谢!
编辑:
我的 application.yaml:
spring:
datasource:
platform: postgres
url: my-jdbc-url
username: my-user
password: my-password
代码根据请求中的参数动态创建带有 WHERE/AND 子句的查询,但相同的请求参数总是创建相同的查询。代码:
public List<MyDatatype> runQuery(MyParams params) {
String sql = createSqlFromParams(params);
List<Object> params = createParamsList(params);
return jdbcTemplate.query(sql, params.toArray(), myDatatypeRowMapper());
}
查询最后看起来像这样(使用 postGIS 函数按坐标之间的距离排序):
SELECT * FROM my_table
WHERE x IN [1,2,3]
AND y BETWEEN 0 AND 1000
AND z BETWEEN 0 AND 500
ORDER BY geom <-> other_geom
LIMIT 1000;
编辑 2:
根据@M.Deinum的建议,添加
spring.datasource.hikari.data-source-properties.preparedStatementCacheQueries=0
问题解决了!
假设您在 Spring 引导中使用默认连接池 HikariCP,您可以使用 spring.datasource.hikari.data-source-properties
来提供额外的、特定于驱动程序的属性。
要禁用 Server Prepared Statements,您需要包含 preparedStatementCacheQueries
属性 并将值设置为 0(默认值为 256)。
spring.datasource.hikari.data-source-properties.preparedStatementCacheQueries=0
这将禁用整个缓存并可能影响应用程序的不同区域。
这些相关问题here and here似乎暗示您可能想要检查磁盘、索引等而不是禁用查询缓存。