Optimize conversation open performance
This commit is contained in:
parent
6a80b4b837
commit
67b108c718
3 changed files with 84 additions and 26 deletions
|
@ -2653,7 +2653,7 @@ function getOldestMessageForConversation(
|
||||||
const row = db
|
const row = db
|
||||||
.prepare<Query>(
|
.prepare<Query>(
|
||||||
`
|
`
|
||||||
SELECT * FROM messages WHERE
|
SELECT received_at, sent_at, id FROM messages WHERE
|
||||||
conversationId = $conversationId AND
|
conversationId = $conversationId AND
|
||||||
isStory IS 0 AND
|
isStory IS 0 AND
|
||||||
(${_storyIdPredicate(storyId, includeStoryReplies)})
|
(${_storyIdPredicate(storyId, includeStoryReplies)})
|
||||||
|
@ -2686,7 +2686,7 @@ function getNewestMessageForConversation(
|
||||||
const row = db
|
const row = db
|
||||||
.prepare<Query>(
|
.prepare<Query>(
|
||||||
`
|
`
|
||||||
SELECT * FROM messages WHERE
|
SELECT received_at, sent_at, id FROM messages WHERE
|
||||||
conversationId = $conversationId AND
|
conversationId = $conversationId AND
|
||||||
isStory IS 0 AND
|
isStory IS 0 AND
|
||||||
(${_storyIdPredicate(storyId, includeStoryReplies)})
|
(${_storyIdPredicate(storyId, includeStoryReplies)})
|
||||||
|
@ -2750,35 +2750,29 @@ function getLastConversationPreview({
|
||||||
}): MessageType | undefined {
|
}): MessageType | undefined {
|
||||||
type Row = Readonly<{
|
type Row = Readonly<{
|
||||||
json: string;
|
json: string;
|
||||||
received_at: number;
|
|
||||||
sent_at: number;
|
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
const db = getInstance();
|
const db = getInstance();
|
||||||
|
|
||||||
const queryTemplate = (extraClause: string): string => {
|
const index = includeStoryReplies
|
||||||
return `
|
? 'messages_preview'
|
||||||
SELECT json, received_at, sent_at FROM messages
|
: 'messages_preview_without_story';
|
||||||
INDEXED BY messages_preview
|
|
||||||
WHERE
|
|
||||||
conversationId IS $conversationId AND
|
|
||||||
shouldAffectPreview IS 1 AND
|
|
||||||
isGroupLeaveEventFromOther IS 0 AND
|
|
||||||
${includeStoryReplies ? '' : 'storyId IS NULL AND'}
|
|
||||||
${extraClause}
|
|
||||||
ORDER BY received_at DESC, sent_at DESC
|
|
||||||
LIMIT 1
|
|
||||||
`;
|
|
||||||
};
|
|
||||||
|
|
||||||
const row: Row | undefined = prepare(
|
const row: Row | undefined = prepare(
|
||||||
db,
|
db,
|
||||||
`
|
`
|
||||||
SELECT * FROM (${queryTemplate('expiresAt IS NULL')})
|
SELECT json FROM (
|
||||||
UNION ALL
|
SELECT json, expiresAt FROM messages
|
||||||
SELECT * FROM (${queryTemplate('expiresAt > $now')})
|
INDEXED BY ${index}
|
||||||
|
WHERE
|
||||||
|
conversationId IS $conversationId AND
|
||||||
|
shouldAffectPreview IS 1 AND
|
||||||
|
isGroupLeaveEventFromOther IS 0
|
||||||
|
${includeStoryReplies ? '' : 'AND storyId IS NULL'}
|
||||||
ORDER BY received_at DESC, sent_at DESC
|
ORDER BY received_at DESC, sent_at DESC
|
||||||
LIMIT 1;
|
)
|
||||||
|
WHERE likely(expiresAt > $now)
|
||||||
|
LIMIT 1
|
||||||
`
|
`
|
||||||
).get({
|
).get({
|
||||||
conversationId,
|
conversationId,
|
||||||
|
@ -2824,7 +2818,7 @@ async function getLastConversationMessage({
|
||||||
const row = db
|
const row = db
|
||||||
.prepare<Query>(
|
.prepare<Query>(
|
||||||
`
|
`
|
||||||
SELECT * FROM messages WHERE
|
SELECT json FROM messages WHERE
|
||||||
conversationId = $conversationId
|
conversationId = $conversationId
|
||||||
ORDER BY received_at DESC, sent_at DESC
|
ORDER BY received_at DESC, sent_at DESC
|
||||||
LIMIT 1;
|
LIMIT 1;
|
||||||
|
@ -2855,7 +2849,7 @@ function getOldestUnseenMessageForConversation(
|
||||||
const row = db
|
const row = db
|
||||||
.prepare<Query>(
|
.prepare<Query>(
|
||||||
`
|
`
|
||||||
SELECT * FROM messages WHERE
|
SELECT received_at, sent_at, id FROM messages WHERE
|
||||||
conversationId = $conversationId AND
|
conversationId = $conversationId AND
|
||||||
seenStatus = ${SeenStatus.Unseen} AND
|
seenStatus = ${SeenStatus.Unseen} AND
|
||||||
isStory IS 0 AND
|
isStory IS 0 AND
|
||||||
|
@ -3130,7 +3124,6 @@ async function getExpiredMessages(): Promise<Array<MessageType>> {
|
||||||
.prepare<Query>(
|
.prepare<Query>(
|
||||||
`
|
`
|
||||||
SELECT json FROM messages WHERE
|
SELECT json FROM messages WHERE
|
||||||
expiresAt IS NOT NULL AND
|
|
||||||
expiresAt <= $now
|
expiresAt <= $now
|
||||||
ORDER BY expiresAt ASC;
|
ORDER BY expiresAt ASC;
|
||||||
`
|
`
|
||||||
|
@ -3181,6 +3174,10 @@ async function getSoonestMessageExpiry(): Promise<undefined | number> {
|
||||||
.pluck(true)
|
.pluck(true)
|
||||||
.get();
|
.get();
|
||||||
|
|
||||||
|
if (result != null && result >= Number.MAX_SAFE_INTEGER) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
return result || undefined;
|
return result || undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
59
ts/sql/migrations/76-optimize-convo-open-2.ts
Normal file
59
ts/sql/migrations/76-optimize-convo-open-2.ts
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
// Copyright 2023 Signal Messenger, LLC
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
import type { Database } from '@signalapp/better-sqlite3';
|
||||||
|
|
||||||
|
import type { LoggerType } from '../../types/Logging';
|
||||||
|
|
||||||
|
export default function updateToSchemaVersion76(
|
||||||
|
currentVersion: number,
|
||||||
|
db: Database,
|
||||||
|
logger: LoggerType
|
||||||
|
): void {
|
||||||
|
if (currentVersion >= 76) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
db.transaction(() => {
|
||||||
|
db.exec(
|
||||||
|
`
|
||||||
|
-- Re-created below
|
||||||
|
DROP INDEX IF EXISTS message_expires_at;
|
||||||
|
DROP INDEX IF EXISTS messages_preview;
|
||||||
|
|
||||||
|
-- Create non-null expiresAt column
|
||||||
|
ALTER TABLE messages
|
||||||
|
DROP COLUMN expiresAt;
|
||||||
|
|
||||||
|
ALTER TABLE messages
|
||||||
|
ADD COLUMN
|
||||||
|
expiresAt INT
|
||||||
|
GENERATED ALWAYS
|
||||||
|
AS (ifnull(
|
||||||
|
expirationStartTimestamp + (expireTimer * 1000),
|
||||||
|
${Number.MAX_SAFE_INTEGER}
|
||||||
|
));
|
||||||
|
|
||||||
|
-- Re-create indexes
|
||||||
|
-- Note the "s" at the end of "messages"
|
||||||
|
CREATE INDEX messages_expires_at ON messages (
|
||||||
|
expiresAt
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Note that expiresAt is intentionally dropped from the index since
|
||||||
|
-- expiresAt > $now is likely to be true so we just try selecting it
|
||||||
|
-- *after* ordering by received_at/sent_at.
|
||||||
|
CREATE INDEX messages_preview ON messages
|
||||||
|
(conversationId, shouldAffectPreview, isGroupLeaveEventFromOther,
|
||||||
|
received_at, sent_at);
|
||||||
|
CREATE INDEX messages_preview_without_story ON messages
|
||||||
|
(conversationId, shouldAffectPreview, isGroupLeaveEventFromOther,
|
||||||
|
received_at, sent_at) WHERE storyId IS NULL;
|
||||||
|
`
|
||||||
|
);
|
||||||
|
|
||||||
|
db.pragma('user_version = 76');
|
||||||
|
})();
|
||||||
|
|
||||||
|
logger.info('updateToSchemaVersion76: success!');
|
||||||
|
}
|
|
@ -51,6 +51,7 @@ import updateToSchemaVersion72 from './72-optimize-call-id-message-lookup';
|
||||||
import updateToSchemaVersion73 from './73-remove-phone-number-discovery';
|
import updateToSchemaVersion73 from './73-remove-phone-number-discovery';
|
||||||
import updateToSchemaVersion74 from './74-optimize-convo-open';
|
import updateToSchemaVersion74 from './74-optimize-convo-open';
|
||||||
import updateToSchemaVersion75 from './75-signal-tokenizer';
|
import updateToSchemaVersion75 from './75-signal-tokenizer';
|
||||||
|
import updateToSchemaVersion76 from './76-optimize-convo-open-2';
|
||||||
|
|
||||||
function updateToSchemaVersion1(
|
function updateToSchemaVersion1(
|
||||||
currentVersion: number,
|
currentVersion: number,
|
||||||
|
@ -1971,6 +1972,7 @@ export const SCHEMA_VERSIONS = [
|
||||||
updateToSchemaVersion73,
|
updateToSchemaVersion73,
|
||||||
updateToSchemaVersion74,
|
updateToSchemaVersion74,
|
||||||
updateToSchemaVersion75,
|
updateToSchemaVersion75,
|
||||||
|
updateToSchemaVersion76,
|
||||||
];
|
];
|
||||||
|
|
||||||
export function updateSchema(db: Database, logger: LoggerType): void {
|
export function updateSchema(db: Database, logger: LoggerType): void {
|
||||||
|
|
Loading…
Reference in a new issue