From dae0f64aa170441e94c343234af23d18779647b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vi=CC=81ctor=20Falco=CC=81n?= Date: Thu, 2 Jul 2026 15:34:55 +0200 Subject: [PATCH] perf(db): index transactions for the daily synced-email query MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SendDailyBankTransactionsSyncedEmailJob filters transactions by (user_id, source, created_at > ?). The only user_id-leading index is idx_transactions_budget_lookup (user_id, transaction_date, category_id), so MySQL narrows to the user's rows then scans them all to filter on source + created_at — the slow query reported as PHP-LARAVEL-3X. Add a (user_id, source, created_at) composite index matching the two equalities and the range. Fixes PHP-LARAVEL-3X --- ...created_at_index_to_transactions_table.php | 30 +++++++++++++++++++ .../DailyEmailTransactionsIndexTest.php | 14 +++++++++ 2 files changed, 44 insertions(+) create mode 100644 database/migrations/2026_07_02_133321_add_user_source_created_at_index_to_transactions_table.php create mode 100644 tests/Feature/OpenBanking/DailyEmailTransactionsIndexTest.php diff --git a/database/migrations/2026_07_02_133321_add_user_source_created_at_index_to_transactions_table.php b/database/migrations/2026_07_02_133321_add_user_source_created_at_index_to_transactions_table.php new file mode 100644 index 00000000..373f5c9e --- /dev/null +++ b/database/migrations/2026_07_02_133321_add_user_source_created_at_index_to_transactions_table.php @@ -0,0 +1,30 @@ + ?). The existing + * indexes only lead with user_id via transaction_date, so that query scans + * every one of the user's rows to filter on source + created_at + * (PHP-LARAVEL-3X). This composite index matches the two equalities and the + * range directly. + */ + public function up(): void + { + Schema::table('transactions', function (Blueprint $table) { + $table->index(['user_id', 'source', 'created_at'], 'idx_transactions_user_source_created'); + }); + } + + public function down(): void + { + Schema::table('transactions', function (Blueprint $table) { + $table->dropIndex('idx_transactions_user_source_created'); + }); + } +}; diff --git a/tests/Feature/OpenBanking/DailyEmailTransactionsIndexTest.php b/tests/Feature/OpenBanking/DailyEmailTransactionsIndexTest.php new file mode 100644 index 00000000..03c3b021 --- /dev/null +++ b/tests/Feature/OpenBanking/DailyEmailTransactionsIndexTest.php @@ -0,0 +1,14 @@ +first(fn (array $index): bool => $index['columns'] === ['user_id', 'source', 'created_at'] + ); + + expect($match)->not->toBeNull( + 'Expected a (user_id, source, created_at) index on transactions for the daily email query.' + ); +});