Suthan Bala
Suthan Bala

Reputation: 3299

Why does Rails runs an additional unnecessary query?

I have the following Rails Code, in which it technically do two queries max, but for some reason, the console shows three different queries as shown in the screenshot below. My question is why does it run the SELECT "pages".* FROM "pages" query for when it's not necessary?

Query

    page = Page.includes(:page_roles)
    page.where(is_deleted: false).index_by(&:name)
    page_results = {}
    page.each do |entry|
        result_entry = entry.as_json;
        result_entry['page_roles'] = entry.page_roles
        page_results[entry.name] = result_entry
    end

Console Output

Page Load (0.0ms)  SELECT "pages".* FROM "pages" WHERE "pages"."is_deleted" = $1  [["is_deleted", false]]
PageRole Load (0.5ms)  SELECT "page_roles".* FROM "page_roles" WHERE "page_roles"."page_id" IN (1, 2, 3, 4)
Page Load (0.5ms)  SELECT "pages".* FROM "pages"
CACHE (0.0ms)  SELECT "page_roles".* FROM "page_roles" WHERE "page_roles"."page_id" IN (1, 2, 3, 4)
Completed 200 OK in 117ms (Views: 16.9ms | ActiveRecord: 17.0ms)

Screenshot of the console

Upvotes: 0

Views: 115

Answers (3)

Sergio Tulentsev
Sergio Tulentsev

Reputation: 230531

Here's why:

page = Page.includes(:page_roles)
page.where(is_deleted: false).index_by(&:name) # your first two queries (pages + page_roles). 
                                               # query is triggered by index_by (method of enumerable, not activerecord) and result is ignored
                                               # as it's not saved anywhere.

page_results = {}
page.each do |entry| # your second two queries. Note that this one doesn't use `is_deleted: false` filter.
                     # page_roles query is served from cache as it didn't change.
    result_entry = entry.as_json;
    result_entry['page_roles'] = entry.page_roles
    page_results[entry.name] = result_entry
end

Upvotes: 1

mr_sudaca
mr_sudaca

Reputation: 1176

that's because the first assignment. You can short all of that by doing:

page_results = 
  Page
    .includes(:page_roles)
    .where(is_deleted: false)
    .group_by(&:name)

Upvotes: 1

ellitt
ellitt

Reputation: 833

I believe this is because you've got the page.where query which will still use the ActiveRecord query interface on the Page table and not use the ActiveRecord collection stored as page.

Upvotes: 0

Related Questions