Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 5c52bc1

Browse files
Remove the query hint section
1 parent 3216e63 commit 5c52bc1

File tree

1 file changed

+5
-216
lines changed

1 file changed

+5
-216
lines changed

‎core/performance.md‎

Lines changed: 5 additions & 216 deletions
Original file line numberDiff line numberDiff line change
@@ -27,218 +27,7 @@ with a huge collection. [Here are some examples to index LIKE
2727
filters](http://use-the-index-luke.com/sql/where-clause/searching-for-ranges/like-performance-tuning) depending on your
2828
database driver.
2929

30-
### Unserialized Properties Hydratation
31-
32-
#### Query Hint
33-
34-
Even though we're selecting only partial results (serialized properties) with Doctrine, it'll try to hydrate some
35-
relations with lazy joins (for example `OneToOne` relations). It's recommended to take a look at the Symfony Profiler,
36-
check what the generated SQL queries are doing in background and see if those may impact performance.
37-
38-
To force Doctrine to only hydrate partial values you need to use the
39-
[`Query::HINT_FORCE_PARTIAL_LOAD`](http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/dql-doctrine-query-language.html#query-hints).
40-
Be careful, using this query hint will force the use of partial selects. Some properties might not be available even if
41-
you expect them. If you want to be sure that Doctrine fetches them, use eager joins and make sure that properties are
42-
serializable.
43-
44-
To do this in API Platform you'd have to build a
45-
[`QueryResultCollectionExtension`](https://github.com/api-platform/core/blob/master/src/Bridge/Doctrine/Orm/Extension/QueryResultCollectionExtensionInterface.php)
46-
or a
47-
[`QueryResultItemExtension`](https://github.com/api-platform/core/blob/master/src/Bridge/Doctrine/Orm/Extension/QueryResultItemExtensionInterface.php).
48-
49-
For example, let's decorate the existing
50-
[`PaginationExtension`](https://github.com/api-platform/core/blob/master/src/Bridge/Doctrine/Orm/Extension/PaginationExtension.php)
51-
by setting the query hint:
52-
53-
```php
54-
<?php
55-
// src/AppBundle/Doctrine/Orm/Extension/QueryHintPaginationExtension.php
56-
57-
namespace AppBundle\Doctrine\Orm\Extension;
58-
59-
use ApiPlatform\Core\Bridge\Doctrine\Orm\Extension\QueryResultCollectionExtensionInterface;
60-
use ApiPlatform\Core\Bridge\Doctrine\Orm\Paginator;
61-
use ApiPlatform\Core\Bridge\Doctrine\Orm\Util\QueryChecker;
62-
use ApiPlatform\Core\Bridge\Doctrine\Orm\Util\QueryNameGeneratorInterface;
63-
use Doctrine\Common\Persistence\ManagerRegistry;
64-
use Doctrine\ORM\QueryBuilder;
65-
use Doctrine\ORM\Tools\Pagination\Paginator as DoctrineOrmPaginator;
66-
use Doctrine\ORM\Query;
67-
68-
final class QueryHintPaginationExtension implements QueryResultCollectionExtensionInterface
69-
{
70-
private $managerRegistry;
71-
private $decorated;
72-
73-
public function __construct(ManagerRegistry $managerRegistry, QueryResultCollectionExtensionInterface $decorated) {
74-
$this->managerRegistry = $managerRegistry;
75-
$this->decorated = $decorated;
76-
}
77-
78-
/**
79-
* {@inheritdoc}
80-
*/
81-
public function supportsResult(string $resourceClass, string $operationName = null) : bool
82-
{
83-
return $this->decorated->supportsResult($resourceClass, $operationName);
84-
}
85-
86-
/**
87-
* {@inheritdoc}
88-
*/
89-
public function getResult(QueryBuilder $queryBuilder)
90-
{
91-
$query = $queryBuilder->getQuery();
92-
// This forces doctrine to not lazy load entities
93-
$query->setHint(Query::HINT_FORCE_PARTIAL_LOAD, true);
94-
95-
$doctrineOrmPaginator = new DoctrineOrmPaginator($query, $this->useFetchJoinCollection($queryBuilder));
96-
$doctrineOrmPaginator->setUseOutputWalkers($this->useOutputWalkers($queryBuilder));
97-
98-
return new Paginator($doctrineOrmPaginator);
99-
}
100-
101-
/**
102-
* {@inheritdoc}
103-
*/
104-
public function applyToCollection(QueryBuilder $queryBuilder, QueryNameGeneratorInterface $queryNameGenerator, string $resourceClass, string $operationName = null)
105-
{
106-
return $this->decorated->applyToCollection($queryBuilder, $queryNameGenerator, $resourceClass, $operationName);
107-
}
108-
109-
/**
110-
* Determines whether the Paginator should fetch join collections, if the root entity uses composite identifiers it should not.
111-
*
112-
* @see https://github.com/doctrine/doctrine2/issues/2910
113-
*
114-
* @param QueryBuilder $queryBuilder
115-
*
116-
* @return bool
117-
*/
118-
private function useFetchJoinCollection(QueryBuilder $queryBuilder): bool
119-
{
120-
return !QueryChecker::hasRootEntityWithCompositeIdentifier($queryBuilder, $this->managerRegistry);
121-
}
122-
123-
/**
124-
* Determines whether output walkers should be used.
125-
*
126-
* @param QueryBuilder $queryBuilder
127-
*
128-
* @return bool
129-
*/
130-
private function useOutputWalkers(QueryBuilder $queryBuilder) : bool
131-
{
132-
/*
133-
* "Cannot count query that uses a HAVING clause. Use the output walkers for pagination"
134-
*
135-
* @see https://github.com/doctrine/doctrine2/blob/900b55d16afdcdeb5100d435a7166d3a425b9873/lib/Doctrine/ORM/Tools/Pagination/CountWalker.php#L50
136-
*/
137-
if (QueryChecker::hasHavingClause($queryBuilder)) {
138-
return true;
139-
}
140-
141-
/*
142-
* "Paginating an entity with foreign key as identifier only works when using the Output Walkers. Call Paginator#setUseOutputWalkers(true) before iterating the paginator."
143-
*
144-
* @see https://github.com/doctrine/doctrine2/blob/900b55d16afdcdeb5100d435a7166d3a425b9873/lib/Doctrine/ORM/Tools/Pagination/LimitSubqueryWalker.php#L87
145-
*/
146-
if (QueryChecker::hasRootEntityWithForeignKeyIdentifier($queryBuilder, $this->managerRegistry)) {
147-
return true;
148-
}
149-
150-
/*
151-
* "Cannot select distinct identifiers from query with LIMIT and ORDER BY on a column from a fetch joined to-many association. Use output walkers."
152-
*
153-
* @see https://github.com/doctrine/doctrine2/blob/900b55d16afdcdeb5100d435a7166d3a425b9873/lib/Doctrine/ORM/Tools/Pagination/LimitSubqueryWalker.php#L149
154-
*/
155-
if (
156-
QueryChecker::hasMaxResults($queryBuilder) &&
157-
QueryChecker::hasOrderByOnToManyJoin($queryBuilder, $this->managerRegistry)
158-
) {
159-
return true;
160-
}
161-
162-
/*
163-
* When using composite identifiers pagination will need Output walkers
164-
*/
165-
if (QueryChecker::hasRootEntityWithCompositeIdentifier($queryBuilder, $this->managerRegistry)) {
166-
return true;
167-
}
168-
169-
// Disable output walkers by default (performance)
170-
return false;
171-
}
172-
}
173-
```
174-
175-
The service definition:
176-
177-
```yaml
178-
# app/config/services.yml
179-
services:
180-
app.doctrine.orm.query_extension.pagination_hint:
181-
class: 'AppBundle\Doctrine\Orm\Extension\QueryHintPaginationExtension'
182-
decorates: api_platform.doctrine.orm.query_extension.pagination
183-
arguments: ['@doctrine', '@api_platform.doctrine.orm.query_extension.pagination_hint.inner']
184-
```
185-
186-
To alter the `Query` object on an item data provider, we can also create an `QueryHintExtension` which will alter the result:
187-
188-
```php
189-
<?php
190-
// src/AppBundle/Doctrine/Orm/Extension/QueryHintExtension.php
191-
192-
namespace AppBundle\Doctrine\Orm\Extension;
193-
194-
use ApiPlatform\Core\Bridge\Doctrine\Orm\Extension\QueryResultItemExtensionInterface;
195-
use ApiPlatform\Core\Bridge\Doctrine\Orm\Util\QueryNameGeneratorInterface;
196-
use Doctrine\ORM\Query;
197-
use Doctrine\ORM\QueryBuilder;
198-
199-
class QueryHintExtension implements QueryResultItemExtensionInterface
200-
{
201-
/**
202-
* {@inheritdoc}
203-
*/
204-
public function applyToItem(QueryBuilder $queryBuilder, QueryNameGeneratorInterface $queryNameGenerator, string $resourceClass, array $identifiers, string $operationName = null);
205-
{
206-
}
207-
208-
/**
209-
* {@inheritdoc}
210-
*/
211-
public function supportsResult(string $resourceClass, string $operationName = null) : bool
212-
{
213-
return true;
214-
}
215-
216-
/**
217-
* {@inheritdoc}
218-
*/
219-
public function getResult(QueryBuilder $queryBuilder)
220-
{
221-
$query = $queryBuilder->getQuery();
222-
$query->setHint(Query::HINT_FORCE_PARTIAL_LOAD, true);
223-
224-
return $query->getResult();
225-
}
226-
}
227-
```
228-
229-
The service definition:
230-
231-
```yaml
232-
# app/config/services.yml
233-
234-
services:
235-
api_platform.doctrine.orm.query_extension.hint:
236-
class: 'AppBundle\Doctrine\Orm\Extension\QueryHintExtension'
237-
tags:
238-
- {name: api_platform.doctrine.orm.query_extension.item}
239-
```
240-
241-
#### Eager loading
30+
### Eager loading
24231

24332
By default Doctrine comes with [lazy loading](http://doctrine-orm.readthedocs.io/en/latest/reference/working-with-objects.html#by-lazy-loading).
24433
Usually a killer time-saving feature and also a performance killer with large applications.
@@ -249,7 +38,7 @@ This can easily be enabled for a relation: `@ORM\ManyToOne(fetch="EAGER")`.
24938
By default in API Platform, we made the choice to force eager loading for all relations, with or without the Doctrine
25039
`fetch` attribute. Thanks to the eager loading [extension](extensions.md).
25140

252-
##### Max joins
41+
#### Max joins
25342

25443
There is a default restriction with this feature. We allow up to 30 joins per query. Beyond, an
25544
`ApiPlatform\Core\Exception\RuntimeException` exception will be thrown but this value can easily be increased with a
@@ -270,7 +59,7 @@ api_platform:
27059
Be careful when you exceed this limit, it's often caused by the result of a circular reference. [Serializer groups](serialization-groups-and-relations.md)
27160
can be a good solution to fix this issue.
27261

273-
##### Force eager
62+
#### Force eager
27463

27564
As mentioned above, by default we force eager loading for all relations. This behaviour can be modified with the
27665
configuration in order to apply it only on join relations having the `EAGER` fetch mode:
@@ -287,7 +76,7 @@ api_platform:
28776
# ...
28877
```
28978

290-
##### Override at resource and operation level
79+
#### Override at resource and operation level
29180

29281
When eager loading is enabled, whatever the status of the `force_eager` parameter, you can easily override it directly
29382
from the configuration of each resource. You can do this at the resource level, at the operations level, or both:
@@ -380,7 +169,7 @@ class Group
380169
Be careful, the operation level is higher priority than the resource level but both are higher priority than the global
381170
configuration.
382171

383-
##### Disable eager loading
172+
#### Disable eager loading
384173

385174
If for any reason you don't want the eager loading feature, you can turn off it in the configuration:
386175

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /