1
0
mirror of https://github.com/laurent22/joplin.git synced 2025-11-23 22:36:32 +02:00

Server: Fix slow delta queries (#13639)

This commit is contained in:
Laurent Cozic
2025-11-08 11:02:55 +01:00
committed by GitHub
parent e8f067a0b2
commit 977edf6e5d
2 changed files with 28 additions and 0 deletions

View File

@@ -33,6 +33,7 @@ describe('db.migrations', () => {
'20220121172409_email_recipient_default',
'20240413141308_changes_optimization',
'20250219183745_changes_optimization',
'20251107113000_fix_delta_performance',
];
let startProcessing = false;

View File

@@ -0,0 +1,27 @@
import { DbConnection, isPostgres } from '../db';
// CREATE INDEX CONCURRENTLY cannot run within a transaction
export const config = { transaction: false };
export const up = async (db: DbConnection) => {
if (isPostgres(db)) {
// This is to optimize the sub-query in ChangeModel::changesForUserQuery() which retrieves
// the item creations and deletions. Having `item_id` first in the index helps PostgreSQL
// quickly find all rows in `changes` that belong to a specific `item_id`. We also filter it
// to `type = 2` (updates) because finding the changes for other types is done in a
// different query and is much easier.
await db.raw('CREATE INDEX CONCURRENTLY IF NOT EXISTS changes_item_id_counter_type2_index ON changes (item_id, counter) WHERE type = 2');
// Drop the old counter-only index. If it remains, the planner wrongly prefers it because it
// appears ideal for `ORDER BY counter`, but in reality it forces Postgres to scan millions
// of rows to find matching item_ids.
await db.raw('DROP INDEX CONCURRENTLY IF EXISTS changes_type2_counter_idx');
}
};
export const down = async (db: DbConnection) => {
if (isPostgres(db)) {
await db.raw('DROP INDEX CONCURRENTLY IF EXISTS changes_item_id_counter_type2_index');
await db.raw('CREATE INDEX CONCURRENTLY IF NOT EXISTS changes_type2_counter_idx ON changes (counter) WHERE type = 2');
}
};