From ae7d31ec161b5aa1534f414a91e5df8946fae3e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dani=C3=ABl=20Klabbers?= Date: Fri, 18 Mar 2022 16:40:30 +0100 Subject: [PATCH 1/3] fix(tags)!: reduce tag filter query from 3+ second This PR removes the subqueries inserted for each selected tag. As this caused the query to take over 3 seconds on communities with hundred million posts. ```sql and (`discussions`.`id` in (select `discussion_id` from `discussion_tag` where `tag_id` = 105)) ``` The above part takes on average 3.85 seconds, with a join it takes 0.00 seconds. BREAKING CHANGE: extending the query might have different outcome as we now use a join and no subquery. --- extensions/tags/src/Query/TagFilterGambit.php | 25 +++++++++---------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/extensions/tags/src/Query/TagFilterGambit.php b/extensions/tags/src/Query/TagFilterGambit.php index 0ef0d1e7f..ac0b48b57 100644 --- a/extensions/tags/src/Query/TagFilterGambit.php +++ b/extensions/tags/src/Query/TagFilterGambit.php @@ -55,21 +55,20 @@ class TagFilterGambit extends AbstractRegexGambit implements FilterInterface { $slugs = explode(',', trim($rawSlugs, '"')); + $query->leftJoin('discussion_tag', 'discussions.id', '=', 'discussion_tag.discussion_id'); + $query->where(function (Builder $query) use ($slugs, $negate) { foreach ($slugs as $slug) { - if ($slug === 'untagged') { - $query->whereIn('discussions.id', function (Builder $query) { - $query->select('discussion_id') - ->from('discussion_tag'); - }, 'or', ! $negate); - } else { - $id = $this->tags->getIdForSlug($slug); - - $query->whereIn('discussions.id', function (Builder $query) use ($id) { - $query->select('discussion_id') - ->from('discussion_tag') - ->where('tag_id', $id); - }, 'or', $negate); + if ($slug === 'untagged' && !$negate) { + $query->orWhereNull('discussion_tag.tag_id'); + } elseif ($slug === 'untagged' && $negate) { + $query->orWhereNotNull('discussion_tag.tag_id'); + } elseif ($id = $this->tags->getIdForSlug($slug)) { + $query->orWhere( + 'discussion_tag.tag_id', + $negate ? '!=' : '=', + $id + ); } } }); From 907b1f10aac30131405d572b2db35cfb72191df7 Mon Sep 17 00:00:00 2001 From: StyleCI Bot Date: Fri, 18 Mar 2022 15:46:30 +0000 Subject: [PATCH 2/3] Apply fixes from StyleCI [ci skip] [skip ci] --- extensions/tags/src/Query/TagFilterGambit.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/tags/src/Query/TagFilterGambit.php b/extensions/tags/src/Query/TagFilterGambit.php index ac0b48b57..70b8afc6b 100644 --- a/extensions/tags/src/Query/TagFilterGambit.php +++ b/extensions/tags/src/Query/TagFilterGambit.php @@ -59,7 +59,7 @@ class TagFilterGambit extends AbstractRegexGambit implements FilterInterface $query->where(function (Builder $query) use ($slugs, $negate) { foreach ($slugs as $slug) { - if ($slug === 'untagged' && !$negate) { + if ($slug === 'untagged' && ! $negate) { $query->orWhereNull('discussion_tag.tag_id'); } elseif ($slug === 'untagged' && $negate) { $query->orWhereNotNull('discussion_tag.tag_id'); From 3343fde5f270348121e1831075422f2bb08ef7b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dani=C3=ABl=20Klabbers?= Date: Wed, 23 Mar 2022 12:04:56 +0100 Subject: [PATCH 3/3] add distinct and clean up code further --- extensions/tags/src/Query/TagFilterGambit.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/extensions/tags/src/Query/TagFilterGambit.php b/extensions/tags/src/Query/TagFilterGambit.php index 70b8afc6b..e4bf8d451 100644 --- a/extensions/tags/src/Query/TagFilterGambit.php +++ b/extensions/tags/src/Query/TagFilterGambit.php @@ -55,9 +55,10 @@ class TagFilterGambit extends AbstractRegexGambit implements FilterInterface { $slugs = explode(',', trim($rawSlugs, '"')); - $query->leftJoin('discussion_tag', 'discussions.id', '=', 'discussion_tag.discussion_id'); - - $query->where(function (Builder $query) use ($slugs, $negate) { + $query + ->distinct() + ->leftJoin('discussion_tag', 'discussions.id', '=', 'discussion_tag.discussion_id') + ->where(function (Builder $query) use ($slugs, $negate) { foreach ($slugs as $slug) { if ($slug === 'untagged' && ! $negate) { $query->orWhereNull('discussion_tag.tag_id');