数据库索引缺失查询缓慢批量优化:MySQL索引缺失导致查询慢

MySQL索引缺失导致查询慢?批量检测与优化完整指南

问题背景与适用场景

当你的网站或应用出现页面加载慢、数据库CPU升高、慢查询日志大量记录时,索引缺失是最常见的原因之一。
MySQL索引就像书的目录,没有索引,查询会全表扫描,数据量越大越慢。
本文围绕“数据库索引缺失查询缓慢批量优化”这一核心需求,教你使用SQL脚本批量检测缺失索引,并自动生成创建语句,适用于MySQL 5.7及以上版本(含MariaDB 10.3+)。

前置准备:你需要知道的几个前提

  • 数据库权限:至少需要 SELECTCREATE INDEXALTER 权限。建议准备一个具有读写权限的账号(如root或拥有SUPER权限的用户)。
  • 确认查询慢的来源:可以通过 SHOW FULL PROCESSLIST 或开启慢查询日志定位高耗时语句。使用宝塔面板的用户可进入「数据库」→「慢查询」查看。
  • 备份数据:对大表添加索引可能短暂锁表,建议先在低峰期操作,或先对生产库创建副本测试。

核心步骤:批量检测与生成索引创建语句

1. 开启 MySQL 的 sys schema(推荐)

MySQL 5.7.7+ 默认自带 sys 库,它提供了视图 schema_unused_indexesschema_index_statistics
执行以下SQL查询当前库中没有被使用的索引(即可能缺失的反面):

SELECT * FROM sys.schema_unused_indexes WHERE object_schema NOT IN ('mysql', 'sys', 'performance_schema', 'information_schema');

这个查询会显示未被使用的索引,它们可以安全删除。
但我们更需要发现“应该存在但缺失”的索引。

2. 利用慢查询日志确定缺失索引的候选列

如果你有慢查询日志,提取出 WHERE 条件、JOIN 关联字段和 ORDER BY 列。
假设慢查询如下:

SELECT * FROM orders WHERE user_id = 123 ORDER BY created_at;

那么 user_idcreated_at 就是需要索引的候选列。

3. 批量生成缺失索引的创建语句

手动检查每个表太慢。
我们可以使用 information_schema 写一个脚本来根据字段名模式批量生成索引创建语句。
注意:此脚本只是个起手模板,请根据实际慢查询涉及的字段调整。

SELECT 
    CONCAT('ALTER TABLE `', TABLE_SCHEMA, '`.`', TABLE_NAME, '` ADD INDEX `idx_', COLUMN_NAME, '` (`', COLUMN_NAME, '`);') AS create_index_sql
FROM 
    information_schema.COLUMNS
WHERE 
    TABLE_SCHEMA NOT IN ('mysql', 'sys', 'performance_schema', 'information_schema')
    -- 这里替换成你要检查的字段名,例:'user_id', 'created_at', 'status'
    AND COLUMN_NAME IN ('user_id', 'created_at', 'status')
    -- 排除已经存在索引的字段(可选,需要多表查询,这里简化)
ORDER BY 
    TABLE_SCHEMA, TABLE_NAME, ORDINAL_POSITION;

运行后会输出类似 ALTER TABLE db1.orders ADD INDEX idx_user_id (user_id); 的一系列语句。
你可以先复制保存到文本文件,复查再执行。

4. 安全执行批量创建(推荐低峰期)

  • 对于小表(< 10万行):直接逐条执行上述 ALTER 语句。
  • 对于大表(> 100万行):使用工具 pt-online-schema-change(Percona Toolkit)在线添加索引,避免锁表。如果无法安装该工具,可以在业务低峰期直接执行,并在执行前设置 lock_wait_timeout 为较小值避免长等待。

效果验证:如何确认索引生效

执行添加索引后,用原慢查询SQL加上 EXPLAIN 前缀:

EXPLAIN SELECT * FROM orders WHERE user_id = 123 ORDER BY created_at;

检查 type 列是否从 ALL(全表扫描)变为 refrange,并且 possible_keyskeys 列出现你新建的索引名。
同时 rows 列估算的行数会大幅降低。

避坑指南与常见问题

❌ 不要一次性对多个大表加索引

在MySQL 5.7下,ALTER TABLE 会重建表,导致源表被锁(只读)。
对于百万级表,建议分批执行,每次间隔10分钟以上。

❌ 不要盲目为所有字段加索引

索引虽然加速查询,但会减慢写入(INSERT/UPDATE/DELETE)。
只对 WHEREJOINORDER BY 中的高频列加索引。

✅ 如何批量删除无效索引?

用第一步 sys.schema_unused_indexes 查出未使用的索引,然后使用 DROP INDEX 删除。
删除也会短暂锁表,同样建议低峰期操作。

❓ 为什么我创建的索引没被使用?

  • 查询中使用了函数包裹字段,如 WHERE DATE(created_at)=...,索引失效。请改写为范围查询。
  • 联合索引顺序不对:需遵循最左前缀原则。
  • 数据量太小:MySQL 可能认为全表扫描更快。

FAQ

Q1:我没有 sys 库怎么办?
A:可使用 performance_schema + information_schema 手动统计;或安装第三方工具 mytop 监控。

Q2:添加索引时提示 Duplicate key name
A:该字段已有同名索引。可以先用 SHOW INDEX FROM table_name 查看已有索引,避免重复创建。

Q3:批量操作时数据库卡死怎么办?
A:立即 KILL 执行中的 ALTER 线程(SHOW PROCESSLISTKILL ID)。建议使用 pt-online-schema-change 或先在测试环境演练。

Q4:我用的宝塔面板,怎么查看慢查询?
A:宝塔面板 → 左侧“数据库” → 选择对应数据库 → 点击“慢查询” → 开启慢查询日志后即可看到执行超过 long_query_time 秒的SQL。

---

完成以上步骤后,你可以明显感受到查询速度的提升。
如果仍有疑问,欢迎继续查阅相关优化教程。
记住:索引优化是持续过程,建议定期(如每月)检查一次慢查询,让优化形成习惯。

分享到:
上一篇
iptables防火墙批量拦截恶意扫描IP地址实操教程
下一篇
爬虫IP黑名单自动拦截恶意抓取:服务器运维实战教程
1
系统公告

机房迁移升级通知

尊敬的用户: IP 段 103.23.148.x、156.224.29.x 原香港一区线路波动、攻击频繁,平台定于 7 月 5 日凌晨分批迁移至香港 GIA 机房,硬件升级 AMD 铂金机型。 迁移均在凌晨操作,最大程度降低业务影响,迁移期间服务器临时关机; 升级后配置不降低、费用不涨价,数据默认同步迁移; 迁移后 IP 全部更换,请及时修改域名解析、防火墙白名单; 建议提前备份重要数据,有问题可联系在线客服。 感谢理解与支持! 泽御云科技 2026.06.30
服务中心
客服
在线客服
24小时为您服务
咨询
联系我们
联系我们,为您的业务提供专属服务。
24/7 技术支持
如果您遇到寻求进一步的帮助,请过工单与我们进行联系。
24/7 即时支持
泽御云
售前客服
泽御云
泽御云
售后客服
泽御云
技术支持
评价
您对当前页面的整体感受是否满意?
😞
非常不满意
😕
不满意
😐
一般
🙂
满意
😊
非常满意