mysql高并发场景如何优化索引_mysql性能调优思路

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

为什么
SELECT *
会拖垮高并发查询

在高并发读场景下,

SELECT *
往往是索引失效的起点。它强制 MySQL 回表获取所有字段,即使只用到其中 1–2 个,也会放大 I/O 和锁竞争。更关键的是,覆盖索引(Covering Index)完全失效——只要查询字段没被索引“包住”,就无法避免回表。

实操建议:

把高频查询的
WHERE
条件字段 +
SELECT
中实际用到的字段,一起建联合索引,顺序按「等值查询字段在前、范围查询字段居中、排序/查询字段在后」排列
EXPLAIN
检查
Extra
列是否含
Using index
;若出现
Using where; Using index
,说明是覆盖索引
避免在索引列上做函数操作,例如
WHERE YEAR(create_time) = 2024
会让
create_time
索引失效,改用
WHERE create_time >= '2024-01-01' AND create_time 

ORDER BY
LIMIT
组合为何容易慢

高并发分页最典型的卡点:类似

SELECT * FROM order WHERE status = 1 ORDER BY created_at DESC LIMIT 10000, 20
。MySQL 仍需扫描前 10000 行才能跳过,索引虽能加速排序,但偏移量越大,回表成本越高。

实操建议:

用游标分页替代
OFFSET
:记录上一页最后一条的
created_at
id
,下一页查
WHERE status = 1 AND (created_at, id) 
确保
ORDER BY
字段在索引中连续且顺序一致;若混合 ASC/DESC,5.7+ 需显式声明,如
INDEX idx_status_ctime_id (status, created_at DESC, id DESC)
对写多读少的表,可考虑冗余一个
sort_order
整型字段,用触发器或应用层维护单调递增,让分页走主键范围扫描

唯一索引 vs 普通索引:高并发写入时怎么选

唯一索引在插入时必须做唯一性校验,会触发额外的

change buffer
合并或直接读页,尤其在二级索引未缓存时,随机 IO 显著上升。普通索引则允许延迟写入,吞吐更高。

实操建议:

业务层能保证唯一性(如订单号由雪花算法生成),就别在数据库加
UNIQUE
约束,用普通索引 + 应用重试兜底
若必须用唯一索引,把唯一字段尽量前置到联合索引最左,减少校验范围;例如
(order_no, user_id)
(user_id, order_no)
更利于快速定位冲突
监控
Innodb_buffer_pool_reads
Innodb_buffer_pool_read_requests
比值,若 > 1%,说明缓冲池命中率低,大量唯一校验被迫走磁盘

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

索引不是越多越好。每个新增索引都会拖慢

INSERT/UPDATE/DELETE
,因为要同步更新 B+ 树;更隐蔽的问题是:多个相似索引(如
(a)
(a,b)
(a,b,c)
)会导致优化器选错执行计划,或因统计信息不准引发全表扫描。

实操建议:

sys.schema_unused_indexes
视图(MySQL 5.7+)或
performance_schema.table_io_waits_summary_by_index_usage
找长期未被使用的索引
检查
SHOW INDEX FROM tbl
Cardinality
极低(如
删除前先用
pt-duplicate-key-checker
工具识别冗余索引,比如已有
(user_id, status)
,再建
(user_id)
就是多余

真正难的不是加索引,是判断哪些查询不该走索引——比如日志类表的

LIKE '%keyword%'
查询,强行加全文索引或改用 Elasticsearch 更实际。索引只是手段,不是目的。

相关推荐