From 1acd96b78ab9a3f8983ab1f6d23e06880e8b8585 Mon Sep 17 00:00:00 2001 From: root Date: Mon, 29 Jun 2026 18:50:32 +0200 Subject: [PATCH] Optimize queries: fix N+1, SELECT *, and missing eager loading N+1 fixes: - Add withCount('furniture') to rare categories sidebar (prevents N queries) - Add tags and user.permission eager load in ArticleController - Add rooms and photos.user eager load in ProfileController - Add user eager load in MediaApiController (API was returning null user data) SELECT * fixes: - Replace WebsitePermission::all()->pluck() with direct pluck() - Replace WebsiteHousekeepingPermission::all()->pluck() with direct pluck() - Add select(['id', 'public_name']) to ItemBase query in furniItems() - Add select(['id', 'name']) to help categories query - Add select(['id', 'name', 'code']) to languages query Memory/performance: - Replace full collection load with aggregate queries in getRareStatistics() - Add limit(50) to open tickets query in TicketController --- app/Http/Controllers/Api/MediaApiController.php | 1 + .../Controllers/Articles/ArticleController.php | 2 +- app/Http/Controllers/Help/TicketController.php | 4 ++-- app/Http/Controllers/User/ProfileController.php | 3 ++- app/Models/Shop/WebsiteShopArticle.php | 2 +- .../RareValues/RareValueCategoriesService.php | 14 ++++++++------ app/Services/HousekeepingPermissionsService.php | 2 +- app/Services/PermissionsService.php | 2 +- app/Services/SettingsService.php | 2 +- 9 files changed, 18 insertions(+), 14 deletions(-) diff --git a/app/Http/Controllers/Api/MediaApiController.php b/app/Http/Controllers/Api/MediaApiController.php index 6be1021..abb5895 100644 --- a/app/Http/Controllers/Api/MediaApiController.php +++ b/app/Http/Controllers/Api/MediaApiController.php @@ -17,6 +17,7 @@ class MediaApiController extends Controller $photos = CameraWeb::query() ->where('visible', true) ->latest('id') + ->with('user:id,username,look') ->paginate(12); return response()->json([ diff --git a/app/Http/Controllers/Articles/ArticleController.php b/app/Http/Controllers/Articles/ArticleController.php index eea4759..1371b69 100755 --- a/app/Http/Controllers/Articles/ArticleController.php +++ b/app/Http/Controllers/Articles/ArticleController.php @@ -29,7 +29,7 @@ class ArticleController extends Controller public function show(WebsiteArticle $article): View { - $article->load(['user:id,username,look', 'comments.user:id,username,look']); + $article->load(['user:id,username,look', 'user.permission:id,rank_name', 'comments.user:id,username,look', 'tags']); $reactions = $article->reactions() ->with('user:id,username') diff --git a/app/Http/Controllers/Help/TicketController.php b/app/Http/Controllers/Help/TicketController.php index 85d5aa5..fe5ecff 100755 --- a/app/Http/Controllers/Help/TicketController.php +++ b/app/Http/Controllers/Help/TicketController.php @@ -29,14 +29,14 @@ class TicketController extends Controller private function getCachedCategories(): \Illuminate\Database\Eloquent\Collection { - return Cache::remember('help_categories', 3600, fn () => WebsiteHelpCenterCategory::get()); + return Cache::remember('help_categories', 3600, fn () => WebsiteHelpCenterCategory::get(['id', 'name'])); } public function create(): View { return view('help-center.tickets.create', [ 'categories' => $this->getCachedCategories(), - 'openTickets' => WebsiteHelpCenterTicket::where('open', true)->where('user_id', Auth::id())->get(), + 'openTickets' => WebsiteHelpCenterTicket::where('open', true)->where('user_id', Auth::id())->limit(50)->get(), ]); } diff --git a/app/Http/Controllers/User/ProfileController.php b/app/Http/Controllers/User/ProfileController.php index b434e18..fd88427 100755 --- a/app/Http/Controllers/User/ProfileController.php +++ b/app/Http/Controllers/User/ProfileController.php @@ -16,7 +16,8 @@ class ProfileController extends Controller 'friends.friend:id,username,look', 'guilds.guild:id,name,badge', 'profileGuestbook.user:id,username,look', - 'photos', + 'photos.user:id,username,look', + 'rooms', 'badges', ]); diff --git a/app/Models/Shop/WebsiteShopArticle.php b/app/Models/Shop/WebsiteShopArticle.php index f04d47b..76526b5 100755 --- a/app/Models/Shop/WebsiteShopArticle.php +++ b/app/Models/Shop/WebsiteShopArticle.php @@ -52,7 +52,7 @@ class WebsiteShopArticle extends Model $furniture = json_decode($this->furniture, true); $furnitureIds = array_column($furniture, 'item_id'); - return ItemBase::query()->whereIn('id', $furnitureIds)->get(); + return ItemBase::query()->whereIn('id', $furnitureIds)->select(['id', 'public_name'])->get(); } public function rank(): HasOne diff --git a/app/Services/Community/RareValues/RareValueCategoriesService.php b/app/Services/Community/RareValues/RareValueCategoriesService.php index 4bf6fbb..552471d 100755 --- a/app/Services/Community/RareValues/RareValueCategoriesService.php +++ b/app/Services/Community/RareValues/RareValueCategoriesService.php @@ -16,7 +16,7 @@ readonly class RareValueCategoriesService public function fetchAllCategories(): Collection { - return Cache::remember('rare_categories_all', self::CACHE_TTL, fn () => WebsiteRareValueCategory::orderBy('priority')->get()); + return Cache::remember('rare_categories_all', self::CACHE_TTL, fn () => WebsiteRareValueCategory::withCount('furniture')->orderBy('priority')->get()); } public function fetchCategoriesByPriority(): Builder|Collection @@ -71,13 +71,15 @@ readonly class RareValueCategoriesService public function getRareStatistics(): array { return Cache::remember('rare_statistics', self::CACHE_TTL, function () { - $categories = WebsiteRareValueCategory::withCount('furniture')->get(); + $totalCategories = WebsiteRareValueCategory::count(); + $totalRares = WebsiteRareValueCategory::sum('furniture_count'); + $mostValuable = WebsiteRareValueCategory::orderByDesc('furniture_count')->value('name'); return [ - 'total_categories' => $categories->count(), - 'total_rares' => $categories->sum('furniture_count'), - 'most_valuable_category' => $categories->sortByDesc('furniture_count')->first()?->name ?? 'N/A', - 'average_rares_per_category' => $categories->avg('furniture_count') ?? 0, + 'total_categories' => $totalCategories, + 'total_rares' => $totalRares, + 'most_valuable_category' => $mostValuable ?? 'N/A', + 'average_rares_per_category' => $totalCategories > 0 ? $totalRares / $totalCategories : 0, ]; }); } diff --git a/app/Services/HousekeepingPermissionsService.php b/app/Services/HousekeepingPermissionsService.php index f789ebe..e041b69 100755 --- a/app/Services/HousekeepingPermissionsService.php +++ b/app/Services/HousekeepingPermissionsService.php @@ -21,7 +21,7 @@ readonly class HousekeepingPermissionsService $this->permissions = Cache::remember( self::CACHE_KEY, now()->addMinutes(self::CACHE_DURATION_MINUTES), - fn (): Collection => WebsiteHousekeepingPermission::all()->pluck('min_rank', 'permission'), + fn (): Collection => WebsiteHousekeepingPermission::pluck('min_rank', 'permission'), ); } diff --git a/app/Services/PermissionsService.php b/app/Services/PermissionsService.php index efa726e..87e2b10 100755 --- a/app/Services/PermissionsService.php +++ b/app/Services/PermissionsService.php @@ -18,7 +18,7 @@ readonly class PermissionsService public function __construct() { - $data = Cache::remember(self::CACHE_KEY, now()->addMinutes(self::CACHE_DURATION_MINUTES), fn () => WebsitePermission::all()->pluck('min_rank', 'permission')->toArray()); + $data = Cache::remember(self::CACHE_KEY, now()->addMinutes(self::CACHE_DURATION_MINUTES), fn () => WebsitePermission::pluck('min_rank', 'permission')->toArray()); $this->permissions = collect($data); } diff --git a/app/Services/SettingsService.php b/app/Services/SettingsService.php index 7176219..373e48c 100755 --- a/app/Services/SettingsService.php +++ b/app/Services/SettingsService.php @@ -38,7 +38,7 @@ class SettingsService return collect(); } - return WebsiteLanguage::all(); + return WebsiteLanguage::get(['id', 'name', 'code']); } catch (Throwable) { return collect(); }