我的Laravel网站出现一些性能问题。 我发现原因是我的代码的一部分。 我在一个循环中进行查询,因为我刚刚发现它不应该这样做。 我不确定如何才能以最佳方式优化此代码(无需更改数据库,因为在此阶段这还不那么容易)。
我当时正在考虑使用foreach
$transactionInfos
来改善这种部分,但是现在我不确定Laravel的语法:
$transactionInfos = ToolTransactionInfo::where('tool_id', $tool->id)
->where('date', $date)
->only(['users'])
//->get();
->all();
if(!empty($transactionInfos)) {
$users = array_sum($transactionInfos);
}
else{
$users = 0;
}
实际代码:
foreach ($data['tools'] as $tool) {
// 30 day user graph data
$count = 30;
$tool_users_30d[$tool->id] = [];
while ($count > 0) {
$date = Carbon::now()->subDays($count)->format('Y-m-d');
$transactionInfos = ToolTransactionInfo::where('tool_id', $tool->id)
->where('date', $date)
->get();
$users = 0;
foreach ($transactionInfos as $transactionInfo) {
$users += $transactionInfo->users;
}
array_push($tool_users_30d[$tool->id], $users);
$count--;
}
}
$data['tool_users_30d'] = $tool_users_30d;
我希望得到一个包含所有工具列表的数组,其中包含每个30天用户数据的数组,例如:
[13] [29] = 10
..
[18] [0] = 50
https://i.imgur.com/VDyZ9uN.png (示例图像显示0个用户,因为本地数据库为空,但这看起来应该是这样)。
答案 0 :(得分:1)
您可以采取以下几项措施来加快速度,以提高性能,并减少对数据库的访问/对函数的调用。
首先,您可以在循环之前一次拉出所有ToolTransactionInfo
。这将帮助您仅执行一次数据库拉取。因此,在循环上方:
$transactionInfosTotal = ToolTransactionInfo::get();
这为您提供了所需的所有信息。然后,在循环中,您可以执行相同的查询,但对内存中已存在的集合执行此查询(即,不返回数据库)。
$transactionInfos = $transactionInfosTotal->where('tool_id', $tool->id)
->where('date', $date)
->get();
有了这个,您就可以在循环中获得相同的集合,以适合正确的日子和工具-然后可以执行计算或根据需要移动到数组。这样只会节省数据库命中数/使其更高效,更快。
您可以做的另一件事是加快时间(碳)的调用时间。节省不了多少,但可能会更快一些。在循环之前,将“ now”设置为变量:
$now = Carbon(now);
然后使用循环中存储在变量中的值进行时间计算,因为它不必返回到现在获取的方法,它已经在内存中了
$date = $now->subDays($count)->format('Y-m-d');
HTH
答案 1 :(得分:1)
您可以将整个算法简化为一个sql查询,类似这样(运行它,至少需要一些引号...),您只需要对结果进行一次遍历即可构建目标多维数组
SELECT tool_id, 30 - datediff(now(), date) as "offset", sum(users)
FROM transaction_info
WHERE date >= (date(now()) - interval 30 days) AND date < date(now())
GROUP BY tool_id, 30 - datediff(now(), date)
答案 2 :(得分:0)
slepic的查询是必经之路。它将页面总加载时间从3.8秒提高到2.5秒(数据页面繁重,但仍有待改进),但这是我可以改善的2个最重的功能之一。谢谢你slepic和所有其他建议。
这是我的解决方法:
// 30 day user graph data
// Prepare array list
$loaded_tool_ids = [];
foreach ($data['tools'] as $tool) {
array_push($loaded_tool_ids, $tool->id);
}
$count = 30;
$now = Carbon::now()->format('Y-m-d');
$oldest_date = Carbon::now()->subDays($count)->format('Y-m-d');
// Query tool history data
$transactionInfos = ToolTransactionInfo::select('tool_id','date',DB::raw("SUM(users) as users"))
->whereIn('tool_id', $loaded_tool_ids)
->where('date', '>=', $oldest_date)
->where('date', '<', $now)
->groupBy('tool_id')
->groupBy('date')
->orderBy('tool_id', 'asc')
->orderBy('date', 'asc')
->get()
->toArray();
// Fill output array with query data
foreach($transactionInfos as $transactionInfo) {
// Get date number
$date_number = $count - Carbon::parse($transactionInfo['date'])->diffInDays($now);
// Fill array
if(!empty($tool_users_30d[$transactionInfo['tool_id']])){
// Fill previous dates with 0 data
$tool_users_30d[$transactionInfo['tool_id']][$date_number] = (int) $transactionInfo['users'];
}
else{
// Create array with the tool id
$tool_users_30d[$transactionInfo['tool_id']] = [];
// Fill date
$tool_users_30d[$transactionInfo['tool_id']][$date_number] = (int) $transactionInfo['users'];
}
}
// Fill output array with loaded tools that have empty days
foreach($loaded_tool_ids as $loaded_tool_id){
if(empty($tool_users_30d[$loaded_tool_id])){
// Create array with the tool id
$tool_users_30d[$loaded_tool_id] = [];
}
}
// Fill days with 0 data
foreach($tool_users_30d as $key => $tool_users){
while($count > 0){
if(empty($tool_users[$count-1])){
$tool_users_30d[$key][$count-1] = 0;
}
$count--;
}
$count = 30;
ksort($tool_users_30d[$key]);
}
$data['tool_users_30d'] = $tool_users_30d;