MySQL 实战调优& 分表基础

索引失效场景复盘 + 项目规范

索引失效场景复盘

5 类索引失效场景+项目约束

索引列使用函数、运算、隐式类型转换
  • 原理:索引存储的是原始字段值,运算后值发生变化,无法匹配索引树
  • 错误示例:where substr(phone,1,3)='138'where phone = 13800000000(字符串手机号不加数字引号,隐式转换)
  • 项目规范:手机号、status、template_id 禁止在条件中做运算、截取
左模糊 / 全模糊 like 查询 like '%xxx' / like '%xxx%'
  • 原理:B + 树前缀有序,后缀匹配无法走索引
  • 业务方案:模糊检索手机号切换 ES 倒排索引;MySQL 仅允许like '138%'右模糊
or 条件一侧字段无索引
  • 原理:or 只要有一个条件无法走索引,整体触发全表扫描
  • 规范:or 关联的所有字段统一建索引,复杂多条件拆分多条 SQL 合并结果
联合索引跳过最左前置字段(违背最左匹配)
  • 示例:联合索引(template_id,status,create_time) 失效写法:where status=0,跳过首位 template_id
  • 强制规范:后台查询短信记录必须携带 template_id
数据倾斜,优化器主动放弃索引
  • 场景:营销活动大量数据 status=0 待发送,符合条件数据占表绝大部分
  • 解决方案:force index 强制指定索引、按时间拆分查询范围缩小数据量

总结:所有查询条件操作索引字段时,保证原始值匹配、不做转换、不跳过联合索引首列,规避全表扫描慢 SQL。

深分页专项优化

深分页底层缺陷

语法 limit offset, size,offset 代表偏移量。 MySQL 执行逻辑:先扫描 offset + size 条数据,丢弃前面 offset 条,只返回后面 size 条。 当 offset 数值很大(如 limit 10000,10),会扫描大量无用数据,IO 开销极高,页面越往后翻查询越慢,短信记录千万级表分页卡顿严重。

三种落地优化方案

主键书签分页(最推荐)

利用自增主键 id 定位起点,不用偏移量。

示例:上一页最后一条 id=10000

sql 复制代码
select phone,template_id,status,create_time 
from sms_record 
where id > 10000 and status=0 limit 10

优势:直接走主键索引,无需扫描前置数据。

延迟关联

先只分页查询主键,再通过主键关联查询完整字段,减少回表开销。

sql 复制代码
select t1.* from sms_record t1
inner join (select id from sms_record where status=0 limit 10000,10) t2
on t1.id = t2.id;

业务层限制

前端限制最大可查询页码,不允许用户查询几万页之后的数据,从业务源头规避深分页。

项目规范补充

禁止使用 select * 分页,只查询页面需要字段,配合覆盖索引进一步提速。

冗余索引识别与清理规范

冗余索引定义

如果已经存在联合索引 (a,b,c),那么单独建立的索引 (a) 就属于冗余索引。 联合索引最左匹配原则,(a,b,c) 本身就能单独命中 a 字段查询,额外建单列 a 索引完全重复,无作用。

短信项目实例

我们给短信记录表建立联合索引:(template_id, status, create_time) 如果再单独创建索引 (template_id),这条单列索引就是冗余索引。 因为仅根据 template_id 查询时,联合索引已经可以满足需求。

联合索引:(template_id, status)

单独创建 (template_id) 单列索引属于冗余索引。

仅按 template_id 查询时,联合索引首字段即可满足查询,单列索引完全多余

索引过多、冗余索引带来的业务负面影响(短信营销场景)

  1. 拖慢写入性能:批量下发短信大量执行 insert,新增 / 修改数据时,所有索引都要同步更新,冗余索引会增加 IO 开销,降低发送吞吐;
  2. 占用磁盘空间:千万级短信记录表,多余索引会持续膨胀磁盘占用;
  3. 增加 SQL 解析耗时:MySQL 优化器需要遍历全部索引匹配最优方案,索引越多,筛选耗时越长

线上运维规范

定期工具查询冗余索引,在业务低峰期清理无用、冗余索引,平衡查询与写入性能。

大表分表实战方案

水平分表(按数据行拆分)

  1. 拆分逻辑 同一张表结构不变,按照某一列规则,把数据分散到多张子表,每张表存储一部分数据。
  2. 短信项目落地:按月拆分
  • 表命名:sms_record_202607sms_record_202608
  • 路由规则:根据短信create_time创建月份,MyBatis-Plus 动态表名插件自动匹配对应分表
  1. 优势 单表数据量可控,索引体积变小,查询、写入速度大幅提升。

