【发布时间】:2020-09-08 22:35:26
【问题描述】:
我已经与这个问题作斗争了几个星期了。
我有一个 Laravel 7 应用程序,它在执行某个查询时似乎绝对会影响数据库。首先,我将概述问题,然后更深入地研究我试图隔离它的内容。
我有一个 Opportunity 模型,该模型上有一个 scopeLucrative() 范围,用于过滤机会,只显示用户定义的阈值之间的机会,如下所示:
public function scopeLucrative($query)
{
$user = auth()->user();
$threshold = $user->preference('quality.threshold');
$expiredThreshold = $user->preference('quality.expired_threshold');
$hideOwnReports = $user->preference('quality.hide_own_price_changed_reports');
/**
* For an Opportunity to be an lucrative one, the value has to be over the user's threshold.
*/
// Where probability is over the user's threshold
return $query->where('probability', '>=', $threshold)
// And where the number of false reports is less than the user's expired threshold
->whereHas('verifiedPriceReports', function ($report) {
$report->where('correct_price', false)->distinct('user_id')->take(15);
}, '<', $expiredThreshold)
// And when the user has 'hide_own_price_changed_reports' on, hide ones they've marked as incorrect
->when($hideOwnReports, function ($query) use ($user) {
return $query->whereDoesntHave('verifiedPriceReports', function ($report) use ($user) {
$report->where('user_id', $user->id)->where('correct_price', false);
});
});
}
当像 Opportunity::with('history', 'verifiedPriceReports')->lucrative()->orderByDesc('updated_at')->paginate(10)) 这样调用时,根据 DigitalOcean 控制面板,数据库似乎正在获取大量行(并且需要 600 毫秒),尽管由于分页,查询只返回了预期的 10 行。
您可以想象,这不能很好地扩展。只有 5 个活动用户,数据库查询开始需要几秒钟才能返回。该查询生成器执行的查询是:
SELECT *
FROM `opportunities`
WHERE `probability` >= '-15'
and (SELECT distinct count(*)
FROM `opportunity_reports`
WHERE `opportunities`.`id` = `opportunity_reports`.`opportunity_id`
and `correct_price` = '0'
and `updated_at` >= '2020-09-06 04:20:17') < 3
and not exists(SELECT *
FROM `opportunity_reports`
WHERE `opportunities`.`id` = `opportunity_reports`.`opportunity_id`
and `user_id` = '1'
and `correct_price` = '0'
and `updated_at` >= '2020-09-06 04:20:17')
ORDER BY `probability` DESC
LIMIT 10 offset 0;
很快就将问题缩小到scopeLucrative,只需简单地调用模型,而lucrative 作用域没有像Opportunity::with('history', 'verifiedPriceReports')->orderByDesc('updated_at')->paginate(10)) 那样按预期执行。
对于如何解决这个问题,我一头雾水。有没有人经历过这样的事情?
【问题讨论】:
-
不确定是否有帮助,但我曾经与
whereHas()有过类似的问题,我追踪了实际执行的查询,结果发现由于不兼容,它总是在查询整个表标识类型。 uuid 被自动转换为 0 并搞砸了一切。 -
感谢您的建议,但运气不佳 - 我没有在任何表中使用 UUID。