索引并非万能,函数、隐式转换、OR 多非索引字段均致失效;应使用 EXPLAIN 检查执行计划,避免在索引列上运算,改用范围查询替代函数操作。

为什么加了索引查询还是慢
索引不是万能的,WHERE 条件里用了函数、类型隐式转换、或 OR 连接多个非索引字段,都可能导致索引失效。比如 WHERE YEAR(created_at) = 2024,MySQL 无法用 created_at 的索引;又比如 WHERE user_id = '123'(user_id 是 INT),触发隐式转换,也可能跳过索引。
实操建议:
- 用
EXPLAIN看type是否为ref/range,key是否命中预期索引,rows是否明显偏大 - 避免在索引列上做计算或函数操作;改写为
WHERE created_at >= '2024-01-01' AND created_at - 字符串比较务必保证类型一致:
user_id是INT,就传整数,别传字符串 - 多个
OR条件尽量拆成UNION或改用IN(前提是语义等价)
UPDATE/DELETE 没加 WHERE 或条件太宽会怎样
这类语句在开发环境可能“能跑”,但上线后可能锁表、拖垮主从延迟、甚至误删全量数据。尤其在 InnoDB 中,UPDATE 若未命中索引,会升级为表级间隙锁,阻塞其他写入。
实操建议:
- 所有线上 DML 必须先用
SELECT COUNT(*)验证条件范围,确认行数合理再执行 - 强制要求
WHERE中至少有一个高选择性索引字段,且该索引已存在 - 在应用层封装写操作时,加默认限制(如
LIMIT 1000),并记录被截断的 warning - 运维侧配置
sql_safe_updates=1(MySQL),可阻止无WHERE或无键条件的UPDATE/DELETE
长事务导致主从延迟和锁堆积
一个跑了 5 分钟的事务,不仅持有行锁/间隙锁不放,还会让 binlog 日志积压,从库重放滞后,监控里 Seconds_Behind_Master 突增,还可能触发 innodb_lock_wait_timeout 报错。
本版升级功能:1、增加“系统参数设置”功能,可在线管理编辑全站数据库路径、备份路径,无须到程序代码下更改;2、改进后台管理员权限分配问题,严谨、完善、安全的根限分配细分到每个功能页面的列表查看权限、添加权限、编辑权限、删除权限都可以在线分配,确保系统在多用户管理下,安全稳定运行;3、更新优化数据库操作,在线备份、压缩、恢复数据库,管理登录日志;4、增加&am
实操建议:
- 业务逻辑中拆分大事务:比如批量更新 10 万条,改成每次 1000 条 +
COMMIT,中间加毫秒级休眠防抖 - 查
information_schema.INNODB_TRX定期抓取运行超 30 秒的事务,自动告警 - 避免在事务里做 RPC 调用、文件读写、sleep 等外部耗时操作
- 设置会话级超时:
SET innodb_lock_wait_timeout = 10,比全局值更可控
没做归档,历史数据膨胀拖慢所有查询
订单表三年积累 2 亿行,即使加了索引,SELECT 扫描成本也远高于 200 万行的表。更麻烦的是,ANALYZE TABLE 变慢、备份时间翻倍、DDL 变得不敢动。
实操建议:
- 按时间维度分区(如
PARTITION BY RANGE (TO_DAYS(created_at))),方便快速DROP PARTITION - 冷数据迁移走后,用
CREATE TABLE ... SELECT构建只读归档库,业务查历史数据走归档库 - 关键表必须定义生命周期策略:比如订单完成 90 天后转入归档,180 天后仅保留摘要
- 禁止直接
DELETE FROM huge_table WHERE ...;改用分批DELETE+pt-archiver工具控制节奏
真正难的不是写出能返回结果的 SQL,而是让这条 SQL 在数据量翻十倍、并发涨五倍、字段加三列之后,依然不报警、不锁表、不拖慢监控。这些细节藏在 EXPLAIN 的 key_len 里,在 INFORMATION_SCHEMA 的 TRX_STATE 里,在凌晨三点的慢查日志滚动窗口里。









