Skip to content

Commit 48b2aa3

Browse files
committed
DOCS-11102: clarify sort-limit coalescence behavior
1 parent 1dbf047 commit 48b2aa3

File tree

2 files changed

+80
-115
lines changed

2 files changed

+80
-115
lines changed

source/core/aggregation-pipeline-optimization.txt

Lines changed: 71 additions & 108 deletions
Original file line numberDiff line numberDiff line change
@@ -169,72 +169,32 @@ The optimizer can add the same :pipeline:`$match` stage before the
169169
{ $redact: { $cond: { if: { $eq: [ "$level", 5 ] }, then: "$$PRUNE", else: "$$DESCEND" } } },
170170
{ $match: { year: 2014, category: { $ne: "Z" } } }
171171

172-
.. _agg-skip-limit-optimization:
172+
.. _agg-project-skip-optimization:
173173

174-
``$skip`` + ``$limit`` Sequence Optimization
175-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
176-
177-
When you have a sequence with :pipeline:`$skip` followed by a
178-
:pipeline:`$limit`, the :pipeline:`$limit` moves before the
179-
:pipeline:`$skip`. With the reordering, the :pipeline:`$limit` value
180-
increases by the :pipeline:`$skip` amount.
181-
182-
For example, if the pipeline consists of the following stages:
183-
184-
.. code-block:: javascript
185-
186-
{ $skip: 10 },
187-
{ $limit: 5 }
188-
189-
During the optimization phase, the optimizer transforms the sequence to
190-
the following:
191-
192-
.. code-block:: javascript
193-
194-
{ $limit: 15 },
195-
{ $skip: 10 }
196-
197-
This optimization allows for more opportunities for
198-
:ref:`agg-sort-limit-coalescence`, such as with ``$sort`` + ``$skip`` +
199-
``$limit`` sequences. See :ref:`agg-sort-limit-coalescence` for details
200-
on the coalescence and :ref:`agg-sort-skip-limit-sequence` for an
201-
example.
202-
203-
For aggregation operations on :doc:`sharded collections
204-
<aggregation-pipeline-sharded-collections>`, this optimization reduces
205-
the results returned from each shard.
206-
207-
.. _agg-project-skip-limit-optimization:
208-
209-
``$project`` + ``$skip`` or ``$limit`` Sequence Optimization
210-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
174+
``$project`` + ``$skip`` Sequence Optimization
175+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
211176

212177
.. versionadded:: 3.2
213178

214-
When you have a sequence with :pipeline:`$project` followed by either
215-
:pipeline:`$skip` or :pipeline:`$limit`, the :pipeline:`$skip` or
216-
:pipeline:`$limit` moves before :pipeline:`$project`. For example, if
179+
When you have a sequence with :pipeline:`$project` followed by
180+
:pipeline:`$skip`, the :pipeline:`$skip`
181+
moves before :pipeline:`$project`. For example, if
217182
the pipeline consists of the following stages:
218183

219184
.. code-block:: javascript
220185

221186
{ $sort: { age : -1 } },
222187
{ $project: { status: 1, name: 1 } },
223-
{ $limit: 5 }
188+
{ $skip: 5 }
224189

225190
During the optimization phase, the optimizer transforms the sequence to
226191
the following:
227192

228193
.. code-block:: javascript
229194

230195
{ $sort: { age : -1 } },
231-
{ $limit: 5 }
232-
{ $project: { status: 1, name: 1 } },
233-
234-
This optimization allows for more opportunities for
235-
:ref:`agg-sort-limit-coalescence`, such as with ``$sort`` + ``$limit``
236-
sequences. See :ref:`agg-sort-limit-coalescence` for details on the
237-
coalescence.
196+
{ $skip: 5 },
197+
{ $project: { status: 1, name: 1 } }
238198

239199
.. _aggregation-pipeline-coalescence-optimization:
240200

@@ -250,14 +210,58 @@ reordering optimization.
250210
``$sort`` + ``$limit`` Coalescence
251211
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
252212

253-
When a :pipeline:`$sort` immediately precedes a :pipeline:`$limit`, the
254-
optimizer can coalesce the :pipeline:`$limit` into the
255-
:pipeline:`$sort`. This allows the sort operation to only maintain the
213+
.. versionchanged:: 4.0
214+
215+
When a :pipeline:`$sort` precedes a :pipeline:`$limit`, the optimizer
216+
can coalesce the :pipeline:`$limit` into the :pipeline:`$sort` if no
217+
intervening stages modify the number of documents
218+
(e.g. :pipeline:`$unwind`, :pipeline:`$group`).
219+
MongoDB will not coalesce the :pipeline:`$limit` into the
220+
:pipeline:`$sort` if there are pipeline stages that change the number of
221+
documents between the :pipeline:`$sort` and :pipeline:`$limit` stages..
222+
223+
For example, if the pipeline consists of the following stages:
224+
225+
.. code-block:: javascript
226+
227+
{ $sort : { age : -1 } },
228+
{ $project : { age : 1, status : 1, name : 1 } },
229+
{ $limit: 5 }
230+
231+
During the optimization phase, the optimizer coalesces the sequence
232+
to the following:
233+
234+
.. code-block:: javascript
235+
236+
{
237+
"$sort" : {
238+
"sortKey" : {
239+
"age" : -1
240+
},
241+
"limit" : NumberLong(5)
242+
}
243+
},
244+
{ "$project" : {
245+
"age" : 1,
246+
"status" : 1,
247+
"name" : 1
248+
}
249+
}
250+
251+
This allows the sort operation to only maintain the
256252
top ``n`` results as it progresses, where ``n`` is the specified limit,
257253
and MongoDB only needs to store ``n`` items in memory
258254
[#coalescence-allowDiskUse]_. See :ref:`sort-and-memory` for more
259255
information.
260256

257+
.. admonition:: Sequence Optimization with $skip
258+
259+
If there is a :pipeline:`$skip` stage between the :pipeline:`$sort`
260+
and :pipeline:`$limit` stages, MongoDB will coalesce the
261+
:pipeline:`$limit` into the :pipeline:`$sort` stage and increase the
262+
:pipeline:`$limit` value by the :pipeline:`$skip` amount. See
263+
:ref:`agg-sort-skip-limit-sequence` for an example.
264+
261265
.. [#coalescence-allowDiskUse] The optimization will still apply when
262266
``allowDiskUse`` is ``true`` and the ``n`` items exceed the
263267
:ref:`aggregation memory limit <agg-memory-restrictions>`.
@@ -378,13 +382,8 @@ option, the ``explain`` output shows the coalesced stage:
378382
}
379383
}
380384

