diff --git a/source/reference/method/cursor.explain.txt b/source/reference/method/cursor.explain.txt index 9a95be87ef7..57b407b93ec 100644 --- a/source/reference/method/cursor.explain.txt +++ b/source/reference/method/cursor.explain.txt @@ -238,28 +238,43 @@ sharded*. For queries on sharded collections, see .. data:: explain.n - :data:`~explain.n` is a number that reflects the number of documents - that match the query selection criteria. + :data:`~explain.n` is the number of documents that match the query + selection criteria. + + For more information on :data:`~explain.n` and query optimization, see + :doc:`/tutorial/analyze-query-plan` and + :doc:`/administration/optimization`. .. data:: explain.nscannedObjects - Specifies the total number of documents scanned during the query. - The :data:`~explain.nscannedObjects` may be lower than - :data:`~explain.nscanned`, such as if the index :ref:`covers - ` a query. See - :data:`~explain.indexOnly`. Additionally, the - :data:`~explain.nscannedObjects` may be lower than - :data:`~explain.nscanned` in the case of multikey index on an array - field with duplicate documents. + :data:`~explain.nscannedObjects` is the total number of documents + scanned during the query. + + The :data:`~explain.nscannedObjects` value may be lower than + :data:`~explain.nscanned`, if the number of documents or index entries + scanned. :data:`~explain.nscannedObjects` will be 0 if there is a + covered query, a query where all the query fields are part of an + index and all fields returned are in the same index. For information + about covered queries, see :data:`~explain.indexOnly`, which indicates + if the query is covered by the index, and :ref:`Create Indexes that + Support Covered Queries `. + + A multikey index on an array field with duplicate documents also + results in an :data:`~explain.nscannedObjects` value lower than + :data:`~explain.nscanned`. + + For more information on :data:`~explain.nscannedOjects` and query + optimization, see :doc:`/tutorial/analyze-query-plan` and + :doc:`/administration/optimization`. .. data:: explain.nscanned - Specifies the total number of documents or index entries scanned - during the database operation. You want :data:`~explain.n` and - :data:`~explain.nscanned` to be close in value as possible. The - :data:`~explain.nscanned` value may be higher than the - :data:`~explain.nscannedObjects` value, such as if the index :ref:`covers - ` a query. See :data:`~explain.indexOnly`. + :data:`~explain.nscanned` is the total number of documents or index + entries scanned during the database operation. + + For more information on :data:`~explain.nscanned` and query + optimization, see :doc:`/tutorial/analyze-query-plan` and + :doc:`/administration/optimization`. .. data:: explain.nscannedObjectsAllPlans diff --git a/source/tutorial/analyze-query-plan.txt b/source/tutorial/analyze-query-plan.txt index 9ab508d4498..dba40dd006f 100644 --- a/source/tutorial/analyze-query-plan.txt +++ b/source/tutorial/analyze-query-plan.txt @@ -4,65 +4,228 @@ Analyze Query Performance .. default-domain:: mongodb -The :method:`~cursor.explain()` cursor method allows you to inspect the -operation of the query system. This method is useful for analyzing the -efficiency of queries, and for determining how the query uses the -index. The :method:`~cursor.explain()` method tests the query -operation, and *not* the timing of query performance. Because -:method:`~cursor.explain()` attempts multiple query plans, it does not -reflect an accurate timing of query performance. +The MongoDB query optimizer processes queries and chooses the most optimal +:doc:`query plan ` for a query given the available +indexes. Sometimes you can optimize a query or index based on their +impact on database performance. + +The :method:`~cursor.explain()` cursor method provides statistics about +the performance of a query. This data output can be useful in measuring +how optimally a query uses indexes, document lookups, and other database +functionality to retrieve information. + +The :method:`~cursor.explain()` method output does not reflect an accurate +timing of query performance. + +See :doc:`/core/query-optimization`, +:doc:`/tutorial/optimize-query-performance-with-indexes-and-projections`, +and :doc:`/applications/indexes` for more information about building +optimal database queries. Evaluate the Performance of a Query ----------------------------------- -To use the :method:`~cursor.explain()` method, call the method on a -cursor returned by :method:`~db.collection.find()`. +You can use the :method:`~cursor.explain()` method to understand and +evaluate the performance characteristics of different query and index +combinations. -.. example:: Evaluate a query on the ``type`` field on the collection - ``inventory`` that has an index on the ``type`` field. +For the following examples, consider a collection with these six documents with fields +for ``id``, ``section``, and ``status``: - .. code-block:: javascript +.. code-block:: javascript - db.inventory.find( { type: 'food' } ).explain() + { "_id" : 1, "section" : 1, "status" : 1 } + { "_id" : 2, "section" : 2, "status" : 1 } + { "_id" : 3, "section" : 1, "status" : 1 } + { "_id" : 4, "section" : 3, "status" : 1 } + { "_id" : 5, "section" : 4, "status" : 0 } + { "_id" : 6, "section" : 4, "status" : 0 } + +Range Query with No Index +~~~~~~~~~~~~~~~~~~~~~~~~~ + +The following range query retrieves documents where the ``section`` +field has a value between ``2`` and ``4``: + +.. code-block:: javascript + + db.posts.find( { section: { $gte: 2, $lte: 4 } } ) + +The query returns these four documents: + +.. code-block:: javascript + + { "_id" : 2, "section" : 2, "status" : 1 } + { "_id" : 4, "section" : 3, "status" : 1 } + { "_id" : 5, "section" : 4, "status" : 0 } + { "_id" : 6, "section" : 4, "status" : 0 } + +The following range query with the :method:`~cursor.explain()` method +generates statistics about the database impact of this query: + +.. code-block:: javascript + + db.posts.find( { section: { $gte: 2, $lte: 4 } } ).explain() - Consider the results: +The :method:`~cursor.explain()` method returns this output: - .. code-block:: javascript +.. code-block:: javascript + + { + "cursor" : "BasicCursor", + "isMultiKey" : false, + "n" : 4, + "nscannedObjects" : 6, + "nscanned" : 6, + "nscannedObjectsAllPlans" : 6, + "nscannedAllPlans" : 6, + "scanAndOrder" : false, + "indexOnly" : false, + "nYields" : 0, + "nChunkSkips" : 0, + "millis" : 0, + "server" : "machine.local:27017", + "filterSet" : false + } + +This query returned 4 documents, as indicated by the :data:`~explain.n` +field. - { - "cursor" : "BtreeCursor type_1", - "isMultiKey" : false, - "n" : 5, - "nscannedObjects" : 5, - "nscanned" : 5, - "nscannedObjectsAllPlans" : 5, - "nscannedAllPlans" : 5, - "scanAndOrder" : false, - "indexOnly" : false, - "nYields" : 0, - "nChunkSkips" : 0, - "millis" : 0, - "indexBounds" : { "type" : [ - [ "food", - "food" ] - ] }, - "server" : "mongodbo0.example.net:27017" } - - The ``BtreeCursor`` value of the :data:`~explain.cursor` field - indicates that the query used an index. - - This query returned 5 documents, as indicated by the - :data:`~explain.n` field. - - To return these 5 documents, the query scanned 5 documents from the - index, as indicated by the :data:`~explain.nscanned` field, and then - read 5 full documents from the collection, as indicated by the - :data:`~explain.nscannedObjects` field. - - Without the index, the query would have scanned the whole collection - to return the 5 documents. - - See :ref:`explain-results` method for full details on the output. +The :data:`~explain.n` field indicates the query returned 4 documents. The +``BasicCursor`` value of the :data:`~explain.cursor` field indicates the +query did not use an index. See :ref:`explain-output` for descriptions of +the other fields in this output. + +The differences between 4 returned documents, 6 documents scanned from the +index, and 6 documents read as a result of the query suggests this might +not be an optimal query. The database scanned and read 2 documents more +than it returned. + +A Query with an Index on One Field +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Add an index on the ``section`` field with the +:method:`~db.collection.ensureIndex` method, then run the following range +query for documents with ``section`` fields with values between ``2`` and +``4`` with the :method:`~cursor.explain()` method: + +.. code-block:: javascript + + db.posts.find( { section: { $gte: 2, $lte: 4 } } ).explain() + +The :method:`~cursor.explain()` method returns this output: + +.. code-block:: javascript + + { + "cursor" : "BtreeCursor section_1", + "isMultiKey" : false, + "n" : 4, + "nscannedObjects" : 4, + "nscanned" : 4, + "nscannedObjectsAllPlans" : 4, + "nscannedAllPlans" : 4, + "scanAndOrder" : false, + "indexOnly" : false, + "nYields" : 0, + "nChunkSkips" : 0, + "millis" : 0, + "indexBounds" : { + "section" : [ + [ + 2, + 4 + ] + ] + }, + "server" : "machine.local:27017", + "filterSet" : false + } + +This query returned 4 documents, as indicated by the :data:`~explain.n` +field. + +To return these 4 documents, the :data:`~explain.nscanned` field indicates +the query scanned 4 documents from the index and the +:data:`~explain.nscannedObjects` field indicates the query read 4 full +documents from the collection. + +The ``BtreeCursor section_1`` value of the :data:`~explain.cursor` field +indicates the query used an index on the ``section`` field. See +:ref:`explain-output` for descriptions of the other fields in this output. + +The numeric equality between 4 returned documents, 4 documents scanned +from the index, and 4 documents read as a result of the query suggests +this might be an optimal query. + +A Query with a Compound Index +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Add a compound index on the ``section`` and ``status`` fields, in that +order, with the :method:`~db.collection.ensureIndex()` method: + +.. code-block:: javascript + + db.collection.ensureIndex( { section: 1, status: 1 } ) + +Then run the following query with the :method:`~cursor.explain()` method +to evaluate the database impact of this query request: + +.. code-block:: javascript + + db.posts.find( { section: { $gte: 2, $lte: 4 }, status: 1 } ).explain() + +The :method:`~cursor.explain()` method returns this output: + +.. code-block:: javascript + + { + "cursor" : "BtreeCursor section_1_status_1", + "isMultiKey" : false, + "n" : 2, + "nscannedObjects" : 2, + "nscanned" : 3, + "nscannedObjectsAllPlans" : 2, + "nscannedAllPlans" : 3, + "scanAndOrder" : false, + "indexOnly" : false, + "nYields" : 0, + "nChunkSkips" : 0, + "millis" : 0, + "indexBounds" : { + "section" : [ + [ + 2, + 4 + ] + ], + "status" : [ + [ + 1, + 1 + ] + ] + }, + "server" : "machine.local:27017", + "filterSet" : false + } + +This query returned 2 documents, as indicated by the :data:`~explain.n` +field. + +To return these 2 documents, the :data:`~explain.nscanned` field indicates +the query scanned 3 documents from the index and the +:data:`~explain.nscannedObjects` field indicates the query read 2 full +documents from the collection. + +The ``BtreeCursor section_1_status_1`` value of the +:data:`~explain.cursor` field indicates the query used a compound index on +the ``section`` field and ``status`` field. See :ref:`explain-output` for +descriptions of the other fields in this output. + +The differences between 2 returned documents, 3 documents scanned from the +index, and 2 documents read as a result of the query suggests a query with +the compound index might be optimal. Compare Performance of Indexes ------------------------------ diff --git a/source/tutorial/evaluate-operation-performance.txt b/source/tutorial/evaluate-operation-performance.txt index 93b3b3e2387..2010cf0fbea 100644 --- a/source/tutorial/evaluate-operation-performance.txt +++ b/source/tutorial/evaluate-operation-performance.txt @@ -45,3 +45,6 @@ query. db.records.find( { a: 1 } ).explain() .. todo Link to Kay's new explain doc + +See :doc:`/tutorial/analyze-query-plan` for more details. +