type=all表示mysql执行全表扫描,是性能严重劣化的明确信号;需结合key(是否为null)、rows(是否接近总行数)和extra(是否含using where)综合判断,常见原因包括隐式类型转换、索引字段使用函数、复合索引顺序错配及优化器成本估算放弃索引。

EXPLAIN 是怎么看的,不是只看有没有索引
EXPLAIN 输出里 type=ALL 是最该警觉的信号,但它不等于“没建索引”——可能是索引没被选中,也可能是查询条件触发了隐式转换。比如 WHERE tradeofferid = ?,但字段是 VARCHAR(64),而传入的是整数,MySQL 会自动转成字符串再比对,导致索引失效。
重点关注三列:type(访问类型)、rows(预估扫描行数)、key(实际使用的索引)。如果 rows 是 240000 却只返回 5 行,哪怕 key 显示用了索引,也是无效覆盖。
- 复合索引顺序必须匹配 WHERE 条件顺序:
WHERE a = ? AND b = ?建(a, b),反过来就用不上 -
ORDER BY created_at DESC想走索引,要么单独建idx_created_at (created_at),要么把created_at放在复合索引最右位 - LIKE 查询要前缀匹配才走索引:
name LIKE 'go%'可以,name LIKE '%go'不行
慢查询日志为什么没记录,Go 程序不背这个锅
Go 应用本身不会生成慢查询日志,slow_query_log 和 long_query_time 是 MySQL 服务端配置项。你在 Go 里调 db.SetLogger 或开 GORM 的 LogMode,只记录“SQL 发了”,不记录它在数据库里执行了多久、扫了多少行。
先确认 MySQL 配置是否真生效:
- 登录 MySQL 执行
SHOW VARIABLES LIKE 'slow_query_log';,值必须是ON -
SHOW VARIABLES LIKE 'long_query_time';,开发环境建议设成0.1秒,别信默认的 10 秒 -
slow_query_log_file路径通常在/var/lib/mysql/xxx-slow.log,不是你的 Go 项目目录下 - MySQL 8.0+ 默认关闭慢日志,
SET GLOBAL是临时生效,必须写进/etc/mysql/my.cnf的[mysqld]段并重启服务
GORM 怎么真正捕获慢 SQL,不是光开 LogMode
只调 LogMode(true) 是无效的——它只打印 SQL,不计时。GORM 的慢查询检测靠 SlowThreshold,必须显式设置:
config := &gorm.Config{
SlowThreshold: 200 * time.Millisecond,
}
db, err := gorm.Open(mysql.Open(dsn), config)
这个阈值是 GORM 在驱动层打点测得的真实执行耗时,不是 Go 程序等待时间。注意它和 context.WithTimeout 完全无关:context 控制的是 Go 层超时,SlowThreshold 才反映 SQL 在 DB 里跑得多慢。
- 原生
database/sql没钩子机制,想监控真实耗时,得包装database/sql/driver.Conn,在Query/Exec方法里统一计时 - 外层套
time.Now()会漏掉网络往返和 DB 执行时间,测出来的是“从 Go 发出请求到拿到结果”的毛时间 - 如果用的是 pgx 或其他非标准驱动,GORM 的
SlowThreshold可能不生效,得查对应驱动是否支持Stats回调
连接池配置不当会让 EXPLAIN 和慢日志都失真
连接池参数错配会导致大量连接处于等待或空闲状态,掩盖真实 SQL 性能问题。比如 SetMaxOpenConns(5) 却有 50 QPS,大部分请求卡在获取连接上,你看到的“慢 SQL”其实是排队耗时,不是执行耗时。
关键参数要协同调:
-
SetMaxOpenConns(25):最大并发连接数,设太小会排队,太大可能压垮 DB -
SetMaxIdleConns(25):空闲连接上限,和MaxOpenConns相等可减少新建连接开销 -
SetConnMaxLifetime(5 * time.Minute):避免长连接因网络抖动僵死,但别设太短(如 30 秒),否则频繁重建连接 - 务必调
db.Ping()验证连接池是否连得上,否则后续所有分析都是空中楼阁
真正难的不是看懂 EXPLAIN,而是确保你分析的那个 SQL,是在一个干净、稳定、符合生产流量特征的连接上下文中执行的——连接池一乱,整个性能归因就偏了。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











