mysql并发操作中如何设计合理索引_mysql优化实践

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

为什么
WHERE
条件字段没加索引会导致并发更新卡死

高并发下执行

UPDATE t SET status = 1 WHERE user_id = 123
,如果
user_id
没有索引,MySQL 会走全表扫描,每行都加
next-key lock
(间隙锁 + 行锁),导致大量无关行被锁住,其他事务一碰就
Lock wait timeout exceeded
。这不是性能慢,是直接阻塞。

必须确保所有
WHERE
JOIN
ORDER BY
GROUP BY
中出现的列,至少被某个联合索引的最左前缀覆盖
EXPLAIN FORMAT=TREE
看执行计划,确认
key
列非
NULL
,且
rows_examined
接近匹配行数,而非表总行数
避免在索引列上做函数操作,比如
WHERE DATE(create_time) = '2024-01-01'
会让索引失效;改用
WHERE create_time >= '2024-01-01' AND create_time 

联合索引字段顺序怎么排才不浪费锁范围

并发更新常带多个条件,比如

UPDATE order SET paid_at = NOW() WHERE user_id = 1001 AND status = 'unpaid' AND created_at > '2024-05-01'
。索引顺序错,可能让锁住的间隙远超必要范围。

等值查询字段放最左(如
user_id
),因为 B+ 树能快速定位到具体子树
范围查询字段(如
created_at > ...
)必须放最后,否则后续字段无法被索引使用
status
是低基数字段(只有 'unpaid'/'paid'/'cancelled'),放在中间或末尾都行,但别放最左——否则索引区分度太低,优化器可能弃用
推荐索引:
INDEX idx_user_status_created (user_id, status, created_at)

唯一性约束和
INSERT ... ON DUPLICATE KEY UPDATE
怎么避免死锁

秒杀场景常用

INSERT INTO stock (item_id, qty) VALUES (101, -1) ON DUPLICATE KEY UPDATE qty = qty - 1
,若
item_id
只有主键、没单独建
UNIQUE INDEX
,MySQL 会在插入过程中对整个聚簇索引间隙加锁,多个事务争抢同一间隙时极易死锁。

必须为
ON DUPLICATE KEY
的判断字段建立
UNIQUE
PRIMARY KEY
约束,否则无法精准定位冲突行,锁范围不可控
避免在同一个语句里同时更新多个唯一键字段,例如
ON DUPLICATE KEY UPDATE a = VALUES(a), b = VALUES(b)
a
b
都是唯一键,会触发多次唯一性检查和锁
高频并发写入时,可考虑把唯一约束从
UNIQUE KEY (a,b)
拆成
UNIQUE KEY (a)
+ 应用层校验
b
,减少索引维护开销

什么时候该删索引而不是加索引

每多一个索引,

INSERT/UPDATE/DELETE
就得多维护一份 B+ 树,尤其在写多读少的并发场景下,索引可能成为瓶颈本身。常见误判是“反正加了不慢,留着备用”。

SELECT * FROM sys.schema_unused_indexes
(MySQL 8.0+)或解析
performance_schema.table_io_waits_summary_by_index_usage
找长期未被使用的索引
删除前确认:该索引是否只被
ORDER BY
GROUP BY
单独使用?如果是,且对应 SQL 并发量极低,大概率可删
特别警惕
prefix index
(如
INDEX idx_name (name(10))
):如果实际查询中经常用
WHERE name = 'xxxlongstring'
,前 10 字符重复率高,这个索引几乎无效,还拖慢写入
SHOW INDEX FROM orders;
-- 看 Key_name、Seq_in_index、Cardinality 列
-- Seq_in_index=1 且 Cardinality 很低的,优先排查是否冗余

索引不是越多越好,而是让每个锁尽可能窄、每次查找尽可能准。很多并发问题表面是锁等待,根子在索引没切中查询的真实边界。

相关推荐