
数据库统计查询慢,核心问题往往不在 PHP 代码本身,而在于 SQL 设计、索引策略和数据访问模式。优化重点应放在减少扫描行数、避免临时表与文件排序、合理利用聚合计算位置(数据库端 vs 应用端)。
精准建索引,覆盖统计条件与分组字段
统计类查询(如 COUNT()、SUM()、GROUP BY)对索引敏感度极高。若 WHERE 条件含 status = 1,且按 category_id 分组求和,理想索引应为:
-
INDEX(status, category_id, amount)—— 前两列支撑过滤+分组,最后一列让索引“覆盖”查询,无需回表取值 - 避免仅对单字段建索引(如只建
status),导致分组时仍需全索引扫描或临时表 - 用
EXPLAIN检查key是否命中、rows是否显著下降、Extra是否出现Using filesort或Using temporary
慎用 COUNT(*),优先考虑业务可接受的近似方案
全表或大范围 COUNT(*) 在 InnoDB 中需遍历索引树,开销大。可结合场景降级处理:
DESTOON B2B网站管理系统是一套完善的B2B(电子商务)行业门户解决方案。系统基于PHP+MySQL开发,采用B/S架构,模板与程序分离,源码开放。模型化的开发思路,可扩展或删除任何功能;创新的缓存技术与数据库设计,可负载千万级别数据容量及访问。
- 总记录数变化不频繁:用缓存(Redis)存储并定时异步更新,PHP 直接读缓存
- 只需“是否有数据”:改用
SELECT 1 FROM table WHERE ... LIMIT 1,查到即返回 - 分页总数非强一致:前端显示 “约 2000+ 条”,后端跳过精确 COUNT,或用采样估算(如
SELECT COUNT(*) * 10 FROM t TABLESAMPLE SYSTEM (10),MySQL 8.0.23+)
拆分复杂聚合,把计算压力留在数据库而非 PHP 循环
避免在 PHP 中查出大量明细再用 foreach 累加——网络传输、内存占用、执行时间三重浪费。
立即学习“PHP免费学习笔记(深入)”;
- 错误做法:
SELECT user_id, amount FROM orders WHERE date >= '2024-01-01'→ PHP 遍历求各用户 sum - 正确做法:
SELECT user_id, SUM(amount) FROM orders WHERE date >= '2024-01-01' GROUP BY user_id→ 数据库完成聚合,只返回几十行结果 - 多维度交叉统计(如按月+地区+品类):用
GROUP BY month, region, category一步到位,而非嵌套 PHP 循环构造二维数组
分区 + 归档,让统计范围自然缩小
历史数据占比高时,统计慢常因扫描了大量无效旧记录。通过数据生命周期管理减小扫描集:
- 按时间分区(如 MySQL RANGE 分区 on
created_at),使WHERE created_at > '2024-01-01'自动裁剪分区 - 将 1 年前订单归档至
orders_archive表,主表仅保留热数据,统计默认只查主表 - 业务允许延迟:凌晨跑定时任务,预计算日/周/月汇总表(如
stat_orders_daily),统计接口直接查汇总表










