Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ruby: Query for N+1 queries problem #18317

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

asgerf
Copy link
Contributor

@asgerf asgerf commented Dec 18, 2024

No description provided.

Copy link
Contributor

QHelp previews:

ruby/ql/src/queries/performance/ActiveRecordAssociationQueriedInLoop.qhelp

ActiveRecord association queried in loop

Performing database queries in a loop can be inefficient compared to performing a single query up front that retrieves all the data at once.

ORMs such as ActiveRecord implicitly query the database when certain members of an object are being accessed. But if such a member is accessed in a loop, it can result in a separate query for each iteration. ActiveRecord provides a way to eagerly load associated data using the includes method, which can be used to speed up such queries.

Recommendation

In ActiveRecord, use includes to eagerly load associated data that you expect to access in a loop.

Example

The following example code gets the names of all podcasts followed by a user:

def get_podcast_names(user):
    user.podcasts.map do |podcast|
        podcast.name
    end
end

However, the call to name inside the loop will result in a separate SQL query being executed to obtain the name. To speed this up, use includes to eagerly load the associated data:

def get_podcast_names(user):
    user.podcasts.includes(:name).map do |podcast|
        podcast.name
    end
end

Now all the associated podcast names are loaded up front with a single SQL query, and the call to name no longer results in a separate query.

References

* @tags performance
*/

// TODO: is a DB query executed as soon as the assocation is called, or when a field on the associated object is used?

Check warning

Code scanning / CodeQL

Misspelling Warning

This comment contains the common misspelling 'assocation', which should instead be 'association'.
node1 = call.getReceiver() and
node2 = call
|
call.getMethodName() = ["to_a"] and

Check warning

Code scanning / CodeQL

Singleton set literal Warning

Singleton set literal can be replaced by its member.
call.getMethodName() = queryBuilderMethodName() and
// Block flow through a few methods:
// - none: produces no output
// - select: modelled more precisely below

Check warning

Code scanning / CodeQL

Misspelling Warning

This comment contains the non-US spelling 'modelled', which should instead be 'modeled'.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant