Add strict loading and preloading of associations - #12590
Open
ruudk wants to merge 1 commit into
Open
Conversation
Lazy loading hides database access behind a normal property read, so N+1
queries are usually found in production and not while writing the code.
This adds a way to detect them, and a way to fix them.
Strict loading reports a lazy load as a violation. It is off by default.
Modes are Disabled, NPlusOneOnly and All. A handler decides what happens:
throw, or log the violation and let the load happen.
Preloading loads an association for many entities at once. It is for
entities that are already in memory, where a fetch join can not help:
$em->preload($users, ['articles.comments']);
$repository->findAll(['articles']);
$query->preload(['articles'])->getResult();
preload() is not on EntityManagerInterface, because adding a method to an
interface breaks every implementation of it. The EntityManager, the
decorator, the repository and the query each use a Preloader instead, so
the method can move to the interface in 4.0.
It also fixes the batching that the eager fetch modes already had. A
nested hydration flushed the batch too early, so one query per owner was
issued instead of one query for all of them. Many to many never batched
at all, and indexed collections were excluded.
Both features are inspired by Ruby on Rails, which has
[strict loading](https://guides.rubyonrails.org/active_record_querying.html#strict-loading)
and [preloading](https://guides.rubyonrails.org/active_record_querying.html#preload).
See discussion doctrine#10931.
Member
|
This is too much at once, why add the preloading API in the same step? The three mode names are not clear enough. What means "also fixes batching wager loads"? |
Contributor
Author
|
I agree this is too much. But for me it served more of a POC to see how I would envision this from a user api perspective. Maybe a first step could be to detect and log n+1 issues and write those to a logfile. But if you would enable that logging mode, how would you be able to preload all those relations at once? You need some kind of way to say: for these entities, load all the X relations in a single query. Otherwise you end up with logs that are not actionable. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Lazy loading hides database access behind a normal property read, so N+1
queries are usually found in production and not while writing the code.
This adds a way to detect them, and a way to fix them.
Strict loading reports a lazy load as a violation. It is off by default.
Modes are Disabled, NPlusOneOnly and All. A handler decides what happens:
throw, or log the violation and let the load happen.
Preloading loads an association for many entities at once. It is for
entities that are already in memory, where a fetch join can not help:
It also fixes the batching that the eager fetch modes already had. A
nested hydration flushed the batch too early, so one query per owner was
issued instead of one query for all of them. Many to many never batched
at all, and indexed collections were excluded.
Both features are inspired by Ruby on Rails, which has strict loading and preloading.
See discussion #10931.