mysql缓存如何使用

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了mysql缓存如何使用相关的知识,希望对你有一定的参考价值。

我们都知道 mysql 的 Table Cache 是表定义的缓存,江湖上流传着各种对这个参数的调优方法。
table cache 的作用,就是节约读取表结构文件的开销。对于table cache 是否命中,其实table cache 是针对于线程的,每个线程有自己的缓存,只缓存本线程的表结构定义。不过我们发现,strace 中没有关于表结构文件的 open 操作(只有 stat 操作,定位表结构文件是否存在),也就是说 table cache 不命中,不一定需要读取表结构文件。这种感觉好像是:在不命中 table cache 时,命中了另外一个表结构缓存。
运维建议:
我们读一下 MySQL 的文档,关于 table_open_cache 的建议值公式:建议值 = 最大并发数 * join 语句涉及的表的最大个数。
通过实验我们容易理解:table_cache 是针对于线程的,所以需要最大并发数个缓存。另外,一个语句 join 涉及的表,需要同时在缓存中存在。所以最小的缓存大小,等于语句 join 涉及的表的最大个数。将这两个数相乘,就得到了 MySQL 的建议值公式。
参考技术A 设置好查询缓存的大小就行了。比如设置个20MB.
SET GLOBAL QUERY_CACHE_SIZE=20000000;
mysql会将查询SQL和结果集存到缓存中,等下次遇到相同的SQL语句时,结果集从缓存中读取。追问

这设置缓存大小有什么学问吗?

追答

1.设置缓存大小时,至少给它40000(即40kb),否则会报错,因为mysql启用缓存得花这么多内存。最多给多少看情况啦,自己学习用的1mb都很够了,生产环境下看访问量和缓存命中率等因素再调整,不过一般都有几百mb吧。
2.以下几个个参数可以看出设置缓存后的效果。
可以用show status like 'Qcache_%' 查看。
Qcache_hits 缓存命中数
Qcache_not_cached 没有没缓存的query数
Qcache_free_memory 空闲缓存大小(如果空闲太多,说明你设置的缓存过大了,调小一些)
Qcache_inserts 载入缓存的query数

追问

哦 谢谢 最后一个问题 缓存保存的时间是多长哈 可以设置等吗

追答

缓存保存query使用的算法是LRU(即least recently used 最近最少使用)。这个是mysql默认的缓存算法,可以通过一些参数的修改使mysql使用其他缓存算法,不过没这个必要,LRU已经是一个非常优秀的算法了。
根据这个算法,当mysql收到一条query,先去缓存中找,没找到的话就把这条query以及结果集写进缓存,如果恰好缓存已经写满,那么mysql会将缓存中最近最少使用的那条query删除,然后写入新的query和结果集。
所以可以这么理解缓存保存query的时间:
如果缓存够大,query数不多,query会一直呆在缓存中;缓存空间不够的话,那些不经常使用的query保存的时间不会太久,因为mysql会优先保留那些经常使用的query。

本回答被提问者采纳

如何使用 MySQL 准备好的语句缓存?

【中文标题】如何使用 MySQL 准备好的语句缓存?【英文标题】:How to use MySQL prepared statement caching? 【发布时间】:2010-09-18 07:58:25 【问题描述】:

如何利用 MySQL 缓存准备好的语句的能力? 使用预准备语句的一个原因是,如果要再次使用同一个预准备语句,则无需多次发送预准备语句本身。

Class.forName("com.mysql.jdbc.Driver");
Connection conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/mydb" +
        "?cachePrepStmts=true", "user", "pass");
for (int i = 0; i < 5; i++) 
    PreparedStatement ps = conn.prepareStatement("select * from MYTABLE where id=?");
    ps.setInt(1, 1);
    ps.execute();

conn.close()

在运行上述 Java 示例时,我在 mysqld 日志文件中看到了 5 对 Prepare 和 Execute 命令。当然,将 ps 分配移到循环之外会导致单个 Prepare 和 5 Execute 命令。连接参数“cachePrepStmts=true”在这里似乎没有任何区别。 当使用 Spring 和 Hibernate 运行类似的程序时,发送的 Prepare 命令的数量(1 或 5)取决于是否启用了 cachePrepStmts 连接参数。 Hibernate 如何执行准备好的语句以利用 cachePrepStmts 设置?是否可以使用纯 JDBC 来模拟这一点? 我在 MySQL Server 4.1.22 和 mysql-connector-java-5.0.4.jar 上运行它

【问题讨论】:

【参考方案1】:

你应该在循环外准备语句。

Connection conn = DatabaseUtil.getConnection();
PreparedStatement stmtUpdate = conn.prepareStatement("UPDATE foo SET bar=? WHERE id = ?");
for(int id=0; id<10; id++)
    stmtUpdate.setString(1, "baz");
    stmtUpdate.setInt(2, id);
    int rows = stmtUpdate.executeUpdate();
    // Clear parameters for reusing the preparedStatement
    stmtUpdate.clearParameters();

conn.close();

我不知道 mysql 缓存准备好的语句,但这是 JDBC 准备好的语句应该被重用的方式。

【讨论】:

【参考方案2】:

您还需要在连接实例上设置语句缓存大小。我假设默认缓存大小为 0。因此不会缓存任何内容。

【讨论】:

【参考方案3】:

首先,您的 PreparedStatement 在循环中重新创建,因此允许 JDBC 驱动程序丢弃准备好的数据。所以你要求丑陋的行为,所以你得到了它。

然后,MySQL 中的 PreparedStatement 是独立的一章。要获得真正的缓存,您必须通过连接属性显式请求它。

因此,您必须将“cachePrepStmts”属性设置为“true”才能缓存准备好的语句。默认情况下,该属性设置为 false。

@有关详细信息,请参阅您的 MySQL 版本的 MySQL 手册

【讨论】:

【参考方案4】:

您应该只在循环之外准备一次语句,然后在循环中绑定参数。这就是准备好的语句具有绑定参数的原因——因此您可以重复使用准备好的语句。

Hibernate 正是这样做的,将所有 SQL 视为幕后准备好的语句,但如果您使用文字而不是绑定参数,您显然会滥用这一点。

【讨论】:

【参考方案5】:

是否可以使用 纯 JDBC?

这实际上不是您通过将准备好的语句调用移出循环所做的吗?

我可能误解了 MySQL 缓存的工作方式,但是日志文件是否一定会报告缓存的工作?可能是 Spring 或 Hibernate 有自己的中间缓存,用于检查准备好的语句与之前发送的语句。这可能是您在使用 Spring 运行程序时所看到的。这意味着对您的系统进行一些跟踪,以查看 mysqld 日志是否只是报告它已发送的语句,而不管它如何处理它们。

【讨论】:

以上是关于mysql缓存如何使用的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 MySQL 准备好的语句缓存?

如何使用MYSQL语句进行数据缓存?

如何清理mysql数据库缓存数据?

MySQL进阶实战11,查询缓存

Redis缓存如何保证一致性

Mysql和Redis数据如何保持一致