使用 MySQL 和 JDBC 准备语句缓存

Posted

技术标签:

【中文标题】使用 MySQL 和 JDBC 准备语句缓存【英文标题】:Prepared Statement Cache with MySQL & JDBC 【发布时间】:2014-02-12 01:30:08 【问题描述】:

我读到 mysql 不支持服务器端查询计划缓存。因此,如果我想使用 PreparedStatements 来获得性能优势,我可以做的是在 JDBC Connection 中启用语句缓存。因此,根据文档,它将启用基于每个连接的准备好的语句的缓存。

与 MySQL 具有服务器端查询计划缓存相比,通过 JDBC 连接进行 PreparedStatement 缓存的性能增益是多少? 那么如果在物理连接的缓存中确实找到了PreparedStatement,是否意味着当它到达mysql服务器时,mysql不会对其进行查询优化,而是可以直接执行它?

在使用 MySQL 作为我的数据库时,我是否应该在 JDBC 连接级别使用语句缓存?我正在使用带有 Mysql JDBC 连接器的 Hikari 数据库连接池。

【问题讨论】:

您使用的是什么版本的 MySQL 和 JDBC? dev.mysql.com/doc/refman/5.7/en/statement-caching.html @emecas 我使用的是 mysql-connector-java 版本 5.1.18。 MySQL 版本是 5.7,因为我打算在 mysql 5.7 版中使用 mysql 附带的 InnoDB Cache 插件 @AnthonyAccioly :感谢您的链接。但是语句缓存仍然是基于每个连接的。它是否比在 JDBC 级别进行语句缓存更好? 两者都可以:)。另外,您的连接池将使“每个连接”缓存值得。 【参考方案1】:

是的,如果您知道自己在做什么,缓存就不会受到伤害。如果您按照应有的方式重用准备好的语句,则将客户端缓存与服务器端缓存结合起来会带来性能优势(很多人忘记了最重要的部分:D)。只需正确设置Connector/J properties 属性:

cachePrepStmts=true&useServerPrepStmts=true

虽然我不是微型基准测试的忠实拥护者,但 here is one 支持我的陈述(蹩脚的双关语)。关于基准测试的有趣部分是它表明启用服务器端缓存实际上可能会在没有一些客户端缓存的情况下减慢速度,但是启用两层缓存以及正确重用准备好的语句,您实际上可能会得到很好的加速.

【讨论】:

谢谢安东尼!顺便说一句,您的 Connector/J 属性链接不起作用【参考方案2】:

HikariCP 的作者之一在这里。请参阅HikariCP wiki,了解如何正确配置 MySQL 以进行准备好的语句缓存。准备好的语句缓存可以显着加快 SQL。此外,如果将用户提供的输入连接到 SQL 普通语句中,它可以避免对代码的 SQL 注入攻击,否则这种攻击会成功。 永远不要编写包含用户提供的输入的 SQL 字符串。 始终使用准备好的语句,并将用户提供的输入设置为替换值。

【讨论】:

你好,brettw。感谢精彩的项目。顺便说一句,c3p0 的基准测试看起来令人印象深刻。只是一件事,为什么你们不推荐useServerPrepStmts=true 用于MySQL?它还可以挤出一些额外的性能。 安东尼,我不知道userServerPrepStmts。我会把它添加到文档中,谢谢! 一些简单的测试表明userServerPrepStmts = false 更快。 Vlad Mihalcea 的answer 也说明了这一点。【参考方案3】:

您可以设置两个属性:

useServerPrepStmts - 启用服务器端准备好的语句,因为默认情况下,准备好的语句是在客户端模拟的。 cachePrepStmts - 启用语句缓存机制

性能结果

对于客户端语句,通过启用cachePrepStmts 设置可以提高吞吐量,如下图所示:

而且,对于服务器端语句,通过启用cachePrepStmts 属性也提高了吞吐量:

因此,语句缓存机制也适用于客户端和服务器端准备好的语句。

在 MySQL 8.0.22 和 8.0.18 上使用单语句和多语句事务进行测试时,客户端预准备语句的性能优于服务器端预准备语句。

Therfeofre,以下配置选项似乎产生了最好的结果:

useServerPrepStmts=false
cachePrepStmts=true
prepStmtCacheSize=500
prepStmtCacheSqlLimit=1024

设置最后两个属性是为了增加缓存限制,因为默认值对于许多数据驱动的应用程序来说太低了。

【讨论】:

【参考方案4】:

与 MySQL 相比,其他品牌和型号的表服务器将通过 JDBC 准备语句为您提供更多的性能优势。例如,Oracle 可以重用执行计划。

但是您仍然应该在 JDBC 中使用准备好的语句。使用它们的原因有很多,包括绑定变量带来的注入阻力。

【讨论】:

以上是关于使用 MySQL 和 JDBC 准备语句缓存的主要内容,如果未能解决你的问题,请参考以下文章

mssql-jdbc MS SQL Server JDBC 驱动程序准备好的语句缓存性能问题与 Hikari CP

我可以在 JDBC 准备查询中使用多个语句吗?

JDBC - 语句、PreparedStatement、CallableStatement 和缓存

通过 Ruby on Rails 和 oracle-enhanced_adapter 使用 Oracle JDBC 语句缓存

MySQL --JDBC

带有 HashMap 的准备好的语句,异常