From 27cdb093cd2fa0e2aeed4a3a99e41587e4ea494e Mon Sep 17 00:00:00 2001 From: Wes Copeland Date: Sat, 25 Jan 2025 17:05:17 -0500 Subject: [PATCH 1/3] perf(CommonPlayersStrategy): add index to reduce suggestions bottleneck --- ...01_25_000000_update_player_games_table.php | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 database/migrations/2025_01_25_000000_update_player_games_table.php diff --git a/database/migrations/2025_01_25_000000_update_player_games_table.php b/database/migrations/2025_01_25_000000_update_player_games_table.php new file mode 100644 index 0000000000..b35e3582c3 --- /dev/null +++ b/database/migrations/2025_01_25_000000_update_player_games_table.php @@ -0,0 +1,29 @@ +index([ + 'user_id', + 'achievements_unlocked', + 'achievements_total', + 'deleted_at', + 'game_id', + ], 'idx_player_games_suggestions'); // custom name needed because the auto-generated one is too long + }); + } + + public function down(): void + { + Schema::table('player_games', function (Blueprint $table) { + $table->dropIndex('idx_player_games_suggestions'); + }); + } +}; From 3b4901fd09e146b26ed555f445116ee49013f1e6 Mon Sep 17 00:00:00 2001 From: Wes Copeland Date: Sun, 26 Jan 2025 10:54:29 -0500 Subject: [PATCH 2/3] fix: address feedback --- .../GameSuggestions/Strategies/CommonPlayersStrategy.php | 6 +++--- .../2025_01_25_000000_update_player_games_table.php | 1 - 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/app/Platform/Services/GameSuggestions/Strategies/CommonPlayersStrategy.php b/app/Platform/Services/GameSuggestions/Strategies/CommonPlayersStrategy.php index a8aeae3296..86b1eceb0f 100644 --- a/app/Platform/Services/GameSuggestions/Strategies/CommonPlayersStrategy.php +++ b/app/Platform/Services/GameSuggestions/Strategies/CommonPlayersStrategy.php @@ -39,7 +39,7 @@ public function select(): ?Game ->whereAllAchievementsUnlocked() ->where('achievements_total', '>', 0) ->where('game_id', '!=', $this->sourceGame->id) - ->whereNull('deleted_at') + ->withTrashed() ->groupBy('game_id') ->orderByRaw('COUNT(*) DESC') ->limit(10) @@ -96,7 +96,7 @@ private function getMasterUserIdsMariaDB(): Collection ->where('game_id', $this->sourceGame->id) ->where('user_id', '!=', $this->user->id) ->whereAllAchievementsUnlocked() - ->whereNull('deleted_at') + ->withTrashed() ->whereRaw('id % 100 < 5') ->limit(5) ->pluck('user_id'); @@ -112,7 +112,7 @@ private function getMasterUserIdsSQLite(): Collection return PlayerGame::where('game_id', $this->sourceGame->id) ->where('user_id', '!=', $this->user->id) ->whereAllAchievementsUnlocked() - ->whereNull('deleted_at') + ->withTrashed() ->orderByRaw('rowid % 100') ->limit(5) ->pluck('user_id'); diff --git a/database/migrations/2025_01_25_000000_update_player_games_table.php b/database/migrations/2025_01_25_000000_update_player_games_table.php index b35e3582c3..9f1a52685c 100644 --- a/database/migrations/2025_01_25_000000_update_player_games_table.php +++ b/database/migrations/2025_01_25_000000_update_player_games_table.php @@ -14,7 +14,6 @@ public function up(): void 'user_id', 'achievements_unlocked', 'achievements_total', - 'deleted_at', 'game_id', ], 'idx_player_games_suggestions'); // custom name needed because the auto-generated one is too long }); From b4beaa3b93e705d6565138af734cd38ad90f07aa Mon Sep 17 00:00:00 2001 From: Wes Copeland Date: Sun, 26 Jan 2025 12:06:01 -0500 Subject: [PATCH 3/3] fix: address feedback --- .../Strategies/CommonPlayersStrategy.php | 33 +------------------ ...01_25_000000_update_player_games_table.php | 17 ++++++++-- 2 files changed, 16 insertions(+), 34 deletions(-) diff --git a/app/Platform/Services/GameSuggestions/Strategies/CommonPlayersStrategy.php b/app/Platform/Services/GameSuggestions/Strategies/CommonPlayersStrategy.php index 86b1eceb0f..25090f6791 100644 --- a/app/Platform/Services/GameSuggestions/Strategies/CommonPlayersStrategy.php +++ b/app/Platform/Services/GameSuggestions/Strategies/CommonPlayersStrategy.php @@ -12,7 +12,6 @@ use App\Platform\Data\GameSuggestionContextData; use App\Platform\Enums\GameSuggestionReason; use Illuminate\Support\Collection; -use Illuminate\Support\Facades\DB; class CommonPlayersStrategy implements GameSuggestionStrategy { @@ -76,44 +75,14 @@ public function reasonContext(): ?GameSuggestionContextData * @return Collection */ private function getMasterUserIds(): Collection - { - $connection = DB::connection()->getDriverName(); - - return match ($connection) { - 'sqlite' => $this->getMasterUserIdsSQLite(), - default => $this->getMasterUserIdsMariaDB(), - }; - } - - /** - * @return Collection - */ - private function getMasterUserIdsMariaDB(): Collection { // Use the optimized index hint for MariaDB. // This is unfortunately not supported by SQLite. - return PlayerGame::from(DB::raw('`player_games` FORCE INDEX (player_games_completion_sample_idx)')) - ->where('game_id', $this->sourceGame->id) - ->where('user_id', '!=', $this->user->id) - ->whereAllAchievementsUnlocked() - ->withTrashed() - ->whereRaw('id % 100 < 5') - ->limit(5) - ->pluck('user_id'); - } - - /** - * @return Collection - */ - private function getMasterUserIdsSQLite(): Collection - { - // For SQLite, we'll use a different approach to get a stable random sample. - // We use the rowid (which SQLite automatically provides) for sampling. return PlayerGame::where('game_id', $this->sourceGame->id) ->where('user_id', '!=', $this->user->id) ->whereAllAchievementsUnlocked() ->withTrashed() - ->orderByRaw('rowid % 100') + ->whereRaw('id % 100 < 5') ->limit(5) ->pluck('user_id'); } diff --git a/database/migrations/2025_01_25_000000_update_player_games_table.php b/database/migrations/2025_01_25_000000_update_player_games_table.php index 9f1a52685c..a9b60af5e1 100644 --- a/database/migrations/2025_01_25_000000_update_player_games_table.php +++ b/database/migrations/2025_01_25_000000_update_player_games_table.php @@ -10,19 +10,32 @@ public function up(): void { Schema::table('player_games', function (Blueprint $table) { + $table->dropIndex('player_games_completion_sample_idx'); + $table->index([ 'user_id', 'achievements_unlocked', 'achievements_total', 'game_id', - ], 'idx_player_games_suggestions'); // custom name needed because the auto-generated one is too long + ], 'player_games_suggestions_index'); // custom name needed because the auto-generated one is too long }); } public function down(): void { Schema::table('player_games', function (Blueprint $table) { - $table->dropIndex('idx_player_games_suggestions'); + $table->dropIndex('player_games_suggestions_index'); + + $table->index( + [ + 'game_id', + 'achievements_unlocked', + 'achievements_total', + 'user_id', + 'id', + ], + 'player_games_completion_sample_idx' // custom name needed because the auto-generated one is too long + ); }); } };