381-
Examples
382-
--------
383-
384-
The following examples are some sequences that can take advantage of
385-
both sequence reordering and coalescence. Generally, coalescence occurs
386-
*after* any sequence reordering optimization.
387-
385+
Example
386+
-------
388387
.. _agg-sort-skip-limit-sequence:
389388

390389
``$sort`` + ``$skip`` + ``$limit`` Sequence
@@ -399,60 +398,24 @@ A pipeline contains a sequence of :pipeline:`$sort` followed by a
399398
{ $skip: 10 },
400399
{ $limit: 5 }
401400

402-
First, the optimizer performs the :ref:`agg-skip-limit-optimization` to
401+
The optimizer performs :ref:`agg-sort-limit-coalescence` to
403402
transforms the sequence to the following:
404403

405404
.. code-block:: javascript
406405

407-
{ $sort: { age : -1 } },
408-
{ $limit: 15 }
409-
{ $skip: 10 }
410-
411-
The :ref:`agg-skip-limit-optimization` increases the :pipeline:`$limit`
412-
amount with the reordering. See :ref:`agg-skip-limit-optimization` for
413-
details.
414-
415-
The reordered sequence now has :pipeline:`$sort` immediately preceding
416-
the :pipeline:`$limit`, and the pipeline can coalesce the two stages to
417-
decrease memory usage during the sort operation. See
418-
:ref:`agg-sort-limit-coalescence` for more information.
419-
420-
``$limit`` + ``$skip`` + ``$limit`` + ``$skip`` Sequence
421-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
422-
423-
A pipeline contains a sequence of alternating :pipeline:`$limit` and
424-
:pipeline:`$skip` stages:
425-
426-
.. code-block:: javascript
427-
428-
{ $limit: 100 },
429-
{ $skip: 5 },
430-
{ $limit: 10 },
431-
{ $skip: 2 }
432-
433-
The :ref:`agg-skip-limit-optimization` reverses the position of the ``{
434-
$skip: 5 }`` and ``{ $limit: 10 }`` stages and increases the limit
435-
amount:
436-
437-
.. code-block:: javascript
438-
439-
{ $limit: 100 },
440-
{ $limit: 15},
441-
{ $skip: 5 },
442-
{ $skip: 2 }
443-
444-
The optimizer then coalesces the two :pipeline:`$limit` stages into a
445-
single :pipeline:`$limit` stage and the two :pipeline:`$skip` stages
446-
into a single :pipeline:`$skip` stage. The resulting sequence is the
447-
following:
448-
449-
.. code-block:: javascript
450-
451-
{ $limit: 15 },
452-
{ $skip: 7 }
406+
{
407+
"$sort" : {
408+
"sortKey" : {
409+
"age" : -1
410+
},
411+
"limit" : NumberLong(15)
412+
}
413+
},
414+
{
415+
"$skip" : NumberLong(10)
416+
}
453417

454-
See :ref:`agg-limit-limit-coalescence` and
455-
:ref:`agg-skip-skip-coalescence` for details.
418+
MongoDB increases the :pipeline:`$limit` amount with the reordering.
456419

457420
.. seealso::
458421
:method:`explain <db.collection.aggregate()>` option in the
Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1-
When a :pipeline:`$sort` immediately precedes a :pipeline:`$limit` in
2-
the pipeline, the :pipeline:`$sort` operation only maintains the top
3-
``n`` results as it progresses, where ``n`` is the specified limit, and
4-
MongoDB only needs to store ``n`` items in memory. This optimization
5-
still applies when ``allowDiskUse`` is ``true`` and the ``n`` items
6-
exceed the :ref:`aggregation memory limit <agg-memory-restrictions>`.
7-
1+
When a :pipeline:`$sort` precedes a :pipeline:`$limit` and there are no
2+
intervening stages that modify the number of documents, the optimizer can
3+
coalesce the :pipeline:`$limit` into the :pipeline:`$sort`. This allows
4+
the :pipeline:`$sort` operation to only
5+
maintain the top ``n`` results as it progresses, where ``n`` is the
6+
specified limit, and ensures that MongoDB only needs to store ``n`` items in memory.
7+
This optimization still applies when ``allowDiskUse`` is ``true`` and
8+
the ``n`` items exceed the :ref:`aggregation memory limit
9+
<agg-memory-restrictions>`.

0 commit comments

Comments
 (0)