You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

相同MySQL查询在Laravel中运行缓慢但phpMyAdmin中极快的优化问题

问题根因分析
  • phpMyAdmin默认自动追加分页限制:你在phpMyAdmin执行无LIMIT的查询时,工具默认会加LIMIT 25这类分页参数,实际只返回前几十条数据,所以耗时极低。你可以在phpMyAdmin的查询结果页底部看到「显示行 0 - 24 (总计 X 行, 查询花费 0.0030 秒)」,3ms是返回前25条的速度,你点击「显示所有」再执行查询,耗时就会和Laravel侧一致。
  • 排序对总耗时影响可以忽略:你去掉排序后Laravel耗时没有下降,是因为排序1900条数据的耗时不到10ms,占总耗时的比例极低,99%的耗时都集中在750万行大表的关联扫描环节。
  • 索引缺失导致全表扫描:你的关联查询没有匹配的联合索引,大表每次查询都要全表扫描,是耗时高的核心原因。
优化方案
  1. 先验证全量查询的实际耗时
    在phpMyAdmin执行查询时手动加SQL_NO_CACHE跳过查询缓存,同时加强制全量返回的LIMIT参数,绕开phpMyAdmin默认分页,确认真实耗时:
SELECT SQL_NO_CACHE `discounts`.`id`, `discounts`.`discount` 
FROM `discounts` 
LEFT JOIN `discount_companies_criteria` ON `discounts`.`id` = `discount_companies_criteria`.`discount_id` AND `discount_companies_criteria`.`is_active` = 1 
WHERE `discount_companies_criteria`.`company_id` IS NULL AND `discounts`.`status` = 1 
GROUP BY `discounts`.`id`
LIMIT 18446744073709551615;
  1. 添加联合索引避免全表扫描
    给750万行的大表建覆盖关联、过滤条件的联合索引,避免回表查询:
CREATE INDEX idx_dcc_discount_active_company ON discount_companies_criteria (discount_id, is_active, company_id);

同时给discounts表的status字段加索引(如果未添加):

CREATE INDEX idx_discounts_status ON discounts (status);

加索引后全量查询耗时会直接降到10ms以内。

  1. 优化查询逻辑提升效率
    你当前的逻辑是查找没有匹配活跃公司规则的折扣,用NOT EXISTS替代LEFT JOIN + GROUP BY的写法,大表场景下效率更高,Laravel代码参考:
DB::table('discounts')
    ->select('id', 'discount')
    ->where('status', 1)
    ->whereNotExists(function ($query) {
        $query->select(DB::raw(1))
              ->from('discount_companies_criteria')
              ->whereColumn('discount_companies_criteria.discount_id', 'discounts.id')
              ->where('is_active', 1);
    })
    ->orderBy('discount', 'ASC') // 需要排序再加,不需要可移除
    ->get();
  1. 按需添加分页
    如果业务场景不需要一次性返回所有1900条数据,加paginate(20)做分页查询,每次只返回需要的条数,耗时会进一步降低。

内容的提问来源于stack exchange,提问作者Alex

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.02 06:36:04