TableCache设置过小造成MyISAM频繁损坏

本文探讨了频繁开关MyISAM表文件导致的数据库损坏问题,分析了table_cache配置的重要性及合理的设置方法,提供了检查和调整操作系统参数的步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前些天说了一下如何修复损坏的MyISAM表 ,可惜只会修复并不能脱离被动的境地,只有查明了故障原因才会一劳永逸。

如果数据库服务非正常关闭(比如说进程被杀,服务器断电等等),并且此时恰好正在更新MyISAM表,那么发生损坏的概率就比较大。今天我要说的是另一种情况:频繁的打开关闭MyISAM表文件造成MyISAM表损坏。

什么时候会出现频繁的打开关闭MyISAM表文件的情况呢?

先查看当前系统的table_cache 设置,它的作用就是缓存表文件描述符,降低打开关闭表的频率,如果这个参数设置得过小,那么很快就会被占满,再有新请求过来的时候,就不得不关闭一些已打开的表以便为新请求腾出空间,从而出现频繁的打开关闭MyISAM表文件的情况:

mysql> show variables like 'table%';

再查看当前系统的打开表的情况:

mysql> show status like 'open%';

有两项关键的结果:Open_tables和Opened_tables,他们的名字类似,其含义的区别在于:

Open_tables:表示当前打开的表数目。
Opened_tables:表示累计已经打开的表数目。

那么如何判断table_cache是否设置合理呢?其判断尺度如下:

如果Opened_tables远大于Open_tables,并且Open_tables很接近table_cache,那么就说明table_cache偏小。

还要注意设置操作系统的参数,因为即便你把table_cache设置得很大,一旦超过了操作系统的限制也没用,可以按如下方法查询当前值:

ulimit -n

设置方法也很简单,比如设置成8k,可以这样:

vi /etc/security/limits.conf

* hard nofile 8192
* soft nofile
8192

这样设定比在/etc/rc.local里设定ulimit -n 8192更合理一些(参考链接 )。

MySQL运行稳定后,查看open_files_limit 参数:

mysql> show variables like '%open%';

在大量使用MyISAM的环境里,应该保证open_files_limit表类型至少是table_cache的二到三倍,这是因为每个MyISAM表都包括三个文件:一个表定义文件,一个表索引文件,一个表数据文件,详细介绍可以参考文档 。而在Innodb的环境里,一个表只有一个文件,明白这些基本知识对解决问题很有帮助。

具体的数据库文件打开情况可以用lsof来查看:

lsof | grep MYI 或者 lsof | grep MYD

可以发现索引文件描述符是客户端共享的,数据文件则不是,你可以这样确认这一点:

lsof | egrep -i 'myd|myi' | awk '{++state[$NF]} END {for(key in state) print state[key], "/t", key}' | sort -nr

为了保险点,或许还要查查内核的相关参数,比如fs.file-max,这些细节往往会影响到MySQL:

sysctl -a | grep "file"

注意到以上这些因素,问题差不多就能解决了。

BTW:如果你比较懒惰,也可以用MySQL Performance Tuning Primer Script 来判断参数是否合理

<think>我们正在讨论MySQLtable_open_cache参数。根据引用,这个参数控制着表缓存的大小,用于减少打开表的开销。当多个查询访问同一张表时,MySQL可以复用已经打开的表句柄,避免重复打开。 作用: - 减少打开表的次数,提高性能。 - 如果设置过小,会导致频繁打开和关闭表,增加系统开销,表现为Opened_tables值快速增长,并且show processlist中可能有大量opening table的状态。 设置方法: - 可以通过命令临时设置:`set global table_open_cache=1024;` - 永久设置需要修改配置文件(如my.cnf),在[mysqld]部分添加:`table_open_cache=1024` 如何确定合适的值? - 观察状态变量:`show global status like 'Open%tables';` Open_tables:当前打开的表数量 Opened_tables:自服务器启动以来打开过的表次数 - 如果Opened_tables的值很大,且Open_tables接近table_open_cache的值,说明缓存不够,需要增大。 - 一些建议:可以设置为max_connections的倍数(因为每个连接可能会同时打开多个表),或者根据同时查询涉及的表数量来估算。但注意不要设置过大,以免占用过多内存。 另外,引用[3]提到table_open_cache_instances参数,用于将表缓存分成多个分区,减少锁竞争。在设置较大的table_open_cache时,可能需要调整这个参数(默认为16)。 因此,我们可以这样回答用户:</think>### MySQL `table_open_cache` 参数详解 #### 一、参数作用 `table_open_cache` 是 MySQL 中控制**表缓存**的关键参数,主要作用包括: 1. **减少文件操作开销** 缓存已打开的表文件描述符(File Descriptor),避免重复打开相同表的系统调用。当查询访问表时,MySQL 优先从缓存获取文件句柄,而非重复打开磁盘文件[^1][^4]。 2. **提升并发性能** 每个线程访问表时需独立维护文件描述符。合理的缓存可减少线程间资源竞争,尤其在高并发场景下(如连接数 `max_connections` 较大时)[^5]。 3. **缓解锁竞争** 配合 `table_open_cache_instances` 参数,将缓存划分为多个分区,降低多线程访问缓存时的锁冲突概率[^3][^4]。 #### 二、设置方式 1. **查看当前值** ```sql SHOW VARIABLES LIKE 'table_open_cache'; -- 当前配置值 SHOW GLOBAL STATUS LIKE 'Open%tables'; -- 实际使用状态 ``` 输出示例: ``` +------------------+-------+ | Variable_name | Value | +------------------+-------+ | table_open_cache | 400 | -- 缓存大小 +------------------+-------+ +---------------+-------+ | Variable_name | Value | +---------------+-------+ | Open_tables | 345 | -- 当前打开表数 | Opened_tables | 9734116| -- 历史累计打开次数 +---------------+-------+ ``` 2. **动态修改(临时生效)** ```sql SET GLOBAL table_open_cache = 2048; -- 立即生效,重启后失效 ``` 3. **永久修改** 在 `my.cnf` 配置文件中添加: ```ini [mysqld] table_open_cache = 2048 ``` #### 三、配置建议 1. **判断依据** - 若 `Opened_tables` 值持续快速增长且 `Open_tables` 接近 `table_open_cache` 值,表明缓存不足[^2][^5]。 - 出现大量 `opening table` 状态的线程时需增大缓存[^2]。 2. **计算公式** 推荐值: ``` table_open_cache ≥ max_connections × N ``` - `N`:单个查询平均涉及的表数量(通常取 2~10)[^2][^5]。 - 示例:若 `max_connections=500`,则建议设置 1000~5000。 3. **注意事项** - 避免过大:过高的值会消耗更多内存(每个表约 20KB~50KB)[^5]。 - 实例分区:当值 > 10,000 时,需调整 `table_open_cache_instances`(默认 16)以分散锁压力[^3]。 - 文件描述符限制:确保系统级 `ulimit -n` 值大于 `table_open_cache`(尤其 MyISAM 表需 2 倍描述符)[^5]。 #### 四、性能优化示例 **问题场景**: 监控发现 `Opened_tables` 每分钟增长 10,000+,且查询延迟明显。 **解决方案**: 1. 将缓存从默认 400 提升至 2000: ```sql SET GLOBAL table_open_cache = 2000; ``` 2. 观察状态变化: ```sql SHOW GLOBAL STATUS LIKE 'Opened_tables'; -- 增速应显著下降 ``` 3. 确认有效后写入配置文件永久生效[^2][^5]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值