Всім привіт.
У мене є код laravel, який фактично візуалізує список користувачів, які представлені на платформі. На жаль, цьому коду потрібно 2453 запити, щоб завантажити ці дані користувачеві-адміністратору. Сьогодні я покажу вам, як можна покращити його лише до 4.
Резюме
: На даний момент у мене є цей код, який має наступний результат:
Event | Amount |
---|---|
Number of Queries | 2453 |
Number of Model Hydration | 7392 |
Memory Uses | 47 MB |
Processing Time | ~7 Second |
Зміст
Дослідження
коду На жаль, цей код написаний не оптимізованим чином, тому я бачу дублювання коду, скидання всіх записів на одній сторінці (без нумерації сторінок) тощо.
Ось контролер:
public function showUsersFeatured(Request $request)
{
if ($request->segment(2) == 'unitedstates') {
$usersfeatured = User::with(['usercity', 'tempphoto'])->where('isfeatured', '!=', 0)->where('featuredin', '=', 'unitedstates')->get();
$usersfeaturedman = User::with(['usercity', 'tempphoto'])->where('isfeatured', '!=', 0)->where('featuredin', '=', 'unitedstates')->where('gender', '=', 'man')->get();
$usersfeaturedwoman = User::with(['usercity', 'tempphoto'])->where('isfeatured', '!=', 0)->where('featuredin', '=', 'unitedstates')->where('gender', '=', 'woman')->get();
$country = 'United States';
return view('admin.featured-users.showfeatured')->with([
'usersfeatured' => $usersfeatured,
'usersfeaturedman' => $usersfeaturedman,
'usersfeaturedwoman' => $usersfeaturedwoman,
'country' => $country,
]);
} elseif ($request->segment(2) == 'singapore') {
$usersfeatured = User::with(['usercity', 'tempphoto'])->where('isfeatured', '!=', 0)->where('featuredin', '=', 'singapore')->get();
$usersfeaturedman = User::with(['usercity', 'tempphoto'])->where('isfeatured', '!=', 0)->where('featuredin', '=', 'singapore')->where('gender', '=', 'man')->get();
$usersfeaturedwoman = User::with(['usercity', 'tempphoto'])->where('isfeatured', '!=', 0)->where('featuredin', '=', 'singapore')->where('gender', '=', 'woman')->get();
$country = 'Singapore';
return view('admin.featured-users.showfeatured')->with([
'usersfeatured' => $usersfeatured,
'usersfeaturedman' => $usersfeaturedman,
'usersfeaturedwoman' => $usersfeaturedwoman,
'country' => $country,
]);
} elseif ($request->segment(2) == 'thailand') {
$usersfeatured = User::with(['usercity', 'tempphoto'])->where('isfeatured', '!=', 0)->where('featuredin', '=', 'thailand')->get();
$usersfeaturedman = User::with(['usercity', 'tempphoto'])->where('isfeatured', '!=', 0)->where('featuredin', '=', 'thailand')->where('gender', '=', 'man')->get();
$usersfeaturedwoman = User::with(['usercity', 'tempphoto'])->where('isfeatured', '!=', 0)->where('featuredin', '=', 'thailand')->where('gender', '=', 'woman')->get();
$country = 'Thailand';
return view('admin.featured-users.showfeatured')->with([
'usersfeatured' => $usersfeatured,
'usersfeaturedman' => $usersfeaturedman,
'usersfeaturedwoman' => $usersfeaturedwoman,
'country' => $country,
]);
} elseif ($request->segment(2) == 'indonesia') {
$usersfeatured = User::with(['usercity', 'tempphoto'])->where('isfeatured', '!=', 0)->where('featuredin', '=', 'indonesia')->get();
$usersfeaturedman = User::with(['usercity', 'tempphoto'])->where('isfeatured', '!=', 0)->where('featuredin', '=', 'indonesia')->where('gender', '=', 'man')->get();
$usersfeaturedwoman = User::with(['usercity', 'tempphoto'])->where('isfeatured', '!=', 0)->where('featuredin', '=', 'indonesia')->where('gender', '=', 'woman')->get();
$country = 'Indonesia';
return view('admin.featured-users.showfeatured')->with([
'usersfeatured' => $usersfeatured,
'usersfeaturedman' => $usersfeaturedman,
'usersfeaturedwoman' => $usersfeaturedwoman,
'country' => $country,
]);
} elseif ($request->segment(2) == 'home') {
$usersfeatured = User::with(['usercity', 'tempphoto'])->where('featurehome', '!=', 0)->get();
$usersfeaturedman = User::with(['usercity', 'tempphoto'])->where('featurehome', '!=', 0)->where('gender', '=', 'man')->get();
$usersfeaturedwoman = User::with(['usercity', 'tempphoto'])->where('featurehome', '!=', 0)->where('gender', '=', 'woman')->get();
$country = 'Home';
return view('admin.featured-users.showfeatured')->with([
'usersfeatured' => $usersfeatured,
'usersfeaturedman' => $usersfeaturedman,
'usersfeaturedwoman' => $usersfeaturedwoman,
'country' => $country,
]);
}
$usersfeatured = User::with(['usercity', 'tempphoto'])->where('isfeatured', '!=', 0)->where('featuredin', '=', 'malaysia')->get();
$usersfeaturedman = User::with(['usercity', 'tempphoto'])->where('isfeatured', '!=', 0)->where('featuredin', '=', 'malaysia')->where('gender', '=', 'man')->get();
$usersfeaturedwoman = User::with(['usercity', 'tempphoto'])->where('isfeatured', '!=', 0)->where('featuredin', '=', 'malaysia')->where('gender', '=', 'woman')->get();
$country = 'Malaysia';
return view('admin.featured-users.showfeatured')->with([
'usersfeatured' => $usersfeatured,
'usersfeaturedman' => $usersfeaturedman,
'usersfeaturedwoman' => $usersfeaturedwoman,
'country' => $country,
]);
return view('admin.featured-users.showfeatured')->with([
'usersfeatured' => $usersfeatured,
'usersfeaturedman' => $usersfeaturedman,
'usersfeaturedwoman' => $usersfeaturedwoman,
'country' => $country,
]);
}
Спостереження:
- Схожий шаблон коду
- Повертайтеся до переглядів кілька разів
- Блок коду if-else
- Мертвий код (не використовується)
Рефакторинг:
Я буду робити рефакторинг крок за кроком.
Крок 1
: Виберіть правильну країну на основі сегмента.
$segment = $request->segment(2);
$countries = [
'unitedstates' => ['name' => 'United States', 'featuredin' => 'unitedstates'],
'singapore' => ['name' => 'Singapore', 'featuredin' => 'singapore'],
'thailand' => ['name' => 'Thailand', 'featuredin' => 'thailand'],
'indonesia' => ['name' => 'Indonesia', 'featuredin' => 'indonesia'],
'home' => ['name' => 'Home', 'featuredin' => null, 'featurehome' => true],
'malaysia' => ['name' => 'Malaysia', 'featuredin' => 'malaysia'], // Default country
];
$countryData = $countries[$segment] ?? $countries['malaysia'];
Крок 2
Класифікуйте поширену поведінку і помістіть її в одне місце.
$baseQuery = User::where('isfeatured', '!=', 0);
if (isset($countryData['featurehome'])) {
$baseQuery->where('featurehome', '!=', 0);
} else {
$baseQuery->where('featuredin', '=', $countryData['featuredin']);
}
Ці 6 рядків коду фактично скорочують 30 рядків коду та багато дубльованих кодів.
Крок 3
: Розбийте сторінки на сторінки $baseQuery
, а потім скористайтеся відкладеним завантаженням записів про зв'язок.
$usersfeatured = $baseQuery->paginate(50);
$usersfeatured->load(['usercity', 'tempphoto']);
$usersfeaturedman = $usersfeatured->where('gender', 'man');
$usersfeaturedwoman = $usersfeatured->where('gender', 'woman');
Після цього я подав заявку, де є умова для отримання рекомендованого користувача для чоловіка та жінки.
Крок 4
: Нарешті, я хотів би передати ці дані представленню даних.
return view('admin.featured-users.showfeatured')->with([
'usersfeatured' => $usersfeatured,
'usersfeaturedman' => $usersfeaturedman,
'usersfeaturedwoman' => $usersfeaturedwoman,
'country' => $countryData['name'],
]);
Повний рефакторинг тут:
public function index(Request $request)
{
$segment = $request->segment(2);
$countries = [
'unitedstates' => ['name' => 'United States', 'featuredin' => 'unitedstates'],
'singapore' => ['name' => 'Singapore', 'featuredin' => 'singapore'],
'thailand' => ['name' => 'Thailand', 'featuredin' => 'thailand'],
'indonesia' => ['name' => 'Indonesia', 'featuredin' => 'indonesia'],
'home' => ['name' => 'Home', 'featuredin' => null, 'featurehome' => true],
'malaysia' => ['name' => 'Malaysia', 'featuredin' => 'malaysia'], // Default country
];
$countryData = $countries[$segment] ?? $countries['malaysia'];
$baseQuery = User::where('isfeatured', '!=', 0);
if (isset($countryData['featurehome'])) {
$baseQuery->where('featurehome', '!=', 0);
} else {
$baseQuery->where('featuredin', '=', $countryData['featuredin']);
}
$usersfeatured = $baseQuery->paginate(50);
$usersfeatured->load(['usercity', 'tempphoto']); // Lazy eager load after main fetch
$usersfeaturedman = $usersfeatured->where('gender', 'man');
$usersfeaturedwoman = $usersfeatured->where('gender', 'woman');
return view('admin.featured-users.showfeatured')->with([
'usersfeatured' => $usersfeatured,
'usersfeaturedman' => $usersfeaturedman,
'usersfeaturedwoman' => $usersfeaturedwoman,
'country' => $countryData['name'],
]);
}
Крок 5
Я також трохи підправив файл перегляду леза (⚠️ що не покращує продуктивність.)
@foreach($usersfeatured as $key => $userfeatured)
<tr class="even:bg-gray-50">
<td class="whitespace-nowrap py-4 pl-4 pr-3 text-sm font-medium text-gray-900 sm:pl-3">{{ ++$key }}</td>
<td class="whitespace-nowrap px-3 py-4 text-sm text-gray-500">{{ $userfeatured->username }}</td>
<td class="whitespace-nowrap px-3 py-4 text-sm text-gray-500">{{ $userfeatured->featuredsince ? $userfeatured->featuredsince->format('d M, Y') : '' }} </td>
<td class="whitespace-nowrap px-3 py-4 text-sm text-gray-500">{{ $userfeatured->featuredin }}</td>
<td class="whitespace-nowrap px-3 py-4 text-sm text-gray-500">{{ $userfeatured->created_at->diffForHumans() }}</td>
<td class="whitespace-nowrap px-3 py-4 text-sm text-gray-500">{{ $userfeatured->membershiptype }}</td>
<td class="whitespace-nowrap px-3 py-4 text-sm text-gray-500">{{ $userfeatured->gender }}</td>
<td class="whitespace-nowrap px-3 py-4 text-sm text-gray-500">{{ optional($userfeatured->usercity)->currentcountry }}</td>
<td class="whitespace-nowrap px-3 py-4 text-sm text-gray-500">
@if($userfeatured->tempphoto)
<a href="" target="_blank">
<img src="{{ $userfeatured->profilePhoto() }}" alt="" width="50" height="50">
</a>
@endif
</td>
<td
class="relative whitespace-nowrap py-4 pl-3 pr-4 text-right text-sm font-medium sm:pr-3">
<a href="#" class="text-indigo-600 hover:text-indigo-900">Unfeature</a>
</td>
</tr>
@endforeach
Оцінка після рефакторингу Після рефакторингу
ось результат, який я знайшов.
Event | Amount |
---|---|
Number of Queries | 4 |
Number of Model Hydration | 150 |
Memory Uses | 2 MB |
Processing Time | ~103 Millisecond |
Повний код
Я створив pull request на github. З повним кодом можна ознайомитися тут.
Ось запропоноване мною рішення
Відеоурок
Якщо ви візуал, а не текст, ви можете переглянути це відео. Я завжди ціную, якщо у вас є різні думки, щоб зробити це краще.
Сподіваюся, це рішення допоможе вам у майбутньому.
Спасибі, що прочитали.