diff --git a/server/channels/store/sqlstore/channel_store_categories.go b/server/channels/store/sqlstore/channel_store_categories.go index f35938d3c61..95502e2ab69 100644 --- a/server/channels/store/sqlstore/channel_store_categories.go +++ b/server/channels/store/sqlstore/channel_store_categories.go @@ -442,6 +442,8 @@ func (s SqlChannelStore) completePopulatingCategoryChannelsT(db dbSelecter, cate return category, nil } + isMySQL := s.DriverName() == model.DatabaseDriverMysql + var channelTypeFilter sq.Sqlizer if category.Type == model.SidebarCategoryDirectMessages { // any DM/GM channels that aren't in any category should be returned as part of the Direct Messages category @@ -457,20 +459,40 @@ func (s SqlChannelStore) completePopulatingCategoryChannelsT(db dbSelecter, cate } // A subquery that is true if the channel does not have a SidebarChannel entry for the current user on the current team - doesNotHaveSidebarChannel := sq.Select("1"). - Prefix("NOT EXISTS ("). - From("SidebarChannels"). - Join("SidebarCategories on SidebarChannels.CategoryId=SidebarCategories.Id"). - Where(sq.And{ - sq.Expr("SidebarChannels.ChannelId = ChannelMembers.ChannelId"), - sq.Eq{"SidebarCategories.UserId": category.UserId}, - sq.Eq{"SidebarCategories.TeamId": category.TeamId}, - }). - Suffix(")") + var doesNotHaveSidebarChannel sq.SelectBuilder + if isMySQL { + doesNotHaveSidebarChannel = sq.Select("/*+ QB_NAME(subq1) */ 1"). + Prefix("NOT EXISTS ("). + From("SidebarChannels"). + // we have to use an index hint for MySQL. + Join("SidebarCategories USE INDEX(idx_sidebarcategories_userid_teamid) on SidebarChannels.CategoryId=SidebarCategories.Id"). + Suffix(")") + } else { + doesNotHaveSidebarChannel = sq.Select("1"). + Prefix("NOT EXISTS ("). + From("SidebarChannels"). + Join("SidebarCategories on SidebarChannels.CategoryId=SidebarCategories.Id"). + Suffix(")") + } + + doesNotHaveSidebarChannel = doesNotHaveSidebarChannel.Where(sq.And{ + sq.Expr("SidebarChannels.ChannelId = ChannelMembers.ChannelId"), + sq.Eq{"SidebarCategories.UserId": category.UserId}, + sq.Eq{"SidebarCategories.TeamId": category.TeamId}, + }) channels := []string{} + var col string + if isMySQL { + // This is a materialization hint for MySQL to materialize + // the doesNotHaveSidebarChannel sub-query + // Without this hint, MySQL is unable to come up with this plan by itself. + col = "/*+ SEMIJOIN(@subq1 MATERIALIZATION) */ Id" + } else { + col = "Id" + } sql, args, err := s.getQueryBuilder(). - Select("Id"). + Select(col). From("ChannelMembers"). LeftJoin("Channels ON Channels.Id=ChannelMembers.ChannelId"). Where(sq.And{