夜雨聆风学习资料网

ARTICLE · 1046352

从源码看MySQL [4]|Handler接口:SQL层和InnoDB之间那道"翻译层"

从源码看MySQL [4]|Handler接口:SQL层和InnoDB之间那道"翻译层"

从源码看MySQL [4]|Handler接口:SQL层和InnoDB之间那道"翻译层"点击下方按钮复制正文,然后粘贴到微信公众号编辑器         

         复制正文     

从源码看MySQL [4]|Handler接口:SQL层和InnoDB之间那道"翻译层"

本系列:《高性能MySQL第三版》源码级伴读

实验环境:MySQL 8.0.46-debug

本文是 Phase 1 第 4 篇:存储引擎抽象层


一、场景:为什么 MySQL 能有那么多存储引擎?

❓ 场景:同事问"我们要不要用 MyISAM?听说查询快一点。"

回答这个问题前,我们得先理解:MySQL 怎么让不同的存储引擎"插拔"?


二、书上怎么说?——《高性能MySQL》关于存储引擎架构

《高性能MySQL》第1章明确指出:

「MySQL 采用插件式存储引擎架构,最上层是 SQL 层,下层是各种存储引擎。」

书里也指出:

  • InnoDB 是 5.5 之后的默认引擎
  • MyISAM 不支持事务和外键
  • Memory 引擎数据存在内存中

书没讲

  • ❌ Handler 接口是怎么设计的
  • ❌ 怎么"看"到引擎调用次数

三、源码:Handler 接口的真相

MySQL 用 C++ 虚函数实现"接口抽象":

C++
"color: #6a737d; font-style: italic;">// sql/handler.h (简化) class handler {  public:   "color: #6a737d; font-style: italic;">// 核心虚函数   virtualint open(constchar *name, int mode, uint test_if_locked) = 0;   virtualint close(void) = 0;   virtualint write_row(uchar *buf) = 0;          "color: #6a737d; font-style: italic;">// INSERT   virtualint update_row(const uchar *old, uchar *new) = 0;  "color: #6a737d; font-style: italic;">// UPDATE   virtualint delete_row(const uchar *buf) = 0;   "color: #6a737d; font-style: italic;">// DELETE   virtualint index_read(uchar *buf, const uchar *key, uint key_len,                           enum ha_rkey_function find_flag) = 0;  "color: #6a737d; font-style: italic;">// SELECT   virtualint index_next(uchar *buf) = 0;   "color: #6a737d; font-style: italic;">// ... 还有几十个 };

InnoDB 的实现storage/innobase/handler/ha_innodb.cc):

C++
class ha_innobase : public handler {  public:   int index_read(uchar *buf, ...) override {     "color: #6a737d; font-style: italic;">// 调用 InnoDB 自己的 row_search_mvcc()     return row_search_mvcc(...);   } };

设计哲学

  • SQL 层只跟 handler 虚函数打交道
  • 不同引擎实现 handler 子类就行
  • 完全符合"开闭原则"
    ——加新引擎不动 SQL 层

四、实测:看你的实例支持哪些引擎

SQL
SHOW ENGINES\G

输出(节选):

Engine: InnoDB    Support: DEFAULT    Comment: Supports transactions, row-level locking, and foreign keys Transactions: YES           XA: YES    Savepoints: YES  Engine: MyISAM    Support: YES Transactions: NO          ← 不支持事务           XA: NO  Engine: MEMORY    Support: YES Transactions: NO          ← 不支持事务    Comment: Hash based, stored in memory, useful for temporary tables  Engine: PERFORMANCE_SCHEMA    Support: YES Transactions: NO          ← 不是真"数据库"

Handler 调用计数

SQL
SHOWSTATUSLIKE'Handler_%';
Variable
含义
何时增加
Handler_read_key
通过索引读
WHERE id = ?
Handler_read_next
索引顺序读
范围扫描
Handler_read_rnd_next
全表扫描
SELECT * FROM t
 无索引
Handler_update
UPDATE 行数
每次 UPDATE
Handler_write
INSERT 行数
每次 INSERT

运维用法

SQL
-- 看 SQL 走没走索引SELECT * FROM orders WHERE id = 1;  -- Handler_read_key +1SELECT * FROM orders;                -- Handler_read_rnd_next +N

五、各引擎能力对比(基于代码)

能力
InnoDB
MyISAM
Memory
事务
行锁
❌(表锁)
❌(表锁)
外键
崩溃恢复
✅(redo log)
❌(重启丢)
全文索引
✅(5.6+)
压缩
适用场景
通用/默认
只读报表
临时表

结论绝大多数情况用 InnoDB。MyISAM 只用于"只读 + 不在乎崩溃" 的极小场景。


六、Handler 计数实战:识别慢查询

SQL
-- 重置计数器(仅当前session) FLUSH STATUS;  -- 跑你的 SQLSELECT * FROM orders WHERE user_id = 1001SELECT * FROM orders WHERE id IN (1,2,3);  -- 看计数器(MySQL 8.0支持WHERE子句)SHOWSESSIONSTATUSWHERE Variable_name LIKE'Handler_%'AND Value > 0;

输出解读

  • Handler_read_key > 0
    :走了索引(好事)
  • Handler_read_rnd_next = N
    :扫描了 N 行(小心,可能是全表扫描)
  • 比例 Handler_read_rnd_next / Handler_read_key > 100:基本确定是慢查询

七、本篇对应解决的运维问题

问题
答案
InnoDB 还是 MyISAM
用 InnoDB
,除非你有非常特殊的需求
怎么判断 SQL 走没走索引
用 Handler_read_* 计数 + EXPLAIN
怎么看真实引擎
SHOW TABLE STATUS LIKE 'table_name'

八、关键参数

参数
默认值
说明
default_storage_engine
InnoDB
新表的默认引擎
internal_tmp_disk_storage_engine
InnoDB
内部磁盘临时表

九、本篇作业 & 下期预告

作业

  1. 执行 SHOW ENGINES\G 看你的实例支持哪些
  2. 跑一条 SELECT * FROM orders,看 Handler_read_rnd_next 增加了多少
  3. 试试建一个 MyISAM 表:CREATE TABLE test_myisam (id INT) ENGINE=MyISAM;(如果支持)

下期预告

Phase 1 第 5 篇|InnoDB 页结构:数据在磁盘上长什么样——Handler 说"读一行",InnoDB 要去一个 16KB 的页里找这行。页是 InnoDB 数据的最小存储单位,结构到底是什么样的?


如果觉得有帮助,请点赞、在看、转发三连。Handler 接口是 SQL 层和存储引擎的"桥梁"——下一站,我们看看这桥通向什么样的数据。


⚖️ 版权声明

  • 本文为原创技术分析文章,非官方授权翻译或转载
  • 对《高性能MySQL第三版》的引用仅限简短概括,用于评论和教学,符合《著作权法》第24条合理使用
  • MySQL 源码引用遵循 GPL v2 开源协议,用于教育目的的代码片段分析不构成"分发"
  • "MySQL"为 Oracle Corporation 注册商标,本文使用仅为技术描述
  • 建议购买原书深入学习:《高性能MySQL》第三版,电子工业出版社
  • 未经作者许可,禁止转载或用于商业用途

已复制到剪贴板!去微信后台粘贴吧

相关学习资料