MySQL MyISAM引擎是什么?有什么致命缺陷?为何现在都不使用了?

数据库 其他数据库
"当我启动 InnoDB 引擎时,服务器内存突然耗尽..." —— 林渊如何用 Buffer Pool 优化化解内存危机?

上一篇《MySQL:MyISAM 锁表致千万损失!穿越工程师如何逆天改命》,我发现自己穿越到了 过去,这个年代的 MySQL 居然还在用 MyISAM……次日上午,技术部紧急会议

"林工,你说要换引擎就换?"

首席 DBA 老张拍案而起,"这系统跑了三年都没事,你才来三天就搞事情?"

林渊默然调出昨晚的监控数据:

# 昨夜事故报告
Lock_time_avg: 12.7s  # 表锁平均等待时间
Table_locks_immediate=2345
Table_locks_waited=8765  # 锁等待率高达78%
  • 1.
  • 2.
  • 3.
  • 4.


"各位请看,"林渊点击投影,"这不是故障,而是架构级癌症。"

连接池危机

诡异现象

SHOW PROCESSLIST;
+-----+------+-----------+------+---------+------+-------+------------------+
| Id  | User | Host      | db   | Command | Time | State | Info             |
+-----+------+-----------+------+---------+------+-------+------------------+
| 101 | app  | 10.0.0.5  | prod | Sleep   | 632  |       | NULL             |
| 102 | app  | 10.0.0.5  | prod | Sleep   | 587  |       | NULL             |
| 103 | app  | 10.0.0.5  | prod | Sleep   | 524  |       | NULL             |
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.

(超过 300 个僵尸连接,消耗 1GB 内存)

技术解析

图片图片

  • 线程泄漏原理: MySQL 4.0 采用"每连接每线程"模型,线程执行完不会销毁而是进入thread_cache
  • 但当wait_timeout设置过大时(默认 8 小时),大量空闲线程堆积。

林渊的解法

// 修改mysqld.cc的线程管理逻辑
void handle_one_connection(THD *thd) {
    while (!abort_loop) {
        if (thd->net.vio->read_packet() == 0) {  // 无数据时主动释放
            thread_scheduler.end_thread(thd, true);
            break;
        }
        do_command(thd);
    }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.

操作结果: 内存占用从 3.2GB 降至 1.8GB,QPS 提升 40%。

SQL 执行过程

惊魂时刻:当林渊试图优化慢查询时,系统突然报错:

ERROR 1064 (42000): You have an error in your SQL syntax...
  • 1.

——用户输入的SELECT * FORM orders竟然未被拦截!

解剖流程

图片图片

关键发现

  • 查询缓存陷阱query_cache_type=ON导致频繁缓存失效(命中率仅 12%)
  • 解析器漏洞:未启用严格模式(sql_mode未设置)允许错误语法通过
  • 优化器缺陷:缺乏直方图统计,错误选择全表扫描

林渊的急救包

SET GLOBAL query_cache_size=0;  -- 关闭毒药级查询缓存
SET GLOBAL sql_mode='STRICT_TRANS_TABLES';  -- 启用严格模式
ANALYZE TABLE orders;  -- 手动更新统计信息
  • 1.
  • 2.
  • 3.

变更存储引擎

惊险时刻:当林渊尝试在线更换存储引擎时

ALTER TABLE orders ENGINE=InnoDB;
  • 1.

系统突然僵死!SHOW PROCESSLIST显示:

| 145 | system user | NULL | NULL | alter table | 89  | copy to tmp table |
  • 1.

引擎切换原理

图片图片

林渊的破局操作

  1. 使用pt-online-schema-change工具在线变更(提前 20 年发明)
  2. 分阶段迁移数据:
# 步骤1:创建影子表
CREATE TABLE _orders_new LIKE orders ENGINE=InnoDB;

# 步骤2:分批拷贝(每次10万条)
INSERT INTO _orders_new SELECT * FROM orders WHERE id BETWEEN ? AND ?;

# 步骤3:原子切换(0.01秒锁定)
RENAME TABLE orders TO _orders_old, _orders_new TO orders;
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.

引擎插件的秘密

林渊在ha_myisam.cc中发现关键结构:

struct st_mysql_storage_engine myisam_storage_engine = {
    "MyISAM",
    "MySQL AB",
    "Default engine with fast read speed",
    { /* 函数指针表 */
        myisam_create_handler,
        myisam_hton_commit,
        NULL  // 事务相关为空
    }
};
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.

"原来 MyISAM 的事务支持是先天残疾..."他若有所思。

下节预告

"当我启动 InnoDB 引擎时,服务器内存突然耗尽..." —— 林渊如何用 Buffer Pool 优化化解内存危机?

且看下一章节《InnoDB 架构设计:行级锁原理、预写日志(WAL)、Change Buffer》!

责任编辑:武晓燕 来源: 码哥跳动
相关推荐

2012-03-20 11:16:24

MySQLMyISAM

2019-06-11 16:11:16

MySQLMyISAMInnoDB

2021-08-23 06:22:00

PaaSDevOps平台即服务

2022-09-08 08:02:26

MySQL隔离

2021-01-21 17:27:05

区块链加密货币稳定币

2022-05-16 23:10:54

稳定币区块链加密货币

2010-11-23 11:27:53

MySQL MyISA

2010-05-11 15:06:24

MySQL MyISA

2010-05-21 16:23:52

MySQL MyISA

2013-04-19 01:42:02

2019-09-12 14:44:53

云计算云架构数据

2022-02-27 15:19:26

云弹性安全技术

2015-10-30 15:55:43

MySQL

2018-01-08 11:09:00

超频DIY主板

2010-05-21 16:10:28

2021-08-27 15:46:29

数字人民币数字货币区块链

2018-06-14 10:44:59

MySQLMyISAMInnoDB

2009-05-05 10:19:37

存储引擎InnoDBMyISAM

2022-04-16 14:20:29

MySQL数据库

2023-03-28 07:03:15

gRPCMetadata
点赞
收藏

51CTO技术栈公众号