From bf3c2c0ce6e945b6c235294a7d89211b9ef944cd Mon Sep 17 00:00:00 2001 From: Agniva De Sarker Date: Wed, 25 Mar 2020 12:39:04 +0530 Subject: [PATCH] MM-23369: Allow mysql to choose a better index (#14119) * MM-23369: Allow mysql to choose a better index When the ORDER BY clause contains a column which is in the WHERE clause and also part of an index, mysql tries to use that specific index to avoid sorting. This is inspite of the fact that there may be other indices which are better for scanning the table and then doing a sort. Essentially, mysql becomes dumb and scans a lot of rows to avoid sorting. Whereas, it could have scanned a lot less rows and do the sorting in no time. To fix this, we use the other columns in the ORDER BY clause as well which are part of the index. This causes no change in the results because the other columns are an EQUAL condition check, but this lets mysql use the right index. Because now mysql sees that it has to order by other columns too, so it better use the other index to scan and then do the sorting. This does not affect tables of smaller size because the LIMIT of rows is always 1. And mysql will stop sorting the moment it gets the first row. So sorting is not the overhead at all. Therefore, this seems like an optimal fix. References: https://dev.mysql.com/doc/refman/5.7/en/table-scan-avoidance.html https://code.openark.org/blog/mysql/7-ways-to-convince-mysql-to-use-the-right-index https://dev.mysql.com/doc/refman/5.7/en/limit-optimization.html * Added a comment to clarify things in code * Incorporating review comments --- store/sqlstore/post_store.go | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/store/sqlstore/post_store.go b/store/sqlstore/post_store.go index 817eb3d96e..e454584cc0 100644 --- a/store/sqlstore/post_store.go +++ b/store/sqlstore/post_store.go @@ -770,7 +770,10 @@ func (s *SqlPostStore) getPostIdAroundTime(channelId string, time int64, before sq.Eq{"ChannelId": channelId}, sq.Eq{"DeleteAt": int(0)}, }). - OrderBy("CreateAt " + sort). + // Adding ChannelId and DeleteAt order columns + // to let mysql choose the "idx_posts_channel_id_delete_at_create_at" index always. + // See MM-23369. + OrderBy("ChannelId", "DeleteAt", "CreateAt "+sort). Limit(1) queryString, args, err := query.ToSql() @@ -797,7 +800,10 @@ func (s *SqlPostStore) GetPostAfterTime(channelId string, time int64) (*model.Po sq.Eq{"ChannelId": channelId}, sq.Eq{"DeleteAt": int(0)}, }). - OrderBy("CreateAt ASC"). + // Adding ChannelId and DeleteAt order columns + // to let mysql choose the "idx_posts_channel_id_delete_at_create_at" index always. + // See MM-23369. + OrderBy("ChannelId", "DeleteAt", "CreateAt ASC"). Limit(1) queryString, args, err := query.ToSql()