根本原因是think_log表缺少create_time字段索引,导致时间范围查询全表扫描;应为其添加普通索引,并用EXPLAIN验证执行计划是否生效。

为什么 think_log 表查响应时间总在 2s 以上
根本原因不是日志量大,而是默认没建索引,SELECT * FROM think_log WHERE create_time > ? ORDER BY id DESC LIMIT 20 这类查询每次全表扫描。尤其当表超 50 万行后,create_time 和 id 都没索引,MySQL 只能靠文件排序 + 全表扫,I/O 和 CPU 双吃紧。
实操建议:
- 必须给
create_time加普通索引(不是唯一索引),这是最常用于时间范围筛选的字段 - 如果常用
ORDER BY id DESC+LIMIT分页,且id是自增主键,那无需额外建索引;但如果查询里混用了WHERE status = ? AND create_time > ?,就得建联合索引(status, create_time) - 避免对
content或trace这类 TEXT 字段建索引——没意义还拖慢写入
如何验证当前日志表有没有生效索引
别只看 SHOW CREATE TABLE think_log 输出里有没有 KEY,得看执行计划是否真走索引。直接跑一条典型查询加 EXPLAIN:
EXPLAIN SELECT * FROM think_log WHERE create_time > '2024-01-01' ORDER BY id DESC LIMIT 20;
重点看三列:
立即学习“PHP免费学习笔记(深入)”;
-
type:要是range或ref,说明走了索引;如果是ALL,就是全表扫 -
key:显示实际用到的索引名,为空就等于没走 -
rows:扫描行数,比总行数小一个数量级才算有效(比如表有 100 万行,这里显示 8000 才算合理)
ThinkPHP 日志驱动配置里哪些参数会放大无索引问题
默认 File 驱动写日志快,但切换成 Db 驱动后,如果没调优,反而让查询雪上加霜。关键在两个地方:
-
level配置太宽泛(比如留着['error', 'info', 'sql']),导致日志表膨胀极快,索引失效概率上升 -
realtime_write设为true(默认),每条日志都触发一次 INSERT,高并发下写入锁竞争加剧,间接拖慢后续查询 -
log_table如果没显式指定,TP 会用默认表名,但你手动建索引时可能忘了对应到这个表,结果白优化
加索引后为什么某些查询还是慢
加了 create_time 索引,但 SELECT COUNT(*) FROM think_log WHERE create_time > '2024-01-01' 依然卡,大概率是 MySQL 统计信息过期或索引选择性差。这时候不能硬扛:
- 执行
ANALYZE TABLE think_log强制更新统计信息,让优化器重估索引价值 - 如果
create_time大量重复(比如秒级精度、批量导入),单列索引效果弱,换成(create_time, id)联合索引更稳 - 注意 MySQL 版本:8.0+ 对 JSON 字段支持更好,但 ThinkPHP 日志若存了完整
$_SERVER到data字段,又没建函数索引,WHERE JSON_CONTAINS(data, '"POST")这类查询永远没法走索引
索引不是银弹,真正卡住的点往往藏在「你以为它走了索引」和「explain 显示它没走」之间的那层认知差里。



















