From dd5e2acab30e4be9a76e48e93b12f36913d7e863 Mon Sep 17 00:00:00 2001 From: Turan Almammadov <16321061+turanalmammadov@users.noreply.github.com> Date: Tue, 24 Feb 2026 17:14:30 +0400 Subject: [PATCH] fix(db): add time_sensitive to oc_jobs index for maintenance window performance The background job scheduler uses this query to find eligible jobs: SELECT * FROM oc_jobs WHERE reserved_at <= ? AND last_checked <= ? AND time_sensitive = ? ORDER BY last_checked ASC LIMIT ? The previous index 'job_lastcheck_reserved' only covered (last_checked, reserved_at), forcing a partial index scan plus individual row reads to evaluate the time_sensitive predicate. Under heavy load this causes unnecessary I/O especially during a maintenance window where most rows will be filtered out by the time_sensitive condition. Changes: 1. New migration drops 'job_lastcheck_reserved' and creates a replacement index 'job_lastcheck_timesens' on (last_checked, reserved_at, time_sensitive). The new index is a covering index for the scheduler query, eliminating the row-level time_sensitive evaluation entirely. 2. AddMissingIndicesListener updated to expect the new index name and columns so that occ db:add-missing-indices picks it up on existing installations. Fixes: nextcloud/server#46126 Co-authored-by: Cursor --- core/Listener/AddMissingIndicesListener.php | 4 +- .../Version33000Date20260224000000.php | 57 +++++++++++++++++++ 2 files changed, 59 insertions(+), 2 deletions(-) create mode 100644 core/Migrations/Version33000Date20260224000000.php diff --git a/core/Listener/AddMissingIndicesListener.php b/core/Listener/AddMissingIndicesListener.php index 27880fabeac9a..d84399993952f 100644 --- a/core/Listener/AddMissingIndicesListener.php +++ b/core/Listener/AddMissingIndicesListener.php @@ -152,8 +152,8 @@ public function handle(Event $event): void { $event->addMissingIndex( 'jobs', - 'job_lastcheck_reserved', - ['last_checked', 'reserved_at'] + 'job_lastcheck_timesens', + ['last_checked', 'reserved_at', 'time_sensitive'], ); $event->addMissingIndex( diff --git a/core/Migrations/Version33000Date20260224000000.php b/core/Migrations/Version33000Date20260224000000.php new file mode 100644 index 0000000000000..30a8f1d1796e7 --- /dev/null +++ b/core/Migrations/Version33000Date20260224000000.php @@ -0,0 +1,57 @@ +hasTable('jobs')) { + return null; + } + + $table = $schema->getTable('jobs'); + + // Drop the old index that only covers last_checked and reserved_at + if ($table->hasIndex('job_lastcheck_reserved')) { + $table->dropIndex('job_lastcheck_reserved'); + } + + // Recreate the index with time_sensitive included. + // This allows the background job scheduler query to use a full index scan + // instead of a partial index + row lookup, improving performance when + // a maintenance window restricts which jobs are eligible to run. + if (!$table->hasIndex('job_lastcheck_timesens')) { + $table->addIndex( + ['last_checked', 'reserved_at', 'time_sensitive'], + 'job_lastcheck_timesens', + ); + } + + return $schema; + } +}