<?xml version="1.0" encoding="utf-8"?>
<ul>
  <li>这是《MySQL 8.0 源码与内核实战》的独立章节版。本章从概念、实操和生产排查三个视角展开，代码块保留了原书可直接运行的版本。目录定位            模块      目录                  SQL 解析与执行      sql/              InnoDB      storage/innobase/              Binlog 事件      libbinlogevents/              组复制      plugin/group_replication/              MTR 测试      mysql-test/              公共头文件      include/      关键调用链dispatch_command  -&gt; mysql_parse     -&gt; mysql_execute_command        -&gt; optimize           -&gt; execute              -&gt; handler::ha_index_read                 -&gt; ha_innobase::index_read                    -&gt; row_search_mvcc写入：Server write path  -&gt; engine prepare     -&gt; binlog write        -&gt; engine commit           -&gt; redo durable常用断点b dispatch_commandb mysql_parseb mysql_execute_commandb JOIN::optimizeb row_search_mvccb row_insert_for_mysqlb row_update_for_mysqlb lock_rec_lockb ReadView::changes_visibleb mtr_t::commit结构体速查            结构      含义                  THD      会话上下文              TABLE_SHARE      共享表定义              TABLE      打开的表实例              handler      Server 到引擎接口              row_prebuilt_t      InnoDB 表操作上下文              buf_block_t      缓冲页块              rec_t      InnoDB 记录              btr_cur_t      B+Tree 游标              trx_t      InnoDB 事务              lock_t      锁对象              mtr_t      mini transaction      SQL 层排查EXPLAIN FORMAT=TREE SELECT ...;EXPLAIN ANALYZE SELECT ...;SET optimizer_trace='enabled=on';SELECT trace FROM information_schema.optimizer_trace\GInnoDB 排查SHOW ENGINE INNODB STATUS;SELECT * FROM information_schema.innodb_trx;SELECT * FROM performance_schema.data_locks;SELECT * FROM performance_schema.data_lock_waits;SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool_read%';SHOW GLOBAL STATUS LIKE 'Innodb_redo_log%';日志与事务            项目      要点                  redo      物理页修改，崩溃恢复              undo      旧版本，回滚与 MVCC              MTR      页级物理一致性              LSN      日志与页面版本              checkpoint      依赖脏页刷盘              purge      依赖最老活跃 read view      DDL 判断            算法      含义                  INSTANT      元数据变更              INPLACE      引擎内执行              COPY      重建复制      上线前检查算法支持、锁模式、磁盘空间、长事务和回滚方案。常见现象定位            现象      优先方向                  执行计划差      统计、索引、trace              commit 慢      redo、binlog、磁盘              锁等待      长事务、索引、隔离级别              undo 膨胀      history list、purge              磁盘不降      delete mark、页合并              DDL 等待      MDL、表缓存              主从延迟      IO/SQL 线程、大事务              写入尖刺      checkpoint、purge、刷脏      实验清单  固定 MySQL 8.0.x 和 commit；  Debug 构建并初始化独立 datadir；  写最小 SQL；  设置断点并保存 backtrace；  记录参数和状态；  对照 MTR；  输出版本化笔记。</li>
  <li>这是《MySQL 8.0 源码与内核实战》的独立章节版。本章从概念、实操和生产排查三个视角展开，代码块保留了原书可直接运行的版本。MySQL 内核学习的目标不是背函数名，而是建立从现象、模块、数据结构到验证方法的完整推理链。31.1 成长阶段            阶段      能力                  入门      编译、调试、看懂调用链              初级      理解 SQL 层和 handler 边界              中级      掌握 B+Tree、Buffer、事务              高级      分析锁、MVCC、日志和恢复              专家      修改内核、贡献补丁、设计方案      31.2 学习路线编译调试  -&gt; SQL 执行路径     -&gt; 优化器与执行器        -&gt; 页面与 B+Tree           -&gt; Buffer Pool              -&gt; undo / MVCC                 -&gt; redo / recovery                    -&gt; lock / purge                       -&gt; replication / DDL31.3 实践方法  每周一个最小复现；  每个结论保存调用栈；  用 MTR 固化行为；  对比两个版本；  读对应测试；  做性能基准；  写技术笔记；  尝试提交小补丁。31.4 进阶方向            方向      内容                  查询优化      代价模型、join search              执行引擎      迭代器、并行、表达式              存储结构      页格式、压缩、索引              事务恢复      WAL、checkpoint、crash safe              高可用      binlog、MGR、failover              云原生      多租户、弹性、存储计算分离      31.5 工程判断内核专家会先问：  问题属于哪一层；  当前版本是什么；  代价和风险是什么；  如何复现；  如何验证；  如何回滚；  是否值得修改内核；  是否可用架构方案替代。本章小结大师之路靠可复现实验和长期积累。沿着 SQL 层到 InnoDB 的路径不断验证，最终能解释行为、定位问题，并在必要时安全修改内核。思考题  你最想深入哪个模块？  如何建立一个长期源码笔记库？  什么情况下才值得修改内核？  如何设计一个内核改动的回滚方案？  下一个最小实验是什么？</li>
  <li>这是《MySQL 8.0 源码与内核实战》的独立章节版。本章从概念、实操和生产排查三个视角展开，代码块保留了原书可直接运行的版本。本章用面试问题串起 MySQL 8.0 内核知识，重点展示推理和证据来源。30.1 SQL 执行路径问题：请描述一条 SELECT 的执行流程。回答：dispatch_command  -&gt; mysql_parse     -&gt; resolver / rewrite        -&gt; optimize           -&gt; execute iterator              -&gt; handler                 -&gt; InnoDB row_search追问点：索引选择、二级索引回表、执行器迭代器、MVCC 可见性。30.2 B+Tree问题：聚簇索引和二级索引有什么区别？回答：  聚簇索引按主键组织完整行；  二级索引叶子存索引列和主键；  查询非覆盖列需要回表；  主键长度影响二级索引大小；  插入顺序影响页分裂。30.3 MVCC问题：RR 下一致性读如何工作？回答：  记录保存 DB_TRX_ID 和 DB_ROLL_PTR；  undo 形成版本链；  read view 记录活跃事务；  按可见性规则沿版本链查找；  RR 事务内快照保持稳定。30.4 锁问题：为什么 UPDATE 没走索引会锁很多行？回答：InnoDB 行锁加在索引记录上。无合适索引时扫描范围扩大，在 RR 下还可能加 gap/next-key 锁。应先优化索引和事务范围。30.5 Redo 与 Undo问题：redo 和 undo 的区别是什么？回答：redo 记录物理页修改用于崩溃恢复重做；undo 记录旧版本用于回滚和 MVCC。写入路径中先写 redo，旧版本进 undo，提交推进持久化，回滚按 undo 反向恢复。30.6 Purge问题：DELETE 后磁盘为什么没变小？回答：删除先标记记录，旧版本进入 undo；purge 在最老活跃快照之后才能物理清理，并可能触发页合并。空间可复用但不一定立即归还操作系统。30.7 DDL问题：8.0 原子 DDL 是不是 Online DDL？回答：不是。原子 DDL 指数据字典变更原子提交或回滚；Online 关注执行期间并发 DML，仍要区分 INSTANT、INPLACE、COPY 和 LOCK 策略。30.8 Buffer Pool问题：Buffer Pool 命中率低怎么办？回答：先判断是内存不足、随机访问、大扫描、冷数据还是索引不合理。结合命中率、脏页、物理读、SQL rows examined 和工作集，再决定扩容或优化查询。30.9 复制问题：主从延迟如何排查？回答：区分 IO 线程和 SQL 线程，查看 relay、applier worker、大事务、锁等待、DDL 和网络。处理大事务、并行重放、索引缺失和业务回压。30.10 源码方法问题：如何验证一个内核结论？回答：固定版本，写最小复现，用 EXPLAIN 和状态定位，gdb 断点看调用栈，MTR 固化行为，最后记录版本、函数和结论。本章小结面试重点是把概念落到模块、路径和证据：B+Tree、MVCC、锁、日志、purge、DDL 和复制都要能从现象推到源码。思考题  如何解释二级索引回表？  read view 可见性规则有哪些？  redo 和 undo 在恢复中各做什么？  原子 DDL 和 Online DDL 有什么区别？  如何证明一个锁范围结论？</li>
  <li>这是《MySQL 8.0 源码与内核实战》的独立章节版。本章从概念、实操和生产排查三个视角展开，代码块保留了原书可直接运行的版本。性能诊断要先把问题定位到网络、锁、CPU、IO、优化器、执行器或 InnoDB，再用源码解释观测指标。29.1 诊断路径slow log  -&gt; statement digest     -&gt; EXPLAIN ANALYZE        -&gt; performance_schema           -&gt; OS metrics              -&gt; source hypothesis                 -&gt; breakpoint / MTR29.2 工具分层            层      工具                  SQL      slow log、EXPLAIN、ANALYZE              语句等待      performance_schema              事务      innodb_trx、data_locks              Buffer      Innodb_buffer_pool_*              IO      Innodb_data_*、iostat              OS      pidstat、perf、vmstat              源码      gdb、MTR      29.3 慢 SQLSELECT schema_name, digest_text, count_star,       sum_timer_wait/1e12 AS total_sFROM performance_schema.events_statements_summary_by_digestORDER BY sum_timer_wait DESCLIMIT 10;判断：            特征      方向                  rows examined 高      索引、计划              no index used      访问路径              Created_tmp_disk_tables      排序聚合              lock time 高      MDL/行锁              CPU 高      表达式、扫描              IO wait 高      Buffer、磁盘      29.4 等待事件SELECT event_name, count_star, sum_timer_wait/1e12 AS total_sFROM performance_schema.events_waits_summary_global_by_event_nameORDER BY sum_timer_wait DESCLIMIT 20;常见映射：            等待      源码方向                  buffer pool mutex      buf 模块              log sync      log 模块              row lock      lock 模块              undo purge      purge              file io      fil / buf              table lock      MDL      29.5 常见问题定位            问题      排查                  commit 慢      redo、binlog、磁盘              DDL 等待      MDL、长事务              大扫描      执行计划、索引              延迟尖刺      checkpoint、purge、merge              CPU 单核高      单会话、锁模块              IO 利用率高      冷数据、随机读              history list 高      长事务      29.6 源码验证# SQL pathb dispatch_commandb mysql_parseb JOIN::optimize# InnoDB read pathb row_search_mvcc# write pathb row_insert_for_mysqlb row_update_for_mysql# lock pathb lock_rec_lock记录调用栈、参数、当前 THD 和事务状态，再对照源码结论。本章小结源码视角的性能诊断不是替代监控，而是解释监控指标。先用 slow log、EXPLAIN、等待事件和 OS 指标定位层，再用断点验证调用路径。思考题  rows examined 高说明什么？  commit 延迟应从哪些模块排查？  MDL 等待如何定位 blocking session？  history list 高和哪个源码模块相关？  如何用 gdb 验证执行路径？</li>
  <li>这是《MySQL 8.0 源码与内核实战》的独立章节版。本章从概念、实操和生产排查三个视角展开，代码块保留了原书可直接运行的版本。Clone Plugin 用于物理克隆本地或远程实例数据，是快速搭建从库和 MGR 成员的常用方式。28.1 方式            类型      说明                  local clone      从本实例克隆到目录              remote cloning      从 donor 克隆到 recipient      远程克隆会替换 recipient 数据，执行前必须确认目标实例可销毁。28.2 使用安装插件：INSTALL PLUGIN clone SONAME 'mysql_clone.so';本地：CLONE LOCAL DATA DIRECTORY='/backup/clone-20260825';远程：SET GLOBAL clone_valid_donor_list='10.0.0.11:3306';CLONE INSTANCE FROM 'clone_user'@'10.0.0.12':3306IDENTIFIED BY 'password';28.3 克隆内容物理克隆包含数据目录相关状态：  InnoDB 数据；  redo；  undo；  数据字典；  配置相关状态；  复制位点或 GTID 信息。克隆后通常要调整 server_uuid、复制配置和实例参数。28.4 过程recipient connect donor  -&gt; check version and compatibility     -&gt; snapshot transfer        -&gt; apply files           -&gt; recover              -&gt; restart recipient可通过 performance_schema 观察阶段。28.5 权限donor 用户需要 BACKUP_ADMIN，recipient 需要 CLONE_ADMIN。网络账号、SSL 和 clone_valid_donor_list 要按环境配置。28.6 与备份恢复对比            方案      特点                  Clone      物理快照，速度快，适合建从库              XtraBackup      物理备份，备份集管理更灵活              mysqldump      逻辑导出，速度慢但兼容性高              snapshot      依赖存储一致性      Clone 不是长期保留多个时间点的备份策略。28.7 注意事项  目标数据会被覆盖；  版本和平台兼容性要确认；  磁盘空间必须充足；  克隆期间 donor 有 IO 压力；  大实例会占用网络；  加密和压缩配置要匹配；  完成后验证 GTID 和数据校验。本章小结Clone Plugin 提供物理克隆能力，适合快速重建从库和 MGR 成员。它的核心优势是速度和一致性，但不能替代完整备份策略。思考题  local clone 和 remote clone 的区别是什么？  克隆后为什么可能要调整 server_uuid？  Clone 与 XtraBackup 的适用场景有什么不同？  donor 和 recipient 各需要什么权限？  为什么 Clone 不能替代多时间点备份？</li>
  <li>这是《MySQL 8.0 源码与内核实战》的独立章节版。本章从概念、实操和生产排查三个视角展开，代码块保留了原书可直接运行的版本。社区 MySQL 8.0 对并行查询的支持有限，聚集计算和多数单条 SELECT 仍以单线程执行为主。并行读取更多出现在发行版、HeatWave 或分析引擎中。本章重点是理解并行模型与瓶颈。27.1 串行执行one worker  -&gt; read rows     -&gt; filter        -&gt; aggregate        -&gt; sort           -&gt; return瓶颈可能：  CPU 单核；  Buffer Pool latch；  B+Tree 并发；  IO；  排序；  网络发送；  行解析。27.2 并行扫描模型coordinator  -&gt; split ranges / pages     -&gt; workers        -&gt; partial aggregation           -&gt; merge适合：  大范围扫描；  少量复杂聚合；  只读分析；  数据分布均匀；  IO 能力充足。不适合：  点查；  小结果集；  强锁读；  高并发 OLTP；  更新和事务冲突明显。27.3 并行聚合SELECT status, COUNT(*), SUM(amount)FROM ordersWHERE created_at &gt;= '2026-01-01'GROUP BY status;模型：workers compute partial results  -&gt; coordinator merge by group key难点：  DISTINCT；  窗口函数；  排序语义；  精度；  分组倾斜；  内存控制。27.4 MySQL 生态差异            方案      特点                  社区 8.0      并行查询能力有限              HeatWave      推送到分析加速层              Percona / PolarDB 等      发行版可能提供并行查询              ClickHouse / Doris      面向分析的原生并行      同一条 SQL 的并行行为不能跨实现假设。27.5 观测EXPLAIN ANALYZE SELECT ...;SELECT * FROM performance_schema.threads WHERE type='foreground';SHOW PROCESSLIST;并行执行要观测：  worker 数；  每个分区扫描行数；  merge 时间；  内存；  p95/p99；  对 OLTP 干扰。27.6 生产判断是否并行应考虑：  查询频率；  扫描量；  SLA；  CPU 水位；  IO 延迟；  并发事务；  缓存命中率；  是否可路由分析库。本章小结社区 MySQL 8.0 不是通用 MPP 数据库，复杂分析应考虑专用链路。并行查询的收益来自大扫描和聚合，代价是 CPU、内存和调度干扰。思考题  哪些 OLTP 点查不适合并行？  并行聚合如何合并部分结果？  为什么 DISTINCT 和窗口函数更难并行？  如何评估并行查询对在线事务的干扰？  社区版与发行版能力为什么不能混为一谈？</li>
  <li>这是《MySQL 8.0 源码与内核实战》的独立章节版。本章从概念、实操和生产排查三个视角展开，代码块保留了原书可直接运行的版本。MySQL 中“临时表”有三类：用户 TEMPORARY 表、SQL 层内部临时表和存储引擎内部临时结构。它们的生命周期、复制行为和内存策略不同。26.1 用户临时表CREATE TEMPORARY TABLE tmp_stat(  user_id BIGINT PRIMARY KEY,  amount DECIMAL(12,2)) ENGINE=InnoDB;特点：  会话可见；  同名临时表遮蔽普通表；  连接关闭自动清理；  不向传统复制流写入普通 DML；  某些 DDL 和复制场景有限制。连接池长连接要显式 DROP TEMPORARY TABLE，避免残留。26.2 内部临时表触发场景：  GROUP BY 无合适索引；  DISTINCT；  UNION；  派生表物化；  子查询物化；  窗口函数；  ORDER BY 无法使用索引；  JSON 或复杂表达式。观测：SHOW STATUS LIKE 'Created_tmp%';EXPLAIN FORMAT=TREE SELECT ...;26.3 TempTable 引擎8.0 内部内存临时表默认使用 TempTable：SHOW VARIABLES LIKE 'internal_tmp_mem_storage_engine';SHOW VARIABLES LIKE 'temptable_max_ram';SHOW VARIABLES LIKE 'temptable_max_mmap';超过内存能力后会转磁盘 InnoDB 临时表，可能产生明显延迟。26.4 磁盘临时表临时表空间：SHOW VARIABLES LIKE 'innodb_temp_data_file_path';SELECT * FROM information_schema.innodb_session_status LIMIT 5;大排序或大聚合会占用会话临时段，连接释放后空间可复用，文件不一定缩小。26.5 降低临时表压力  为 GROUP BY / ORDER BY 建匹配索引；  减少返回行和列；  先过滤再聚合；  拆分复杂 SQL；  分页避免大 offset；  大报表走分析库；  控制排序缓冲和临时表阈值。26.6 MEMORY 表MEMORY 引擎表数据放内存，默认 HASH 索引，重启后数据清空。适合临时配置或小字典，不适合持久业务数据。限制：  变长类型支持有限；  重启丢数据；  复制和恢复语义需谨慎；  不支持 InnoDB 事务能力。本章小结临时对象要区分用户临时表、内部内存临时表和磁盘临时表。查询大量落盘通常是排序、分组或物化导致，应从索引、过滤和查询结构优化。思考题  用户临时表为什么在长连接中要显式清理？  哪些 SQL 会创建内部临时表？  TempTable 超过内存后会发生什么？  如何通过索引减少排序落盘？  MEMORY 表适合哪些场景？</li>
  <li>这是《MySQL 8.0 源码与内核实战》的独立章节版。本章从概念、实操和生产排查三个视角展开，代码块保留了原书可直接运行的版本。MySQL 8.0 的数据字典支持原子 DDL，使元数据变更要么提交要么回滚。执行层面仍要区分 INSTANT、INPLACE 和 COPY，以及锁和并发 DML。25.1 原子 DDLprepare dictionary  -&gt; storage engine prepare     -&gt; commit dictionary        -&gt; post DDL原子性解决：  .frm 与引擎元数据不一致；  DDL 中断后字典残留；  部分提交状态；  重复重试困难。25.2 算法            算法      特点                  INSTANT      修改元数据              INPLACE      引擎内变更              COPY      重建并复制数据      指定方式：ALTER TABLE t ADD COLUMN c INT, ALGORITHM=INSTANT;ALTER TABLE t ADD INDEX idx_c(c), ALGORITHM=INPLACE;如果操作不支持指定算法，DDL 会失败而不是降级。25.3 并发 DMLALTER TABLE t ADD INDEX idx_c(c), ALGORITHM=INPLACE, LOCK=NONE;锁模式：            模式      含义                  NONE      允许并发 DML              SHARED      允许读、阻塞写              EXCLUSIVE      阻塞读写      即使 LOCK=NONE，DDL 仍需要短暂元数据锁，长事务会阻塞它。25.4 Online DDL 阶段MDL exclusive probe  -&gt; prepare     -&gt; build        |-- concurrent DML log        +-- read data           -&gt; apply row log              -&gt; commit                 -&gt; final MDL大表 Online DDL 仍可能占用：  临时磁盘；  row log；  redo；  CPU 和 IO；  长时间 MDL 窗口。25.5 常见操作            操作      常见方式                  加列      8.0 多数可 INSTANT，受位置和版本限制              删列      通常 INPLACE 或 COPY              加索引      INPLACE              删索引      INPLACE              修改列类型      常 COPY              更改主键      重建              字符集转换      可能 COPY      必须按当前小版本验证。25.6 第三方在线 DDLgh-ost 和 pt-online-schema-change 通过影子表和增量同步减少锁影响。选择：            工具      思路                  gh-ost      binlog 异步复制到影子表              pt-osc      触发器同步      使用前要评估磁盘、binlog、延迟、触发器兼容性和切换窗口。25.7 生产流程评估算法和锁  -&gt; 测试库演练     -&gt; 测量耗时和空间        -&gt; 检查长事务           -&gt; 低峰执行              -&gt; 监控 MDL/IO/延迟                 -&gt; 验证结构和数据本章小结原子 DDL 保证数据字典一致性，执行代价仍由算法和锁决定。生产 DDL 要先确认当前版本支持情况，评估空间和锁窗口，并在低峰执行或使用在线工具。思考题  原子 DDL 是否等于不锁表？  INSTANT、INPLACE、COPY 的差异是什么？  为什么 LOCK=NONE 仍可能等待 MDL？  Online DDL 的 row log 有什么代价？  什么时候选择 gh-ost 或 pt-osc？</li>
  <li>这是《MySQL 8.0 源码与内核实战》的独立章节版。本章从概念、实操和生产排查三个视角展开，代码块保留了原书可直接运行的版本。Group Replication 用分布式一致性协议维护成员视图和事务认证，提供多主或单主高可用方案。它建立在 Binlog 和 GTID 之上。24.1 架构MySQL Server  -&gt; binlog     -&gt; group replication plugin        -&gt; certification           -&gt; group communication              -&gt; apply local transaction组件：  local capture；  certification；  applier；  recovery；  group communication system；  membership。24.2 单主与多主            模式      特点                  single-primary      一个主写，切换由选举决定              multi-primary      多点写入，需避免写冲突      生产更常用 single-primary，配合代理和探活实现自动切换。24.3 事务流程local trx commit  -&gt; broadcast to group     -&gt; certify conflict        |-- conflict: rollback        +-- no conflict:           -&gt; consensus order              -&gt; write relay                 -&gt; apply                    -&gt; ack认证依赖 GTID 和 write set。binlog_transaction_dependency_tracking 与 transaction_write_set_extraction 等配置会影响冲突检测能力。24.4 冲突多主下两个节点同时修改同一行可能冲突：trx A certified firsttrx B same row  -&gt; B rollback减少冲突：  按业务分片写入节点；  主键设计稳定；  避免跨分片热点；  缩短事务；  应用重试确定性错误；  优先单主模式。24.5 Flow Control组复制包含流控，避免快节点长期等待慢节点：            变量      说明                  group_replication_flow_control_mode      是否启用              group_replication_flow_control_applier_threshold      applier 队列阈值              group_replication_flow_control_certifier_threshold      认证队列阈值      队列积压时限制事务进入组，表现为写入延迟上升。24.6 Recovery新成员或落后成员加入时：joiner  -&gt; select donor     -&gt; clone or incremental recovery        -&gt; catch up           -&gt; online大量落后时优先使用 Clone Plugin 重建；小差距可用增量恢复。24.7 观测SELECT * FROM performance_schema.replication_group_members;SELECT * FROM performance_schema.replication_group_member_stats;SELECT * FROM performance_schema.replication_connection_status;重点看成员状态、队列长度、冲突事务、认证延迟和事务吞吐。24.8 生产要点  网络延迟直接影响提交；  三节点或更多奇数成员；  单主模式减少冲突；  代理必须识别主角色；  大事务会造成队列积压；  表必须有主键；  与 MGR 不兼容的特性需提前评审；  切换演练不可省略。本章小结组复制通过成员协议、事务认证和恢复机制构建高可用集群。单主模式更易治理，核心风险是网络延迟、队列积压、写冲突和大事务。思考题  MGR 与传统异步复制的提交差异是什么？  多主冲突如何检测和处理？  flow control 为什么会造成写入延迟？  新成员加入有哪些恢复方式？  为什么 MGR 要求表有主键？</li>
  <li>这是《MySQL 8.0 源码与内核实战》的独立章节版。本章从概念、实操和生产排查三个视角展开，代码块保留了原书可直接运行的版本。MySQL 复制基于 Binlog 传播和重放。主库记录逻辑变更，从库接收 relay log 并由 applier 执行。23.1 链路Primary  commit + write binlog  -&gt; dump thread     -&gt; network        -&gt; replica io thread           -&gt; relay log              -&gt; sql/applier thread                 -&gt; apply transactions23.2 Binlog 格式            格式      特点                  STATEMENT      记录 SQL，依赖上下文              ROW      记录行变更，一致性较好              MIXED      按语句选择      8.0 默认 ROW。生产通常优先 ROW，可减少不确定性函数和顺序差异带来的数据漂移。23.3 GTIDGTID = server_uuid:transaction_id价值：  事务全局标识；  自动定位位点；  failover 更简单；  重放可判断已执行；  多源复制更清晰。查看：SHOW MASTER STATUS;SHOW REPLICA STATUS\GSELECT @@gtid_executed;23.4 线程模型            线程      职责                  Binlog dump      主库发送事件              Replica IO      接收 relay log              SQL thread      协调重放              worker      并行重放事务      并行复制参数：            参数      说明                  replica_parallel_workers      worker 数              replica_parallel_type      并行粒度              binlog_transaction_dependency_tracking      依赖来源              replica_preserve_commit_order      提交顺序      23.5 一致性异步复制可能丢失最新事务；半同步复制至少等待从库确认收到 binlog 或事务已提交，具体取决于配置和应答模式。SHOW VARIABLES LIKE 'rpl_semi_sync_master%';不同发行版参数名可能变化，需按当前版本确认。23.6 延迟排查SHOW REPLICA STATUS\GSELECT * FROM performance_schema.replication_applier_status_by_worker;            延迟      排查                  IO 延迟      网络、binlog 发送、磁盘              SQL 延迟      大事务、单线程、锁              应用侧      冲突、索引缺失              主库写入尖刺      batch、DDL      处理方向是拆小事务、优化重放 SQL、合理并行、控制大 DDL 并持续监控延迟。23.7 源码入口            文件      职责                  sql/rpl_binlog_sender.cc      主库发送              sql/rpl_replica.cc      从库线程              sql/rpl_handler.cc      复制钩子              libbinlogevents/      事件定义              sql/log_event.cc      事件解析      本章小结复制核心是 binlog 产生、传输和重放。ROW 与 GTID 是现代生产的基础，延迟治理要区分 IO、SQL 和事务依赖，重点处理大事务、锁和并行度。思考题  ROW 和 STATEMENT 各有什么风险？  GTID 如何帮助 failover？  大事务为什么造成复制延迟？  并行复制的依赖如何产生？  异步复制和半同步复制的差异是什么？</li>
  <li>这是《MySQL 8.0 源码与内核实战》的独立章节版。本章从概念、实操和生产排查三个视角展开，代码块保留了原书可直接运行的版本。InnoDB 的稳定运行依赖后台线程：刷脏、purge、IO、日志、统计和监控。它们决定写入平滑性、恢复速度和延迟抖动。22.1 线程全景            线程      职责                  master thread      协调后台任务              page cleaner      刷脏页              purge coordinator/worker      清理 undo              log writer/flusher/checkpointer      redo 链路              read ahead / aio      异步 IO              dict stats      统计采集              monitor thread      周期检查      查看：SELECT NAME, TYPE, PROCESSLIST_INFOFROM performance_schema.threadsWHERE NAME LIKE '%innodb%';22.2 Page Cleanerdirty page pressure  -&gt; calculate target     -&gt; choose pages from LRU/flush list        -&gt; doublewrite           -&gt; write data files目标：  控制脏页比例；  推进 checkpoint；  保留干净页；  避免用户线程大量 flush；  平滑 IO。参数：SHOW VARIABLES LIKE 'innodb_page_cleaners';SHOW VARIABLES LIKE 'innodb_io_capacity%';SHOW VARIABLES LIKE 'innodb_max_dirty_pages_pct%';22.3 IO 线程SHOW VARIABLES LIKE 'innodb_read_io_threads';SHOW VARIABLES LIKE 'innodb_write_io_threads';关注随机读、顺序预读、脏页写入、异步排队和设备队列深度。云盘与本地 NVMe 差异明显，应以压测为准。22.4 日志线程8.0.30 及以后版本使用 innodb_redo_log_capacity 管理 redo 容量；早期 8.0 使用 innodb_log_file_size 与 innodb_log_files_in_group。日志链路：log buffer  -&gt; writer  -&gt; flusher  -&gt; write notifier  -&gt; checkpointer22.5 观测SELECT event_name, count_star, sum_timer_waitFROM performance_schema.events_waits_summary_global_by_event_nameWHERE event_name LIKE 'wait/io/innodb%'ORDER BY sum_timer_wait DESC;22.6 常见故障            现象      排查                  写入尖刺      checkpoint、purge、脏页              IO 队列高      io threads、设备能力              CPU 单核高      单模块锁或单线程瓶颈              history list 高      长事务              shutdown 慢      刷脏和 purge              恢复慢      redo、脏页、大事务      本章小结后台线程承担 InnoDB 的刷脏、清理、日志和 IO 工作。调优要围绕压力来源，而不是只改线程数；观测应同时看状态、等待和操作系统 IO。思考题  page cleaner 如何降低用户线程 flush？  redo 容量参数在 8.0 版本间有什么差异？  IO 线程数是否越大越好？  写入尖刺常见来源有哪些？  如何区分 InnoDB 内部等待和操作系统 IO 压力？</li>
  <li>这是《MySQL 8.0 源码与内核实战》的独立章节版。本章从概念、实操和生产排查三个视角展开，代码块保留了原书可直接运行的版本。DELETE 和 UPDATE 不一定立即物理删除旧记录。Purge 线程负责清理 delete mark、undo 历史和无效页，是空间回收和版本链缩短的关键。21.1 为什么需要 PurgeUPDATE row  -&gt; old version in undo     -&gt; current record points to old version        -&gt; old snapshots may need it           -&gt; purge after no reader needs itPurge 做的事：  从 undo history 找可清理记录；  物理删除 delete-mark 记录；  清理索引记录；  推进 purge lag；  尝试页合并；  回收 undo 空间。21.2 可见性与清理边界Purge 只能清理早于最老活跃 read view 的版本：oldest active read view  -&gt; purge cannot remove newer needed versions因此长事务、长查询、大事务和延迟提交都会阻碍 purge。21.3 参数            参数      说明                  innodb_purge_threads      purge 线程数              innodb_purge_batch_size      批处理大小              innodb_max_purge_lag      延迟 DML 控制阈值              innodb_max_purge_lag_delay      最大延迟              innodb_undo_log_truncate_frequency      undo truncate 频率      21.4 观测SHOW GLOBAL STATUS LIKE 'Innodb_history_list_length';SHOW ENGINE INNODB STATUS;SELECT trx_id, trx_startedFROM information_schema.innodb_trxORDER BY trx_started;排查：            现象      方向                  history list 增长      长事务、purge 慢              undo 膨胀      purge 阻塞、空间压力              delete 后磁盘不降      页碎片、未合并              写入延迟      purge 滞后、二级索引              CPU 高      purge 并发过高      21.5 大删除不推荐一次性删除超大范围：DELETE FROM logs WHERE created_at &lt; '2025-01-01';推荐分批：DELETE FROM logsWHERE created_at &lt; '2025-01-01'ORDER BY idLIMIT 1000;每批之间提交，让 purge 和复制有机会推进。历史表可使用分区后 DROP PARTITION。21.6 源码入口            文件      职责                  trx0purge.cc      purge 主流程              row0purge.cc      行级清理              row0umod.cc      undo 修改处理              row0uins.cc      插入 undo      断点：b trx_purgeb row_purge_record本章小结Purge 清理旧版本和 delete-mark 记录，推进依赖最老活跃快照。长事务会让 history list 和 undo 空间持续增长；大批删除应分批或使用分区。思考题  为什么 DELETE 后磁盘空间可能不变？  history list length 反映什么？  长查询如何影响 purge？  大范围删除如何分批？  purge 和 undo truncate 有什么关系？</li>
  <li>这是《MySQL 8.0 源码与内核实战》的独立章节版。本章从概念、实操和生产排查三个视角展开，代码块保留了原书可直接运行的版本。InnoDB 锁系统管理表锁、索引记录锁、间隙锁、next-key 锁和插入意向锁，与隔离级别、索引结构和事务顺序密切相关。20.1 锁层次Server MDL  -&gt; InnoDB table lock/intention lock     -&gt; index record lock        |-- gap lock        |-- next-key lock        +-- insert intention lock行锁加在索引记录上。没有可用索引时，扫描范围可能扩大，导致锁住大量记录或间隙。20.2 锁模式            模式      说明                  S      共享              X      排他              IS      意向共享              IX      意向排他              AI      自增锁      兼容性遵循 S/S 兼容，X 与其他基本冲突，意向锁用于表级快速判断。20.3 锁类型            类型      说明                  record lock      锁索引记录              gap lock      锁记录前间隙              next-key lock      record + gap              insert intention      插入前等待间隙冲突              auto-inc lock      自增分配      RR 下范围扫描可能使用 gap/next-key 防止幻读；RC 下间隙锁使用范围明显缩小。20.4 加锁示例CREATE TABLE t(  id BIGINT PRIMARY KEY,  a INT,  KEY idx_a(a)) ENGINE=InnoDB;BEGIN;SELECT * FROM t WHERE a BETWEEN 10 AND 20 FOR UPDATE;在 RR 下可能锁定：idx_a 中满足条件的记录及间隙其他事务在对应间隙插入会被阻塞。20.5 锁等待SELECT * FROM information_schema.innodb_trx;SELECT * FROM performance_schema.data_locks;SELECT * FROM performance_schema.data_lock_waits;SELECT * FROM sys.innodb_lock_waits;排查顺序：  找 waiting thread；  找 blocking thread；  查看锁对象和模式；  查看 SQL 和事务开始时间；  判断是否长事务；  决定等待、回滚或 kill；  优化索引和访问模式。20.6 死锁trx A holds row1 waits row2trx B holds row2 waits row1处理：  检测等待环；  选择回滚代价较小事务；  写入死锁日志；  另一事务继续。SHOW VARIABLES LIKE 'innodb_print_all_deadlocks';减少死锁：  表和行按相同顺序访问；  缩短事务；  索引精确；  避免锁后再等待外部资源；  重试幂等操作；  控制并发批处理。20.7 自增锁SHOW VARIABLES LIKE 'innodb_autoinc_lock_mode';            模式      特点                  0      传统模式              1      连续，简单插入更轻量              2      交错，性能高，语句序列可能不连续      主从复制和 binlog 格式会影响可接受模式。20.8 源码入口            文件      职责                  lock0lock.cc      锁系统              lock0priv.h      内部结构              row0sel.cc      读取加锁路径              row0ins.cc      插入冲突      断点：b lock_rec_lockb lock_deadlock_occurs本章小结InnoDB 行锁绑定索引记录，隔离级别和访问路径共同决定锁范围。排查锁要看等待关系、事务、索引和 SQL；优化锁要缩短事务、精确索引并统一访问顺序。思考题  为什么没有索引会扩大锁范围？  gap lock 和 next-key lock 的区别是什么？  RR 和 RC 下间隙锁行为有什么差异？  如何定位 blocking thread？  死锁的常见预防方法有哪些？</li>
  <li>这是《MySQL 8.0 源码与内核实战》的独立章节版。本章从概念、实操和生产排查三个视角展开，代码块保留了原书可直接运行的版本。Redo log 记录物理页修改，用于崩溃恢复时重做到已提交状态。InnoDB 采用 WAL 思路：先记录日志，再择机刷脏页。19.1 WALmodify page  -&gt; write redo log buffer     -&gt; write log file        -&gt; fsync as needed           -&gt; later flush dirty page崩溃后：load page  -&gt; if page LSN older     -&gt; apply redo from checkpoint19.2 MTRmini transaction 是物理一致性单位：  修改多个页；  写一组 redo；  保证页级操作原子性；  持有相关 latch；  提交时写 log buffer。示例：insert row  -&gt; modify leaf page  -&gt; maybe update page directory  -&gt; mtr commit writes redo records19.3 LSNLSN 表示日志序列号：            位置      含义                  log buffer 末尾      已写入内存              flushed LSN      已写盘              checkpoint LSN      前缀可以不再重做              page LSN      页面最新修改      checkpoint 推进依赖脏页刷盘和旧版本清理。19.4 刷盘策略SHOW VARIABLES LIKE 'innodb_flush_log_at_trx_commit';            值      行为                  1      每次提交 fsync              0      延迟写和刷              2      提交写 OS cache，不强制 fsync      值为 1 最利于持久性；0/2 在故障时可能丢事务，需业务接受。19.5 Redo 容量SHOW VARIABLES LIKE 'innodb_redo_log_capacity';SHOW GLOBAL STATUS LIKE 'Innodb_redo_log%';容量小的影响：  checkpoint 频繁；  脏页刷盘压力放大；  写入抖动；  用户线程被迫 flush。容量大也不是无限收益，要结合恢复时间和磁盘能力评估。19.6 组提交多个事务提交时可以合并 log flush：trx1 fsynctrx2 fsynctrx3 fsync  -&gt; group fsync收益依赖并发、设备延迟和 binlog sync 策略。相关：SHOW VARIABLES LIKE 'sync_binlog';sync_binlog=1 与 redo 双 1 组合提供更强的持久性保障。19.7 恢复start  -&gt; read checkpoint     -&gt; scan redo        -&gt; build page hash           -&gt; apply redo              -&gt; rollback uncommitted trxundo 恢复负责回滚未提交事务，redo 负责重做已提交修改。19.8 常见问题            现象      方向                  commit 延迟高      redo fsync、binlog sync              checkpoint age 高      redo 容量、脏页、IO              刷脏抖动      io_capacity、redo 压力              恢复时间长      redo 量、脏页、大事务回滚              写入尖刺      checkpoint、merge、统计任务      19.9 源码入口            文件      职责                  log0log.cc      redo 核心              mtr0mtr.cc      mini transaction              buf0flu.cc      checkpoint 相关刷脏              log0recv.cc      恢复      断点：b mtr_t::commitb log_write_flush_to_diskb log_checkpoint本章小结Redo 通过 WAL 保证页修改可恢复。MTR 组织物理修改，LSN 串联日志与页面状态，checkpoint 依赖脏页刷盘推进。刷盘策略、redo 容量和 IO 能力共同决定写入延迟。思考题  为什么修改页前先写 redo？  MTR 和事务有什么区别？  checkpoint 为什么依赖脏页刷盘？  innodb_flush_log_at_trx_commit=2 在断电时可能发生什么？  redo 容量过大有什么代价？</li>
  <li>这是《MySQL 8.0 源码与内核实战》的独立章节版。本章从概念、实操和生产排查三个视角展开，代码块保留了原书可直接运行的版本。Undo log 记录行的旧版本，用于事务回滚和 MVCC 一致性读。旧版本通过版本链关联，长时间活跃事务会阻止 purge 清理。18.1 事务 IDBEGIN  -&gt; first read snapshot  -&gt; modifying statement     -&gt; assign trx_id / roll_ptr        -&gt; write undo           -&gt; modify row聚簇索引记录中的隐藏字段：            字段      含义                  DB_TRX_ID      最近修改事务              DB_ROLL_PTR      指向 undo 记录              hidden row id      无主键表使用      18.2 Undo 类型            类型      场景                  insert undo      插入回滚              update undo      更新或删除回滚与 MVCC      INSERT 旧版本对一致性读不可见，回滚后可较快清理；UPDATE/DELETE undo 需要服务快照读取。18.3 回滚ROLLBACK  -&gt; scan undo records     -&gt; restore old values        -&gt; undo secondary index changes           -&gt; write redo for rollback              -&gt; finish trx大事务回滚耗时与修改量相关，可能持续产生 IO 和锁等待。18.4 MVCC一致性读根据 read view 判断版本可见性：current record  -&gt; visible?     |-- yes: return     +-- no: follow DB_ROLL_PTR        -&gt; old version           -&gt; visible?Read View 记录活跃事务集合：  m_ids；  min_trx_id；  max_trx_id；  creator_trx_id。可见性判断核心：            条件      可见性                  trx_id == creator      自己修改可见              trx_id &lt; min      已提交早于快照，可见              trx_id &gt;= max      快照后开启，不可见              在活跃列表      快照时未提交，不可见      18.5 RR 与 RC            隔离级别      read view                  REPEATABLE READ      事务内一致性读快照通常较稳定              READ COMMITTED      每条一致性读语句创建新快照      锁读仍按锁规则执行，REPEATABLE READ 不等价于完全串行化。18.6 长事务长事务持有旧 read view：long transaction active  -&gt; old versions needed     -&gt; purge cannot advance        -&gt; history list grows           -&gt; undo tablespace grows排查：SELECT trx_id, trx_state, trx_started, trx_rows_modifiedFROM information_schema.innodb_trxORDER BY trx_started;SHOW ENGINE INNODB STATUS;18.7 Undo 表空间8.0 支持独立 undo 表空间管理：SELECT * FROM information_schema.innodb_tablespacesWHERE SPACE_TYPE='Undo';可执行 truncate，但前提是 purge 能推进且无活跃事务依赖旧版本。18.8 源码入口            文件      职责                  trx0trx.cc      事务生命周期              trx0rseg.cc      回滚段              row0undo.cc      行回滚              row0vers.cc      版本可见性              read0read.cc      Read View      断点：b ReadView::changes_visibleb trx_assign_read_viewb row_vers_build_for_consistent_read本章小结Undo 同时服务回滚和 MVCC。当前记录通过 roll pointer 连接历史版本，read view 决定可见性。长事务会延长版本链并阻塞 purge。思考题  DB_ROLL_PTR 的作用是什么？  INSERT undo 和 UPDATE undo 有什么差异？  read view 如何判断版本可见？  长事务为什么导致 undo 膨胀？  RC 和 RR 的 read view 创建时机有什么不同？</li>
  <li>这是《MySQL 8.0 源码与内核实战》的独立章节版。本章从概念、实操和生产排查三个视角展开，代码块保留了原书可直接运行的版本。Change Buffer 优化二级索引写入，AHI 加速热点页内记录定位。两者都受访问模式影响，并非总是有效。17.1 Change Buffer当二级索引页不在 Buffer Pool 时，InnoDB 可以先缓存插入或删除操作，避免立即读页。insert secondary index  -&gt; page in buffer pool?     |-- yes: modify directly     +-- no:        |-- unique index: must read page to check        +-- non-unique: buffer change           -&gt; merge later适用：  非唯一二级索引；  写多读少；  索引页访问分散；  二级索引较多；  页不在内存。不适合：  唯一索引；  写后立刻读；  热点索引；  内存充足且命中率极高；  只读或大量顺序维护场景。17.2 Mergebackground or page access  -&gt; read index page     -&gt; apply buffered changes        -&gt; write redo           -&gt; remove change record合并可能造成延迟抖动，尤其在读取冷索引或后台批量 merge 时。观测：SHOW GLOBAL STATUS LIKE 'Innodb_ibuf%';关注：  merge 次数；  merge 耗时；  slot 使用；  size；  segment size。17.3 参数            参数      说明                  innodb_change_buffering      开启操作类型              innodb_change_buffer_max_size      最大占 Buffer Pool 比例      8.0 部分小版本对 change buffer 支持范围有变化，使用前应确认当前版本文档和源码条件。17.4 AHI自适应哈希索引为热点页建立索引项到记录位置的哈希缓存：index tuple prefix  -&gt; hash     -&gt; page and record position适用：  等值查询；  热点页；  相同前缀模式；  页内记录较多；  B+Tree 下降成本明显。不适合：  范围扫描；  模式极其分散；  写入频繁导致哈希维护成本高；  latch 争用明显。17.5 AHI 观测SHOW GLOBAL STATUS LIKE 'Innodb_hash%';重点：            状态      含义                  searches      命中搜索              searches_run      执行次数              nodes      节点数      若哈希搜索比例不高但争用高，可评估关闭：SET GLOBAL innodb_adaptive_hash_index=OFF;变更要逐项观测，不能盲目跟从网上建议。17.6 源码入口            文件      内容                  ibuf0ibuf.cc      Change Buffer              btr0sea.cc      AHI              ha0ha.cc      哈希辅助      断点：b ibuf_insertb btr_search_guess_on_hash17.7 判断方法问题：二级索引写入慢  -&gt; buffer hit rate  -&gt; ibuf merge status  -&gt; index cardinality  -&gt; whether unique问题：等值查询 CPU 高  -&gt; AHI searches  -&gt; mutex waits  -&gt; page access pattern本章小结Change Buffer 用延迟合并降低冷二级索引写入 IO，AHI 用哈希降低热点页定位成本。二者都依赖访问模式，必须结合状态指标和 latch 争用判断收益。思考题  为什么唯一索引不能直接使用 Change Buffer？  Change Buffer merge 何时发生？  AHI 对范围查询为什么收益有限？  如何判断 AHI 是否引发争用？  内存充足时 Change Buffer 是否一定有收益？</li>
  <li>这是《MySQL 8.0 源码与内核实战》的独立章节版。本章从概念、实操和生产排查三个视角展开，代码块保留了原书可直接运行的版本。Buffer Pool 是 InnoDB 的内存页缓存。脏页、干净页、索引页、undo 页、锁信息和 AHI 都与其生命周期相关。16.1 基本结构logical page request  -&gt; page hash lookup     |-- hit: return block     +-- miss:        -&gt; read page from disk           -&gt; insert into LRU              -&gt; return block关键点：  以页为单位缓存；  查找通过 page hash；  淘汰通过 LRU 变体；  修改页成为脏页；  脏页由 page cleaner 刷盘；  页 latch 控制并发访问。16.2 LRU 变体InnoDB 使用 young/old 子链表，降低全表扫描污染热数据的风险。new pages  -&gt; old sublist     -&gt; survive threshold time        -&gt; move to young sublist相关参数：            参数      说明                  innodb_buffer_pool_size      总大小              innodb_buffer_pool_instances      实例数              innodb_old_blocks_pct      old 区比例              innodb_old_blocks_time      进入 young 的停留时间      16.3 脏页刷盘modify page in memory  -&gt; mark dirty     -&gt; write redo first     -&gt; page cleaner flush        -&gt; doublewrite           -&gt; data file触发条件：  redo 空间压力；  脏页比例；  LRU 空间不足；  checkpoint；  shutdown；  用户线程辅助。相关参数：            参数      说明                  innodb_max_dirty_pages_pct      脏页比例目标              innodb_io_capacity      正常刷盘能力              innodb_io_capacity_max      压力上限              innodb_lru_scan_depth      LRU 扫描深度      16.4 命中率SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool_read%';常用计算：hit rate = 1 - Innodb_buffer_pool_reads / Innodb_buffer_pool_read_requests            现象      方向                  命中率低      内存不足、随机 IO、冷数据、大扫描              命中率高但慢      CPU、锁、日志、网络              脏页高      刷盘能力不足              free wait      LRU 空间紧张      16.5 并发控制Buffer Pool 并发涉及：  buffer pool instance mutex；  page latch；  LRU list mutex；  flush list mutex；  free list mutex；  AHI latch。性能视图：SELECT event_name, count_star, sum_timer_waitFROM performance_schema.events_waits_summary_global_by_event_nameWHERE event_name LIKE 'wait/synch/mutex/innodb/%'ORDER BY sum_timer_wait DESC;16.6 在线调整SET GLOBAL innodb_buffer_pool_size=8589934592;在线调整可能引发内存分配和内部锁等待，应在低峰执行并监控状态：SHOW STATUS LIKE 'Innodb_buffer_pool_resize_status';生产建议提前规划内存，不把它当常规动态调优手段。16.7 页面观测SELECT SPACE, PAGE_TYPE, COUNT(*) AS pagesFROM information_schema.innodb_buffer_pageGROUP BY SPACE, PAGE_TYPEORDER BY pages DESCLIMIT 20;查询系统表可能产生额外开销，生产上应限流或在测试库分析。16.8 源码入口            文件      内容                  buf0buf.cc      Buffer Pool 核心              buf0lru.cc      LRU 和淘汰              buf0flu.cc      刷脏              buf0rea.cc      预读              buf0dblwr.cc      doublewrite      断点：b buf_page_get_genb buf_LRU_get_free_blockb buf_flush_page本章小结Buffer Pool 通过 LRU 变体缓存页，通过脏页列表和 page cleaner 异步落盘。命中率和脏页趋势是内存与 IO 判断的核心指标，在线调大需谨慎。思考题  为什么 InnoDB LRU 分 young/old 区？  redo log 压力如何影响脏页刷盘？  命中率低有哪些原因？  dirty pages 高说明什么？  在线调整 Buffer Pool 应注意什么？</li>
  <li>这是《MySQL 8.0 源码与内核实战》的独立章节版。本章从概念、实操和生产排查三个视角展开，代码块保留了原书可直接运行的版本。记录格式决定一行数据在页内如何编码，影响 NULL 处理、变长列、主键生成、页利用率和 SQL 层字段转换。15.1 行格式            格式      说明                  REDUNDANT      老格式              COMPACT      8.0 常见默认              DYNAMIC      长字段更倾向溢出页              COMPRESSED      支持压缩      查看：SELECT NAME, ROW_FORMATFROM information_schema.innodb_tablesWHERE NAME LIKE 'db/%';15.2 COMPACT 记录头variable length list  NULL bitmap    record header      column values记录头包含：  delete mark；  min rec 标记；  owned 记录数；  heap number；  record type；  next record offset；  info flags。页内记录通过 next offset 串成有序链。15.3 NULLNULL 存在于 bitmap 中，不为 NULL 值本身分配列空间，但列定义仍影响元数据和上限。CREATE TABLE t(  id INT PRIMARY KEY,  a VARCHAR(100),  b INT) ENGINE=InnoDB;影响：  索引仍可包含 NULL；  NULL 参与比较遵循 SQL 三值逻辑；  聚合函数处理不同；  唯一索引允许多个 NULL，除非列声明 NOT NULL；  NULL 排序顺序与排序方向相关。15.4 变长列VARCHAR 长度列表记录实际字节数。字符集决定最大字节：CREATE TABLE t(  id BIGINT PRIMARY KEY,  name VARCHAR(100)) DEFAULT CHARSET=utf8mb4;utf8mb4 每字符最多 4 字节，因此 VARCHAR(100) 最大可到 400 字节。15.5 隐式主键若表没有主键也没有非 NULL 唯一索引：InnoDB generates hidden row id问题：  隐藏 ID 全局递增，写入竞争集中；  无法作为业务定位；  复制和增量工具处理不友好。生产建议显式定义主键。15.6 大字段DYNAMIC 行格式倾向于只保留前缀在 B+Tree 内，其余放溢出页。            影响      说明                  页占用      大字段可能溢出              IO      读取完整值更多页              缓存      命中率下降              网络      返回大字段变慢              排序      临时表成本增加      大字段业务建议分表或放对象存储，数据库只存引用。15.7 记录解析InnoDB 内部记录与 MySQL Field 之间需要转换：InnoDB record bytes  -&gt; row mysql template     -&gt; MySQL Field / Item        -&gt; result set相关源码：            文件      职责                  rem0rec.cc      记录头和格式              row0mysql.cc      记录转换              data0data.cc      数据类型              field.cc      Server 字段      15.8 页利用率行越宽，一页容纳的行越少，范围扫描读取相同行数需要更多页。优化：  使用合适类型；  避免超长 VARCHAR；  大字段分离；  减少冗余列；  控制主键长度；  避免无效索引。本章小结记录格式决定行在页内的物理表达。COMPACT 和 DYNAMIC 是重点，理解记录头、NULL 位图、变长列表、溢出页和隐藏主键，有助于解释页碎片、行宽、回表和大字段性能。思考题  NULL 为什么可能节省页内空间但仍有代价？  字符集如何影响 VARCHAR 最大字节？  为什么建议显式主键？  DYNAMIC 与 COMPACT 对长字段处理有什么差异？  行宽如何影响范围扫描？</li>
  <li>这是《MySQL 8.0 源码与内核实战》的独立章节版。本章从概念、实操和生产排查三个视角展开，代码块保留了原书可直接运行的版本。InnoDB 索引本质是 B+Tree。聚簇索引叶子包含完整行记录，二级索引叶子包含索引列和主键。14.1 结构root  internal node    leaf page      leaf page特点：  数据按 key 有序；  叶子节点通过双向链表连接；  内部节点存子页指针；  根页固定，可缓存；  查找复杂度与树高相关；  三层 B+Tree 通常可支撑大量行。14.2 查找root  -&gt; choose child by key     -&gt; internal page        -&gt; leaf page           -&gt; page directory binary search              -&gt; record源码入口：btr_cur_search_to_nth_levelbtr_pcur_openrow_search_mvcc断点：b btr_cur_search_to_nth_level14.3 插入locate leaf  -&gt; check space     |-- enough: insert record     +-- not enough: split page        -&gt; update parent           -&gt; maybe split upper level分裂要点：  选择分裂点；  复制记录到新页；  更新兄弟链表；  更新父节点；  写 MTR redo；  维护锁和 latch。14.4 更新与删除主键更新通常等价于删除旧记录并插入新记录，可能引起二级索引维护。删除流程：delete-mark record  -&gt; commit later     -&gt; purge physically remove因此大量 DELETE 后文件不一定立即缩小，purge 和页合并滞后会造成空间碎片。14.5 二级索引回表CREATE TABLE orders(  id BIGINT PRIMARY KEY,  user_id BIGINT,  amount DECIMAL(10,2),  KEY idx_user(user_id)) ENGINE=InnoDB;SELECT * FROM orders WHERE user_id=100;路径：idx_user leaf  -&gt; get PK id     -&gt; clustered index lookup        -&gt; return full row若只查 user_id 和 id，可覆盖索引避免回表。14.6 页合并删除或页分裂后，InnoDB 可能合并低填充率页：page fill below threshold  -&gt; check sibling     -&gt; merge records        -&gt; update parent           -&gt; free page影响合并的因素：  页填充率；  兄弟页状态；  latch 争用；  后台时机；  索引访问模式。14.7 索引统计B+Tree 统计会估计：  索引基数；  不同 key 数；  树高；  页数量；  记录数。刷新：ANALYZE TABLE orders;统计不准时，连接顺序和索引选择可能异常。14.8 观测SHOW INDEX FROM orders;EXPLAIN FORMAT=TREE SELECT * FROM orders WHERE user_id=100;SELECT SPACE, NAME, N_ROWS, PAGE_SIZEFROM information_schema.innodb_tablesWHERE NAME='test/orders';14.9 常见问题            现象      原因                  插入随机 key 导致页分裂      单调主键更友好              删除后空间不释放      delete mark + purge              二级索引查询慢      大量回表              索引失效      条件、类型、统计              二级索引变大      主键过长              索引维护慢      索引过多      本章小结B+Tree 是 InnoDB 有序存储的核心。查找依赖页内二分和树内导航，插入可能触发分裂，删除先标记再由 purge 清理。二级索引回表和页分裂是理解索引性能的关键。思考题  为什么二级索引叶子保存主键？  页分裂如何影响写入性能？  DELETE 后空间为什么不会立即释放？  覆盖索引如何减少 IO？  主键过长对二级索引有什么影响？</li>
  <li>这是《MySQL 8.0 源码与内核实战》的独立章节版。本章从概念、实操和生产排查三个视角展开，代码块保留了原书可直接运行的版本。InnoDB 以表空间管理文件，以页为基本 IO 单位。理解页面布局是理解 B+Tree、Buffer Pool、redo 和恢复的基础。13.1 文件类型            文件      职责                  system tablespace      数据字典历史结构、undo、双写等，取决于配置              file-per-table .ibd      每表独立表空间              general tablespace      多表共享              temporary tablespace      临时数据              undo tablespace      回滚段              redo log      WAL 日志      SHOW VARIABLES LIKE 'innodb_file_per_table';SELECT SPACE, NAME FROM information_schema.innodb_sys_tablespaces LIMIT 10;13.2 空间组织tablespace  -&gt; segment     -&gt; extent = 1MB        -&gt; page = 16KB默认：            单位      大小                  page      16KB              extent      64 pages              segment      若干 extent      页号是表空间内定位页的基本编号。13.3 页类型            类型      用途                  FSP_HDR      文件空间头              IBUF_BITMAP      Change Buffer 位图              INODE      段信息              INDEX      B+Tree 页              SYSTEM      系统页              TRX_SYS      事务系统              UNDO_LOG      Undo 页              BLOB      大字段页      文件头包含页号、表空间 ID、校验和、LSN 等信息。13.4 INDEX 页布局fil header  page header    infimum + supremum      user records        free space          page directory            fil trailer关键区域：  infimum：最小虚拟记录；  supremum：最大虚拟记录；  user records：按主键顺序组织的记录；  page directory：槽，支持二分定位；  trailer：校验和与 LSN。13.5 行溢出InnoDB 尽量将行放在 B+Tree 页内。长 VARCHAR、TEXT、BLOB 可能溢出到 BLOB 页。CREATE TABLE t(  id BIGINT PRIMARY KEY,  body TEXT) ENGINE=InnoDB;影响：  聚簇索引页存放前缀；  剩余数据放溢出页；  读取大字段增加 IO；  行格式影响前缀长度；  大字段会降低缓冲命中率。查看行格式：SELECT NAME, ROW_FORMATFROM information_schema.innodb_tablesWHERE NAME LIKE 'db/t';13.6 Doublewrite脏页  -&gt; doublewrite file     -&gt; 数据文件作用：防止部分页写坏。若数据文件写入中断，可先从 doublewrite 恢复完整页，再应用 redo。SHOW VARIABLES LIKE 'innodb_doublewrite';13.7 表空间监控SELECT file_name, tablespace_name, total_extents, free_extentsFROM information_schema.files;SHOW GLOBAL STATUS LIKE 'Innodb_data%';关注：  .ibd 增长；  碎片；  临时表空间膨胀；  undo 表空间；  redo 容量；  可用磁盘水位。13.8 源码入口            文件      内容                  fil0fil.cc      文件和表空间              fut0lst.cc      文件链表              fsp0fsp.cc      文件空间管理              page0page.cc      页面操作              buf0buf.cc      页缓存      调试：b fil_space_t::iob buf_page_get_gen本章小结表空间由段、区和页组成，INDEX 页是 B+Tree 的物理载体。页头、页目录、记录区和校验信息共同支撑定位与恢复；行溢出和 doublewrite 会直接影响 IO 与可靠性。思考题  extent 和 page 的关系是什么？  page directory 有什么作用？  为什么需要 doublewrite？  长字段为什么会降低缓存效率？  如何查看表空间和页面相关状态？</li>
  <li>这是《MySQL 8.0 源码与内核实战》的独立章节版。本章从概念、实操和生产排查三个视角展开，代码块保留了原书可直接运行的版本。InnoDB 是事务存储引擎，负责页面存储、B+Tree、行操作、事务、锁、MVCC、日志、恢复和后台维护。12.1 总体结构ha_innobase  -&gt; row module     |-- btr: B+Tree     |-- page: page layout     |-- rem: record format     |-- buf: buffer pool     |-- lock: row/table locks     |-- trx: transaction     |-- undo: undo log     |-- log: redo log     |-- mtr: physical consistency     +-- fil: tablespace12.2 目录地图            目录      职责                  storage/innobase/btr/      B+Tree 操作              storage/innobase/page/      页面结构              storage/innobase/rem/      记录格式              storage/innobase/row/      行读写与更新              storage/innobase/buf/      Buffer Pool              storage/innobase/ibuf/      Change Buffer              storage/innobase/lock/      锁系统              storage/innobase/trx/      事务              storage/innobase/undo/      Undo              storage/innobase/log/      Redo              storage/innobase/fil/      表空间              storage/innobase/dict/      引擎数据字典              storage/innobase/purge/      清理              storage/innobase/row/row0mysql.cc      handler 桥接      12.3 数据组织Instance  -&gt; tablespace     -&gt; segments        -&gt; extents           -&gt; pages              -&gt; records默认页大小 16KB：SHOW VARIABLES LIKE 'innodb_page_size';聚簇索引按主键组织数据；二级索引叶子存主键值，查询非索引列需要回表。12.4 事务路径BEGIN  -&gt; assign trx     -&gt; read / modify rows        |-- lock records        |-- write undo        +-- write redo in mtr     -&gt; prepare        -&gt; write binlog           -&gt; commit              -&gt; release locks事务模块与 undo、redo、锁和 purge 紧耦合，需要整体阅读。12.5 后台线程            线程      职责                  master thread      统筹后台任务              purge thread      清理 delete-mark 和 undo              page cleaner      刷脏页              read ahead / IO thread      异步 IO              log flusher / writer      redo 日志刷盘              dict stats      统计收集      12.6 观测入口SHOW ENGINE INNODB STATUS;SELECT * FROM information_schema.innodb_trx;SELECT * FROM information_schema.innodb_buffer_page_lru LIMIT 10;SHOW GLOBAL STATUS LIKE 'Innodb_%';源码定位：rg "Innodb_buffer_pool_read_requests" storage/innobaserg "row_lock_current_waits" storage/innobase本章小结InnoDB 可以按存储结构、行操作、事务并发、日志恢复和后台线程五条线阅读。先建立模块地图，再沿一条 SQL 的读写路径进入源码，能显著降低复杂度。思考题  聚簇索引和二级索引的存储关系是什么？  InnoDB 哪些模块参与一次 UPDATE？  purge thread 清理什么数据？  如何从 InnoDB 状态变量定位源码？  为什么事务模块要与 undo、redo、lock 一起读？</li>
  <li>这是《MySQL 8.0 源码与内核实战》的独立章节版。本章从概念、实操和生产排查三个视角展开，代码块保留了原书可直接运行的版本。优化器用代价模型把 IO、CPU、内存和网络估算统一为可比较的成本。代价不是精确时间，而是相对排序依据。11.1 代价来源            成本      示例                  IO      页读取、回表、临时表              CPU      表达式计算、比较、聚合              memory      join buffer、sort buffer              engine estimate      引擎返回的扫描代价              first row      LIMIT 场景      估算输入：  表行数；  索引基数；  range 区间数；  记录长度；  页大小；  缓存命中率假设；  条件选择率；  连接顺序。11.2 系统表代价常量存储在引擎代价表中：SELECT * FROM mysql.engine_cost;SELECT * FROM mysql.server_cost;常见项：            表      成本                  engine_cost      io block read              server_cost      row evaluate              server_cost      memory tmp table create              server_cost      disk tmp table create      修改示例：UPDATE mysql.engine_costSET cost_value=2.0WHERE cost_name='io_block_read_cost';FLUSH OPTIMIZER_COSTS;生产环境修改必须有基线、回滚和评测，不应作为常规调优手段。11.3 选择率等值条件常见思路：selectivity = 1 / distinct_values范围条件依赖：  列类型；  min/max；  直方图；  索引统计；  条件形式；  NULL 比例；  字符集。查看直方图：ANALYZE TABLE orders UPDATE HISTOGRAM ON status, user_id;SELECT * FROM information_schema.column_statistics\G直方图适合列相关性弱但数据倾斜明显的场景。11.4 单表代价scan cost  = estimated pages * io cost  + estimated rows * row evaluate costindex lookup cost  = range count * io cost  + matching rows * row evaluate cost  + back to clustered index cost影响判断：  预估返回行数；  是否覆盖索引；  回表页分散程度；  LIMIT；  ORDER BY；  统计准确性。11.5 连接代价Nested Loop：cost = outer cost     + outer rows * inner lookup costHash Join：cost = build input scan + hash build     + probe input scan + hash probe优化器会依据估算行数、可用索引和内存代价选择。无索引等值大表连接常更容易走 hash join。11.6 覆盖索引SELECT user_id, COUNT(*)FROM ordersWHERE status=1GROUP BY user_id;若存在：KEY idx_status_user(status,user_id)二级索引可能覆盖查询，避免聚簇索引回表。覆盖索引收益取决于：  返回列；  索引列顺序；  行宽；  范围条件；  排序分组需求。11.7 LIMIT 与 first rowSELECT * FROM orders ORDER BY created_at DESC LIMIT 10;如果有 idx_created(created_at)，按索引反向读取前 10 行可能代价很低。无索引时则必须扫描并排序更多行。优化器会区分：  全量执行代价；  找到第一批行的代价；  是否可提前停止。11.8 代价模型局限  统计是估算；  缓存效果难以精确建模；  相关列分布难处理；  远程存储延迟差异大；  运行时并发影响 IO；  UDF 和复杂函数代价难估计；  参数化值不同导致计划差异。因此执行计划可能随数据分布变化。11.9 调优流程慢 SQL  -&gt; EXPLAIN ANALYZE     -&gt; compare estimated and actual rows        -&gt; check statistics / histogram           -&gt; analyze access path              -&gt; rewrite SQL or index                 -&gt; regression test常见修复：  补充合适索引；  收集统计；  增加直方图；  改写条件；  消除隐式转换；  减少返回列；  拆分复杂 SQL；  局部使用 hint。本章小结代价模型把页 IO、行计算、临时表和连接成本折算为相对值，用于选择访问路径和连接顺序。理解统计、选择率、覆盖索引、first row 和模型局限，才能正确解读执行计划。思考题  代价单位和执行时间是否等价？  为什么等值条件常用基数倒数估算选择率？  直方图适合解决什么统计问题？  覆盖索引如何改变代价？  EXPLAIN ANALYZE 中估算行数和实际行数差异说明什么？</li>
  <li>这是《MySQL 8.0 源码与内核实战》的独立章节版。本章从概念、实操和生产排查三个视角展开，代码块保留了原书可直接运行的版本。MySQL 8.0 使用事务性数据字典存储表、列、索引、字符集和约束等元数据。Server 层表缓存、MDL 和 InnoDB 字典缓存共同决定 DDL 与 DML 的并发行为。10.1 元数据演进            版本      方式                  5.7 及以前      .frm 等文件保存表定义              8.0      DD 表存储元数据      8.0 带来：  原子 DDL；  元数据事务化；  支持更完整的字符集和 collation；  移除 .frm；  统一系统表存储。原子 DDL 表示 DDL 的数据字典更新整体提交或回滚，不等价于所有 DDL 都不锁表或不重建表。10.2 核心对象            对象      职责                  DD tables      存储元数据              Dictionary Client      Server 层访问接口              dd::Table      表定义              dd::Column      列定义              dd::Index      索引定义              TABLE_SHARE      可共享表定义              TABLE      每个表实例的运行时对象              InnoDB dict cache      引擎层缓存      10.3 表缓存open_tables  -&gt; table cache hit?     |-- yes: reuse TABLE     +-- no: load DD definition        -&gt; create TABLE           -&gt; open handler相关参数：            参数      说明                  table_open_cache      表缓存数量              table_open_cache_instances      缓存分区              table_definition_cache      表定义缓存              open_files_limit      文件句柄上限      观测：SHOW GLOBAL STATUS LIKE 'Open_%';SHOW GLOBAL STATUS LIKE 'Opened_%';10.4 MDL元数据锁保护表结构在语句或事务期间不被不兼容 DDL 破坏。常见锁：            类型      场景                  SHARED_READ      SELECT              SHARED_WRITE      DML              SHARED_UPGRADABLE      部分 DDL 前置阶段              EXCLUSIVE      阻塞读写      问题场景：长事务持有 SHARED_READ  -&gt; DDL 等待 EXCLUSIVE     -&gt; 后续 DML 排队排查：SELECT * FROM performance_schema.metadata_locks;SELECT * FROM sys.schema_table_lock_waits;10.5 DDL 阶段通用阶段：acquire MDL  -&gt; prepare     -&gt; algorithm decision        -&gt; prepare output table           -&gt; alter table data if needed              -&gt; commit DD                 -&gt; release locksALGORITHM：            算法      说明                  INSTANT      只改元数据，受版本和操作限制              INPLACE      引擎内执行，可能允许并发 DML              COPY      重建表并复制数据      指定不支持的算法会报错：ALTER TABLE t ADD COLUMN c INT, ALGORITHM=INSTANT;10.6 LOCK 策略ALTER TABLE t ADD INDEX idx_c(c), ALGORITHM=INPLACE, LOCK=NONE;            锁      含义                  NONE      允许并发 DML              SHARED      允许读，阻塞写              EXCLUSIVE      阻塞读写      实际支持由操作、索引类型、版本和引擎决定：SHOW ALGORITHM STATUS;或查看 information_schema.innodb_alter_algorithm，取决于版本支持情况。10.7 临时表SQL 层临时表：  会话可见；  不进入 binlog 主流复制路径；  可由引擎内部临时表或用户 TEMPORARY 表；  DDL 和 MDL 行为不同。内部临时表可能由内存引擎转为磁盘 InnoDB 临时表，受 internal_tmp_mem_storage_engine、tmp_table_size、max_heap_table_size 等影响。10.8 字符集与排序规则元数据记录：  表默认字符集；  列字符集；  collation；  表达式推导规则。示例：CREATE TABLE t(  a VARCHAR(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci,  b VARCHAR(32)) DEFAULT CHARSET=utf8mb4;collation 影响：  等值比较；  排序；  索引查找；  前缀匹配；  函数结果推导。10.9 DDL 故障排查            现象      方向                  DDL 等待 metadata lock      长事务、表缓存              DDL 后查询计划变化      统计、索引、字符集              instant 失败      操作或版本不支持              inplace 长时间      在线 DDL 日志和重建              copy 占用磁盘      临时表空间              DDL 卡在 finalize      锁和后台操作      处理：  找 waiting thread；  找 blocking thread；  评估长事务；  使用低峰窗口；  预留磁盘；  大表使用 gh-ost/pt-osc 评估；  记录回滚方案。本章小结表与元数据链路覆盖 DD 存储、表定义缓存、运行时 TABLE、handler 打开和 MDL。理解这条链路能解释 DDL 等待、原子性、并发 DML 和统计刷新行为，也是后续读 DDL 源码的基础。思考题  MySQL 8.0 原子 DDL 解决了什么问题？  TABLE_SHARE 和 TABLE 的区别是什么？  为什么长事务会阻塞 DDL 并间接阻塞后续 DML？  INSTANT、INPLACE、COPY 的核心差异是什么？  collation 如何影响索引查找？</li>
  <li>这是《MySQL 8.0 源码与内核实战》的独立章节版。本章从概念、实操和生产排查三个视角展开，代码块保留了原书可直接运行的版本。优化器生成计划后，执行器负责驱动迭代器、调用 handler 接口、计算表达式、执行聚合排序，并处理写入路径。MySQL 8.0 的执行模型相比老版本更明显地转向迭代器式组织。9.1 执行模型Query_expression  -&gt; iterator root     |-- table scan iterator     |-- index range iterator     |-- filter iterator     |-- join iterator     |-- aggregate iterator     |-- sort iterator     +-- limit iterator每个迭代器常见接口：init()read()set_key()close()执行时由上层节点驱动下层节点读取行，再应用过滤和投影。9.2 读路径Server 层：Executor iterator  -&gt; handler::ha_index_read / ha_rnd_next     -&gt; ha_innobase        -&gt; row_search_mvcc            调用      场景                  ha_rnd_next      全表或临时表顺序读              ha_index_first      索引第一条              ha_index_next      索引顺序读              ha_index_read_map      按 key 查找              ha_index_next_same      相同前缀继续读      9.3 表达式计算表达式由 Item 树执行：WHERE a + 1 &gt; 10 AND b = 'x'  -&gt; Item_cond_and     |-- Item_func_gt     |   |-- Item_func_plus     +-- Item_func_equal执行关注：  NULL 语义；  类型转换；  字符集排序；  短路求值；  函数确定性；  错误传播；  资源消耗。9.4 过滤与投影SELECT user_id, amountFROM ordersWHERE status=1;执行流程：read row  -&gt; evaluate status condition     -&gt; if false skip        -&gt; evaluate user_id, amount           -&gt; send to client / upper iterator投影影响：  返回字段；  覆盖索引可能性；  网络流量；  临时表列；  结果元数据。9.5 聚合与分组SELECT user_id, COUNT(*), SUM(amount)FROM ordersGROUP BY user_id;两种路径：            路径      条件                  流式聚合      按分组列顺序读取，索引顺序匹配              临时表聚合      无序数据或内存/磁盘临时表      8.0 移除了查询缓存，但临时表引擎和聚合执行仍在持续演进。查看：EXPLAIN FORMAT=TREE SELECT ...;SHOW STATUS LIKE 'Created_tmp%';SHOW STATUS LIKE 'Sort%';9.6 排序与 LIMITSELECT * FROM ordersORDER BY created_at DESCLIMIT 20;可能方式：  使用索引顺序；  priority queue top N；  内存 sort buffer；  文件排序；  磁盘临时文件合并。相关参数：            参数      说明                  sort_buffer_size      每会话排序缓冲              max_length_for_sort_data      影响附加列策略              max_sort_length      字符串排序长度      9.7 写入路径INSERT：mysql_insert  -&gt; write_row     -&gt; handler::ha_write_row        -&gt; ha_innobase::write_row           -&gt; row_insert_for_mysqlUPDATE：read row  -&gt; evaluate set expressions     -&gt; handler::ha_update_row        -&gt; InnoDB row update           -&gt; undo / redo / index maintenanceDELETE：read row  -&gt; handler::ha_delete_row     -&gt; InnoDB delete mark        -&gt; purge later9.8 多表更新UPDATE orders oJOIN users u ON u.id=o.user_idSET o.level=u.levelWHERE u.status=1;执行器先按计划读取满足连接条件的行，再逐行计算 SET 表达式并调用更新。触发器、外键和唯一索引都会增加写入路径复杂度。9.9 执行观测SELECT event_name, count_star, sum_timer_waitFROM performance_schema.events_statements_summary_by_digestORDER BY sum_timer_wait DESCLIMIT 10;EXPLAIN ANALYZE SELECT * FROM orders WHERE user_id=100;EXPLAIN ANALYZE 能查看实际行数和每个迭代器耗时，适合与估算计划对比。9.10 常见问题            现象      排查                  估算行数差异大      统计和 trace              临时表暴涨      分组、排序、派生表              排序落盘      sort buffer 和索引              回表过多      覆盖索引和投影              写入慢      唯一检查、redo、锁              LIMIT 仍慢      前置扫描量      本章小结执行器把计划转换为迭代器驱动和 handler 调用，负责过滤、投影、连接、聚合、排序和写入。源码阅读应从 EXPLAIN FORMAT=TREE 的节点入手，找到对应迭代器，再进入 InnoDB 行操作。思考题  ha_rnd_next 和 ha_index_read 的使用场景有什么不同？  聚合什么时候可以流式执行？  为什么投影列会影响覆盖索引？  top N 排序可能使用什么策略？  EXPLAIN ANALYZE 与普通 EXPLAIN 的区别是什么？</li>
  <li>这是《MySQL 8.0 源码与内核实战》的独立章节版。本章从概念、实操和生产排查三个视角展开，代码块保留了原书可直接运行的版本。优化器决定 SQL 的物理执行方式：使用哪个索引、按什么顺序连接表、是否物化子查询、使用哪种聚合策略。它的目标是基于代价模型估计总成本，而不是保证绝对最优。8.1 输入输出Query_block  -&gt; logical transformations  -&gt; candidate access methods  -&gt; join order search  -&gt; access method selection  -&gt; physical plan核心决策：  单表访问路径；  连接顺序；  连接算法；  是否使用索引条件下推；  是否使用覆盖索引；  是否物化派生表；  是否使用临时表；  排序是否可由索引完成。8.2 单表访问路径            路径      说明                  table scan      全表扫描              index scan      扫描整个索引              range scan      范围或多个区间              ref / eq_ref      使用索引等值或前缀匹配              full text      全文索引              index merge      合并多个索引              skip scan      联合索引跳过前导列，受版本和条件限制      示例：CREATE TABLE orders(  id BIGINT PRIMARY KEY,  user_id BIGINT,  status TINYINT,  created_at DATETIME,  KEY idx_user_created(user_id, created_at)) ENGINE=InnoDB;EXPLAIN FORMAT=TREESELECT * FROM ordersWHERE user_id=100 AND created_at&gt;='2026-01-01';如果查询只返回少量行，二级索引加回表可能优于全表扫描。8.3 连接算法            算法      过程                  Nested Loop      外层每行到内层查找              Block Nested Loop      外层分块后比较              Hash Join      构建小表哈希表并探测      8.0 逐步增强 hash join，用于无可用索引的等值连接。执行计划中可通过 EXPLAIN FORMAT=TREE 观察 join 节点。影响连接代价：  外层行数；  内层访问方式；  缓冲区；  过滤条件；  join buffer；  回表次数；  内存排序。8.4 连接顺序搜索多表连接的顺序组合会快速增长：table count N -&gt; permutations N!优化器会做剪枝，并受 optimizer_search_depth、optimizer_prune_level 等参数影响。常见策略：  先估计单表过滤后的行数；  优先低代价访问路径；  依赖连接条件传播；  限制搜索深度；  保留候选计划；  读取系统统计和引擎统计。8.5 统计信息InnoDB 统计包括：  表行数估计；  索引基数；  不同值数量；  索引层级；  聚簇索引大小；  二级索引大小。查看：SHOW INDEX FROM orders;ANALYZE TABLE orders;SELECT * FROM information_schema.innodb_tablestats;控制方式：SET GLOBAL innodb_stats_persistent_sample_pages=64;统计过旧或抽样偏差会导致行数估计错误，进而影响连接顺序。8.6 条件处理可传递条件：t1.id = t2.id AND t1.id = 100=&gt; t2.id = 100不可直接使用索引的常见形式：            写法      影响                  col+1=10      需要表达式重写或无法使用              LOWER(col)='a'      取决于函数和排序规则              col LIKE '%x'      前导通配无法普通 range              隐式类型转换      可能无法使用索引              OR 非索引列      可能退化为扫描      8.7 子查询SELECT * FROM usersWHERE id IN (SELECT user_id FROM orders WHERE status=1);策略：  semijoin；  materialization；  first match；  loose scan；  duplicate weedout；  correlated subquery execution。EXPLAIN FORMAT=TREE 和 optimizer trace 能看到选择。8.0 对子查询策略有多轮增强，版本差异明显。8.8 Optimizer TraceSET optimizer_trace='enabled=on,one_line=off';SELECT * FROM orders WHERE user_id=100;SELECT traceFROM information_schema.optimizer_trace\G重点看：  range 分析；  每个索引估计行数；  单表访问代价；  join 顺序候选；  最终计划原因；  是否物化；  是否下推条件。8.9 Hint常见 hint：SELECT /*+ INDEX(orders idx_user_created) */ *FROM orders WHERE user_id=100;SELECT /*+ JOIN_ORDER(orders, users) */ *FROM orders JOIN users ON users.id=orders.user_id;SELECT /*+ NO_HASH_JOIN(orders, users) */ ...使用原则：  先确认默认计划不合理的原因；  用最小范围加 hint；  记录版本和数据分布；  上线后监控；  数据变化后重新评估；  不把 hint 当作长期掩盖统计问题的手段。8.10 源码入口常见文件：            文件      职责                  sql/sql_optimizer.cc      优化主流程              sql/sql_select.cc      SELECT 逻辑和计划              sql/range_optimizer/*      range 分析              sql/join_optimizer/*      连接优化              sql/sql_executor.cc      计划执行              sql/opt_hints.cc      hint 解析      调试断点：b JOIN::optimizeb mysql_selectb calculate_scan_cost本章小结优化器基于统计信息和代价模型，在候选访问路径与连接顺序中做搜索。读源码时要结合 EXPLAIN、optimizer trace 和统计信息，理解行数估计、过滤条件、连接策略和版本差异。思考题  为什么优化器不能保证最优计划？  统计信息如何影响连接顺序？  range、ref、index scan 的代价差异是什么？  子查询 semijoin 和物化的适用条件有什么不同？  optimizer trace 应重点查看哪些字段？</li>
  <li>这是《MySQL 8.0 源码与内核实战》的独立章节版。本章从概念、实操和生产排查三个视角展开，代码块保留了原书可直接运行的版本。解析树经过语义解析和改写后，才能进入优化器。这个阶段会绑定表和列、展开视图、处理派生表、推导类型，并生成更适合优化的内部表示。7.1 阶段目标Parse Tree  -&gt; name resolution  -&gt; view / derived table merge  -&gt; type aggregation  -&gt; condition simplification  -&gt; query block     -&gt; optimizer主要工作：  确认表、列、函数存在；  解析别名和作用域；  展开视图；  处理 CTE 和派生表；  推导表达式类型；  常量折叠；  条件简化；  权限检查准备；  构造 Query_block / Query_expression。7.2 名称解析示例：SELECT u.id, o.noFROM users uJOIN orders o ON o.user_id=u.idWHERE u.status='active';解析内容：  users 映射到表对象；  u 是表别名；  u.id 绑定字段；  o.user_id 参与连接条件；  status 的字符集和排序规则；  权限上下文。作用域错误示例：SELECT id FROM users ORDER BY total如果 total 不是输出列或可解析列，会在语义阶段报错。7.3 视图展开CREATE VIEW active_users ASSELECT * FROM users WHERE status='active';SELECT id FROM active_users WHERE id&lt;100;处理方式：query on view  -&gt; get view definition     -&gt; merge or materialize        -&gt; combined query block简单视图可以合并到外层查询；包含聚合、LIMIT、UNION 等情况的视图可能物化。EXPLAIN 中会出现 DERIVED 或相关提示。7.4 派生表与 CTEWITH recent AS (  SELECT user_id, MAX(id) AS max_id  FROM orders GROUP BY user_id)SELECT * FROM recent LIMIT 10;处理选择：            结构      可能方式                  简单派生表      merge              聚合派生表      materialize              递归 CTE      逐层执行              多次引用 CTE      可能多次物化              window + limit      物化      optimizer_switch 和版本差异会影响合并行为，需用当前版本执行计划验证。7.5 表达式与 ItemServer 层表达式常见为 Item 体系：            类型      示例                  常量      1、'abc'              字段      Item_field              函数      Item_func_*              聚合      Item_sum_*              子查询      Item_subselect              窗口      window function item      表达式类型推导影响：  比较；  隐式转换；  排序规则；  索引可用性；  临时表列类型；  结果元数据。7.6 常量折叠改写前：SELECT * FROM t WHERE a = 1 + 1;改写后：a = 2进一步优化：  布尔条件化简；  删除恒真条件；  识别不可能条件；  传播常量；  折叠简单函数；  规范化比较。复杂函数是否可折叠取决于确定性和参数是否常量。7.7 隐式转换示例：CREATE TABLE t(id INT PRIMARY KEY, vc VARCHAR(32), KEY idx_vc(vc));SELECT * FROM t WHERE vc=123;字符串列与数字比较可能导致规则和索引使用变化。语义阶段负责确定比较和转换方式，优化器据此判断索引条件。排查：EXPLAIN SELECT * FROM t WHERE vc='123';EXPLAIN SELECT * FROM t WHERE vc=123;生产建议尽量保持类型一致。7.8 Query Block优化器以 Query_block 组织 SELECT 语句单元：Query_expression  |-- Query_block  |   |-- tables  |   |-- conditions  |   |-- group by  |   |-- having|   +-- order by  +-- set operations / union子查询、CTE、视图都会形成一个或多个 query block。EXPLAIN FORMAT=TREE 能看到物化和连接顺序的近似结果。7.9 调试与观测断点：b mysql_parseb mysql_execute_commandb Query_block::prepareb Query_block::resolve_placeholder_tables观测：SET optimizer_trace='enabled=on';SELECT * FROM t WHERE a=1;SELECT trace FROM information_schema.optimizer_trace\Gtrace 中可看到 query block、条件、代价和候选计划信息。7.10 常见问题            现象      阶段                  unknown column      name resolution              unknown table      open table / resolver              view merged      resolver              derived materialized      resolver / optimizer              implicit conversion      type derivation              condition removed      simplification              recursive CTE error      CTE semantic      本章小结解析后的重写阶段把语法结构绑定到真实表、列和类型，处理视图、派生表、CTE、常量折叠和条件简化。它是 Parser 与 Optimizer 之间承上启下的一层，许多“执行计划不符合书写直觉”的问题要从这里开始排查。思考题  视图什么时候不能直接合并到外层查询？  Item 表达式类型推导如何影响索引？  派生表 merge 和 materialize 的区别是什么？  隐式转换为什么会改变执行计划？  optimizer trace 中 query block 能提供哪些线索？</li>
  <li>这是《MySQL 8.0 源码与内核实战》的独立章节版。本章从概念、实操和生产排查三个视角展开，代码块保留了原书可直接运行的版本。Parser 将 SQL 文本转换为解析树。它决定语法是否合法，并保留语句结构供语义解析和优化使用。6.1 输入输出SQL text  -&gt; lexer     -&gt; token stream        -&gt; parser           -&gt; Parse Tree              -&gt; Resolver / TransformerParser 只处理语法和基本结构，不做：  表是否存在；  列类型是否匹配；  权限是否允许；  索引是否有效；  执行代价是否合理。这些属于后续阶段。6.2 相关源码            文件      职责                  sql/sql_lex.cc      词法与 LEX 相关逻辑              sql/sql_yacc.yy      Bison 语法规则              sql/parser_yystype.h      语义值类型              sql/parse_tree_*      解析树节点              sql/sql_parse.cc      解析入口              sql/sql_parser.cc      Parser 封装      入口调用：mysql_parse  -&gt; parser_state initialization     -&gt; parse_sql        -&gt; generated parser           -&gt; Parse_tree_root6.3 词法词法分析处理：  关键字；  标识符；  字符串；  数字；  注释；  字符集前缀；  运算符；  参数占位符。示例：SELECT id, name FROM users WHERE id = ?会被切分为关键字、标识符和符号 token。字符集会影响字符串 token 和标识符解析，这也是某些 SQL 在不同 character_set_client 下表现不同的原因。6.4 语法规则Bison 规则示意：select_statement:  SELECT select_list  FROM table_references  WHERE expr实际源码规则更复杂，包含：  WITH CTE；  window function；  JOIN 语法；  GROUP BY / HAVING；  ORDER BY / LIMIT；  锁子句；  UNION；  子查询；  DML；  DDL。调试可从错误信息入手：rg "syntax to use near" sql/6.5 解析树节点常见节点：            节点      对应语法                  PT_select      SELECT              PT_table_factor      表引用              PT_item_expr      表达式              PT_join      JOIN              PT_window      窗口              PT_insert      INSERT              PT_update      UPDATE              PT_delete      DELETE              PT_create_table      CREATE TABLE      解析树保留源码书写结构，后续阶段会继续规范化和改写。6.6 预处理语句PREPARE s FROM 'SELECT * FROM t WHERE id=?';SET @id=1;EXECUTE s USING @id;DEALLOCATE PREPARE s;流程：prepare  -&gt; parse     -&gt; prepare_expr / resolve        -&gt; keep statement structureexecute  -&gt; bind parameter     -&gt; optimize if needed        -&gt; execute注意 max_prepared_stmt_count、会话生命周期和 SQL 注入防护。6.7 错误处理常见错误：            错误      阶段                  ER_PARSE_ERROR      语法错误              ER_UNKNOWN_TABLE      解析后语义解析              ER_BAD_FIELD_ERROR      列解析              ER_SYNTAX_ERROR      语法规则失败              ER_NOT_SUPPORTED_YET      语法存在但特性不支持      解析错误要记录完整 SQL 和字符集环境。截断后的 SQL 可能无法复现。6.8 调试 Parserb mysql_parseb parse_sqlrunbtp parser_statep thd-&gt;query().str最小实验：SELECT 1;SELECT * FROM mysql.user LIMIT 1;SELECT * FROM (SELECT 1) AS x;观察不同语句生成的解析入口和树结构。6.9 性能影响解析通常不是最大瓶颈，但以下场景会放大：  超长 SQL；  大量 IN 列表；  深嵌套子查询；  频繁执行相同 SQL 但不使用 prepared statement；  ORM 生成巨型查询；  每次都解析上千条批量值。优化方向：  应用侧参数化；  拆分巨型 SQL；  减少不必要列；  批量写入分批；  缓存业务结果。6.10 与优化器边界Parser 输出的是“写了什么”，优化器决定“怎么做”。SELECT * FROM t WHERE a=1;Parser 只识别 SELECT、表和谓词；优化器再比较全表扫描、索引扫描和覆盖索引代价。本章小结Parser 负责把 SQL 文本转换为解析树，核心在词法、Bison 语法规则和 Parse Tree 节点。它不做权限和执行计划决策。读 Parser 时应从错误码、入口函数和最小语法用例切入。思考题  Parser 和 Resolver 的职责边界是什么？  字符集为什么会影响解析？  prepared statement 在哪个阶段保存结构？  哪些 SQL 会放大解析成本？  如何通过 ER_PARSE_ERROR 定位源码？</li>
  <li>这是《MySQL 8.0 源码与内核实战》的独立章节版。本章从概念、实操和生产排查三个视角展开，代码块保留了原书可直接运行的版本。连接是 SQL 执行的入口。理解连接、线程、会话上下文和调度方式，有助于排查连接风暴、慢查询阻塞和线程资源问题。5.1 连接路径Client connect()  -&gt; TCP / Unix socket     -&gt; connection_accept        -&gt; Connection Handler           -&gt; create / reuse THD              -&gt; authenticate                 -&gt; command loop                    -&gt; dispatch_command一次连接包含：  网络事件；  线程分配；  会话上下文；  认证授权；  字符集协商；  命令循环；  断开清理。5.2 THDTHD 是 Server 层最重要的会话上下文：            区域      内容                  连接信息      socket、客户端地址、协议              安全上下文      用户、host、权限              语句状态      query、lex、command              事务状态      transaction、XA、savepoint              调度状态      killed、stage、time              变量      session variables              诊断      diagnostics area              资源      tables、MDL、临时表      排查时可通过 processlist 观察其外部表现：SELECT id,user,host,db,command,time,state,infoFROM information_schema.processlist;5.3 线程模型传统连接模型是一个客户端连接对应一个服务线程。Listener  -&gt; accept connection     -&gt; thread cache hit?        |-- yes: wake cached thread        +-- no: create thread相关参数：            参数      说明                  max_connections      最大连接数              thread_cache_size      空闲线程缓存              thread_handling      线程调度模型              back_log      连接等待队列              max_connect_errors      错误主机限制              connect_timeout      握手超时      线程不等于用户线程池。MySQL 企业版或 Percona 等发行版可能提供线程池插件。5.4 命令循环核心入口：do_command  -&gt; dispatch_command     -&gt; COM_QUERY        -&gt; mysql_parse     -&gt; COM_STMT_PREPARE        -&gt; mysql_stmt_prepare     -&gt; COM_QUIT        -&gt; close connection断点示例：b dispatch_commandcommandsbtcend可以观察 command type、包长度和会话状态。5.5 认证与权限handshake  -&gt; auth plugin     -&gt; check credentials        -&gt; ACL cache           -&gt; assign Security_context相关对象：  Security_context  ACL_USER  LEX_USER  auth plugin权限检查贯穿 SQL 执行，不只发生在连接时。视图、存储过程、动态 SQL 和 DEFINER 都会影响上下文。5.6 断开与清理连接退出时要释放：  打开的表；  元数据锁；  事务资源；  预处理语句；  临时表；  线程资源；  诊断信息；  performance_schema 会话行。如果事务未提交，连接断开会触发回滚。大事务回滚可能耗时，不能简单理解为“断开立即结束”。5.7 连接观测SHOW GLOBAL STATUS LIKE 'Threads_%';SHOW GLOBAL STATUS LIKE 'Connections';SHOW GLOBAL STATUS LIKE 'Aborted_%';SELECT *FROM performance_schema.threadsWHERE type='foreground';指标含义：            指标      说明                  Threads_connected      当前连接              Threads_running      正在执行命令              Threads_created      累计创建线程              Aborted_clients      客户端异常断开              Aborted_connects      连接失败              Connection_errors_max_connections      达到上限      5.8 连接风暴典型现象：  Threads_connected 快速上升；  CPU 用于线程创建和调度；  大量连接等待锁或执行 SQL；  应用连接池失效；  max_connections 拒绝服务。排查：SELECT host, count(*) AS cntFROM information_schema.processlistGROUP BY hostORDER BY cnt DESC;处理顺序：  识别来源；  kill 异常会话；  应用限流或重启发布；  缩短慢查询；  调整连接池；  评估线程池；  拆分读写入口。5.9 KILL 与取消KILL query 设置 THD 的 killed 标记，执行过程中在安全点检查：KILL QUERY  -&gt; set killed status     -&gt; executor / storage engine check        -&gt; stop returning rows           -&gt; cleanup有些操作不能立即响应取消，例如某些 DDL 阶段、I/O、锁等待或大事务回滚。5.10 生产注意事项  应用侧必须使用连接池；  监控 Threads_running 而不只连接数；  为管理员保留连接配额；  避免用超小 wait_timeout 强制业务频繁重连；  大规模连接来源要有审计；  云环境关注代理层连接模型；  变更 max_connections 要同步评估内存和 CPU。本章小结MySQL 传统模型以连接线程为中心，THD 保存会话的语句、权限、事务和诊断上下文。连接调优要同时看网络、认证、线程、锁等待和业务连接池，避免只调大 max_connections。思考题  THD 中哪些状态会贯穿整个 SQL 生命周期？  Threads_connected 和 Threads_running 有什么区别？  为什么连接断开后事务回滚可能继续占用资源？  KILL QUERY 如何传递到执行器？  连接风暴的处理顺序是什么？</li>
  <li>这是《MySQL 8.0 源码与内核实战》的独立章节版。本章从概念、实操和生产排查三个视角展开，代码块保留了原书可直接运行的版本。MySQL 8.0 可以分为 Server 层、存储引擎层、插件、复制和工具链。理解模块边界比记住函数细节更重要。4.1 分层Client  -&gt; Protocol / Connection     -&gt; Server SQL Layer        |-- Parser        |-- Resolver / Transformer        |-- Optimizer        |-- Executor        |-- Metadata Lock        |-- Query Cache removed in 8.0        +-- Binlog     -&gt; handler API        -&gt; InnoDB / MyISAM / CSV / engines4.2 Server 层模块            模块      目录线索      职责                  Connection      sql/conn_handler/      连接和线程管理              Protocol      sql/protocol*      客户端协议              Parser      sql/sql_yacc.yy      语法解析              Resolver      sql/sql_resolver.cc      表列解析和改写              Optimizer      sql/sql_optimizer.cc      计划选择              Executor      sql/sql_executor.cc      迭代执行              Item      sql/item*      表达式和函数              Field      sql/field*      字段类型              Table      sql/table*      表定义和缓存              Lock      sql/lock.cc      元数据锁              Session      sql/sql_class*      THD 上下文      4.3 InnoDB 模块            前缀      职责                  btr      B+Tree 查找、插入、分裂              page      页头、记录、目录              rem      记录格式              row      行级读写和更新              buf      Buffer Pool 和页面淘汰              ibuf      Change Buffer              lock      行锁和表锁              trx      事务状态              undo      回滚段和 undo 日志              log      redo log              mtr      mini transaction              fil      文件和表空间              dict      数据字典缓存              purge      undo 清理              row0mysql      handler 到行操作的桥      4.4 关键接口handler 是 Server 调用引擎的核心接口：handler::ha_openhandler::ha_index_inithandler::ha_index_readhandler::ha_rnd_nexthandler::ha_write_rowhandler::ha_update_rowhandler::ha_delete_rowhandler::ha_external_lockInnoDB 侧入口常见于 ha_innobase：ha_innobase::index_readha_innobase::general_fetchha_innobase::write_rowha_innobase::update_rowha_innobase::delete_row4.5 事务边界BEGIN / first statement  -&gt; transaction begin     -&gt; InnoDB trx assigned        -&gt; row changes           -&gt; undo              -&gt; redo        -&gt; XA prepare           -&gt; binlog write              -&gt; engine commit相关模块：  sql/transaction.cc  sql/rpl_binlog_sender.cc  storage/innobase/trx/  storage/innobase/log/  storage/innobase/undo/4.6 元数据MySQL 8.0 使用事务性数据字典，取代 5.7 的 .frm 文件。            组件      职责                  DD tables      MySQL 系统表存储元数据              dd::Table      表定义对象              Dictionary Client      Server 层访问接口              InnoDB dict cache      引擎层缓存              MDL      元数据并发控制      这使许多 DDL 具备原子性，但仍要区分算法和锁模式。4.7 复制模块            模块      职责                  Binlog      记录逻辑变更              Dump thread      主库发送 binlog              IO thread      从库接收 relay log              SQL thread / applier      重放事务              GTID      事务标识和幂等              MGR      组复制一致性协议      源码目录包括 sql/rpl_*、libbinlogevents/、plugin/group_replication/。4.8 观测接口与源码关系            观测      源码入口                  processlist      THD              performance_schema stages      stage instrumentation              waits      instrument classes              innodb_trx      trx_t              innodb_locks / data_locks      lock system              optimizer trace      optimizer candidates              show status      status variables      定位方式：rg "Innodb_data_reads" storage/innobaserg "stage/executing" sqlrg "row_lock_waits" storage/innobase4.9 插件体系常见插件：  存储引擎；  全文索引插件；  认证插件；  审计插件；  daemon 插件；  clone 插件；  group replication；  半同步复制。插件通过 MySQL 插件 API 注册，但仍要尊重 Server 层锁和事务语义。4.10 学习地图第一层：SQL 层一条语句路径第二层：handler 与 InnoDB 行操作第三层：Page / B+Tree / Buffer Pool第四层：trx / lock / undo / redo第五层：binlog / replication / recovery第六层：后台线程与性能诊断本章小结MySQL 8.0 的核心边界是 Server 层与存储引擎层。Server 负责协议、解析、优化、执行、元数据和 Binlog；InnoDB 负责页面、行、事务、锁、MVCC、日志和恢复。按模块地图推进，可以避免在庞大源码中迷失。思考题  handler 接口为什么重要？  MySQL 8.0 数据字典与 5.7 有什么关键差异？  一条 UPDATE 涉及哪些 Server 和 InnoDB 模块？  如何从状态变量定位源码位置？  InnoDB 模块推荐阅读顺序是什么？</li>
  <li>这是《MySQL 8.0 源码与内核实战》的独立章节版。本章从概念、实操和生产排查三个视角展开，代码块保留了原书可直接运行的版本。MySQL 源码量大，直接逐行读效率很低。有效方法是问题驱动：从现象入手，建立调用链，再用调试器和测试验证。3.1 问题驱动阅读前先定义问题：现象：SELECT 使用二级索引后为什么回表？问题：InnoDB 在哪里从二级索引回到聚簇索引？验证：断点 row_search_mvcc输出：调用链和最小复现适合入手的问题：  一条 SQL 的解析和执行路径；  一个执行计划为什么选择某个索引；  一个锁为什么被持有；  一个参数如何生效；  一个状态计数在哪里增加；  一个错误码在哪里返回。3.2 从入口到出口SELECT 调用链：dispatch_command  -&gt; mysql_parse     -&gt; mysql_execute_command        -&gt; open_tables        -&gt; optimize        -&gt; execute           -&gt; handler::ha_rnd_next / ha_index_read              -&gt; InnoDB row operationsUPDATE 调用链：parse  -&gt; resolve     -&gt; optimize        -&gt; scan/index read           -&gt; row update              -&gt; undo log              -&gt; redo log              -&gt; binlog              -&gt; commit先画粗链路，再深入分支。3.3 静态搜索常用搜索：rg "dispatch_command" sql/rg "class THD" sql/ include/rg "row_search_mvcc" storage/innobase/rg "SAVEPOINT" sql/ storage/innobase/rg "ER_DUP_ENTRY" sql/ include/搜索策略：  函数名；  错误码字符串；  状态变量名；  配置参数名；  注释中的 RFC 或 Worklog；  MTR 测试名；  结构体字段。3.4 调用栈验证静态搜索会给出多个候选，调用栈能确认实际路径。b row_search_mvccrunbt#0 row_search_mvcc#1 row_search_index_step#2 row_search_for_mysql#3 ha_innobase::index_read验证内容：  入口函数；  参数含义；  分支条件；  返回值；  错误路径；  资源释放；  调用方。3.5 阅读结构体不要一开始读完所有字段，先看生命周期：            结构      生命周期      关注点                  THD      一个客户端线程      security、query、transaction              TABLE      打开的表对象      字段、索引、触发器              handler      一次表访问      引擎接口              row_prebuilt_t      InnoDB 表操作上下文      游标、事务、模板              trx_t      InnoDB 事务      id、state、lock              mtr_t      mini transaction      页修改和日志      字段含义可通过初始化、赋值和引用位置交叉验证。3.6 版本对比git log --oneline -- sql/sql_optimizer.ccgit blame -L 100,160 sql/sql_executor.ccgit show &lt;commit&gt; -- storage/innobase/lock/lock0lock.cc版本对比适合：  参数默认值变化；  新执行计划输出；  锁实现重构；  数据字典改造；  性能优化引入的行为变化。结论必须落到当前使用版本。3.7 结合观测工具            工具      作用                  EXPLAIN FORMAT=TREE      执行计划              optimizer_trace      代价和候选计划              performance_schema      等待和阶段              SHOW ENGINE INNODB STATUS      事务和锁              information_schema.innodb_trx      当前事务              sys.innodb_lock_waits      锁等待              error log      启动和异常      示例：SET optimizer_trace="enabled=on";SELECT * FROM t WHERE a=1;SELECT trace FROM information_schema.optimizer_trace;3.8 记录源码笔记建议模板：版本：mysql-8.0.40问题：复现 SQL：调用链：关键函数：关键结构：分支条件：验证方式：结论：注意事项：笔记要保存复现命令，不只是函数名。3.9 常见误区            误区      后果                  逐行读所有代码      快速失去全局              只看博客结论      版本不匹配              只看函数名      忽略状态和锁              不看调用方      误解生命周期              不写复现      无法验证              混淆 5.7 与 8.0      结论过时              忽略测试用例      遗漏边界行为      3.10 阅读路线推荐顺序：连接与线程  -&gt; Parser / Resolver     -&gt; Optimizer        -&gt; Executor           -&gt; handler              -&gt; InnoDB page / B+Tree                 -&gt; Buffer Pool                    -&gt; trx / lock / undo                       -&gt; redo / recovery                          -&gt; background threads先掌握数据路径，再深入恢复和复制。本章小结源码阅读要以现象为入口、调用链为主线、调试器和 MTR 为验证手段。搜索、断点、版本对比和观测工具结合，才能把源码结论变成可复现、可落地的内核理解。思考题  为什么静态搜索不能替代调用栈？  阅读 THD 时应先关注哪些生命周期信息？  git blame 在源码研究中的用途是什么？  optimizer trace 能帮助定位哪类源码问题？  如何写一份可复现的源码笔记？</li>
  <li>这是《MySQL 8.0 源码与内核实战》的独立章节版。本章从概念、实操和生产排查三个视角展开，代码块保留了原书可直接运行的版本。读源码必须能构建和调试。断点、调用栈、变量和测试用例能验证推测，避免把社区博客结论直接套到当前版本。2.1 环境准备推荐 Linux：            工具      用途                  gcc / clang      编译器              cmake      构建配置              ninja / make      构建执行              gdb / lldb      调试              git      版本管理              bison / flex      Parser 生成              openssl      TLS              ncurses      终端              pkg-config      依赖发现      Ubuntu 示例：sudo apt updatesudo apt install -y build-essential cmake ninja-build gdb git \  bison libssl-dev libncurses-dev libtirpc-dev pkg-config2.2 获取源码git clone https://github.com/mysql/mysql-server.gitcd mysql-servergit checkout mysql-8.0.40git submodule update --init --recursive建议固定一个 8.0.x 小版本，并在笔记中记录 commit hash。不同小版本的结构和默认行为可能变化。2.3 构建mkdir buildcd buildcmake .. -GNinja \  -DCMAKE_BUILD_TYPE=Debug \  -DWITH_DEBUG=ON \  -DWITH_UNIT_TESTS=OFF \  -DWITH_BOOST=systemninja -j$(nproc)常用选项：            选项      说明                  CMAKE_BUILD_TYPE=Debug      保留调试信息              WITH_DEBUG=ON      打开 Server debug 支持              WITH_UNIT_TESTS=OFF      减少构建时间              WITH_BOOST=system      使用系统 Boost              CMAKE_INSTALL_PREFIX      安装目录      如果依赖下载慢，可先手动准备依赖，并保持构建配置可复现。2.4 初始化与启动mkdir -p /tmp/mysql-test-data./runtime_output_directory/mysqld \  --initialize-insecure \  --datadir=/tmp/mysql-test-data \  --basedir=../runtime_output_directory/mysqld \  --datadir=/tmp/mysql-test-data \  --socket=/tmp/mysql-test.sock \  --port=3306 \  --log-error=/tmp/mysql-error.log连接：./runtime_output_directory/mysql \  --socket=/tmp/mysql-test.sock \  -uroot2.5 gdb 调试启动服务：gdb --args ./runtime_output_directory/mysqld \  --datadir=/tmp/mysql-test-data \  --socket=/tmp/mysql-test.sock常用断点：b dispatch_commandb mysql_parseb mysql_execute_commandb mysql_selectb ha_innobase::index_readb row_search_mvccb trx_commitrunbtp thd-&gt;query()info threads调试技巧：  用最小 SQL 复现；  先看调用栈，再进入细节；  记录断点、线程和参数；  多线程场景关注 THD 与 InnoDB 线程；  不在生产实例上调试；  Debug 断言失败时先看触发条件。2.6 VS Code 配置.vscode/launch.json 示例：{  "version": "0.2.0",  "configurations": [    {      "name": "mysqld",      "type": "cppdbg",      "request": "launch",      "program": "${workspaceFolder}/build/runtime_output_directory/mysqld",      "args": ["--datadir=/tmp/mysql-test-data"],      "stopAtEntry": false,      "cwd": "${workspaceFolder}"    }  ]}配合 clangd 或 IntelliSense 可以快速跳转结构体和函数。2.7 MTR 测试MySQL 测试框架位于 mysql-test/：cd mysql-testperl mysql-test-run.pl --vardir=/tmp/mtr-vardir main.select测试文件结构：-- source include/have_innodb.incCREATE TABLE t(id INT PRIMARY KEY, v INT) ENGINE=InnoDB;INSERT INTO t VALUES(1,1),(2,2);SELECT * FROM t WHERE id=2;DROP TABLE t;MTR 价值：  固定复现步骤；  验证行为差异；  修改源码后做回归；  学习内部特性开关；  观察错误码和状态。2.8 Debug 支持Debug 构建可以打开更多诊断：SET GLOBAL debug = 'd:t:o,/tmp/mysqld.trace';InnoDB monitor：SHOW ENGINE INNODB STATUS;SET GLOBAL innodb_status_output=ON;SET GLOBAL innodb_status_output_locks=ON;performance_schema：SELECT event_name, count_starFROM performance_schema.events_waits_summary_global_by_event_nameORDER BY count_star DESCLIMIT 10;2.9 常见构建问题            问题      处理                  缺 Boost      指定系统或下载路径              bison 版本不匹配      按文档升级              内存耗尽      降低并行度              找不到 OpenSSL      安装 dev 包并检查路径              增量构建异常      清理后重建              符号缺失      确认 Debug 构建              运行目录异常      使用独立 datadir      2.10 工作流推荐流程：提出问题  -&gt; 写最小 SQL     -&gt; 设置断点        -&gt; 观察调用栈           -&gt; 查看结构体              -&gt; 对照源码                 -&gt; 写 MTR                    -&gt; 归档结论本章小结编译调试是源码阅读的基础。固定版本、使用 Debug 构建、维护独立数据目录、通过 gdb 查看 SQL 层和 InnoDB 关键断点，并用 MTR 固化实验结论，可以显著降低阅读误差。思考题  为什么读源码前要记录具体版本和 commit？  Debug 构建和 Release 构建在源码阅读上有什么差异？  dispatch_command 和 mysql_parse 分别适合观察什么？  MTR 测试对源码研究有什么价值？  如何构建一个可重复的调试环境？</li>
  <li>这是《MySQL 8.0 源码与内核实战》的独立章节版。本章从概念、实操和生产排查三个视角展开，代码块保留了原书可直接运行的版本。MySQL 8.0 源码庞大，但它有清晰的模块边界。读源码的第一步不是逐行阅读，而是建立地图：连接如何进入 Server 层，SQL 如何解析和优化，执行器如何调用存储引擎，InnoDB 如何管理页面、事务、锁和日志。本章目标是建立 MySQL 8.0 源码阅读的全局视角。1.1 为什么要读源码读源码能解决文档没有覆盖的问题：  理解执行计划为什么这样选；  理解锁范围为什么比预期大；  理解参数默认值背后的机制；  理解错误日志和状态指标来源；  判断性能问题在 SQL 层还是引擎层；  验证社区博客结论是否适用当前版本；  为内核修改和深度排障打基础。读源码不是为了背代码行数，而是为了建立可验证的机制模型。1.2 源码目录概览以 MySQL 8.0 社区源码为例，常见目录：            目录      职责                  sql/      SQL 层核心、解析、优化、执行、协议              storage/innobase/      InnoDB 存储引擎              include/      公共头文件              mysys/      系统库封装              libbinlogevents/      Binlog 事件定义              client/      客户端工具              router/      MySQL Router              plugin/      插件              unittest/      单元测试              mysql-test/      MTR 测试              cmake/      构建配置      最重要的两个目录：sql/  -&gt; Server layerstorage/innobase/  -&gt; InnoDB1.3 一条 SQL 的调用链查询的大致路径：mysql_real_query / COM_QUERY  -&gt; dispatch_command     -&gt; mysql_parse        -&gt; parse_tree           -&gt; mysql_execute_command              -&gt; open_tables              -&gt; optimize              -&gt; execute                 -&gt; handler interface                    -&gt; ha_innobase                       -&gt; row_search / row_insert / row_update写入语句还涉及：Server层  -&gt; binlog prepare  -&gt; engine prepare  -&gt; binlog write  -&gt; engine commit这就是 redo log 和 binlog 的两阶段提交路径。1.4 SQL 层核心模块            模块      主要职责                  Connection Handler      管理客户端连接和线程              Protocol      编解码 MySQL 协议包              Parser      语法解析              Resolver      语义解析、表和列解析              Transformer      逻辑改写              Optimizer      代价估算、连接顺序、访问方法              Executor      执行迭代器              Table Cache      表定义缓存              Lock Manager      Server 层元数据锁              Binlog      逻辑日志      MySQL 8.0 优化器和执行器相比 5.6/5.7 有明显重构，例如基于迭代器的执行模型和新优化器结构。1.5 InnoDB 核心模块            模块      职责                  fil      文件空间管理              buf      Buffer Pool              btr      B+Tree              row      行操作              rem      记录管理              lock      锁系统              trx      事务              undo      回滚段和版本链              log      redo log              mtr      mini transaction              page      页面管理              ibuf      Change Buffer              purge      清理 delete mark              dict      数据字典缓存              fts      全文索引      推荐阅读顺序：buf -&gt; page -&gt; btr -&gt; row -&gt; trx -&gt; lock -&gt; undo -&gt; log -&gt; purge先懂页面和索引，再懂事务和锁，最后读恢复和后台线程。1.6 编译与调试准备获取源码：git clone https://github.com/mysql/mysql-server.gitcd mysql-servergit checkout mysql-8.0.xx常见依赖：sudo apt install build-essential cmake ninja-build \  libssl-dev libncurses-dev libtirpc-dev \  bison pkg-config构建：mkdir buildcd buildcmake .. -GNinja \  -DCMAKE_BUILD_TYPE=Debug \  -DWITH_UNIT_TESTS=OFF \  -DWITH_DEBUG=ONninja启动调试：./runtime_output_directory/mysqld --defaults-file=my.cnf --user=mysql调试建议：  使用 Debug 构建；  固定小数据集；  用 MTR 复现；  在 SQL 层入口和 handler 接口断点；  结合 EXPLAIN FORMAT=TREE；  结合 performance_schema；  阅读对应测试用例。1.7 源码阅读方法推荐方法：  先写可复现实验；  再看执行计划；  根据现象猜测模块；  从入口函数进入；  画调用链；  记录关键结构体；  用断点验证；  对照测试；  输出笔记。例如调查二级索引回表：CREATE TABLE t (  id BIGINT PRIMARY KEY,  a INT,  b VARCHAR(64),  KEY idx_a(a)) ENGINE=InnoDB;EXPLAIN SELECT * FROM t WHERE a = 10;源码路径：Optimizer 选择 ref/index scan  -&gt; Executor 调用 handler read     -&gt; InnoDB secondary index lookup        -&gt; row_search_mvcc           -&gt; return PK              -&gt; clustered index lookup1.8 关键数据结构            结构      说明                  THD      一个客户端线程的会话上下文              TABLE      打开的表对象              handler      Server 调用引擎的接口              row_prebuilt_t      InnoDB 表操作上下文              buf_block_t      Buffer Pool 页块              rec_t      InnoDB 记录              btr_cur_t      B+Tree 游标              trx_t      InnoDB 事务              lock_t      InnoDB 锁对象              mtr_t      mini transaction      不要一开始就追所有字段，先理解生命周期和模块关系。本章小结MySQL 8.0 源码可以按 Server 层和 InnoDB 分开阅读。Server 层关注连接、解析、优化、执行和 Binlog；InnoDB 关注页面、B+Tree、事务、锁、MVCC、日志和后台线程。源码阅读要从可复现实验和调用链入手，用调试器和测试验证理解。思考题  sql/ 和 storage/innobase/ 的边界是什么？  一条 SELECT 的关键调用链包含哪些阶段？  redo log 和 binlog 两阶段提交涉及哪些模块？  为什么建议先读 Buffer Pool、Page、B+Tree，再读事务和锁？  如何用 MTR 测试验证一个源码结论？</li>
</ul>
