PERF: N+1 queries when viewing tags (#19891)
When the `tags_listed_by_group` site setting is enabled, we were seeing the N+1 queries problem when multiple `TagGroup` records are listed. This commit fixes that by ensuring that we are not filtering through the `tags` association after the association has been eager loaded.
This commit is contained in:
parent
14983c5b8e
commit
1e8a1a0d24
|
@ -46,14 +46,14 @@ class TagsController < ::ApplicationController
|
|||
TagGroup
|
||||
.visible(guardian)
|
||||
.order("name ASC")
|
||||
.includes(:tags)
|
||||
.includes(:none_synonym_tags)
|
||||
.map do |tag_group|
|
||||
{
|
||||
id: tag_group.id,
|
||||
name: tag_group.name,
|
||||
tags:
|
||||
self.class.tag_counts_json(
|
||||
tag_group.tags.where(target_tag_id: nil),
|
||||
tag_group.none_synonym_tags,
|
||||
show_pm_tags: guardian.can_tag_pms?,
|
||||
),
|
||||
}
|
||||
|
|
|
@ -5,6 +5,10 @@ class TagGroup < ActiveRecord::Base
|
|||
|
||||
has_many :tag_group_memberships, dependent: :destroy
|
||||
has_many :tags, through: :tag_group_memberships
|
||||
has_many :none_synonym_tags,
|
||||
-> { where(target_tag_id: nil) },
|
||||
through: :tag_group_memberships,
|
||||
source: "tag"
|
||||
has_many :category_tag_groups, dependent: :destroy
|
||||
has_many :category_required_tag_groups, dependent: :destroy
|
||||
has_many :categories, through: :category_tag_groups
|
||||
|
|
|
@ -80,9 +80,10 @@ RSpec.describe TagsController do
|
|||
|
||||
it "works for tags in groups" do
|
||||
tag_group = Fabricate(:tag_group, tags: [test_tag, topic_tag, synonym])
|
||||
get "/tags.json"
|
||||
expect(response.status).to eq(200)
|
||||
|
||||
get "/tags.json"
|
||||
|
||||
expect(response.status).to eq(200)
|
||||
tags = response.parsed_body["tags"]
|
||||
expect(tags.length).to eq(0)
|
||||
group = response.parsed_body.dig("extras", "tag_groups")&.first
|
||||
|
@ -90,6 +91,47 @@ RSpec.describe TagsController do
|
|||
expect(group["tags"].length).to eq(2)
|
||||
expect(group["tags"].map { |t| t["id"] }).to contain_exactly(test_tag.name, topic_tag.name)
|
||||
end
|
||||
|
||||
it "does not result in N+1 queries with multiple tag_groups" do
|
||||
tag_group = Fabricate(:tag_group, tags: [test_tag, topic_tag, synonym])
|
||||
|
||||
# warm up
|
||||
get "/tags.json"
|
||||
expect(response.status).to eq(200)
|
||||
|
||||
initial_sql_queries_count =
|
||||
track_sql_queries do
|
||||
get "/tags.json"
|
||||
|
||||
expect(response.status).to eq(200)
|
||||
|
||||
tag_groups = response.parsed_body.dig("extras", "tag_groups")
|
||||
|
||||
expect(tag_groups.length).to eq(1)
|
||||
expect(tag_groups.map { |tag_group| tag_group["name"] }).to contain_exactly(
|
||||
tag_group.name,
|
||||
)
|
||||
end.length
|
||||
|
||||
tag_group2 = Fabricate(:tag_group, tags: [topic_tag])
|
||||
|
||||
new_sql_queries_count =
|
||||
track_sql_queries do
|
||||
get "/tags.json"
|
||||
|
||||
expect(response.status).to eq(200)
|
||||
|
||||
tag_groups = response.parsed_body.dig("extras", "tag_groups")
|
||||
|
||||
expect(tag_groups.length).to eq(2)
|
||||
expect(tag_groups.map { |tag_group| tag_group["name"] }).to contain_exactly(
|
||||
tag_group.name,
|
||||
tag_group2.name,
|
||||
)
|
||||
end.length
|
||||
|
||||
expect(new_sql_queries_count).to be <= initial_sql_queries_count
|
||||
end
|
||||
end
|
||||
|
||||
context "with tags_listed_by_group disabled" do
|
||||
|
|
Loading…
Reference in New Issue