mirror of
https://github.com/chatmail/core.git
synced 2026-10-02 03:00:40 +03:00
perf: Add timestamp to msgs_index7 and speed up Chatlist::try_load() (#7848)
This speeds up chatlisting by 3--4 times on my biggest profile, so the difference is visually noticeable, particularly after dropping disk caches. Before, `msgs_index2` was used which has less ordering and requires a full scan of `msgs` table.
This commit is contained in:
+46
-53
@@ -115,10 +115,23 @@ impl Chatlist {
|
|||||||
ChatId::new(0)
|
ChatId::new(0)
|
||||||
};
|
};
|
||||||
|
|
||||||
// select with left join and minimum:
|
macro_rules! last_visible_msg_id_in {
|
||||||
//
|
($chat_id:expr) => {
|
||||||
// - the inner select must use `hidden` and _not_ `m.hidden`
|
concat!(
|
||||||
// which would refer the outer select and take a lot of time
|
"
|
||||||
|
(SELECT id FROM msgs WHERE
|
||||||
|
-- state=`OutDraft`.
|
||||||
|
state=19 AND hidden=1 AND chat_id=",
|
||||||
|
$chat_id,
|
||||||
|
" OR
|
||||||
|
-- `InFresh`...`OutDelivered` inclusive, except `OutDraft`.
|
||||||
|
state IN (10,13,16,20,24,26) AND hidden=0 AND chat_id=",
|
||||||
|
$chat_id,
|
||||||
|
"
|
||||||
|
ORDER BY timestamp DESC, id DESC LIMIT 1)"
|
||||||
|
)
|
||||||
|
};
|
||||||
|
}
|
||||||
// - `GROUP BY` is needed several messages may have the same
|
// - `GROUP BY` is needed several messages may have the same
|
||||||
// timestamp
|
// timestamp
|
||||||
// - the list starts with the newest chats
|
// - the list starts with the newest chats
|
||||||
@@ -127,23 +140,18 @@ impl Chatlist {
|
|||||||
// groups. Otherwise it would be hard to follow conversations.
|
// groups. Otherwise it would be hard to follow conversations.
|
||||||
let ids = if let Some(query_contact_id) = query_contact_id {
|
let ids = if let Some(query_contact_id) = query_contact_id {
|
||||||
// show chats shared with a given contact
|
// show chats shared with a given contact
|
||||||
context.sql.query_map_vec(
|
context.sql.query_map_vec(concat!(
|
||||||
"SELECT c.id, m.id
|
"SELECT c.id, m.id
|
||||||
FROM chats c
|
FROM chats c
|
||||||
LEFT JOIN msgs m
|
LEFT JOIN msgs m
|
||||||
ON c.id=m.chat_id
|
ON c.id=m.chat_id
|
||||||
AND m.id=(
|
AND m.id=", last_visible_msg_id_in!("c.id"), "
|
||||||
SELECT id
|
|
||||||
FROM msgs
|
|
||||||
WHERE chat_id=c.id
|
|
||||||
AND (hidden=0 OR state=?1)
|
|
||||||
ORDER BY timestamp DESC, id DESC LIMIT 1)
|
|
||||||
WHERE c.id>9
|
WHERE c.id>9
|
||||||
AND c.blocked!=1
|
AND c.blocked!=1
|
||||||
AND c.id IN(SELECT chat_id FROM chats_contacts WHERE contact_id=?2 AND add_timestamp >= remove_timestamp)
|
AND c.id IN(SELECT chat_id FROM chats_contacts WHERE contact_id=? AND add_timestamp >= remove_timestamp)
|
||||||
GROUP BY c.id
|
GROUP BY c.id
|
||||||
ORDER BY c.archived=?3 DESC, IFNULL(NULLIF(m.timestamp,0),c.created_timestamp) DESC, m.id DESC;",
|
ORDER BY c.archived=? DESC, IFNULL(NULLIF(m.timestamp,0),c.created_timestamp) DESC, m.id DESC"),
|
||||||
(MessageState::OutDraft, query_contact_id, ChatVisibility::Pinned),
|
(query_contact_id, ChatVisibility::Pinned),
|
||||||
process_row,
|
process_row,
|
||||||
).await?
|
).await?
|
||||||
} else if flag_archived_only {
|
} else if flag_archived_only {
|
||||||
@@ -154,22 +162,22 @@ impl Chatlist {
|
|||||||
context
|
context
|
||||||
.sql
|
.sql
|
||||||
.query_map_vec(
|
.query_map_vec(
|
||||||
"SELECT c.id, m.id
|
concat!(
|
||||||
|
"
|
||||||
|
SELECT c.id, m.id
|
||||||
FROM chats c
|
FROM chats c
|
||||||
LEFT JOIN msgs m
|
LEFT JOIN msgs m
|
||||||
ON c.id=m.chat_id
|
ON c.id=m.chat_id
|
||||||
AND m.id=(
|
AND m.id=",
|
||||||
SELECT id
|
last_visible_msg_id_in!("c.id"),
|
||||||
FROM msgs
|
"
|
||||||
WHERE chat_id=c.id
|
|
||||||
AND (hidden=0 OR state=?)
|
|
||||||
ORDER BY timestamp DESC, id DESC LIMIT 1)
|
|
||||||
WHERE c.id>9
|
WHERE c.id>9
|
||||||
AND c.blocked!=1
|
AND c.blocked!=1
|
||||||
AND c.archived=1
|
AND c.archived=1
|
||||||
GROUP BY c.id
|
GROUP BY c.id
|
||||||
ORDER BY IFNULL(NULLIF(m.timestamp,0),c.created_timestamp) DESC, m.id DESC;",
|
ORDER BY IFNULL(NULLIF(m.timestamp,0),c.created_timestamp) DESC, m.id DESC"
|
||||||
(MessageState::OutDraft,),
|
),
|
||||||
|
(),
|
||||||
process_row,
|
process_row,
|
||||||
)
|
)
|
||||||
.await?
|
.await?
|
||||||
@@ -188,24 +196,19 @@ impl Chatlist {
|
|||||||
let str_like_cmd = format!("%{}%", query.to_lowercase());
|
let str_like_cmd = format!("%{}%", query.to_lowercase());
|
||||||
context
|
context
|
||||||
.sql
|
.sql
|
||||||
.query_map_vec(
|
.query_map_vec(concat!(
|
||||||
"SELECT c.id, m.id
|
"SELECT c.id, m.id
|
||||||
FROM chats c
|
FROM chats c
|
||||||
LEFT JOIN msgs m
|
LEFT JOIN msgs m
|
||||||
ON c.id=m.chat_id
|
ON c.id=m.chat_id
|
||||||
AND m.id=(
|
AND m.id=", last_visible_msg_id_in!("c.id"), "
|
||||||
SELECT id
|
WHERE c.id>9 AND c.id!=?
|
||||||
FROM msgs
|
|
||||||
WHERE chat_id=c.id
|
|
||||||
AND (hidden=0 OR state=?1)
|
|
||||||
ORDER BY timestamp DESC, id DESC LIMIT 1)
|
|
||||||
WHERE c.id>9 AND c.id!=?2
|
|
||||||
AND c.blocked!=1
|
AND c.blocked!=1
|
||||||
AND IFNULL(c.name_normalized,c.name) LIKE ?3
|
AND IFNULL(c.name_normalized,c.name) LIKE ?
|
||||||
AND (NOT ?4 OR EXISTS (SELECT 1 FROM msgs m WHERE m.chat_id = c.id AND m.state == ?5 AND hidden=0))
|
AND (NOT ? OR EXISTS (SELECT 1 FROM msgs m WHERE m.chat_id = c.id AND m.state == ? AND hidden=0))
|
||||||
GROUP BY c.id
|
GROUP BY c.id
|
||||||
ORDER BY IFNULL(NULLIF(m.timestamp,0),c.created_timestamp) DESC, m.id DESC;",
|
ORDER BY IFNULL(NULLIF(m.timestamp,0),c.created_timestamp) DESC, m.id DESC"),
|
||||||
(MessageState::OutDraft, skip_id, str_like_cmd, only_unread, MessageState::InFresh),
|
(skip_id, str_like_cmd, only_unread, MessageState::InFresh),
|
||||||
process_row,
|
process_row,
|
||||||
)
|
)
|
||||||
.await?
|
.await?
|
||||||
@@ -237,25 +240,20 @@ impl Chatlist {
|
|||||||
})
|
})
|
||||||
.collect::<std::result::Result<Vec<_>, _>>()
|
.collect::<std::result::Result<Vec<_>, _>>()
|
||||||
};
|
};
|
||||||
context.sql.query_map(
|
context.sql.query_map(concat!(
|
||||||
"SELECT c.id, c.type, c.param, m.id
|
"SELECT c.id, c.type, c.param, m.id
|
||||||
FROM chats c
|
FROM chats c
|
||||||
LEFT JOIN msgs m
|
LEFT JOIN msgs m
|
||||||
ON c.id=m.chat_id
|
ON c.id=m.chat_id
|
||||||
AND m.id=(
|
AND m.id=", last_visible_msg_id_in!("c.id"), "
|
||||||
SELECT id
|
|
||||||
FROM msgs
|
|
||||||
WHERE chat_id=c.id
|
|
||||||
AND (hidden=0 OR state=?)
|
|
||||||
ORDER BY timestamp DESC, id DESC LIMIT 1)
|
|
||||||
WHERE c.id>9 AND c.id!=?
|
WHERE c.id>9 AND c.id!=?
|
||||||
AND c.blocked=0
|
AND c.blocked=0
|
||||||
AND NOT c.archived=?
|
AND NOT c.archived=?
|
||||||
AND (c.type!=? OR c.id IN(SELECT chat_id FROM chats_contacts WHERE contact_id=? AND add_timestamp >= remove_timestamp))
|
AND (c.type!=? OR c.id IN(SELECT chat_id FROM chats_contacts WHERE contact_id=? AND add_timestamp >= remove_timestamp))
|
||||||
GROUP BY c.id
|
GROUP BY c.id
|
||||||
ORDER BY c.id=? DESC, c.archived=? DESC, IFNULL(NULLIF(m.timestamp,0),c.created_timestamp) DESC, m.id DESC;",
|
ORDER BY c.id=? DESC, c.archived=? DESC, IFNULL(NULLIF(m.timestamp,0),c.created_timestamp) DESC, m.id DESC"),
|
||||||
(
|
(
|
||||||
MessageState::OutDraft, skip_id, ChatVisibility::Archived,
|
skip_id, ChatVisibility::Archived,
|
||||||
Chattype::Group, ContactId::SELF,
|
Chattype::Group, ContactId::SELF,
|
||||||
sort_id_up, ChatVisibility::Pinned,
|
sort_id_up, ChatVisibility::Pinned,
|
||||||
),
|
),
|
||||||
@@ -264,23 +262,18 @@ impl Chatlist {
|
|||||||
).await?
|
).await?
|
||||||
} else {
|
} else {
|
||||||
// show normal chatlist
|
// show normal chatlist
|
||||||
context.sql.query_map_vec(
|
context.sql.query_map_vec(concat!(
|
||||||
"SELECT c.id, m.id
|
"SELECT c.id, m.id
|
||||||
FROM chats c
|
FROM chats c
|
||||||
LEFT JOIN msgs m
|
LEFT JOIN msgs m
|
||||||
ON c.id=m.chat_id
|
ON c.id=m.chat_id
|
||||||
AND m.id=(
|
AND m.id=", last_visible_msg_id_in!("c.id"), "
|
||||||
SELECT id
|
|
||||||
FROM msgs
|
|
||||||
WHERE chat_id=c.id
|
|
||||||
AND (hidden=0 OR state=?)
|
|
||||||
ORDER BY timestamp DESC, id DESC LIMIT 1)
|
|
||||||
WHERE c.id>9 AND c.id!=?
|
WHERE c.id>9 AND c.id!=?
|
||||||
AND (c.blocked=0 OR c.blocked=2)
|
AND (c.blocked=0 OR c.blocked=2)
|
||||||
AND NOT c.archived=?
|
AND NOT c.archived=?
|
||||||
GROUP BY c.id
|
GROUP BY c.id
|
||||||
ORDER BY c.id=0 DESC, c.archived=? DESC, IFNULL(NULLIF(m.timestamp,0),c.created_timestamp) DESC, m.id DESC;",
|
ORDER BY c.id=0 DESC, c.archived=? DESC, IFNULL(NULLIF(m.timestamp,0),c.created_timestamp) DESC, m.id DESC"),
|
||||||
(MessageState::OutDraft, skip_id, ChatVisibility::Archived, ChatVisibility::Pinned),
|
(skip_id, ChatVisibility::Archived, ChatVisibility::Pinned),
|
||||||
process_row,
|
process_row,
|
||||||
).await?
|
).await?
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -2477,6 +2477,16 @@ UPDATE msgs SET state=24 WHERE state=18; -- Change OutPreparing to OutFailed.
|
|||||||
.await?;
|
.await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inc_and_check(&mut migration_version, 156)?;
|
||||||
|
if dbversion < migration_version {
|
||||||
|
sql.execute_migration(
|
||||||
|
"DROP INDEX IF EXISTS msgs_index7;
|
||||||
|
CREATE INDEX msgs_index7 ON msgs (state, hidden, chat_id, timestamp);",
|
||||||
|
migration_version,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
|
|
||||||
let new_version = sql
|
let new_version = sql
|
||||||
.get_raw_config_int(VERSION_CFG)
|
.get_raw_config_int(VERSION_CFG)
|
||||||
.await?
|
.await?
|
||||||
|
|||||||
Reference in New Issue
Block a user