From d753fe8fcb7a976b5cacb623b226e441fb991a33 Mon Sep 17 00:00:00 2001 From: Scott Nonnenberg Date: Thu, 2 Jun 2022 18:09:13 -0700 Subject: [PATCH] getUnreadByConversationAndMarkRead: Only query incoming messages --- ts/sql/Server.ts | 6 ++- ts/sql/migrations/59-update-expiring-index.ts | 39 +++++++++++++++++++ ts/test-node/sql_migrations_test.ts | 38 ++++++++++++++++++ 3 files changed, 81 insertions(+), 2 deletions(-) create mode 100644 ts/sql/migrations/59-update-expiring-index.ts diff --git a/ts/sql/Server.ts b/ts/sql/Server.ts index 102ae21bb..f51f9a433 100644 --- a/ts/sql/Server.ts +++ b/ts/sql/Server.ts @@ -2101,13 +2101,15 @@ async function getUnreadByConversationAndMarkRead({ expirationStartTimestamp = $expirationStartTimestamp, json = json_patch(json, $jsonPatch) WHERE + conversationId = $conversationId AND + (${_storyIdPredicate(storyId, isGroup)}) AND + isStory IS 0 AND + type IS 'incoming' AND ( expirationStartTimestamp IS NULL OR expirationStartTimestamp > $expirationStartTimestamp ) AND expireTimer > 0 AND - conversationId = $conversationId AND - (${_storyIdPredicate(storyId, isGroup)}) AND received_at <= $newestUnreadAt; ` ).run({ diff --git a/ts/sql/migrations/59-update-expiring-index.ts b/ts/sql/migrations/59-update-expiring-index.ts new file mode 100644 index 000000000..0d2f436ed --- /dev/null +++ b/ts/sql/migrations/59-update-expiring-index.ts @@ -0,0 +1,39 @@ +// Copyright 2021-2022 Signal Messenger, LLC +// SPDX-License-Identifier: AGPL-3.0-only + +import type { Database } from 'better-sqlite3'; + +import type { LoggerType } from '../../types/Logging'; + +export default function updateToSchemaVersion59( + currentVersion: number, + db: Database, + logger: LoggerType +): void { + if (currentVersion >= 59) { + return; + } + + db.transaction(() => { + db.exec( + ` + DROP INDEX expiring_message_by_conversation_and_received_at; + + CREATE INDEX expiring_message_by_conversation_and_received_at + ON messages + ( + conversationId, + storyId + expirationStartTimestamp, + expireTimer, + received_at, + ) + WHERE isStory IS 0 AND type IS 'incoming'; + ` + ); + + db.pragma('user_version = 59'); + })(); + + logger.info('updateToSchemaVersion59: success!'); +} diff --git a/ts/test-node/sql_migrations_test.ts b/ts/test-node/sql_migrations_test.ts index 4a45c1870..47ab9556a 100644 --- a/ts/test-node/sql_migrations_test.ts +++ b/ts/test-node/sql_migrations_test.ts @@ -2286,4 +2286,42 @@ describe('SQL migrations test', () => { ); }); }); + + describe('updateToSchemaVersion59', () => { + it('updates index to make query efficient', () => { + updateToVersion(47); + + const items = db + .prepare( + ` + EXPLAIN QUERY PLAN + UPDATE messages + INDEXED BY expiring_message_by_conversation_and_received_at + SET + expirationStartTimestamp = 342342, + json = json_patch(json, '{ "something": true }') + WHERE + conversationId = 'conversationId' AND + storyId IS NULL AND + isStory IS 0 AND + type IS 'incoming' AND + ( + expirationStartTimestamp IS NULL OR + expirationStartTimestamp > 23423423 + ) AND + expireTimer > 0 AND + received_at <= 234234; + ` + ) + .all(); + const detail = items.map(item => item.detail).join('\n'); + + assert.notInclude(detail, 'B-TREE'); + assert.notInclude(detail, 'SCAN'); + assert.include( + detail, + 'SEARCH messages USING INDEX expiring_message_by_conversation_and_received_at (expirationStartTimestamp=? AND expireTimer>?)' + ); + }); + }); });