PHP MySQL报表查询优化求助:多表关联查询耗时10秒
多表关联查询性能优化:从10秒到毫秒级的排查思路
嘿,看起来你在多表报表查询的性能上遇到了大麻烦——10秒的响应时间完全没法接受,而且加了索引没见效,这说明问题可能出在索引策略不对或者查询逻辑设计不合理上。我来帮你一步步拆解:
一、先确认索引是不是真的在干活
你说加了部分字段索引但没改善,先别着急加更多索引,先搞清楚这些索引有没有被查询实际用到:
- 给你的查询语句前面加
EXPLAIN执行,看输出结果里的type列:如果是ALL,说明数据库在做全表扫描,你的索引根本没生效;key列会显示实际用到的索引,如果是空的,那就是索引没被命中。 - 检查索引字段的使用场景:如果索引字段被函数包裹(比如
DATE(create_time) = '2024-01-01')、用了不等于(!=)、或者模糊查询用了前缀通配符(%abc),都会直接导致索引失效。 - 多表关联时,关联字段的数据类型必须完全一致(比如主表是
INT(11),关联表也得是INT(11),不能一个是INT一个是VARCHAR),类型不匹配会让数据库放弃使用索引。
二、优化“满足条件则跳过”的筛选逻辑
你提到的“其余查询用于筛选,满足则跳过”,这种逻辑很容易写成NOT EXISTS或者NOT IN,但这两种写法在数据量大的时候性能极差——数据库会反复扫描子查询的表,越查越慢。
推荐替换方案:用LEFT JOIN + IS NULL替代NOT EXISTS/NOT IN
举个例子,如果你原来的查询是这样的:
SELECT * FROM main_table m WHERE NOT EXISTS (SELECT 1 FROM filter_table1 f1 WHERE m.id = f1.main_id AND f1.status = 'skip') AND NOT EXISTS (SELECT 1 FROM filter_table2 f2 WHERE m.id = f2.main_id AND f2.type = 'exclude')
改成LEFT JOIN的写法:
SELECT m.* FROM main_table m LEFT JOIN filter_table1 f1 ON m.id = f1.main_id AND f1.status = 'skip' LEFT JOIN filter_table2 f2 ON m.id = f2.main_id AND f2.type = 'exclude' WHERE f1.main_id IS NULL AND f2.main_id IS NULL
这种写法让数据库只需要扫描一次关联表,性能会提升很多。
三、你的报表HTML转Markdown格式
你提供的报表HTML可以转换成更简洁易读的Markdown表格(补充完整表头字段即可使用):
List of Outstandings
| # | 字段1 | 字段2 | 字段3 | ... |
|---|---|---|---|---|
| 1 | 数据1 | 数据1 | 数据1 | ... |
| 2 | 数据2 | 数据2 | 数据2 | ... |
四、其他快速优化点
- 分页查询:如果报表数据量很大,别一次性返回所有结果,用
LIMIT 0, 20这样的分页语句,配合前端分页,能瞬间把响应时间压下来。 - 缓存常用数据:检查数据库的内存缓存配置(比如MySQL的
innodb_buffer_pool_size),确保常用的表数据能缓存在内存里,减少磁盘IO的开销。 - **避免SELECT ***:只查询你需要的字段,别用
SELECT *,减少数据传输和内存占用。
内容的提问来源于stack exchange,提问作者Hemin
相关产品推荐
相关产品推荐

