diff --git a/prisma/postgresql-migrations/20261028200000_add_message_key_indexes/migration.sql b/prisma/postgresql-migrations/20261028200000_add_message_key_indexes/migration.sql new file mode 100644 index 0000000000..b018f867ea --- /dev/null +++ b/prisma/postgresql-migrations/20261028200000_add_message_key_indexes/migration.sql @@ -0,0 +1,29 @@ +-- Index the message key (issue #2753). +-- +-- "Message" had only its primary key and "instanceId", so every lookup by chat or by message id +-- read all messages of the instance. The key is filtered in two forms, and PostgreSQL uses an +-- expression index only for the same expression: +-- * Prisma JSON path filters (key: { path: ['remoteJid'], equals }) compile to "key" #> '{remoteJid}'. +-- * Raw queries (getMessage, messages.update, the read and unread updates, fetchChats and the +-- Chatwoot service) use "key"->>'id' and "key"->>'remoteJid'. +-- Prisma cannot declare expression indexes in the schema, so they live in this migration. +-- +-- CONCURRENTLY keeps writes to "Message" going while each index builds. prisma migrate deploy runs +-- the statements of this file one by one, outside a transaction, so CONCURRENTLY is allowed here. +-- If a build fails part-way, PostgreSQL leaves an INVALID index under that name: drop it +-- (DROP INDEX CONCURRENTLY ""), mark the migration rolled back and deploy again. + +-- CreateIndex +CREATE INDEX CONCURRENTLY IF NOT EXISTS "Message_instanceId_keyId_idx" ON "Message"("instanceId", ("key" ->> 'id')); + +-- CreateIndex +CREATE INDEX CONCURRENTLY IF NOT EXISTS "Message_instanceId_keyRemoteJid_idx" ON "Message"("instanceId", ("key" ->> 'remoteJid')); + +-- CreateIndex +CREATE INDEX CONCURRENTLY IF NOT EXISTS "Message_instanceId_keyIdPath_idx" ON "Message"("instanceId", ("key" #> '{id}')); + +-- CreateIndex +CREATE INDEX CONCURRENTLY IF NOT EXISTS "Message_instanceId_keyRemoteJidPath_idx" ON "Message"("instanceId", ("key" #> '{remoteJid}')); + +-- CreateIndex +CREATE INDEX CONCURRENTLY IF NOT EXISTS "Message_instanceId_keyRemoteJidAltPath_idx" ON "Message"("instanceId", ("key" #> '{remoteJidAlt}')); diff --git a/prisma/postgresql-schema.prisma b/prisma/postgresql-schema.prisma index 661a564c04..21a3d9d909 100644 --- a/prisma/postgresql-schema.prisma +++ b/prisma/postgresql-schema.prisma @@ -179,6 +179,8 @@ model Message { session IntegrationSession? @relation(fields: [sessionId], references: [id]) @@index([instanceId]) + // Expression indexes on "key" (id, remoteJid, remoteJidAlt) are created in migration + // 20261028200000_add_message_key_indexes: Prisma cannot declare them here. } model MessageUpdate { diff --git a/prisma/psql_bouncer-schema.prisma b/prisma/psql_bouncer-schema.prisma index acc23b6723..2c846fa702 100644 --- a/prisma/psql_bouncer-schema.prisma +++ b/prisma/psql_bouncer-schema.prisma @@ -178,6 +178,8 @@ model Message { session IntegrationSession? @relation(fields: [sessionId], references: [id]) @@index([instanceId]) + // Expression indexes on "key" (id, remoteJid, remoteJidAlt) are created in migration + // 20261028200000_add_message_key_indexes: Prisma cannot declare them here. } model MessageUpdate {