Problem/Motivation
After #3551308: Combine single cardinality fields into a single database query when loading entities SqlContentEntityStorage executes one database query for the shared table (if there is one - e.g. node_field_data), and one query for fields in dedicated tables.
It should be possible to combine those queries into one - join on the shared table, then the individual field tables, and then extract the field results using very similar logic.
This will require deprecating one or probably both of the protected methods so that the logic can be combined in a single consolidated method.
The end result of this issue plus the previous two issues will be:
Initial loading query - unchanged
One database query to load data/revision/single cardinality fields.
One (optional) database query to load mulitiple cardinality fields.
So either 2 or 3 queries to load entities in all cases, instead of between 2 and over 100.
Steps to reproduce
Proposed resolution
Change the query for single cardinality fields so that it also loads values from the data/revision tables where necessary. This is a relatively small change to the query and allows us to drop (deprecate) ::loadFromSharedTables() entirely.
Remaining tasks
User interface changes
Introduced terminology
API changes
Data model changes
Release notes snippet
| Comment | File | Size | Author |
|---|
Issue fork drupal-3561960
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
- 3561960-11x
changes, plain diff MR !15595
- 3561960-combine-queries
changes, plain diff MR !15089
Comments
Comment #2
catchLet's do #3564689: Combine multiple cardinality field loading into a single database query first.
Comment #4
alexpottThe blocking issues have gone in.
Comment #6
catchPushed an initial MR here (was an empty issue fork before, think I hit the button by mistake).
This is non-trivial to get right because of the various combinations of base/revision/data tables that entities may or may not have along with whether we're loading revisions or not. However I'm down to a handful of test failures in core's kernel entity tests so worth seeing what else breaks.
Comment #7
catchA bit closer - all green on kernel tests although I get one content_moderation kernel test failure locally.
Performance tests are failing in the right way, but won't update those until everything else is passing in case the queries need to change again.
Haven't looked at the functional test failures yet.
Comment #8
catchOK we're green now.
The MR is stacked on #3576129: Reduce calls to FieldDefinition::getColumns() which is RTBC, so marking PP-1 but also needs review because it would nice to get some high level reviews.
This removes a query from pretty much every entity load. It's less than the previous two issues it was postponed on, but it's also a similar-ish percentage of some requests because we've removed so many other queries now - e.g. 5-10% of database queries in various scenarios, higher percentages in the 'cool cache' cases.
The diff is quite big partly due to the stacked MR, but also partly because it removes an if statement when loading single cardinality fields, since we always do run that query now to get the base fields.
The tricky thing is the langcode handling, we have to handle both revision and non-revision queries in the same place, and the base table langcode logic is slightly different from the dedicated tables langcode logic, due to things like revisions and translations being added, removed etc. It's not dramatically more complex than the logic it's replacing but it was hard to get right because there's so many combinations with different entity schemas.
Not very happy with how long ::loadFromDedicatedTables() is becoming, maybe we can find some logic to move to helper methods.
Had to add a new parameter to ::loadFromDedicatedTables(), we might need to search contrib just to check that never actually gets called or overriden anywhere, doubt it does tbh.
We also need to decide if we're going to rename loadFromDedicatedTables() and also whether we do it in this issue or not.
Comment #9
catchPostgres and sqlite are green but MariaDb is unfortunately not https://git.drupalcode.org/project/drupal/-/jobs/8948781 - I saw this failure once or twice on my local but didn't realise it wasn't fixed by changes that fixed other tests.
This is another symptom of:
Comment #10
catchFixed the last remaining test failure and the blocker is in.
Comment #11
catchComment #12
catchAdded the ::loadFromSharedTables() deprecation.
Comment #13
catchTagging for release highlights. Along with #3564689: Combine multiple cardinality field loading into a single database query and #3551308: Combine single cardinality fields into a single database query when loading entities this is worth its own sentence.
Comment #14
heddnTagged for adding a CR. If we are going to rename loadFromDedicatedTables, we should do it here so it and shared tables both go away at the same time. Otherwise we risk contrib/custom extension points having to make changes multiple times.
Comment #15
catchI checked usages:
https://search.tresbien.tech/search?q=loadFromDedicatedTables%20-f%3Acor...
https://search.tresbien.tech/search?q=loadFromSharedTables%20-f%3Acore&n...
Looking at the actual file: https://git.drupalcode.org/project/civicrm_entity/-/blob/4.0.x/src/CiviE... - this is a complete re-implementation of the storage with the same method name, no override, and it's called from another method in that class.
So there are zero usages in contrib, seems even less likely there is custom code around this for this particular change.
Part of the reason I didn't rename the method yet apart from laziness is not having great ideas. We could do
loadFromTablesmaybe? OrloadFieldRecords? But I'm not sure these are dramatically better than ::loadFromDedicatedTables()I think if we rename, we also need to decide whether the old method will call the new one with the new code, or whether to restore the old code to it, which would be deprecated dead code then. Given the zero usages this probably doesn't matter in practice.
Comment #16
catchSwitching the CR tag to needs CR updates since I think we can update https://www.drupal.org/node/3562172 to cover all three issues - at least as long as this gets into 11.4 (which would be great considering how closely linked the changes are, and it'll be much easier to talk about the performance improvement).
Comment #17
heddnI guess I'm not a big fan of semantically renaming things on a whim. Certainly there aren't a lot (any?) implementations that override the method. So there wouldn't be a lot of repercussions, but the name of the method(s) here are pretty internal to the entity API. I don't think we need to change the name.
If we are going to only update the existing CR, we should add its link to the code instead of https://www.drupal.org/project/drupal/issues/3561960.
Comment #18
catchArghh I forgot all my previous arguments and ended up opening a separate CR. But now having written it, the previous CR was practical information for site owners instead they suddenly run into OOM https://www.drupal.org/node/3562172 and the new CR for a deprecation of a method we're pretty sure no-one is overriding or calling. So... that is probably fine, moving back to needs review.
Also had to rebase for performance test changes.
Comment #19
needs-review-queue-bot commentedThe Needs Review Queue Bot tested this issue. It no longer applies to Drupal core. Therefore, this issue status is now "Needs work".
This does not mean that the patch necessarily needs to be re-rolled or the MR rebased. Read the Issue Summary, the issue tags and the latest discussion here to determine what needs to be done.
Consult the Drupal Contributor Guide to find step-by-step guides for working with issues.
Comment #20
catchRebased.
Comment #21
heddnLGTM
Comment #22
alexpottThis looks amazing. Really nice to get to this point. I have just one small concern about
base_langcodeand clashes with custom entities. I added some suggestions to the MR about possible mitigations.Comment #23
catchHad to fight both myself and gitlab but back to green. Ridiculous amount of MR activity for what is one alias rename but since that's all it actually is, moving back to RTBC.
Comment #24
alexpottCommitted 4c021ea and pushed to main. Thanks!
Comment #27
catchBackport MR is up - only query counts in performance tests differed.
Comment #28
alexpottCommitted 529ca79 and pushed to 11.x. Thanks!
Comment #32
quietone commentedCorrect branch on the CR.