From 065502f562f493b8984f2ade86871638ee4df16e Mon Sep 17 00:00:00 2001 From: Jonathan Schweder Date: Tue, 16 Dec 2025 15:34:50 +0000 Subject: [PATCH] Create idx_bucket_data_compact index --- ...1734384000000-bucket-data-compact-index.ts | 41 +++++++++++++++++++ .../src/storage/PostgresCompactor.ts | 6 +-- .../src/__snapshots__/storage.test.ts.snap | 2 +- 3 files changed, 45 insertions(+), 4 deletions(-) create mode 100644 modules/module-postgres-storage/src/migrations/scripts/1734384000000-bucket-data-compact-index.ts diff --git a/modules/module-postgres-storage/src/migrations/scripts/1734384000000-bucket-data-compact-index.ts b/modules/module-postgres-storage/src/migrations/scripts/1734384000000-bucket-data-compact-index.ts new file mode 100644 index 000000000..1a695ea42 --- /dev/null +++ b/modules/module-postgres-storage/src/migrations/scripts/1734384000000-bucket-data-compact-index.ts @@ -0,0 +1,41 @@ +import { migrations } from '@powersync/service-core'; + +import { openMigrationDB } from '../migration-utils.js'; + +/** + * Migration: Add specialized index for bucket_data compaction query optimization + * + * This migration creates an index optimized for the compaction query in PostgresCompactor.ts + * which uses COLLATE "C" (binary collation) and DESC ordering. + * The index enables PostgreSQL to push COLLATE "C" conditions into Index Cond + * instead of applying them as filters, significantly reducing rows scanned. + */ +export const up: migrations.PowerSyncMigrationFunction = async (context) => { + const { + service_context: { configuration } + } = context; + await using client = openMigrationDB(configuration.storage); + + await client.transaction(async (db) => { + await db.sql` + CREATE INDEX IF NOT EXISTS idx_bucket_data_compact ON bucket_data ( + group_id, + bucket_name COLLATE "C" DESC, + op_id DESC + ) + `.execute(); + + await db.sql`ANALYZE bucket_data`.execute(); + }); +}; + +export const down: migrations.PowerSyncMigrationFunction = async (context) => { + const { + service_context: { configuration } + } = context; + await using client = openMigrationDB(configuration.storage); + + await client.transaction(async (db) => { + await db.sql`DROP INDEX IF EXISTS idx_bucket_data_compact`.execute(); + }); +}; diff --git a/modules/module-postgres-storage/src/storage/PostgresCompactor.ts b/modules/module-postgres-storage/src/storage/PostgresCompactor.ts index b19d866eb..3d5f89185 100644 --- a/modules/module-postgres-storage/src/storage/PostgresCompactor.ts +++ b/modules/module-postgres-storage/src/storage/PostgresCompactor.ts @@ -123,16 +123,16 @@ export class PostgresCompactor { bucket_data WHERE group_id = ${{ type: 'int4', value: this.group_id }} - AND bucket_name >= ${{ type: 'varchar', value: bucketLower }} + AND bucket_name >= ${{ type: 'varchar', value: bucketLower }} COLLATE "C" AND ( ( - bucket_name = ${{ type: 'varchar', value: bucketUpper }} + bucket_name = ${{ type: 'varchar', value: bucketUpper }} COLLATE "C" AND op_id < ${{ type: 'int8', value: upperOpIdLimit }} ) OR bucket_name < ${{ type: 'varchar', value: bucketUpper }} COLLATE "C" -- Use binary comparison ) ORDER BY - bucket_name DESC, + bucket_name COLLATE "C" DESC, op_id DESC LIMIT ${{ type: 'int4', value: this.moveBatchQueryLimit }} diff --git a/modules/module-postgres-storage/test/src/__snapshots__/storage.test.ts.snap b/modules/module-postgres-storage/test/src/__snapshots__/storage.test.ts.snap index d1b24f45b..79e1e6242 100644 --- a/modules/module-postgres-storage/test/src/__snapshots__/storage.test.ts.snap +++ b/modules/module-postgres-storage/test/src/__snapshots__/storage.test.ts.snap @@ -2,7 +2,7 @@ exports[`Postgres Sync Bucket Storage - Data > empty storage metrics 1`] = ` { - "operations_size_bytes": 16384, + "operations_size_bytes": 24576, "parameters_size_bytes": 32768, "replication_size_bytes": 16384, }