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

WHERE字段无索引会导致全表扫描并加next-key lock,大量无关行被锁,引发高并发更新卡死;必须为查询条件列建立合适索引,避免函数操作、优化索引顺序,并定期清理无效索引。

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

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

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

  • 必须确保所有 WHEREJOINORDER BYGROUP 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 会在插入过程中对整个聚簇索引间隙加锁,多个事务争抢同一间隙时极易死锁。

迅易年度企业管理系统开源完整版

迅易年度企业管理系统开源完整版

系统功能强大、操作便捷并具有高度延续开发的内容与知识管理系统,并可集合系统强大的新闻、产品、下载、人才、留言、搜索引擎优化、等功能模块,为企业部门提供一个简单、易用、开放、可扩展的企业信息门户平台或电子商务运行平台。开发人员为脆弱页面专门设计了防刷新系统,自动阻止恶意访问和攻击;安全检查应用于每一处代码中,每个提交到系统查询语句中的变量都经过过滤,可自动屏蔽恶意攻击代码,从而全面防止SQL注入攻击

下载

  • 必须为 ON DUPLICATE KEY 的判断字段建立 UNIQUEPRIMARY KEY 约束,否则无法精准定位冲突行,锁范围不可控
  • 避免在同一个语句里同时更新多个唯一键字段,例如 ON DUPLICATE KEY UPDATE a = VALUES(a), b = VALUES(b)ab 都是唯一键,会触发多次唯一性检查和锁
  • 高频并发写入时,可考虑把唯一约束从 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 BYGROUP 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 很低的,优先排查是否冗余

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

https://www.php.cn/faq/2034667.html

发表回复

Your email address will not be published. Required fields are marked *