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

来源:这里教程网 时间:2026-02-28 20:44:17 作者:

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
,比看一百篇理论有用。

相关推荐