垂直分表(按字段拆分)

  1. 拆分逻辑 把一张宽表,拆分为两张表,主键一致,冷热字段分离。 短字段做主表,大文本、低频读取字段做附表。
  2. 短信项目落地
  • 主表 sms_record:id、phone、template_id、status、create_time(短字段,页面常用)
  • 附表 sms_record_detail:record_id、sms_content、third_callback(短信内容、第三方回执大文本)
  1. 优势 减少单条数据存储体积,降低磁盘 IO,列表查询不需要加载大字段。

分表衍生问题配套解决方案

  1. 跨月分页、跨月统计麻烦 近 3 个月热数据直接查分表;半年以上冷数据归档至独立归档库。
  2. 报表统计复杂 通过定时任务预聚合发送量、成功失败量,存入 Redis 缓存,前端报表直接读缓存。

冷热数据分离配套方案

  • 热数据:近 3 个月短信记录,存按月分表,支持实时查询;
  • 冷数据:半年以上历史数据,归档归档库,不参与日常分页查询。

慢 SQL 线上排查流程

完整排查五步流程(短信报表超时场景标准流程)

  1. 开启慢查询日志捕获慢 SQL 运维提前配置 MySQL 慢日志:设置超时阈值(如 1s),自动记录所有执行超时、全表扫描的 SQL,短信报表、列表慢语句都会被日志捕获。
  2. 从慢日志定位超时 SQL 筛选接口对应执行耗时高、扫描行数巨大的目标 SQL。
  3. 使用 explain 分析执行计划 解析 SQL 索引使用、扫描行数、额外性能隐患,重点观察两处风险:
    • type=ALL:代表全表扫描,无有效索引;
    • Extra 字段出现 Using filesort / Using temporary,是严重性能损耗点。
  4. 针对性优化 SQL / 索引
    • 出现Using filesort:给排序字段 create_time 建立联合索引,避免磁盘排序;
    • 出现Using temporary:拆分复杂 group by 统计 SQL,营销报表数据用定时任务预聚合存入 Redis;
    • 全表扫描:补充匹配业务条件的联合索引,规避索引失效场景。
  5. 本地压测验证优化效果 对比优化前后执行耗时,确认查询速度大幅下降后,再上线发布。

两个关键隐患标识详解

Using filesort 文件排序

SQL 存在 order by 排序,但没有覆盖索引,MySQL 需要在内存 / 磁盘排序,千万级表排序极慢。

优化方案:联合索引包含 where 筛选字段 + 排序字段。

Using temporary 临时表

group by、distinct 多字段分组时,MySQL 创建临时表存放中间数据,占用大量内存 / 磁盘,报表统计极易触发。

优化方案:拆分复杂统计、预聚合数据缓存。

短信项目应急方案(活动高峰期报表阻塞)

活动期间临时下线实时报表,通过定时任务提前统计发送总量、成功率存入 Redis,前端直接读取缓存,避免大量慢 SQL 并发拖垮数据库。

相关推荐
万亿少女的梦1681 小时前
基于Spring Boot的游戏交易管理系统设计与实现
java·spring boot·mysql·系统设计·交易管理
Database_Cool_1 小时前
云数据库如何保证高可用、故障了怎么办:阿里云 RDS MySQL 高可用架构详解
数据库·mysql·阿里云
中微极客2 小时前
Veo视频生成与Gemini Agent平台集成实践
数据库·人工智能·oracle·音视频
Mem0rin2 小时前
[MySQL] 聚合函数、分组查询、连接查询
android·mysql
一棵星2 小时前
内网 MySQL 表结构一键导出 Word 文档:直连 + Agent 双模式实战
数据库·mysql·word
向日的葵0063 小时前
Redis会话机制vsJWT机制深度解析
数据库·redis·python·缓存·系统架构·jwt
bosins3 小时前
如何配置SQL Server数据库定时自动备份
数据库
烟雨归来3 小时前
RAC数据库OS进程消失,GV$SESSION长期残留KILLED僵尸会话处理
数据库·oracle
小龙报4 小时前
【优选算法】1. 水果成蓝 2.找到字符串中所有字母的异位词
java·c语言·数据结构·数据库·c++·redis·算法