MySQL执行原理与索引优化实战:从SQL发出到数据返回的全过程

发布时间:2026/10/31 22:46:17
MySQL执行原理与索引优化实战:从SQL发出到数据返回的全过程 简介本资源是一份面向MySQL数据库工程师、后端开发人员及技术面试者的高频考点精编资料系统梳理MySQL面试中必问的核心原理与实战陷阱。内容覆盖关系型与非关系型数据库本质区别、SQL语句全链路执行流程连接器→查询缓存→分析器→优化器→执行器、索引设计底层逻辑哈希表/有序数组/N叉树对比、B树在InnoDB中的独特优势、聚簇索引与二级索引差异、覆盖索引与索引下推机制、以及9类典型索引失效场景等硬核知识点。资源为1个40KB的Word文档.docx结构清晰、要点凝练适合作为考前速记、技术复盘或团队内训材料。目前已有255人学习下载内容直击面试官追问逻辑助读者不仅知其然更知其所以然。1. MySQL面试题不是考你背了多少条命令而是看你能不能把数据库“想明白”你有没有过这种经历翻着几十页的“MySQL面试题汇总”越看越慌——索引、redo log、两阶段提交、B树、change buffer……每个词都认识连起来却像天书背下答案能应付面试但一写SQL就慢得离谱一加索引反而更卡一重启数据库就心惊肉跳……这不是你记性差是缺了一张“MySQL内部地图”它不告诉你命令怎么敲而是帮你搞懂——当一条SELECT * FROM users WHERE age 25发出去后MySQL里到底发生了什么谁在动谁在等谁在偷偷擦黑板又重写这就像坐进一辆车光记住“油门加速、刹车减速”不够真要开稳得知道发动机怎么点火、变速箱怎么换挡、ABS什么时候介入。MySQL面试题的本质就是一套“驾驶舱认知体检表”它不考你会不会修引擎但必须确认你坐上驾驶位时眼睛扫得到仪表盘上每一个灯亮没亮耳朵听得出异响来自哪里手本能知道该不该踩下那个踏板。这份资料不是题库而是一份带注释的“MySQL运行实况录像脚本”——从连接建立到数据返回从磁盘读取到内存刷盘从索引查找再到日志落盘每一步都标好了“谁干的、为什么这么干、不这么干会怎样”。搞懂它你写的SQL才有底气你加的索引才不踩坑你调的参数才不玄学。2. 一条SQL执行全过程MySQL不是单线程流水线而是一支分工明确的特种作战小队MySQL执行一条SQL绝不是“输入→输出”这么简单。它背后是一支由Server层和存储引擎层协同作战的特种小队各司其职环环相扣。理解这支小队的协作逻辑是所有性能优化和故障排查的起点。2.1 客户端请求不是“发个包”就完事而是信任建立的第一步当你在命令行输入mysql -u root -p -h 127.0.0.1 -P 3306或应用代码调用connection.createStatement()第一步不是执行SQL而是建立连接。这个过程由连接器Connector完成它验证你的用户名密码、检查IP白名单、分配线程资源、初始化会话变量比如autocommit1、sql_mode。提示连接不是免费的。频繁创建/销毁连接如短连接会极大消耗CPU和内存。生产环境务必使用连接池如HikariCP复用已建立的连接。2.2 查询缓存一个“好心办坏事”的老将MySQL 8.0 已正式退役在旧版MySQL中连接器之后是查询缓存Query Cache它会把SELECT * FROM config WHERE keysite_name这样的查询结果连同SQL文本一起存进一块共享内存。下次遇到一模一样的SQL注意必须完全一致空格、大小写、注释都不能差直接返回缓存结果跳过后续所有步骤。听起来很美但它有致命缺陷只要config表有任何一次INSERT/UPDATE/DELETE整个表相关的所有缓存全部失效。在读写混合场景下缓存命中率极低反而因维护缓存锁带来额外开销。注意MySQL 8.0 起已彻底移除查询缓存模块。现在看到的“缓存”都是操作系统页缓存Page Cache或InnoDB Buffer Pool的功劳它们按数据页而非SQL语句缓存更底层、更高效。2.3 分析器SQL的“语法医生”专治“写错字”和“说错话”缓存未命中或8.0版本SQL进入分析器Parser。它干两件事词法分析把SELECT name, age FROM users WHERE age 25 ORDER BY name拆成一个个“单词”SELECT、name、age、FROM、users……语法分析检查这些“单词”是否符合MySQL语法规则。比如SELECT * FROM users WHERE;会报错You have an error in your SQL syntax因为WHERE后面缺条件SELECT name, COUNT(*) FROM users也会报错因为非聚合字段name不能和COUNT(*)混用除非开启sql_modeonly_full_group_by。这一步不涉及表是否存在、字段有没有纯粹是“文字游戏”。语法正确才进入下一步。2.4 优化器SQL的“战略参谋”决定走哪条路最快分析无误SQL交给优化器Optimizer。这才是真正的“智能核心”。它不关心你要查什么只关心怎么查最快。它会做三件关键决策表关联顺序SELECT * FROM orders o JOIN users u ON o.user_id u.id WHERE u.status active是先扫描users再关联orders还是反过来优化器基于统计信息如users表中statusactive的行数占比估算成本选代价最小的路径。索引选择如果users表有(status)索引和(status, id)联合索引优化器会判断哪个过滤效果更好。执行策略是用全表扫描type: ALL还是索引扫描type: index或是索引范围查询type: range你可以用EXPLAIN命令查看优化器的决策结果EXPLAIN SELECT * FROM users WHERE age 25 AND city Beijing;输出中的key列显示实际使用的索引rows列是优化器预估的扫描行数Extra列里的Using where; Using index意味着走了覆盖索引——这是性能优化的黄金信号。2.5 执行器最终的“战场指挥官”手握权限与引擎接口优化器给出执行计划后执行器Executor开始干活。但它自己不读数据而是调用存储引擎如InnoDB的API去取。执行前它会做最后一道安检检查用户对该表是否有SELECT权限。没有权限直接报错Access denied连引擎层都不让进。有权限执行器就按计划调用引擎接口如果计划是“用idx_age索引查age 25”执行器就告诉InnoDB“请用idx_age索引找所有age值大于25的记录”。InnoDB在索引树中定位、遍历把满足条件的主键ID返回给执行器。执行器再拿着这些ID逐个回表即根据主键去聚簇索引中查整行数据组装成结果集。关键点执行器是Server层的“统一调度员”它屏蔽了不同引擎的差异。你换MyISAM或InnoDBSQL写法不变执行器自动适配对应引擎的调用方式。2.6 引擎层数据的真正守护者InnoDB的“肌肉与神经”数据最终由存储引擎这里是InnoDB负责存取。它才是和磁盘、内存打交道的实体读数据先查Buffer Pool内存缓存命中则直接返回未命中则从磁盘读取数据页16KB加载进Buffer Pool再返回。写数据先修改Buffer Pool中的页同时写入redo log保证崩溃可恢复再异步刷盘flush。索引操作所有索引主键、二级索引都以B树结构组织查找、插入、删除都遵循B树规则。执行器拿到引擎返回的数据最后通过网络发回客户端。整个过程结束。3. 索引为什么快不是“建了就快”而是它重构了数据的物理访问路径很多人以为“加个索引SQL变快”结果发现SELECT * FROM logs WHERE content LIKE %error%加了索引也没用。问题不在索引本身而在没理解索引的本质作用它不是给SQL“提速开关”而是为数据重建了一套更高效的物理组织方式让数据库能绕过大海捞针式的全表扫描。3.1 索引即目录书没变但找内容的方式彻底升级想象一本1000页的《MySQL内核详解》你想找“WAL技术”在哪一页。没有目录你只能一页页翻全表扫描有了目录你先查目录页看到“WAL技术P327”直接翻到327页索引查找。索引对数据库的作用一模一样。但注意目录只告诉你“关键词在哪页”不包含“关键词的全文”。所以SELECT title FROM books WHERE author HeiXuan只查标题能用作者索引快速定位但SELECT * FROM books WHERE author HeiXuan查整行就需要先通过作者索引找到主键再用主键去聚簇索引里查所有字段——这就是“回表”。3.2 三种底层结构哈希、数组、B树各自守着不同的城门索引快不快取决于它的底层数据结构是否匹配你的查询模式。MySQLInnoDB默认用B树但理解其他两种才能明白为什么选它结构类型适用场景优势劣势MySQL中典型应用哈希表等值查询WHERE id 100O(1)时间复杂度极致快不支持范围查询WHERE id 100、排序ORDER BY、模糊匹配LIKE abc%Memory引擎、InnoDB自适应哈希索引AHI有序数组静态只读表如配置表等值、范围、排序查询都极快二分查找插入/删除需移动大量元素O(n)复杂度无法应对高并发写极少用于主索引多见于某些OLAP引擎的列存排序B树通用OLTP场景读多写少、需范围/排序/模糊查找、插入、删除均为O(log n)叶节点链表支持高效范围扫描高度平衡IO稳定相比哈希等值查询稍慢log n vs 1相比数组范围查询略逊但远胜哈希InnoDB所有索引的默认结构举个直观例子一个10亿行的用户表主键是自增ID。InnoDB的B树索引树高通常只有3~4层。这意味着查任意一个ID最多读取3~4个数据页16KB/页就能定位到数据——而全表扫描需要读取数TB数据。这就是“随机IO变顺序IO”的威力。3.3 主键索引 vs 二级索引InnoDB里数据只存一份但“入口”有多个InnoDB的索引设计有个核心原则数据即索引索引即数据。这导致主键索引聚簇索引和二级索引非主键索引有本质区别主键索引聚簇索引叶子节点存储的是整行数据。表数据文件.ibd本身就是按主键B树组织的。所以主键查询是最快的无需回表。二级索引非主键索引叶子节点存储的不是数据而是对应主键的值。例如你在email字段建索引叶子节点存的是user_id假设主键是user_id。查SELECT * FROM users WHERE email ab.com时MySQL先在email索引树中找到user_id123再拿着123去主键索引树中查整行数据——这就是一次“回表”。-- 建表语句示意 CREATE TABLE users ( id BIGINT PRIMARY KEY AUTO_INCREMENT, email VARCHAR(100), name VARCHAR(50), created_at DATETIME, INDEX idx_email (email), -- 二级索引叶子存id INDEX idx_created (created_at) -- 二级索引叶子存id );关键洞察二级索引的“回表”是性能瓶颈。如果查询只需要索引字段本身如SELECT email FROM users WHERE email ab.com就构成覆盖索引无需回表速度飙升。这也是为什么推荐“只查需要的字段”而不是盲目SELECT *。3.4 B树为何是InnoDB的终极选择不是因为它最炫而是因为它最“务实”为什么InnoDB放弃更简单的B树或更快的哈希死磕B树答案藏在两个现实约束里磁盘IO是瓶颈CPU处理数据飞快但磁盘寻道Seek要10ms是内存访问的10万倍。B树所有数据都在叶子节点且叶子节点用双向链表相连。查WHERE age BETWEEN 20 AND 30时找到第一个age20的叶子页顺着链表往后读全是顺序IO效率极高。而B树非叶子节点也存数据范围查询可能频繁跳转产生大量随机IO。写操作必须可靠哈希索引写入快但崩溃后无法恢复无事务日志。B树配合redo log能保证即使断电已提交事务的数据也不丢。所以B树不是“理论最优”而是“工程最优”它在查询性能、写入性能、崩溃恢复、内存友好性之间找到了最适合关系型数据库的平衡点。4. 日志系统双雄redo log 和 binlog一个管“活命”一个管“续命”MySQL的可靠性不靠运气靠两套日志系统精密协作redo log重做日志管“活命”——确保宕机后数据不丢binlog归档日志管“续命”——支撑主从复制和时间点恢复。混淆它们就像分不清急救室ICU和档案馆Library——一个救当下一个备未来。4.1 redo logInnoDB的“生命维持仪”专治崩溃失忆症想象一下你正在转账UPDATE accounts SET balance balance - 100 WHERE id 1001刚执行完银行系统突然断电。内存里改过的余额数据没了钱是不是就消失了redo log就是防止这事发生的“手术记录本”。它不记录最终数据是什么而是记录“在哪个数据页的哪个偏移量把哪个字节从A改成B”。写入时机事务提交前必须把这次修改对应的redo log写入磁盘由innodb_flush_log_at_trx_commit参数控制设为1最安全。循环写redo log文件如ib_logfile0、ib_logfile1是固定大小、首尾相连的环形缓冲区。write pos是当前写入位置checkpoint是已刷盘到数据文件的安全位置。两者之间是待刷盘的“脏日志”。崩溃恢复重启时InnoDB扫描redo log把checkpoint之后的所有日志“重放”replay一遍就把内存里丢失的修改补回来了。-- 查看当前redo log状态 SHOW ENGINE INNODB STATUS\G -- 在输出中找 LOG 部分能看到 write_pos, checkpoint_pos 等关键指标注意redo log是InnoDB私有的Server层包括binlog看不到它。它只保证单机数据不丢不解决主从同步。4.2 binlogMySQL Server层的“历史档案”主从同步的唯一信使如果redo log是ICU里的实时监护仪binlog就是医院的电子病历系统——它记录的是“做了什么手术”而不是“手术刀划了哪几毫米”。记录内容以逻辑日志形式记录所有引起数据变更的SQL语句Statement格式或具体行变更Row格式。写入时机在事务提交后由Server层写入与引擎无关MyISAM也用binlog。用途主从复制从库拉取主库的binlog重放其中的事件实现数据同步。时间点恢复PITR某天误删了表用最近一次全备 从备份时间到误删前的binlog重放到临时库再导出数据。-- 查看binlog格式推荐ROW最安全 SHOW VARIABLES LIKE binlog_format; -- 查看当前binlog文件及位置 SHOW MASTER STATUS;关键区别binlog是追加写append-only永不覆盖redo log是循环写circular旧日志会被新日志覆盖。binlog不保证crash-safe写入binlog后崩溃数据可能还在内存没刷盘所以必须和redo log配合。4.3 两阶段提交2PC让redo log和binlog“步调一致”的军令状既然redo log保命binlog续命那它们必须保持一致。否则会出现灾难性场景先写redo log再写binlog中间崩溃→ 主库数据已更新redo log里有但从库没收到binlog → 主从数据不一致。先写binlog再写redo log中间崩溃→ 从库重放了binlog但主库数据没更新redo log没写 → 从库有数据主库没有。两阶段提交就是解决这个问题的协议Prepare阶段InnoDB将事务写入redo log并标记为PREPARE状态但不刷盘。此时事务还未提交。写binlogServer层将该事务的binlog写入磁盘。Commit阶段InnoDB收到Server层“可以提交”的指令将redo log中的PREPARE记录刷盘并标记为COMMIT。崩溃恢复时InnoDB检查redo log若看到COMMIT记录 → 直接重放数据已生效。若看到PREPARE记录 → 检查对应binlog是否存在且完整 → 存在则提交不存在则回滚。这就是“逻辑一致性”的保障binlog的存在是redo log中PREPARE事务能否最终提交的“最终裁决权”。4.4 常见误区 / 易混概念别再把日志当“同一个东西”来用易混点为什么混怎么区分redo log 和 binlog 都是日志所以功能差不多名字里都有“log”都跟数据持久化有关。根本不同层redo log是InnoDB引擎私有物理日志记录页修改binlog是MySQL Server层逻辑日志记录SQL或行变更。用途不同redo log只用于崩溃恢复binlog用于主从复制和PITR。开启了binlog就不用管redo log了以为binlog能替代redo log的崩溃保护能力。binlog无法保证crash-safe。它写入后数据可能还在内存Buffer Pool中未刷盘。只有redo log能保证“已提交事务必不丢失”。二者是互补非替代。innodb_flush_log_at_trx_commit1和sync_binlog1都设为1就绝对安全认为两个“1”叠加等于万无一失。仍存在微小窗口在prepare写入redo log后、commit写入binlog前崩溃或反之。但概率极低且2PC协议能保证最终一致性。生产环境强烈建议两者都为1。binlog_formatSTATEMENT 比 ROW 更省空间所以应该用它只看到日志体积小的优点。STATEMENT有严重缺陷函数NOW()、UUID()、触发器、存储过程等在主从上执行结果可能不同导致数据不一致。ROW格式是生产环境唯一推荐它记录的是最终行变更100%确定。redo log文件越大越好能减少刷盘次数类比“缓存越大越好”的直觉。过大有风险崩溃恢复时需要重放的日志越多启动时间越长。官方建议总大小所有ib_logfile之和为innodb_buffer_pool_size的25%-100%通常48MB~256MB足够。5. 索引失效的10种“翻车现场”不是SQL写错了而是你没看清索引的“脾气”加了索引SQL却依然慢如蜗牛别急着骂MySQL大概率是你的查询方式无意中触发了索引的“禁用模式”。索引不是魔法它有明确的“服务条款”——违反条款它就直接罢工退回到全表扫描。下面这10种场景就是开发者最常踩的“索引失效”深坑。5.1 模糊匹配LIKE的“左百分号”是索引杀手-- ❌ 失效无法利用索引进行范围查找只能全表扫描 SELECT * FROM users WHERE name LIKE %明; -- ❌ 失效同上左右都有%完全无法定位起始点 SELECT * FROM users WHERE name LIKE %明%; -- ✅ 有效前缀匹配索引可以快速定位到所有name以张开头的叶子节点 SELECT * FROM users WHERE name LIKE 张%;原理B树索引是按字符串字典序排序的。张%可以快速定位到第一个张开头的记录然后顺序扫描所有张开头的记录但%明意味着“任何以‘明’结尾的字符串”索引树无法预知这些字符串散落在哪里只能全表扫。5.2 函数/表达式对索引字段“动手动脚”索引就认不出它了-- ❌ 失效索引存的是原始值2023-10-01不是YEAR(2023-10-01)2023 SELECT * FROM orders WHERE YEAR(create_time) 2023; -- ❌ 失效LOWER(email)改变了原始值索引无法匹配 SELECT * FROM users WHERE LOWER(email) ab.com; -- ✅ 有效用函数处理查询值索引字段保持原样 SELECT * FROM orders WHERE create_time 2023-01-01 AND create_time 2024-01-01; -- ✅ 有效建函数索引MySQL 8.0 CREATE INDEX idx_email_lower ON users (LOWER(email));原理索引是建立在字段原始值上的“快照”。一旦你对字段施加函数或计算MySQL就必须对每一行都执行该函数再比较结果——这等于放弃了索引的有序性。5.3 隐式类型转换字符串和数字“强行恋爱”索引默默退出-- ❌ 失效假设phone是VARCHAR类型传入数字13800138000MySQL会隐式转换为字符串再比较 -- 但索引是按字符串排序的而数字比较规则不同可能导致索引失效或错误结果 SELECT * FROM users WHERE phone 13800138000; -- ✅ 有效显式转换或确保类型一致 SELECT * FROM users WHERE phone 13800138000;原理隐式转换是MySQL的“好意”但它可能改变索引的比较逻辑。更危险的是它可能引发全表扫描且不易察觉。5.4 OR条件只要有一个分支没索引“全家”都得扫-- ❌ 失效即使email有索引status没索引整个WHERE条件也无法用索引 SELECT * FROM users WHERE email ab.com OR status deleted; -- ✅ 有效为OR中所有字段都建索引或改用UNION需评估成本 SELECT * FROM users WHERE email ab.com UNION SELECT * FROM users WHERE status deleted;原理OR是“或”关系MySQL无法保证两个条件能用同一个索引路径高效合并。它倾向于选择成本最低的单个索引或干脆全表扫描。5.5 联合索引的“最左前缀”不是“包含”就行而是“从左开始连续”-- 假设建了联合索引 INDEX idx_name_age_city (name, age, city) -- ✅ 有效完全匹配最左前缀 SELECT * FROM users WHERE name 张三; -- ✅ 有效匹配最左前缀下一个字段 SELECT * FROM users WHERE name 张三 AND age 25; -- ✅ 有效匹配全部三个字段 SELECT * FROM users WHERE name 张三 AND age 25 AND city 北京; -- ❌ 失效跳过name直接查age无法利用索引的有序性 SELECT * FROM users WHERE age 25; -- ❌ 失效name用了范围查询后面的city字段索引失效 SELECT * FROM users WHERE name 张 AND city 北京; -- city无法走索引原理联合索引是按(name, age, city)的字典序排序的。name是第一排序键age是第二city是第三。没有name就无法定位到索引树的某个子树name用了范围age和city的有序性在该范围内就乱了。5.6 其他经典失效场景!或操作符通常导致全表扫描但MySQL 8.0对某些情况有优化。IS NULL/IS NOT NULL对允许NULL的字段索引可能失效取决于统计信息和优化器判断。SELECT * 二级索引必然回表若表很大回表IO开销巨大。索引字段参与计算WHERE price * 1.1 100同函数失效。统计信息过期ANALYZE TABLE users未执行优化器基于错误的行数估算选错索引。血泪经验每次写完WHERE条件立刻用EXPLAIN看key和rows。如果key为空或rows接近表总行数说明索引没走赶紧检查以上10种场景。6. 什么时候该用索引什么时候该删索引一个DBA的“索引生死簿”实践清单索引不是越多越好也不是越少越省。它像一把双刃剑用对了SQL飞一般快用错了写入变慢、存储暴涨、查询更卡。我见过太多团队线上表有20多个索引INSERT耗时从10ms飙到500msALTER TABLE加个字段要锁表1小时……最终发现90%的索引从未被查询用过。这份“索引生死簿”是我从模拟项目X、某高校教务系统、某跨平台电商后台等真实场景中总结出的落地判断清单。6.1 必须建索引的5种“刚需场景”这些场景下不建索引性能就是硬伤没有商量余地场景判断依据推荐索引类型示例主键与唯一约束表必须有主键InnoDB强制要求业务上有唯一性要求如手机号、邮箱主键索引聚簇、唯一索引PRIMARY KEY(id),UNIQUE KEY uk_phone(phone)高频WHERE查询字段EXPLAIN显示该字段在WHERE中出现且rows远小于表总行数单列索引或联合索引按查询频率排序WHERE status paid AND created_at 2023-01-01→INDEX idx_status_time(status, created_at)ORDER BY / GROUP BY 字段查询中有ORDER BY col且无WHERE或GROUP BY col导致Using filesort或Using temporary在ORDER BY/GROUP BY字段上建索引SELECT * FROM logs ORDER BY created_at DESC LIMIT 10→INDEX idx_time(created_at)JOIN关联字段EXPLAIN显示type: ALL全表扫描在被驱动表上在被驱动表的ON条件字段建索引SELECT u.name FROM orders o JOIN users u ON o.user_id u.id→users表上建INDEX idx_uid(user_id)覆盖索引需求查询只涉及少数几个字段且这些字段能组成一个索引创建包含所有查询字段的联合索引SELECT email, name, status FROM users WHERE status active→INDEX idx_cover_status_email_name(status, email, name)6.2 必须删索引的4种“毒瘤信号”这些信号一出现索引就是负担该删就删别心疼信号如何验证后果行动零查询使用查询performance_schema.table_io_waits_summary_by_index_usagecount_star0索引纯占空间、拖慢写入、增加维护成本DROP INDEX idx_unused ON table_name;写入远超查询监控INFORMATION_SCHEMA.INNODB_METRICSdml_inserts/dml_updatesindex_read_requests每次INSERT/UPDATE/DELETE都要维护索引树CPU和IO压力剧增删除该索引或评估是否真需要此查询索引碎片率过高SHOW INDEX FROM table_name看Cardinality基数远低于实际行数或OPTIMIZE TABLE后性能显著提升索引树不平衡查找效率下降甚至退化为全表扫描OPTIMIZE TABLE table_name;重建表和索引或ALTER TABLE ... ENGINEInnoDB;重复索引pt-duplicate-key-checker工具扫描或手动对比SHOW CREATE TABLE多个索引覆盖相同字段组合浪费空间写入时多维护一份保留最宽字段最多或最常用的那个删掉其余-- 查看索引使用情况MySQL 5.6 SELECT OBJECT_SCHEMA AS db, OBJECT_NAME AS tbl, INDEX_NAME AS idx, COUNT_STAR AS total_usage, SUM_TIMER_WAIT AS total_latency FROM performance_schema.table_io_waits_summary_by_index_usage WHERE OBJECT_SCHEMA your_db AND COUNT_STAR 0;6.3 一个真实案例从“慢SQL报警”到“索引瘦身”的48小时某公司订单系统凌晨3点开始持续报警“SELECT * FROM orders WHERE status shipped ORDER BY created_at DESC LIMIT 20耗时5s”。Step 10-2hEXPLAIN发现type: ALLrows: 2,000,000Extra: Using where; Using filesort。Step 22-6h检查索引发现只有INDEX idx_status(status)但ORDER BY created_at没索引导致filesort。Step 36-12h创建联合索引INDEX idx_status_time(status, created_at)查询降到80ms。Step 412-48h审计全表索引发现idx_status_old、idx_status_v2、idx_status_created等5个相似索引performance_schema显示其中3个COUNT_STAR0。全部删除。结果INSERT平均耗时从320ms降至45ms磁盘空间节省12GBALTER TABLE加字段时间从1h降至3min。从那以后我每次上线新SQL都强制走一遍“索引四问”这个WHERE/ORDER BY/GROUP BY字段有没有被现有索引覆盖如果没有建新索引的成本空间、写入延迟是否可接受如果有EXPLAIN是否真的走了它rows是否合理这个索引过去7天有没有被任何查询用过查performance_schema希望帮到你。本文还有配套的精品资源点击获取

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询