MyISAM 不支持事务,别在它上面硬套 ACID 场景
如果业务需要
ROLLBACK、
SAVEPOINT或强一致性读,直接排除
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;
MyISAM的
SELECT COUNT(*)很快,但
InnoDB需要扫聚簇索引——如果只是统计总数且不介意小延迟,加个缓存字段或定时任务更新更稳
InnoDB 的主键设计直接影响二级索引大小和查询效率
InnoDB的二级索引叶子节点存的是主键值,不是行地址。所以主键越短、越稳定,二级索引占用空间越小,范围扫描和回表成本越低。常见错误是用
VARCHAR(255)UUID 做主键:不仅索引体积翻倍,还导致插入时频繁页分裂。
实操建议:
优先用自增BIGINT或
INT;若需分布式 ID,考虑
ULID或时间前缀+序列组合,避免纯随机字符串 联合主键慎用——除非业务天然有不可拆分的复合唯一约束,否则容易让
WHERE条件无法命中最左前缀 已有大主键表想优化?可新增隐藏自增列
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY FIRST,再重建主键,但要注意外键和应用层引用是否同步改
事务中不要混用 SELECT ... FOR UPDATE
和非事务语句
在
AUTOCOMMIT=1下执行
SELECT ... FOR UPDATE,MySQL 会隐式开启事务,但很多人忘了显式
COMMIT或
ROLLBACK,导致锁一直挂着,后续
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 BY
和 GROUP BY
的字段顺序
覆盖索引(
Using index)确实快,但
EXPLAIN显示
Extra: Using filesort或
Using temporary时,说明排序/分组没走索引,还是得临时表+磁盘排序。比如
INDEX(a,b,c)支持
WHERE a=1 ORDER BY b,但不支持
WHERE a=1 ORDER BY c—— 因为
c不在
b后连续有序。
实操建议:
用EXPLAIN FORMAT=JSON SELECT ...查看
used_columns和
key_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,比看一百篇理论有用。
