mysql存储引擎中的索引与事务性能优化

9次阅读

MyISAM不支持事务,高并发写入性能差,应优先选用InnoDB;主键宜短且稳定,避免UUID;事务中需显式提交,长事务须设超时;覆盖索引需匹配查询与排序字段顺序。

mysql存储引擎中的索引与事务性能优化

MyISAM 不支持事务,别在它上面硬套 ACID 场景

如果业务需要 ROLLBACKSAVEPOint 或强一致性读,直接排除 MyISAM。它用的是表级锁 + 全文索引(FULLTEXT),但 INSERT/UPDATE 期间整张表被锁死,高并发写入时会卡成单线程。很多老项目迁移时踩坑:以为只是换引擎,结果发现应用层的事务逻辑全失效了。

实操建议:

  • 确认当前表引擎:
    SHOW table STATUS LIKE 'your_table';

    Engine 字段

  • 切换前先备份:
    CREATE TABLE your_table_innodb AS select * FROM your_table;

    ALTER TABLE your_table_innodb ENGINE=InnoDB;

  • MyISAMSELECT count(*) 很快,但 InnoDB 需要扫聚簇索引——如果只是统计总数且不介意小延迟,加个缓存字段或定时任务更新更稳

InnoDB 的主键设计直接影响二级索引大小和查询效率

InnoDB 的二级索引叶子节点存的是主键值,不是行地址。所以主键越短、越稳定,二级索引占用空间越小,范围扫描和回表成本越低。常见错误是用 VARCHAR(255) UUID 做主键:不仅索引体积翻倍,还导致插入时频繁页分裂。

实操建议:

  • 优先用自增 BIGINTINT;若需分布式 ID,考虑 ULID 或时间前缀+序列组合,避免纯随机字符串
  • 联合主键慎用——除非业务天然有不可拆分的复合唯一约束,否则容易让 WHERE 条件无法命中最左前缀
  • 已有大主键表想优化?可新增隐藏自增列 id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY FIRST,再重建主键,但要注意外键和应用层引用是否同步改

事务中不要混用 SELECT ... for UPDATE 和非事务语句

AUTOCOMMIT=1 下执行 SELECT ... FOR UPDATEmysql 会隐式开启事务,但很多人忘了显式 COMMITROLLBACK,导致锁一直挂着,后续 UPDATE 被阻塞,监控看到 innodb_row_lock_waits 持续上涨。

实操建议:

  • 检查当前连接事务状态:
    SELECT TRX_ID, TRX_STATE, TRX_MYSQL_THREAD_ID FROM INFORMATION_SCHEMA.INNODB_TRX;
  • 长事务必须设超时:SET innodb_lock_wait_timeout = 10;(单位秒),比默认 50 更早暴露问题
  • 批量更新别在一个事务里干完:按主键分片,每次 UPDATE ... WHERE id BETWEEN ? AND ?,配合 COMMIT 释放锁

覆盖索引能绕过回表,但要注意 ORDER BYGROUP BY 的字段顺序

覆盖索引(using index)确实快,但 EXPLAIN 显示 Extra: Using filesortUsing temporary 时,说明排序/分组没走索引,还是得临时表+磁盘排序。比如 INDEX(a,b,c) 支持 WHERE a=1 ORDER BY b,但不支持 WHERE a=1 ORDER BY c —— 因为 c 不在 b 后连续有序。

实操建议:

  • EXPLAIN FORMAT=jsON SELECT ...

    查看 used_columnskey_parts,确认是否真覆盖

  • GROUP BY 字段必须是索引最左前缀,且不能有函数包装,GROUP BY YEAR(created_at) 就没法用 created_at 索引
  • 宽表场景下,宁可多建几个精简索引(如 (a,b), (a,c)),也别一个 (a,b,c,d,e) 五列索引——维护成本高,且 WHERE a=1 AND c=2 还是用不上

索引和事务优化不是调几个参数就能一劳永逸的事。真正卡点往往藏在「主键类型和业务查询模式不匹配」「长事务没设超时」「以为加了索引就万事大吉却忽略排序字段顺序」这些细节里。上线前拿真实慢查日志跑一遍 EXPLAIN,比看一百篇理论有用。

text=ZqhQzanResources