You need to enable JavaScript to run this app. Laravel多对多关联下对比Eloquent与Query Builder的执行效率及测试方法
优惠活动
大模型
产品
解决方案
定价
更多

Laravel多对多关联下对比Eloquent与Query Builder的执行效率及测试方法

两种实现方式的执行效率对比

*通常场景下,第二种基于DB Query Builder的实现执行时间更短、效率更优,二者的性能差距核心来源如下:

  • ORM层开销差异:第一种实现基于Eloquent模型层,执行过程中会自动加载Green模型的关联定义、触发模型生命周期事件、为每条匹配结果实例化完整的Green模型对象,哪怕只需要提取ID,也会产生不可忽略的框架层开销;当返回的Green ID数量较多(比如超过1万条)时,这部分开销会被进一步放大。第二种实现完全跳过模型层,直接操作中间关联表,不存在上述额外开销。
  • SQL执行效率差异:第一种实现的whereHas会生成两个嵌套的EXISTS子查询,最终SQL大致为:
select id from greens 
where exists (
    select 1 from red_green 
    where red_green.green_id = greens.id and red_green.red_id = 123
) 
or exists (
    select 1 from blue_green 
    where blue_green.green_id = greens.id and blue_green.blue_id in (2,3,5)
)

数据库优化器对这类跨表嵌套子查询的执行计划选择,往往不如直接查两张中间关联表的单表查询高效;第二种实现的两次查询都是针对中间表的简单单表查询,只要red_green.red_id、green_blue.blue_id建立了普通索引,数据库可以直接命中索引返回结果,无需关联主表扫描。

  • 潜在逻辑隐患:两种原实现都存在返回结果重复的问题——同一个Green可能同时被目标Red、目标Blue关联,合并后的ID数组会存在重复值,需要额外用array_unique处理;第一种实现如果查询构造器的条件嵌套不当,OR逻辑可能会打破原有查询约束,最终返回全表Green的无效结果。
准确测量二者执行效率的方法

要避免单次测试的偶然误差,需要在可控的测试环境下按照以下方法测量:

  • 统一测试环境基线
    • 固定数据库的索引配置、测试数据量级(建议准备和线上环境同规模的测试数据集),关闭PHP、数据库、框架层的所有缓存,避免冷启动、缓存命中带来的测试偏差。
    • 测量时关闭所有第三方调试工具(如Debugbar、Telescope实时采集),避免埋点工具本身的开销干扰测试结果。
  • 多维度对照测量
    • 用microtime(true)分别记录两段代码从启动到拿到最终结果数组的全程耗时,覆盖ORM层、SQL层、PHP数组处理的全部开销,而不是只单独测量SQL的执行时间。
    • 开启Laravel查询日志DB::enableQueryLog(),抓取两段代码实际生成的全部SQL,通过EXPLAIN分析每条SQL的执行计划,对比索引命中率、扫描行数、临时表使用等数据库侧的性能差异。
  • 消除偶然误差
    • 单轮测量的结果受CPU调度、磁盘IO波动影响极大,需要将两段逻辑分别循环执行100-1000次,取平均耗时作为最终对比依据。
    • 对比耗时前先校验结果一致性:确保两段代码最终返回的Green ID集合完全相同,避免因为逻辑漏洞(漏查、重复查、条件错误)导致的耗时对比无意义。

注:原代码中存在多处变量名不匹配的问题,比如Eloquent实现中引用的$red、$blues与定义的$red_id、$blue_ids不一致,DB实现中引用的$user->red_id与给定的目标Red ID参数不一致,实际运行时需要先修正这类语法错误。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.28 11:54:04