From da3d5c73fe48f4f6053740f34f8b6a2c65c81e46 Mon Sep 17 00:00:00 2001 From: Agniva De Sarker Date: Mon, 10 Jul 2023 10:19:44 +0530 Subject: [PATCH] MM-53406: Fix userstore.count to avoid antijoin (#23953) For MySQL, a query for type LEFT JOIN .. IS NULL leads to a nested antijoin which leads to poor performance. We fix this by rewriting the query to avoid the antijoin. See the JIRA epic for more context behind this. We also make another improvement to remove the DISTINCT clause. It didn't serve any purpose since userids would already be unique. https://mattermost.atlassian.net/browse/MM-53406 ```release-note NONE ``` --- server/channels/store/sqlstore/user_store.go | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/server/channels/store/sqlstore/user_store.go b/server/channels/store/sqlstore/user_store.go index fdacc1edc0..a1f733b9ac 100644 --- a/server/channels/store/sqlstore/user_store.go +++ b/server/channels/store/sqlstore/user_store.go @@ -1304,19 +1304,24 @@ func (us SqlUserStore) PermanentDelete(userId string) error { } func (us SqlUserStore) Count(options model.UserCountOptions) (int64, error) { - isPostgreSQL := us.DriverName() == model.DatabaseDriverPostgres - query := us.getQueryBuilder().Select("COUNT(DISTINCT u.Id)").From("Users AS u") + query := us.getQueryBuilder().Select("COUNT(*)").From("Users AS u") if !options.IncludeDeleted { query = query.Where("u.DeleteAt = 0") } + isPostgreSQL := us.DriverName() == model.DatabaseDriverPostgres if options.IncludeBotAccounts { if options.ExcludeRegularUsers { query = query.Join("Bots ON u.Id = Bots.UserId") } } else { - query = query.LeftJoin("Bots ON u.Id = Bots.UserId").Where("Bots.UserId IS NULL") + if isPostgreSQL { + query = query.LeftJoin("Bots ON u.Id = Bots.UserId").Where("Bots.UserId IS NULL") + } else { + query = query.Where(sq.Expr("u.Id NOT IN (SELECT UserId FROM Bots)")) + } + if options.ExcludeRegularUsers { // Currently this doesn't make sense because it will always return 0 return int64(0), errors.New("query with IncludeBotAccounts=false and excludeRegularUsers=true always return 0")