Laravel DataTable仅2条数据却加载缓慢(含GROUP_CONCAT查询)
Laravel DataTable仅2条数据却加载缓慢(含GROUP_CONCAT查询)
嘿,我来帮你分析下这个问题~你的情况很典型,虽然只有2条数据,但GROUP_CONCAT加上多表关联的组合查询,大概率是缺少合适的数据库索引或者分组/关联逻辑导致数据库做了大量不必要的计算,咱们一步步来优化:
1. 优先检查并补充数据库索引
多表左连接+分组查询最吃索引,哪怕数据量小,没有索引的话数据库会做全表扫描,叠加起来就会变慢。建议给这些字段加索引:
- 主表
spareparts:id(主键应该已有,但确认下)、created_at、is_deleted、email - 关联表:
sparepart_products.sparepart_id(关联spareparts的外键)users.email(关联spareparts的字段)shipping_addresses.email(关联users的字段)kategori_produks.id(关联sparepart_products的外键)- 地址关联的
provinces.id、regencies.id、districts.id
示例SQL(可以直接在数据库执行,或者加到Laravel迁移文件):
ALTER TABLE sparepart_products ADD INDEX idx_sparepart_id (sparepart_id); ALTER TABLE users ADD INDEX idx_email (email); ALTER TABLE shipping_addresses ADD INDEX idx_email (email);
2. 简化GROUP BY与去掉冗余的DISTINCT
你当前的GROUP BY列了大量字段:
->groupBy('spareparts.id', 'shipping_addresses.full_address','r.name', 'd.name', 'p.name', 'regencies.name', 'districts.name', 'provinces.name')
如果spareparts.id是主键(唯一标识一条订单),理论上只需要按spareparts.id分组就足够了——主键唯一,其他关联字段应该和该主键一一对应,不需要额外加入分组。这样能大幅降低数据库分组计算的开销。
另外,->distinct()和GROUP BY功能重叠,分组本身就会去重,直接去掉这个调用即可。
3. 把格式化/拼接逻辑从数据库转移到PHP层
你在查询里用了大量DATE_FORMAT和CONCAT函数,这些函数会让数据库无法使用对应字段的索引,还会增加数据库的计算压力:
- 比如
DATE_FORMAT(spareparts.created_at,"%d-%m-%Y"),可以在查询时只查原始的created_at,然后在Laravel模型里加访问器做格式化:// 在Sparepart模型里 public function getOrderDateAttribute() { return $this->created_at->format('d-m-Y'); } - 地址拼接同理,比如用户地址的
CONCAT(users.address, ', ', regencies.name, ...),可以在查询时单独取出各个地址字段,然后在模型或DataTable回调里拼接,把计算压力转移到PHP层面,减轻数据库负担。
4. 用EXPLAIN分析查询执行计划
找到慢查询的根本原因最直接的方式是看执行计划:
- 在控制器里开启查询日志,导出实际执行的SQL:
DB::enableQueryLog(); // 你的查询代码($spareparts部分) dd(DB::getQueryLog()); - 把导出的SQL拿到数据库里,用
EXPLAIN前缀执行:EXPLAIN SELECT ... -- 这里放你导出的完整SQL
看结果里的type列,如果是ALL说明是全表扫描,key列如果是空的说明没用到索引,针对这些点去优化即可。
5. 拆分复杂查询(可选)
如果多表关联实在太复杂,可以考虑拆分查询:
- 先查询
spareparts关联sparepart_products、users的核心数据(不带地址关联和GROUP_CONCAT) - 再单独查询地址信息,或者在DataTable的
addColumn回调里补充地址、拼接GROUP_CONCAT的内容
这种方式能降低主查询的复杂度,适合关联层级特别多的场景。
备注:内容来源于stack exchange,提问作者PinballWizard
相关产品推荐
相关产品推荐

