From d69511bcad4df0706eae412a0a304576fa47b221 Mon Sep 17 00:00:00 2001 From: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com> Date: Thu, 24 Jul 2025 22:36:08 +0000 Subject: [PATCH] core: improve indexes (#6095) * core: improve indexes * update plans * queries * postgres migration * optimize query * lint * plans * add indexes * schema * plans * postgres schema --------- Co-authored-by: Evgeny Poberezkin --- simplex-chat.cabal | 2 + src/Simplex/Chat/Store/Direct.hs | 4 +- src/Simplex/Chat/Store/Messages.hs | 6 +- src/Simplex/Chat/Store/Postgres/Migrations.hs | 4 +- .../Postgres/Migrations/M20250721_indexes.hs | 37 +++++++ .../Store/Postgres/Migrations/chat_schema.sql | 6 +- src/Simplex/Chat/Store/SQLite/Migrations.hs | 4 +- .../SQLite/Migrations/M20250721_indexes.hs | 34 +++++++ .../SQLite/Migrations/chat_query_plans.txt | 96 +++++++++---------- .../Store/SQLite/Migrations/chat_schema.sql | 14 ++- tests/SchemaDump.hs | 4 +- 11 files changed, 153 insertions(+), 58 deletions(-) create mode 100644 src/Simplex/Chat/Store/Postgres/Migrations/M20250721_indexes.hs create mode 100644 src/Simplex/Chat/Store/SQLite/Migrations/M20250721_indexes.hs diff --git a/simplex-chat.cabal b/simplex-chat.cabal index 6500f030d5..b4a98a85f2 100644 --- a/simplex-chat.cabal +++ b/simplex-chat.cabal @@ -111,6 +111,7 @@ library Simplex.Chat.Store.Postgres.Migrations.M20250702_contact_requests_remove_cascade_delete Simplex.Chat.Store.Postgres.Migrations.M20250704_groups_conn_link_prepared_connection Simplex.Chat.Store.Postgres.Migrations.M20250709_profile_short_descr + Simplex.Chat.Store.Postgres.Migrations.M20250721_indexes else exposed-modules: Simplex.Chat.Archive @@ -247,6 +248,7 @@ library Simplex.Chat.Store.SQLite.Migrations.M20250702_contact_requests_remove_cascade_delete Simplex.Chat.Store.SQLite.Migrations.M20250704_groups_conn_link_prepared_connection Simplex.Chat.Store.SQLite.Migrations.M20250709_profile_short_descr + Simplex.Chat.Store.SQLite.Migrations.M20250721_indexes other-modules: Paths_simplex_chat hs-source-dirs: diff --git a/src/Simplex/Chat/Store/Direct.hs b/src/Simplex/Chat/Store/Direct.hs index 08dc2f09c3..6fd064d853 100644 --- a/src/Simplex/Chat/Store/Direct.hs +++ b/src/Simplex/Chat/Store/Direct.hs @@ -724,9 +724,9 @@ getContactRequest' db User {userId} contactRequestId = DB.query db (contactRequestQuery <> " WHERE cr.user_id = ? AND cr.contact_request_id = ?") (userId, contactRequestId) getBusinessContactRequest :: DB.Connection -> User -> GroupId -> IO (Maybe UserContactRequest) -getBusinessContactRequest db User {userId} groupId = +getBusinessContactRequest db _user groupId = maybeFirstRow toContactRequest $ - DB.query db (contactRequestQuery <> " WHERE cr.user_id = ? AND cr.business_group_id = ?") (userId, groupId) + DB.query db (contactRequestQuery <> " WHERE cr.business_group_id = ?") (Only groupId) contactRequestQuery :: Query contactRequestQuery = diff --git a/src/Simplex/Chat/Store/Messages.hs b/src/Simplex/Chat/Store/Messages.hs index 7f82a8ee5f..a09ed349ef 100644 --- a/src/Simplex/Chat/Store/Messages.hs +++ b/src/Simplex/Chat/Store/Messages.hs @@ -832,7 +832,7 @@ findGroupChatPreviews_ db User {userId} pagination clq = ( SELECT chat_item_id FROM chat_items ci - WHERE ci.user_id = ? AND ci.group_id = g.group_id AND ci.group_scope_tag IS NULL + WHERE ci.user_id = ? AND ci.group_id = g.group_id AND ci.group_scope_tag IS NULL AND ci.group_scope_group_member_id IS NULL ORDER BY ci.item_ts DESC LIMIT 1 ) AS chat_item_id, @@ -845,7 +845,7 @@ findGroupChatPreviews_ db User {userId} pagination clq = LEFT JOIN ( SELECT group_id, COUNT(1) AS UnreadCount, SUM(user_mention) as UnreadMentions, MIN(chat_item_id) AS MinUnread FROM chat_items - WHERE user_id = ? AND group_id IS NOT NULL AND group_scope_tag IS NULL AND item_status = ? + WHERE user_id = ? AND group_id IS NOT NULL AND group_scope_tag IS NULL AND group_scope_group_member_id IS NULL AND item_status = ? GROUP BY group_id ) ChatStats ON ChatStats.group_id = g.group_id LEFT JOIN ( @@ -1608,7 +1608,7 @@ getGroupUnreadCount_ :: DB.Connection -> User -> GroupInfo -> Maybe GroupChatSco getGroupUnreadCount_ db user g scopeInfo_ contentFilter = head <$> queryUnreadGroupItems db user g scopeInfo_ contentFilter baseQuery "" where - baseQuery = "SELECT COUNT(1), COALESCE(SUM(user_mention), 0) FROM chat_items WHERE user_id = ? AND group_id = ? AND group_scope_tag IS NULL " + baseQuery = "SELECT COUNT(1), COALESCE(SUM(user_mention), 0) FROM chat_items WHERE user_id = ? AND group_id = ? AND group_scope_tag IS NULL AND group_scope_group_member_id IS NULL " getGroupReportsCount_ :: DB.Connection -> User -> GroupInfo -> Bool -> IO Int getGroupReportsCount_ db User {userId} GroupInfo {groupId} archived = diff --git a/src/Simplex/Chat/Store/Postgres/Migrations.hs b/src/Simplex/Chat/Store/Postgres/Migrations.hs index b3ca626ca3..b5b7be8adb 100644 --- a/src/Simplex/Chat/Store/Postgres/Migrations.hs +++ b/src/Simplex/Chat/Store/Postgres/Migrations.hs @@ -12,6 +12,7 @@ import Simplex.Chat.Store.Postgres.Migrations.M20250526_short_links import Simplex.Chat.Store.Postgres.Migrations.M20250702_contact_requests_remove_cascade_delete import Simplex.Chat.Store.Postgres.Migrations.M20250704_groups_conn_link_prepared_connection import Simplex.Chat.Store.Postgres.Migrations.M20250709_profile_short_descr +import Simplex.Chat.Store.Postgres.Migrations.M20250721_indexes import Simplex.Messaging.Agent.Store.Shared (Migration (..)) schemaMigrations :: [(String, Text, Maybe Text)] @@ -23,7 +24,8 @@ schemaMigrations = ("20250526_short_links", m20250526_short_links, Just down_m20250526_short_links), ("20250702_contact_requests_remove_cascade_delete", m20250702_contact_requests_remove_cascade_delete, Just down_m20250702_contact_requests_remove_cascade_delete), ("20250704_groups_conn_link_prepared_connection", m20250704_groups_conn_link_prepared_connection, Just down_m20250704_groups_conn_link_prepared_connection), - ("20250709_profile_short_descr", m20250709_profile_short_descr, Just down_m20250709_profile_short_descr) + ("20250709_profile_short_descr", m20250709_profile_short_descr, Just down_m20250709_profile_short_descr), + ("20250721_indexes", m20250721_indexes, Just down_m20250721_indexes) ] -- | The list of migrations in ascending order by date diff --git a/src/Simplex/Chat/Store/Postgres/Migrations/M20250721_indexes.hs b/src/Simplex/Chat/Store/Postgres/Migrations/M20250721_indexes.hs new file mode 100644 index 0000000000..6c07730828 --- /dev/null +++ b/src/Simplex/Chat/Store/Postgres/Migrations/M20250721_indexes.hs @@ -0,0 +1,37 @@ +{-# LANGUAGE QuasiQuotes #-} + +module Simplex.Chat.Store.Postgres.Migrations.M20250721_indexes where + +import Data.Text (Text) +import qualified Data.Text as T +import Text.RawString.QQ (r) + +m20250721_indexes :: Text +m20250721_indexes = + T.pack + [r| +DROP INDEX idx_contact_requests_xcontact_id; + +CREATE INDEX idx_contact_requests_xcontact_id ON contact_requests(user_id, xcontact_id); + +CREATE INDEX idx_chat_items_group_scope_stats_all ON chat_items ( + user_id, + group_id, + group_scope_tag, + group_scope_group_member_id, + item_status, + chat_item_id, + user_mention +); +|] + +down_m20250721_indexes :: Text +down_m20250721_indexes = + T.pack + [r| +DROP INDEX idx_contact_requests_xcontact_id; + +CREATE INDEX idx_contact_requests_xcontact_id ON contact_requests(xcontact_id); + +DROP INDEX idx_chat_items_group_scope_stats_all; +|] diff --git a/src/Simplex/Chat/Store/Postgres/Migrations/chat_schema.sql b/src/Simplex/Chat/Store/Postgres/Migrations/chat_schema.sql index 81a2cdc505..b236093a79 100644 --- a/src/Simplex/Chat/Store/Postgres/Migrations/chat_schema.sql +++ b/src/Simplex/Chat/Store/Postgres/Migrations/chat_schema.sql @@ -1624,6 +1624,10 @@ CREATE INDEX idx_chat_items_group_scope_item_ts ON test_chat_schema.chat_items U +CREATE INDEX idx_chat_items_group_scope_stats_all ON test_chat_schema.chat_items USING btree (user_id, group_id, group_scope_tag, group_scope_group_member_id, item_status, chat_item_id, user_mention); + + + CREATE UNIQUE INDEX idx_chat_items_group_shared_msg_id ON test_chat_schema.chat_items USING btree (user_id, group_id, group_member_id, shared_msg_id); @@ -1784,7 +1788,7 @@ CREATE INDEX idx_contact_requests_user_contact_link_id ON test_chat_schema.conta -CREATE INDEX idx_contact_requests_xcontact_id ON test_chat_schema.contact_requests USING btree (xcontact_id); +CREATE INDEX idx_contact_requests_xcontact_id ON test_chat_schema.contact_requests USING btree (user_id, xcontact_id); diff --git a/src/Simplex/Chat/Store/SQLite/Migrations.hs b/src/Simplex/Chat/Store/SQLite/Migrations.hs index fb13f1dcc8..47f1f5c041 100644 --- a/src/Simplex/Chat/Store/SQLite/Migrations.hs +++ b/src/Simplex/Chat/Store/SQLite/Migrations.hs @@ -135,6 +135,7 @@ import Simplex.Chat.Store.SQLite.Migrations.M20250526_short_links import Simplex.Chat.Store.SQLite.Migrations.M20250702_contact_requests_remove_cascade_delete import Simplex.Chat.Store.SQLite.Migrations.M20250704_groups_conn_link_prepared_connection import Simplex.Chat.Store.SQLite.Migrations.M20250709_profile_short_descr +import Simplex.Chat.Store.SQLite.Migrations.M20250721_indexes import Simplex.Messaging.Agent.Store.Shared (Migration (..)) schemaMigrations :: [(String, Query, Maybe Query)] @@ -269,7 +270,8 @@ schemaMigrations = ("20250526_short_links", m20250526_short_links, Just down_m20250526_short_links), ("20250702_contact_requests_remove_cascade_delete", m20250702_contact_requests_remove_cascade_delete, Just down_m20250702_contact_requests_remove_cascade_delete), ("20250704_groups_conn_link_prepared_connection", m20250704_groups_conn_link_prepared_connection, Just down_m20250704_groups_conn_link_prepared_connection), - ("20250709_profile_short_descr", m20250709_profile_short_descr, Just down_m20250709_profile_short_descr) + ("20250709_profile_short_descr", m20250709_profile_short_descr, Just down_m20250709_profile_short_descr), + ("20250721_indexes", m20250721_indexes, Just down_m20250721_indexes) ] -- | The list of migrations in ascending order by date diff --git a/src/Simplex/Chat/Store/SQLite/Migrations/M20250721_indexes.hs b/src/Simplex/Chat/Store/SQLite/Migrations/M20250721_indexes.hs new file mode 100644 index 0000000000..98ebc0195b --- /dev/null +++ b/src/Simplex/Chat/Store/SQLite/Migrations/M20250721_indexes.hs @@ -0,0 +1,34 @@ +{-# LANGUAGE QuasiQuotes #-} + +module Simplex.Chat.Store.SQLite.Migrations.M20250721_indexes where + +import Database.SQLite.Simple (Query) +import Database.SQLite.Simple.QQ (sql) + +m20250721_indexes :: Query +m20250721_indexes = + [sql| +DROP INDEX idx_contact_requests_xcontact_id; + +CREATE INDEX idx_contact_requests_xcontact_id ON contact_requests(user_id, xcontact_id); + +CREATE INDEX idx_chat_items_group_scope_stats_all ON chat_items ( + user_id, + group_id, + group_scope_tag, + group_scope_group_member_id, + item_status, + chat_item_id, + user_mention +); +|] + +down_m20250721_indexes :: Query +down_m20250721_indexes = + [sql| +DROP INDEX idx_contact_requests_xcontact_id; + +CREATE INDEX idx_contact_requests_xcontact_id ON contact_requests(xcontact_id); + +DROP INDEX idx_chat_items_group_scope_stats_all; +|] diff --git a/src/Simplex/Chat/Store/SQLite/Migrations/chat_query_plans.txt b/src/Simplex/Chat/Store/SQLite/Migrations/chat_query_plans.txt index f985852d7a..968697b1c3 100644 --- a/src/Simplex/Chat/Store/SQLite/Migrations/chat_query_plans.txt +++ b/src/Simplex/Chat/Store/SQLite/Migrations/chat_query_plans.txt @@ -410,7 +410,7 @@ Query: LIMIT 1 Plan: -SEARCH cr USING INDEX idx_contact_requests_updated_at (user_id=?) +SEARCH cr USING INDEX idx_contact_requests_xcontact_id (user_id=? AND xcontact_id=?) SEARCH p USING INTEGER PRIMARY KEY (rowid=?) Query: @@ -2132,7 +2132,7 @@ Query: ( SELECT chat_item_id FROM chat_items ci - WHERE ci.user_id = ? AND ci.group_id = g.group_id AND ci.group_scope_tag IS NULL + WHERE ci.user_id = ? AND ci.group_id = g.group_id AND ci.group_scope_tag IS NULL AND ci.group_scope_group_member_id IS NULL ORDER BY ci.item_ts DESC LIMIT 1 ) AS chat_item_id, @@ -2145,7 +2145,7 @@ Query: LEFT JOIN ( SELECT group_id, COUNT(1) AS UnreadCount, SUM(user_mention) as UnreadMentions, MIN(chat_item_id) AS MinUnread FROM chat_items - WHERE user_id = ? AND group_id IS NOT NULL AND group_scope_tag IS NULL AND item_status = ? + WHERE user_id = ? AND group_id IS NOT NULL AND group_scope_tag IS NULL AND group_scope_group_member_id IS NULL AND item_status = ? GROUP BY group_id ) ChatStats ON ChatStats.group_id = g.group_id LEFT JOIN ( @@ -2168,7 +2168,7 @@ Query: ORDER BY g.chat_ts DESC LIMIT ? Plan: MATERIALIZE ChatStats -SEARCH chat_items USING INDEX idx_chat_items_groups_user_mention (user_id=? AND group_id>?) +SEARCH chat_items USING COVERING INDEX idx_chat_items_group_scope_stats_all (user_id=? AND group_id>?) MATERIALIZE ReportCount SEARCH chat_items USING COVERING INDEX idx_chat_items_groups_msg_content_tag_deleted (user_id=? AND group_id>?) SEARCH g USING INDEX idx_groups_chat_ts (user_id=?) @@ -2176,7 +2176,7 @@ SEARCH gp USING INTEGER PRIMARY KEY (rowid=?) SEARCH ChatStats USING AUTOMATIC COVERING INDEX (group_id=?) LEFT-JOIN SEARCH ReportCount USING AUTOMATIC COVERING INDEX (group_id=?) LEFT-JOIN CORRELATED SCALAR SUBQUERY 1 -SEARCH ci USING INDEX idx_chat_items_groups_item_ts (user_id=? AND group_id=?) +SEARCH ci USING COVERING INDEX idx_chat_items_group_scope_item_ts (user_id=? AND group_id=? AND group_scope_tag=? AND group_scope_group_member_id=?) Query: SELECT @@ -2185,7 +2185,7 @@ Query: ( SELECT chat_item_id FROM chat_items ci - WHERE ci.user_id = ? AND ci.group_id = g.group_id AND ci.group_scope_tag IS NULL + WHERE ci.user_id = ? AND ci.group_id = g.group_id AND ci.group_scope_tag IS NULL AND ci.group_scope_group_member_id IS NULL ORDER BY ci.item_ts DESC LIMIT 1 ) AS chat_item_id, @@ -2198,7 +2198,7 @@ Query: LEFT JOIN ( SELECT group_id, COUNT(1) AS UnreadCount, SUM(user_mention) as UnreadMentions, MIN(chat_item_id) AS MinUnread FROM chat_items - WHERE user_id = ? AND group_id IS NOT NULL AND group_scope_tag IS NULL AND item_status = ? + WHERE user_id = ? AND group_id IS NOT NULL AND group_scope_tag IS NULL AND group_scope_group_member_id IS NULL AND item_status = ? GROUP BY group_id ) ChatStats ON ChatStats.group_id = g.group_id LEFT JOIN ( @@ -2215,14 +2215,14 @@ Query: ORDER BY g.chat_ts DESC LIMIT ? Plan: MATERIALIZE ChatStats -SEARCH chat_items USING INDEX idx_chat_items_groups_user_mention (user_id=? AND group_id>?) +SEARCH chat_items USING COVERING INDEX idx_chat_items_group_scope_stats_all (user_id=? AND group_id>?) MATERIALIZE ReportCount SEARCH chat_items USING COVERING INDEX idx_chat_items_groups_msg_content_tag_deleted (user_id=? AND group_id>?) SEARCH g USING INDEX idx_groups_chat_ts (user_id=?) SEARCH ChatStats USING AUTOMATIC COVERING INDEX (group_id=?) LEFT-JOIN SEARCH ReportCount USING AUTOMATIC COVERING INDEX (group_id=?) LEFT-JOIN CORRELATED SCALAR SUBQUERY 1 -SEARCH ci USING INDEX idx_chat_items_groups_item_ts (user_id=? AND group_id=?) +SEARCH ci USING COVERING INDEX idx_chat_items_group_scope_item_ts (user_id=? AND group_id=? AND group_scope_tag=? AND group_scope_group_member_id=?) Query: SELECT @@ -2231,7 +2231,7 @@ Query: ( SELECT chat_item_id FROM chat_items ci - WHERE ci.user_id = ? AND ci.group_id = g.group_id AND ci.group_scope_tag IS NULL + WHERE ci.user_id = ? AND ci.group_id = g.group_id AND ci.group_scope_tag IS NULL AND ci.group_scope_group_member_id IS NULL ORDER BY ci.item_ts DESC LIMIT 1 ) AS chat_item_id, @@ -2244,7 +2244,7 @@ Query: LEFT JOIN ( SELECT group_id, COUNT(1) AS UnreadCount, SUM(user_mention) as UnreadMentions, MIN(chat_item_id) AS MinUnread FROM chat_items - WHERE user_id = ? AND group_id IS NOT NULL AND group_scope_tag IS NULL AND item_status = ? + WHERE user_id = ? AND group_id IS NOT NULL AND group_scope_tag IS NULL AND group_scope_group_member_id IS NULL AND item_status = ? GROUP BY group_id ) ChatStats ON ChatStats.group_id = g.group_id LEFT JOIN ( @@ -2260,14 +2260,14 @@ Query: AND g.chat_ts < ? ORDER BY g.chat_ts DESC LIMIT ? Plan: MATERIALIZE ChatStats -SEARCH chat_items USING INDEX idx_chat_items_groups_user_mention (user_id=? AND group_id>?) +SEARCH chat_items USING COVERING INDEX idx_chat_items_group_scope_stats_all (user_id=? AND group_id>?) MATERIALIZE ReportCount SEARCH chat_items USING COVERING INDEX idx_chat_items_groups_msg_content_tag_deleted (user_id=? AND group_id>?) SEARCH g USING INDEX idx_groups_chat_ts (user_id=? AND chat_ts ? ORDER BY g.chat_ts ASC LIMIT ? Plan: MATERIALIZE ChatStats -SEARCH chat_items USING INDEX idx_chat_items_groups_user_mention (user_id=? AND group_id>?) +SEARCH chat_items USING COVERING INDEX idx_chat_items_group_scope_stats_all (user_id=? AND group_id>?) MATERIALIZE ReportCount SEARCH chat_items USING COVERING INDEX idx_chat_items_groups_msg_content_tag_deleted (user_id=? AND group_id>?) SEARCH g USING INDEX idx_groups_chat_ts (user_id=? AND chat_ts>?) SEARCH ChatStats USING AUTOMATIC COVERING INDEX (group_id=?) LEFT-JOIN SEARCH ReportCount USING AUTOMATIC COVERING INDEX (group_id=?) LEFT-JOIN CORRELATED SCALAR SUBQUERY 1 -SEARCH ci USING INDEX idx_chat_items_groups_item_ts (user_id=? AND group_id=?) +SEARCH ci USING COVERING INDEX idx_chat_items_group_scope_item_ts (user_id=? AND group_id=? AND group_scope_tag=? AND group_scope_group_member_id=?) Query: SELECT @@ -2321,7 +2321,7 @@ Query: ( SELECT chat_item_id FROM chat_items ci - WHERE ci.user_id = ? AND ci.group_id = g.group_id AND ci.group_scope_tag IS NULL + WHERE ci.user_id = ? AND ci.group_id = g.group_id AND ci.group_scope_tag IS NULL AND ci.group_scope_group_member_id IS NULL ORDER BY ci.item_ts DESC LIMIT 1 ) AS chat_item_id, @@ -2334,7 +2334,7 @@ Query: LEFT JOIN ( SELECT group_id, COUNT(1) AS UnreadCount, SUM(user_mention) as UnreadMentions, MIN(chat_item_id) AS MinUnread FROM chat_items - WHERE user_id = ? AND group_id IS NOT NULL AND group_scope_tag IS NULL AND item_status = ? + WHERE user_id = ? AND group_id IS NOT NULL AND group_scope_tag IS NULL AND group_scope_group_member_id IS NULL AND item_status = ? GROUP BY group_id ) ChatStats ON ChatStats.group_id = g.group_id LEFT JOIN ( @@ -2350,14 +2350,14 @@ Query: ORDER BY g.chat_ts DESC LIMIT ? Plan: MATERIALIZE ChatStats -SEARCH chat_items USING INDEX idx_chat_items_groups_user_mention (user_id=? AND group_id>?) +SEARCH chat_items USING COVERING INDEX idx_chat_items_group_scope_stats_all (user_id=? AND group_id>?) MATERIALIZE ReportCount SEARCH chat_items USING COVERING INDEX idx_chat_items_groups_msg_content_tag_deleted (user_id=? AND group_id>?) SEARCH g USING INDEX idx_groups_chat_ts (user_id=?) SEARCH ChatStats USING AUTOMATIC COVERING INDEX (group_id=?) LEFT-JOIN SEARCH ReportCount USING AUTOMATIC COVERING INDEX (group_id=?) LEFT-JOIN CORRELATED SCALAR SUBQUERY 1 -SEARCH ci USING INDEX idx_chat_items_groups_item_ts (user_id=? AND group_id=?) +SEARCH ci USING COVERING INDEX idx_chat_items_group_scope_item_ts (user_id=? AND group_id=? AND group_scope_tag=? AND group_scope_group_member_id=?) Query: SELECT @@ -2366,7 +2366,7 @@ Query: ( SELECT chat_item_id FROM chat_items ci - WHERE ci.user_id = ? AND ci.group_id = g.group_id AND ci.group_scope_tag IS NULL + WHERE ci.user_id = ? AND ci.group_id = g.group_id AND ci.group_scope_tag IS NULL AND ci.group_scope_group_member_id IS NULL ORDER BY ci.item_ts DESC LIMIT 1 ) AS chat_item_id, @@ -2379,7 +2379,7 @@ Query: LEFT JOIN ( SELECT group_id, COUNT(1) AS UnreadCount, SUM(user_mention) as UnreadMentions, MIN(chat_item_id) AS MinUnread FROM chat_items - WHERE user_id = ? AND group_id IS NOT NULL AND group_scope_tag IS NULL AND item_status = ? + WHERE user_id = ? AND group_id IS NOT NULL AND group_scope_tag IS NULL AND group_scope_group_member_id IS NULL AND item_status = ? GROUP BY group_id ) ChatStats ON ChatStats.group_id = g.group_id LEFT JOIN ( @@ -2395,14 +2395,14 @@ Query: AND g.chat_ts < ? ORDER BY g.chat_ts DESC LIMIT ? Plan: MATERIALIZE ChatStats -SEARCH chat_items USING INDEX idx_chat_items_groups_user_mention (user_id=? AND group_id>?) +SEARCH chat_items USING COVERING INDEX idx_chat_items_group_scope_stats_all (user_id=? AND group_id>?) MATERIALIZE ReportCount SEARCH chat_items USING COVERING INDEX idx_chat_items_groups_msg_content_tag_deleted (user_id=? AND group_id>?) SEARCH g USING INDEX idx_groups_chat_ts (user_id=? AND chat_ts ? ORDER BY g.chat_ts ASC LIMIT ? Plan: MATERIALIZE ChatStats -SEARCH chat_items USING INDEX idx_chat_items_groups_user_mention (user_id=? AND group_id>?) +SEARCH chat_items USING COVERING INDEX idx_chat_items_group_scope_stats_all (user_id=? AND group_id>?) MATERIALIZE ReportCount SEARCH chat_items USING COVERING INDEX idx_chat_items_groups_msg_content_tag_deleted (user_id=? AND group_id>?) SEARCH g USING INDEX idx_groups_chat_ts (user_id=? AND chat_ts>?) SEARCH ChatStats USING AUTOMATIC COVERING INDEX (group_id=?) LEFT-JOIN SEARCH ReportCount USING AUTOMATIC COVERING INDEX (group_id=?) LEFT-JOIN CORRELATED SCALAR SUBQUERY 1 -SEARCH ci USING INDEX idx_chat_items_groups_item_ts (user_id=? AND group_id=?) +SEARCH ci USING COVERING INDEX idx_chat_items_group_scope_item_ts (user_id=? AND group_id=? AND group_scope_tag=? AND group_scope_group_member_id=?) Query: SELECT @@ -2456,7 +2456,7 @@ Query: ( SELECT chat_item_id FROM chat_items ci - WHERE ci.user_id = ? AND ci.group_id = g.group_id AND ci.group_scope_tag IS NULL + WHERE ci.user_id = ? AND ci.group_id = g.group_id AND ci.group_scope_tag IS NULL AND ci.group_scope_group_member_id IS NULL ORDER BY ci.item_ts DESC LIMIT 1 ) AS chat_item_id, @@ -2469,7 +2469,7 @@ Query: LEFT JOIN ( SELECT group_id, COUNT(1) AS UnreadCount, SUM(user_mention) as UnreadMentions, MIN(chat_item_id) AS MinUnread FROM chat_items - WHERE user_id = ? AND group_id IS NOT NULL AND group_scope_tag IS NULL AND item_status = ? + WHERE user_id = ? AND group_id IS NOT NULL AND group_scope_tag IS NULL AND group_scope_group_member_id IS NULL AND item_status = ? GROUP BY group_id ) ChatStats ON ChatStats.group_id = g.group_id LEFT JOIN ( @@ -2485,14 +2485,14 @@ Query: ORDER BY g.chat_ts DESC LIMIT ? Plan: MATERIALIZE ChatStats -SEARCH chat_items USING INDEX idx_chat_items_groups_user_mention (user_id=? AND group_id>?) +SEARCH chat_items USING COVERING INDEX idx_chat_items_group_scope_stats_all (user_id=? AND group_id>?) MATERIALIZE ReportCount SEARCH chat_items USING COVERING INDEX idx_chat_items_groups_msg_content_tag_deleted (user_id=? AND group_id>?) SEARCH g USING INDEX idx_groups_chat_ts (user_id=?) SEARCH ChatStats USING AUTOMATIC COVERING INDEX (group_id=?) LEFT-JOIN SEARCH ReportCount USING AUTOMATIC COVERING INDEX (group_id=?) LEFT-JOIN CORRELATED SCALAR SUBQUERY 1 -SEARCH ci USING INDEX idx_chat_items_groups_item_ts (user_id=? AND group_id=?) +SEARCH ci USING COVERING INDEX idx_chat_items_group_scope_item_ts (user_id=? AND group_id=? AND group_scope_tag=? AND group_scope_group_member_id=?) Query: SELECT @@ -2501,7 +2501,7 @@ Query: ( SELECT chat_item_id FROM chat_items ci - WHERE ci.user_id = ? AND ci.group_id = g.group_id AND ci.group_scope_tag IS NULL + WHERE ci.user_id = ? AND ci.group_id = g.group_id AND ci.group_scope_tag IS NULL AND ci.group_scope_group_member_id IS NULL ORDER BY ci.item_ts DESC LIMIT 1 ) AS chat_item_id, @@ -2514,7 +2514,7 @@ Query: LEFT JOIN ( SELECT group_id, COUNT(1) AS UnreadCount, SUM(user_mention) as UnreadMentions, MIN(chat_item_id) AS MinUnread FROM chat_items - WHERE user_id = ? AND group_id IS NOT NULL AND group_scope_tag IS NULL AND item_status = ? + WHERE user_id = ? AND group_id IS NOT NULL AND group_scope_tag IS NULL AND group_scope_group_member_id IS NULL AND item_status = ? GROUP BY group_id ) ChatStats ON ChatStats.group_id = g.group_id LEFT JOIN ( @@ -2527,14 +2527,14 @@ Query: WHERE g.user_id = ? AND g.chat_ts < ? ORDER BY g.chat_ts DESC LIMIT ? Plan: MATERIALIZE ChatStats -SEARCH chat_items USING INDEX idx_chat_items_groups_user_mention (user_id=? AND group_id>?) +SEARCH chat_items USING COVERING INDEX idx_chat_items_group_scope_stats_all (user_id=? AND group_id>?) MATERIALIZE ReportCount SEARCH chat_items USING COVERING INDEX idx_chat_items_groups_msg_content_tag_deleted (user_id=? AND group_id>?) SEARCH g USING INDEX idx_groups_chat_ts (user_id=? AND chat_ts ? ORDER BY g.chat_ts ASC LIMIT ? Plan: MATERIALIZE ChatStats -SEARCH chat_items USING INDEX idx_chat_items_groups_user_mention (user_id=? AND group_id>?) +SEARCH chat_items USING COVERING INDEX idx_chat_items_group_scope_stats_all (user_id=? AND group_id>?) MATERIALIZE ReportCount SEARCH chat_items USING COVERING INDEX idx_chat_items_groups_msg_content_tag_deleted (user_id=? AND group_id>?) SEARCH g USING INDEX idx_groups_chat_ts (user_id=? AND chat_ts>?) SEARCH ChatStats USING AUTOMATIC COVERING INDEX (group_id=?) LEFT-JOIN SEARCH ReportCount USING AUTOMATIC COVERING INDEX (group_id=?) LEFT-JOIN CORRELATED SCALAR SUBQUERY 1 -SEARCH ci USING INDEX idx_chat_items_groups_item_ts (user_id=? AND group_id=?) +SEARCH ci USING COVERING INDEX idx_chat_items_group_scope_item_ts (user_id=? AND group_id=? AND group_scope_tag=? AND group_scope_group_member_id=?) Query: SELECT @@ -2585,7 +2585,7 @@ Query: ( SELECT chat_item_id FROM chat_items ci - WHERE ci.user_id = ? AND ci.group_id = g.group_id AND ci.group_scope_tag IS NULL + WHERE ci.user_id = ? AND ci.group_id = g.group_id AND ci.group_scope_tag IS NULL AND ci.group_scope_group_member_id IS NULL ORDER BY ci.item_ts DESC LIMIT 1 ) AS chat_item_id, @@ -2598,7 +2598,7 @@ Query: LEFT JOIN ( SELECT group_id, COUNT(1) AS UnreadCount, SUM(user_mention) as UnreadMentions, MIN(chat_item_id) AS MinUnread FROM chat_items - WHERE user_id = ? AND group_id IS NOT NULL AND group_scope_tag IS NULL AND item_status = ? + WHERE user_id = ? AND group_id IS NOT NULL AND group_scope_tag IS NULL AND group_scope_group_member_id IS NULL AND item_status = ? GROUP BY group_id ) ChatStats ON ChatStats.group_id = g.group_id LEFT JOIN ( @@ -2611,14 +2611,14 @@ Query: WHERE g.user_id = ? ORDER BY g.chat_ts DESC LIMIT ? Plan: MATERIALIZE ChatStats -SEARCH chat_items USING INDEX idx_chat_items_groups_user_mention (user_id=? AND group_id>?) +SEARCH chat_items USING COVERING INDEX idx_chat_items_group_scope_stats_all (user_id=? AND group_id>?) MATERIALIZE ReportCount SEARCH chat_items USING COVERING INDEX idx_chat_items_groups_msg_content_tag_deleted (user_id=? AND group_id>?) SEARCH g USING INDEX idx_groups_chat_ts (user_id=?) SEARCH ChatStats USING AUTOMATIC COVERING INDEX (group_id=?) LEFT-JOIN SEARCH ReportCount USING AUTOMATIC COVERING INDEX (group_id=?) LEFT-JOIN CORRELATED SCALAR SUBQUERY 1 -SEARCH ci USING INDEX idx_chat_items_groups_item_ts (user_id=? AND group_id=?) +SEARCH ci USING COVERING INDEX idx_chat_items_group_scope_item_ts (user_id=? AND group_id=? AND group_scope_tag=? AND group_scope_group_member_id=?) Query: SELECT @@ -4784,7 +4784,7 @@ Query: cr.peer_chat_min_version, cr.peer_chat_max_version FROM contact_requests cr JOIN contact_profiles p USING (contact_profile_id) - WHERE cr.user_id = ? AND cr.business_group_id = ? + WHERE cr.business_group_id = ? Plan: SEARCH cr USING INDEX idx_contact_requests_business_group_id (business_group_id=?) SEARCH p USING INTEGER PRIMARY KEY (rowid=?) @@ -5826,9 +5826,9 @@ Query: SELECT COUNT(1) FROM groups WHERE user_id = ? AND chat_item_ttl > 0 Plan: SEARCH groups USING INDEX idx_groups_chat_ts (user_id=?) -Query: SELECT COUNT(1), COALESCE(SUM(user_mention), 0) FROM chat_items WHERE user_id = ? AND group_id = ? AND group_scope_tag IS NULL AND group_scope_tag IS NULL AND group_scope_group_member_id IS NULL AND item_status = ? +Query: SELECT COUNT(1), COALESCE(SUM(user_mention), 0) FROM chat_items WHERE user_id = ? AND group_id = ? AND group_scope_tag IS NULL AND group_scope_group_member_id IS NULL AND group_scope_tag IS NULL AND group_scope_group_member_id IS NULL AND item_status = ? Plan: -SEARCH chat_items USING INDEX idx_chat_items_group_scope_item_status (user_id=? AND group_id=? AND group_scope_tag=? AND group_scope_group_member_id=? AND item_status=?) +SEARCH chat_items USING COVERING INDEX idx_chat_items_group_scope_stats_all (user_id=? AND group_id=? AND group_scope_tag=? AND group_scope_group_member_id=? AND item_status=?) Query: SELECT accepted_at FROM operator_usage_conditions WHERE server_operator_id = ? AND conditions_commit = ? Plan: diff --git a/src/Simplex/Chat/Store/SQLite/Migrations/chat_schema.sql b/src/Simplex/Chat/Store/SQLite/Migrations/chat_schema.sql index 8352b4f952..322814385f 100644 --- a/src/Simplex/Chat/Store/SQLite/Migrations/chat_schema.sql +++ b/src/Simplex/Chat/Store/SQLite/Migrations/chat_schema.sql @@ -687,7 +687,6 @@ CREATE INDEX contact_profiles_index ON contact_profiles( full_name ); CREATE INDEX idx_groups_inv_queue_info ON groups(inv_queue_info); -CREATE INDEX idx_contact_requests_xcontact_id ON contact_requests(xcontact_id); CREATE INDEX idx_contacts_xcontact_id ON contacts(xcontact_id); CREATE INDEX idx_messages_shared_msg_id ON messages(shared_msg_id); CREATE UNIQUE INDEX idx_chat_items_direct_shared_msg_id ON chat_items( @@ -1073,3 +1072,16 @@ CREATE INDEX idx_contacts_contact_request_id ON contacts(contact_request_id); CREATE INDEX idx_contact_requests_business_group_id ON contact_requests( business_group_id ); +CREATE INDEX idx_contact_requests_xcontact_id ON contact_requests( + user_id, + xcontact_id +); +CREATE INDEX idx_chat_items_group_scope_stats_all ON chat_items( + user_id, + group_id, + group_scope_tag, + group_scope_group_member_id, + item_status, + chat_item_id, + user_mention +); diff --git a/tests/SchemaDump.hs b/tests/SchemaDump.hs index 807fa4a0cb..df1739449e 100644 --- a/tests/SchemaDump.hs +++ b/tests/SchemaDump.hs @@ -127,7 +127,9 @@ skipComparisonForDownMigrations = -- indexes move down to the end of the file "20250130_indexes", -- index moves down to the end of the file - "20250227_member_acceptance" + "20250227_member_acceptance", + -- index moves down to the end of the file + "20250721_indexes" ] getSchema :: FilePath -> FilePath -> IO String