提高现有功能的性能,Laravel
Improve performance to an existing function , Laravel
我尝试重构我的代码,但这次我的表现很差。目标是获得具有唯一 "answer_id"
的数组列表,并获得一些 "Score"、"Votes" 等等。
在我现有的第一个中,我首先检查 $most_voted 是否为空,如果是,我分配第一个元素,然后我将在第二个 foreach
中插入一个新元素,或者我更新现有元素。但是从我的第二个 foreach
开始,我就过得很糟糕。关于这个逻辑有什么建议吗?
$answers = $history->toArray(); //here I have an array of arrays
$most_voted = [];
foreach ($answers as $key => $answer) {
if (!empty($most_voted) ) {
// in this if I create new arrays or I update existing ones
foreach ($most_voted as $k => $v) {
//If value already exists, increase Votes/Score/Percentage
if (intval($most_voted[$k]['answer_id']) === intval($answer['lkp_answer_id'])) {
$most_voted[$k]['Votes'] = $most_voted[$k]['Votes'] + 1;
$most_voted[$k]['Score'] = $most_voted[$k]['Score'] + $answer['score'];
$most_voted[$k]['Percentage'] = substr((($most_voted[$k]['Votes'] * 100) / $votes), 0, 5);
$most_voted[$k]['Weight'] = substr((($most_voted[$k]['Score'] * 100) / $total_scoring), 0, 5);
//Else add new array element
} else {
$name = LkpAnswer::where('id', '=', $answer['lkp_answer_id'])->pluck('name');
(isset($name[0]) && $name[0] !== null) ? $name = $name[0] : '';
if(! empty($answer['lkp_answer_id'])){
$most_voted[$key] = [
'answer_id' => $answer['lkp_answer_id'],
'Name' => $name,
'Votes' => 1,
'Score' => $answer['score'],
'Percentage' => substr(((1 * 100) / $votes), 0, 5),
'Weight' => substr((($answer['score'] * 100) / $total_scoring), 0, 5),
];
}
}
}
} else {
$name = LkpAnswer::where('id', '=', $answer['lkp_answer_id'])->pluck('name');
(isset($name[0]) && $name[0] !== '') ? $name = $name[0] : '';
//If $most_voted is null, insert first value
$most_voted[$key] = [
'answer_id' => $answer['lkp_answer_id'],
'Name' => $name,
'Votes' => 1,
'Score' => $answer['score'],
'Percentage' => substr(((1 * 100) / $votes), 0, 5),
'Weight' => substr((($answer['score'] * 100) / $total_scoring), 0, 5),
];
}
}
我在这里 dd($answers);
0 => array:14 [
"id" => 68
"user_id" => 57
"round_number" => 1
"lkp_answer_id" => 15
"question_id" => 65
"paragraph_id" => null
"answer_time" => 386
"answer_type" => "none"
"answer_type_second_menu" => null
"score" => 1
"user_score_for_answer" => 2
"correct_answer_score" => 2
"created_at" => null
"updated_at" => null
]
1 => array:14 [
"id" => 262
"user_id" => 44
"round_number" => 1
"lkp_answer_id" => 26
"question_id" => 65
"paragraph_id" => null
"answer_time" => 716
"answer_type" => ""
"answer_type_second_menu" => null
"score" => 1
"user_score_for_answer" => 2
"correct_answer_score" => 1
"created_at" => null
"updated_at" => null
] //and many more..
优化的第一条规则(在我看来),
从不 运行 在循环内查询。
循环开始前:
// Fetch all data at once and use select() whenever possible
$LkpAnswers = LkpAnswer::whereIn('id', collect($answers)->pluck('lkp_answer_id')->toArray())->select('name')->get();
在你的其他条件下(在第二个循环内)做这样的事情。
// Before, this query was inside 2 for loops (n^2). For every n, there's 1 query.
// This right here is a Collection of LkpAnswer::model. Collection is very useful for optimization
$name = $LkpAnswers->where('id', $answer['lkp_answer_id'])->pluck('name')->toArray();
使用这个并改变你的第二个 else 条件。仅通过这样做,您将节省近 50% 的 运行 时间。另请查看 上的此答案。它讨论了缓存、索引、select()和类型转换.
让我在下面的评论中发布。
我尝试重构我的代码,但这次我的表现很差。目标是获得具有唯一 "answer_id"
的数组列表,并获得一些 "Score"、"Votes" 等等。
在我现有的第一个中,我首先检查 $most_voted 是否为空,如果是,我分配第一个元素,然后我将在第二个 foreach
中插入一个新元素,或者我更新现有元素。但是从我的第二个 foreach
开始,我就过得很糟糕。关于这个逻辑有什么建议吗?
$answers = $history->toArray(); //here I have an array of arrays
$most_voted = [];
foreach ($answers as $key => $answer) {
if (!empty($most_voted) ) {
// in this if I create new arrays or I update existing ones
foreach ($most_voted as $k => $v) {
//If value already exists, increase Votes/Score/Percentage
if (intval($most_voted[$k]['answer_id']) === intval($answer['lkp_answer_id'])) {
$most_voted[$k]['Votes'] = $most_voted[$k]['Votes'] + 1;
$most_voted[$k]['Score'] = $most_voted[$k]['Score'] + $answer['score'];
$most_voted[$k]['Percentage'] = substr((($most_voted[$k]['Votes'] * 100) / $votes), 0, 5);
$most_voted[$k]['Weight'] = substr((($most_voted[$k]['Score'] * 100) / $total_scoring), 0, 5);
//Else add new array element
} else {
$name = LkpAnswer::where('id', '=', $answer['lkp_answer_id'])->pluck('name');
(isset($name[0]) && $name[0] !== null) ? $name = $name[0] : '';
if(! empty($answer['lkp_answer_id'])){
$most_voted[$key] = [
'answer_id' => $answer['lkp_answer_id'],
'Name' => $name,
'Votes' => 1,
'Score' => $answer['score'],
'Percentage' => substr(((1 * 100) / $votes), 0, 5),
'Weight' => substr((($answer['score'] * 100) / $total_scoring), 0, 5),
];
}
}
}
} else {
$name = LkpAnswer::where('id', '=', $answer['lkp_answer_id'])->pluck('name');
(isset($name[0]) && $name[0] !== '') ? $name = $name[0] : '';
//If $most_voted is null, insert first value
$most_voted[$key] = [
'answer_id' => $answer['lkp_answer_id'],
'Name' => $name,
'Votes' => 1,
'Score' => $answer['score'],
'Percentage' => substr(((1 * 100) / $votes), 0, 5),
'Weight' => substr((($answer['score'] * 100) / $total_scoring), 0, 5),
];
}
}
我在这里 dd($answers);
0 => array:14 [
"id" => 68
"user_id" => 57
"round_number" => 1
"lkp_answer_id" => 15
"question_id" => 65
"paragraph_id" => null
"answer_time" => 386
"answer_type" => "none"
"answer_type_second_menu" => null
"score" => 1
"user_score_for_answer" => 2
"correct_answer_score" => 2
"created_at" => null
"updated_at" => null
]
1 => array:14 [
"id" => 262
"user_id" => 44
"round_number" => 1
"lkp_answer_id" => 26
"question_id" => 65
"paragraph_id" => null
"answer_time" => 716
"answer_type" => ""
"answer_type_second_menu" => null
"score" => 1
"user_score_for_answer" => 2
"correct_answer_score" => 1
"created_at" => null
"updated_at" => null
] //and many more..
优化的第一条规则(在我看来),
从不 运行 在循环内查询。
循环开始前:
// Fetch all data at once and use select() whenever possible
$LkpAnswers = LkpAnswer::whereIn('id', collect($answers)->pluck('lkp_answer_id')->toArray())->select('name')->get();
在你的其他条件下(在第二个循环内)做这样的事情。
// Before, this query was inside 2 for loops (n^2). For every n, there's 1 query.
// This right here is a Collection of LkpAnswer::model. Collection is very useful for optimization
$name = $LkpAnswers->where('id', $answer['lkp_answer_id'])->pluck('name')->toArray();
使用这个并改变你的第二个 else 条件。仅通过这样做,您将节省近 50% 的 运行 时间。另请查看
让我在下面的评论中发布。