From 2eb4f45f15454467eb4adfede999fd440a51d2d2 Mon Sep 17 00:00:00 2001 From: mscherer Date: Tue, 17 Mar 2026 17:58:21 +0100 Subject: [PATCH] Update default eager loading strategy to subquery Document the change from 'select' to 'subquery' as the default eager loading strategy for HasMany and BelongsToMany associations. Refs cakephp/cakephp#19345 --- docs/en/appendices/5-4-migration-guide.md | 16 ++++++++++++++- docs/en/orm/associations.md | 24 +++++++++++------------ 2 files changed, 27 insertions(+), 13 deletions(-) diff --git a/docs/en/appendices/5-4-migration-guide.md b/docs/en/appendices/5-4-migration-guide.md index f039961a1a..0005559b55 100644 --- a/docs/en/appendices/5-4-migration-guide.md +++ b/docs/en/appendices/5-4-migration-guide.md @@ -16,7 +16,21 @@ bin/cake upgrade rector --rules cakephp54 ## Behavior Changes -- WIP +### ORM + +The default eager loading strategy for `HasMany` and `BelongsToMany` associations +has changed from ``select`` to ``subquery``. The ``subquery`` strategy performs +better for larger datasets as it avoids packet size limits from large ``WHERE IN`` +clauses and reduces PHP memory usage by keeping IDs in the database. + +If you need the previous behavior, you can explicitly set the strategy when +defining associations: + +```php +$this->hasMany('Comments', [ + 'strategy' => 'select', +]); +``` ## Deprecations diff --git a/docs/en/orm/associations.md b/docs/en/orm/associations.md index af8401795d..8d4a36a97b 100644 --- a/docs/en/orm/associations.md +++ b/docs/en/orm/associations.md @@ -462,9 +462,9 @@ Possible keys for hasMany association arrays include: - **propertyName**: The property name that should be filled with data from the associated table into the source table results. By default, this is the underscored & plural name of the association so `comments` in our example. -- **strategy**: Defines the query strategy to use. Defaults to 'select'. The - other valid value is 'subquery', which replaces the `IN` list with an - equivalent subquery. +- **strategy**: Defines the query strategy to use. Defaults to 'subquery'. The + other valid value is 'select', which uses the `IN` list of parent keys + directly instead of a subquery. - **saveStrategy**: Either `append` or `replace`. Defaults to `append`. When `append` the current records are appended to any records in the database. When `replace` associated records not in the current set will be removed. If the foreign key is a nullable @@ -487,15 +487,15 @@ The above would output SQL similar to: ```sql SELECT * FROM articles; -SELECT * FROM comments WHERE article_id IN (1, 2, 3, 4, 5); +SELECT * FROM comments WHERE article_id IN (SELECT id FROM articles); ``` -When the subquery strategy is used, SQL similar to the following will be +When the select strategy is used, SQL similar to the following will be generated: ```sql SELECT * FROM articles; -SELECT * FROM comments WHERE article_id IN (SELECT id FROM articles); +SELECT * FROM comments WHERE article_id IN (1, 2, 3, 4, 5); ``` You may want to cache the counts for your hasMany associations. This is useful @@ -616,9 +616,9 @@ Possible keys for belongsToMany association arrays include: - **propertyName**: The property name that should be filled with data from the associated table into the source table results. By default, this is the underscored & plural name of the association, so `tags` in our example. -- **strategy**: Defines the query strategy to use. Defaults to 'select'. The - other valid value is 'subquery', which replaces the `IN` list with an - equivalent subquery. +- **strategy**: Defines the query strategy to use. Defaults to 'subquery'. The + other valid value is 'select', which uses the `IN` list of parent keys + directly instead of a subquery. - **saveStrategy**: Either `append` or `replace`. Defaults to `replace`. Indicates the mode to be used for saving associated entities. The former will only create new links between both side of the relation and the latter will @@ -645,11 +645,11 @@ SELECT * FROM articles; SELECT * FROM tags INNER JOIN articles_tags ON ( tags.id = article_tags.tag_id - AND article_id IN (1, 2, 3, 4, 5) + AND article_id IN (SELECT id FROM articles) ); ``` -When the subquery strategy is used, SQL similar to the following will be +When the select strategy is used, SQL similar to the following will be generated: ```sql @@ -657,7 +657,7 @@ SELECT * FROM articles; SELECT * FROM tags INNER JOIN articles_tags ON ( tags.id = article_tags.tag_id - AND article_id IN (SELECT id FROM articles) + AND article_id IN (1, 2, 3, 4, 5) ); ```