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

do not load all child records for inverse case #10566

Merged
merged 1 commit into from
Jun 18, 2013
Merged

do not load all child records for inverse case #10566

merged 1 commit into from
Jun 18, 2013

Conversation

neerajsingh0101
Copy link

currently post.comments.find(Comment.first.id) would load all
comments for the given post to set the inverse association.

This has a huge performance penalty. Because if post has 100k
records and all these 100k records would be loaded in memory
even though the comment id was supplied.

Fix is to use in-memory records only if loaded? is true. Otherwise
load the records using full sql.

Fixes #10509

/cc @wangjohn @jeremy @jonleighton

man = Man.create!
interest = Interest.create!(man: man)

man.interests.find(interest.id)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this line should verify the specific result returned, to ensure that even though other interests aren't loaded, your specific query still works correctly

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jonleighton
Copy link
Member

Happy to merge once the above is dealt with.

@neerajsingh0101
Copy link
Author

@jonleighton your feedback has been taken into account and the unnecessary line has been removed. There is already another test confirming that inverse is being set on the records.

@jonleighton
Copy link
Member

Could you rebase? Thanks

currently `post.comments.find(Comment.first.id)` would load all
comments for the given post to set the inverse association.

This has a huge performance penalty. Because if post has 100k
records and all these 100k records would be loaded in memory
even though the comment id was supplied.

Fix is to use in-memory records only if loaded? is true. Otherwise
load the records using full sql.

Fixes #10509
@neerajsingh0101
Copy link
Author

@jonleighton rebased.

jonleighton added a commit that referenced this pull request Jun 18, 2013
do not load all child records for inverse case
@jonleighton jonleighton merged commit 2b817a5 into rails:master Jun 18, 2013
@arunagw
Copy link
Member

arunagw commented Jun 19, 2013

Broke the build for mysql and postgresql.

https://travis-ci.org/rails/rails/jobs/8224880#L119

thanks

@neerajsingh0101
Copy link
Author

When I run full stack test bundle exec rake test_mysql then the test is failing but when I run that test individually then it is passing.

The failing test is

    invalid_id = 2394823094892348920348523452345
    assert_raise(ActiveRecord::RecordNotFound) { man.interests.find(invalid_id) }

I think it should be ok to reduce the invalid_id number from such a larger number to a bit smaller number since the intent is to test ActiveRecord::RecordNotFound .

jonleighton added a commit that referenced this pull request Jun 19, 2013
This reverts commit 2b817a5, reversing
changes made to 353a398.

Conflicts:
	activerecord/CHANGELOG.md

Reason: the build broke
@jonleighton
Copy link
Member

@arunagw thanks for the heads up

@neerajdotname I've reverted for now until we can figure out the problems.

thedarkone pushed a commit to thedarkone/rails that referenced this pull request Aug 20, 2013
PR rails#10566 had to be reverted
because after applying the fix test
"test_raise_record_not_found_error_when_invalid_ids_are_passed"
started failing.

In this test invalid_id is being assigned a really large number
which was causing following failure when PR rails#10566 was applied.

```
RangeError: bignum too big to convert into `long long'
SELECT  `interests`.* FROM `interests`
WHERE `interests`.`man_id` = ? AND `interests`.`id` = ?
LIMIT 1  [["man_id", 970345987], ["id", 2394823094892348920348523452345]]
```

This test is not failing in master because when test code
`man.interests.find(invalid_id)` is executed then interests
are fully loaded in memory and no database query is executed.

After PR rails#10566 was merged then test code
`man.interests.find(invalid_id)` started executing sql query
and hence the error.

In case someone is wondering why the second part of query is not
failing, then that's because the actual query does not require
any variable substituation where the number is large. In that
case the sql generate is following.

```
SELECT `interests`.* FROM `interests`
WHERE `interests`.`man_id` = ? AND `interests`.`id`
IN (8432342, 2390102913, 2453245234523452)  [["man_id", 970345987]]
```
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Calling #find on a has_many association loads all associated objects.
5 participants