Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
Performance Tuning
Tom Schreiber
Senior Consulting Engineer, MongoDB
MongoDB's unique architecture
MongoDB's unique architecture
Indexes are the single biggest tunable
performance factor in MongoDB
🔍
{'a': 9,
{'a': 3, {'b': 40, {'a': 1, {'a': 5,
{'b': 30} 'b': 4, {'a': 11} {'a': 17}
'b': 20} 'a': 1 } 'b': 20} 'b': 80}
'a': 7}
1
Full collection scan
🔍
{'a': 9,
{'a': 3, {'b': 40, {'a': 1, {'a': 5,
{'b': 30} 'b': 4, {'a': 11} {'a': 17}
'b': 20} 'a': 1 } 'b': 20} 'b': 80}
'a': 7}
2
Full collection scan
🔍
{'a': 9,
{'a': 3, {'b': 40, {'a': 1, {'a': 5,
{'b': 30} 'b': 4, {'a': 11} {'a': 17}
'b': 20} 'a': 1 } 'b': 20} 'b': 80}
'a': 7}
3
Full collection scan
🔍
{'a': 9,
{'a': 3, {'b': 40, {'a': 1, {'a': 5,
{'b': 30} 'b': 4, {'a': 11} {'a': 17}
'b': 20} 'a': 1 } 'b': 20} 'b': 80}
'a': 7}
4
Full collection scan
🔍
{'a': 9,
{'a': 3, {'b': 40, {'a': 1, {'a': 5,
{'b': 30} 'b': 4, {'a': 11} {'a': 17}
'b': 20} 'a': 1 } 'b': 20} 'b': 80}
'a': 7}
5
Full collection scan
🔍
{'a': 9,
{'a': 3, {'b': 40, {'a': 1, {'a': 5,
{'b': 30} 'b': 4, {'a': 11} {'a': 17}
'b': 20} 'a': 1 } 'b': 20} 'b': 80}
'a': 7}
6
Full collection scan
🔍
{'a': 9,
{'a': 3, {'b': 40, {'a': 1, {'a': 5,
{'b': 30} 'b': 4, {'a': 11} {'a': 17}
'b': 20} 'a': 1 } 'b': 20} 'b': 80}
'a': 7}
7
Full collection scan
🔍
{'a': 9,
{'a': 3, {'b': 40, {'a': 1, {'a': 5,
{'b': 30} 'b': 4, {'a': 11} {'a': 17}
'b': 20} 'a': 1 } 'b': 20} 'b': 80}
'a': 7}
8
Index scan
Index on 'a'
7
3 11
1 5 9 17
{'a': 9,
{'a': 3, {'b': 40, {'a': 1, {'a': 5,
{'b': 30} 'b': 4, {'a': 11} {'a': 17}
'b': 20} 'a': 1 } 'b': 20} 'b': 80}
'a': 7}
Indexes areIndex scan biggest tu
the single
Search for document(s) with 'a': 5
db.test.find({a:5})
🔍
Index on 'a' # index entries scanned:
3 11
1 5 9 17
{'a': 9,
{'a': 3, {'b': 40, {'a': 1, {'a': 5,
{'b': 30} 'b': 4, {'a': 11} {'a': 17}
'b': 20} 'a': 1 } 'b': 20} 'b': 80}
'a': 7}
Indexes areIndex scan biggest tu
the single
Search for document(s) with 'a': 5
db.test.find({a:5})
1 🔍 3
5 9
11
17
{'a': 9,
{'a': 3, {'b': 40, {'a': 1, {'a': 5,
{'b': 30} 'b': 4, {'a': 11} {'a': 17}
'b': 20} 'a': 1 } 'b': 20} 'b': 80}
'a': 7}
Indexes areIndex scan biggest tu
the single
Search for document(s) with 'a': 5
db.test.find({a:5})
3 11
🔍
1 5 9 17
{'a': 9,
{'a': 3, {'b': 40, {'a': 1, {'a': 5,
{'b': 30} 'b': 4, {'a': 11} {'a': 17}
'b': 20} 'a': 1 } 'b': 20} 'b': 80}
'a': 7}
Index scan
db.test.find({a:5})
🔍
log2 10.000 = 13
log2 100.000 = 16
1 5 9 17
log2 1.000.000 = 19
{'a': 9,
{'a': 3, {'b': 40, {'a': 1, {'a': 5,
{'b': 30} 'b': 4, {'a': 11} {'a': 17}
'b': 20} 'a': 1 } 'b': 20} 'b': 80}
'a': 7}
MongoDB Indexes are B-Trees
Searches, Insertions, and Deletions in logarithmic time.
Index on a
db.col.query(...)
index on x
Terminate
index on y
Choose and Remenber
t0 tresult
Each stage passes its results (i.e. documents or index keys) to the parent node.
{
"queryPlanner" : {
[...],
"winningPlan" : { plan root
"stage" : "FETCH",
"inputStage" : {
"stage" : "IXSCAN",
"keyPattern" : {
"a" : 5 stage
},
"indexName" : "a_1", FETCH
"isMultiKey" : false,
"direction" : "forward",
"indexBounds" : {
"a" : [
"[5.0, 5.0]" stage
]
}
IXSCAN
}
}
},
[...]
}
db.test.find({a:5}).explain()
{
"queryPlanner" : {
[...],
"winningPlan" : { plan root
"stage" : "FETCH",
"inputStage" : {
"stage" : "IXSCAN",
"keyPattern" : {
"a" : 5 stage
},
"indexName" : "a_1", FETCH
"isMultiKey" : false,
"direction" : "forward",
"indexBounds" : {
"a" : [ stage
"[5.0, 5.0]"
] IXSCAN
} Index on {a:1}
}
} [-∞, 5) [5, 10) [10, ∞)
},
[...]
} [-∞, 5) buckets [5, 7) [7, 9) [9, 10) [10, ∞) buckets
queryPlanner
"Which plan will MongoDB choose to run my query?"
executionStats
"How is my query performing?"
allPlansExecution
"I want as much information as possible to diagnose a slow query."
db.test.find({a:5}).explain()
plan root
stage
FETCH
stage
IXSCAN
Index on {a:1}
[-∞, 5) [5, 10) [10, ∞)
{
[...],
"executionStats" : {
plan root
"executionSuccess" : true,
"nReturned" : 1,
"executionTimeMillis" : 0,
"totalKeysExamined" : 1,
"totalDocsExamined" : 1,
stage
"executionStages" : {
FETCH
"stage" : "FETCH",
"nReturned" : 1,
"executionTime stage
MillisEstimate" : 0,
IXSCAN
"works" : 2,
"advanced" : 1,
Index on {a:1}
"needTime" : 0,
[-∞, 5) [5, 10) [10, ∞)
"needFetch" : 0,
"saveState" : 0,
"restoreState" : 0,
[-∞, 5) buckets [5, 7) [7, 9) [9, 10) [10, ∞) buckets
"isEOF" : 1,
"invalidates" : 0,
"docsExamined" : 1,
"alreadyHasObj" : 0,
{...} {...} {...} {...} {...} {...} {...} {...} {...}
"inputStage" : {
"stage" : "IXSCAN",
"executionTimeMillis" : 0,
"totalKeysExamined" : 1,
db.test.find({a:5}).explain("executionStats")
"totalDocsExamined" : 1,
"executionStages" : {
"stage" : "FETCH",
"nReturned" : 1,
plan root
"executionTime
MillisEstimate" : 0,
"works" : 2,
"advanced" : 1,
"needTime" : 0,
stage
"needFetch" : 0,
"saveState" : 0,
FETCH
"restoreState" : 0,
"isEOF" : 1,
"invalidates" : 0,
"docsExamined" : 1,
stage
"alreadyHasObj" : 0,
IXSCAN
"inputStage" : {
Index on {a:1}
[-∞, 5) [5, 10) [10, ∞)
"stage" : "IXSCAN",
"nReturned" : 1,
"executionTime [-∞, 5) buckets [5, 7) [7, 9) [9, 10) [10, ∞) buckets
MillisEstimate" : 0,
"works" : 1,
"advanced" : 1,
"needTime" : 0,
"needFetch" : 0,
{...} {...} {...} {...} {...} {...} {...} {...} {...}
"saveState" : 0,
"restoreState" : 0,
"isEOF" : 1,
"invalidates" : 0,
"docsExamined" : 1,
db.test.find({a:5}).explain("executionStats")
"alreadyHasObj" : 0,
"inputStage" : {
"stage" : "IXSCAN",
"nReturned" : 1,
plan root
"executionTime
MillisEstimate" : 0,
"works" : 1,
"advanced" : 1,
"needTime" : 0,
stage
"needFetch" : 0,
"saveState" : 0,
FETCH
"restoreState" : 0,
"isEOF" : 1,
"invalidates" : 0,
"keyPattern" : {
stage
"a" : 5
IXSCAN
},
"indexName" : "a_1",
Index on {a:1}
"isMultiKey" : false,
[-∞, 5) [5, 10) [10, ∞)
"direction" : "forward",
"indexBounds" : {
"a" : [
[-∞, 5) buckets [5, 7) [7, 9) [9, 10) [10, ∞) buckets
"[5.0, 5.0]"
]
},
"keysExamined" : 1,
"dupsTested" : 0,
{...} {...} {...} {...} {...} {...} {...} {...} {...}
"dupsDropped" : 0,
"seenInvalidated" : 0,
"matchTested" : 0
db.test.find({a:5}).explain("executionStats")
{
[...],
"executionStats" : {
plan root
"executionSuccess" : true,
"nReturned" : 1,
"executionTimeMillis" : 0,
"totalKeysExamined" : 1,
"totalDocsExamined" : 1,
stage
"executionStages" : {
FETCH
"stage" : "FETCH",
"nReturned" : 1,
"executionTime stage
MillisEstimate" : 0,
IXSCAN
"works" : 2,
"advanced" : 1,
Index on {a:1}
"needTime" : 0,
[-∞, 5) [5, 10) [10, ∞)
"needFetch" : 0,
"saveState" : 0,
"restoreState" : 0,
[-∞, 5) buckets [5, 7) [7, 9) [9, 10) [10, ∞) buckets
"isEOF" : 1,
"invalidates" : 0,
"docsExamined" : 1,
"alreadyHasObj" : 0,
{...} {...} {...} {...} {...} {...} {...} {...} {...}
"inputStage" : {
"stage" : "IXSCAN",
Explain() method key metrics
{
[...],
"executionStats" : {
"executionSuccess" : true,
"nReturned" : 1,
"executionTimeMillis" : 0,
"totalKeysExamined" : 1,
"totalDocsExamined" : 1,
"executionStages" : {
"stage" : "FETCH",
"nReturned" : 1,
"executionTime
MillisEstimate" : 0,
"works" : 2,
"advanced" : 1,
Index on {a:1}
"needTime" : 0,
[-∞, 5) [5, 10) [10, ∞)
"needFetch" : 0,
"saveState" : 0,
"restoreState" : 0,
[-∞, 5) buckets [5, 7) [7, 9) [9, 10) [10, ∞) buckets
"isEOF" : 1,
"invalidates" : 0,
"docsExamined" : 1,
"alreadyHasObj" : 0,
{...} {...} {...} {...} {...} {...} {...} {...} {...}
"inputStage" : {
"stage" : "IXSCAN",
Explain() method key metrics
{
[...],
"executionStats" : {
"executionSuccess" : true,
# documents returned
"nReturned" : 1
"nReturned" : 1,
"executionTimeMillis" : 0,
"executionTimeMillis" : 0
"totalKeysExamined" : 1,
"totalKeysExamined" : 1
How long did the query take
"totalDocsExamined" : 1,
"totalDocsExamined" : 1
# index entries scanned
"executionStages" : {
"stage" : "FETCH",
# documents scanned
"nReturned" : 1,
"executionTime
MillisEstimate" : 0,
"works" : 2,
"advanced" : 1,
Index on {a:1}
"needTime" : 0,
[-∞, 5) [5, 10) [10, ∞)
"needFetch" : 0,
"saveState" : 0,
"restoreState" : 0,
[-∞, 5) buckets [5, 7) [7, 9) [9, 10) [10, ∞) buckets
"isEOF" : 1,
"invalidates" : 0,
"docsExamined" : 1,
"alreadyHasObj" : 0,
{...} {...} {...} {...} {...} {...} {...} {...} {...}
"inputStage" : {
"stage" : "IXSCAN",
"docsExamined" : 1,
"seenInvalidated" : 0,
"matchTested" : 0
}
Performance Tuning
with Indexes
Sample Data
zips.json
db.zips.find() 29353 documents
{ "zip" : "01001", "city" : "AGAWAM", "loc" : [ -72.622739, 42.070206 ], "pop" : 15338, "state" : "MA" }
{ "zip" : "01002", "city" : "CUSHMAN", "loc" : [ -72.51564999999999, 42.377017 ], "pop" : 36963, "state" : "MA" }
{ "zip" : "01005", "city" : "BARRE", "loc" : [ -72.10835400000001, 42.409698 ], "pop" : 4546, "state" : "MA" }
{ "zip" : "01007", "city" : "BELCHERTOWN", "loc" : [ -72.41095300000001, 42.275103 ], "pop" : 10579, "state" : "MA" }
{ "zip" : "01008", "city" : "BLANDFORD", "loc" : [ -72.936114, 42.182949 ], "pop" : 1240, "state" : "MA" }
{ "zip" : "01010", "city" : "BRIMFIELD", "loc" : [ -72.188455, 42.116543 ], "pop" : 3706, "state" : "MA" }
{ "zip" : "01011", "city" : "CHESTER", "loc" : [ -72.988761, 42.279421 ], "pop" : 1688, "state" : "MA" }
{ "zip" : "01012", "city" : "CHESTERFIELD", "loc" : [ -72.833309, 42.38167 ], "pop" : 177, "state" : "MA" }
{ "zip" : "01013", "city" : "CHICOPEE", "loc" : [ -72.607962, 42.162046 ], "pop" : 23396, "state" : "MA" }
{ "zip" : "01020", "city" : "CHICOPEE", "loc" : [ -72.576142, 42.176443 ], "pop" : 31495, "state" : "MA" }
{ "zip" : "01022", "city" : "WESTOVER AFB", "loc" : [ -72.558657, 42.196672 ], "pop" : 1764, "state" : "MA" }
{ "zip" : "01026", "city" : "CUMMINGTON", "loc" : [ -72.905767, 42.435296 ], "pop" : 1484, "state" : "MA" }
{ "zip" : "01027", "city" : "MOUNT TOM", "loc" : [ -72.67992099999999, 42.264319 ], "pop" : 16864, "state" : "MA" }
{ "zip" : "01028", "city" : "EAST LONGMEADOW", "loc" : [ -72.505565, 42.067203 ], "pop" : 13367, "state" : "MA" }
{ "zip" : "01030", "city" : "FEEDING HILLS", "loc" : [ -72.675077, 42.07182 ], "pop" : 11985, "state" : "MA" }
{ "zip" : "01031", "city" : "GILBERTVILLE", "loc" : [ -72.19858499999999, 42.332194 ], "pop" : 2385, "state" : "MA" }
{ "zip" : "01032", "city" : "GOSHEN", "loc" : [ -72.844092, 42.466234 ], "pop" : 122, "state" : "MA" }
{ "zip" : "01033", "city" : "GRANBY", "loc" : [ -72.52000099999999, 42.255704 ], "pop" : 5526, "state" : "MA" }
{ "zip" : "01034", "city" : "TOLLAND", "loc" : [ -72.908793, 42.070234 ], "pop" : 1652, "state" : "MA" }
{ "zip" : "01035", "city" : "HADLEY", "loc" : [ -72.571499, 42.36062 ], "pop" : 4231, "state" : "MA" }
{ "zip" : "01036", "city" : "HAMPDEN", "loc" : [ -72.43182299999999, 42.064756 ], "pop" : 4709, "state" : "MA" }
{ "zip" : "01038", "city" : "HATFIELD", "loc" : [ -72.61673500000001, 42.38439 ], "pop" : 3184, "state" : "MA" }
{ "zip" : "01039", "city" : "HAYDENVILLE", "loc" : [ -72.70317799999999, 42.381799 ], "pop" : 1387, "state" : "MA" }
{ "zip" : "01040", "city" : "HOLYOKE", "loc" : [ -72.626193, 42.202007 ], "pop" : 43704, "state" : "MA" }
{ "zip" : "01050", "city" : "HUNTINGTON", "loc" : [ -72.873341, 42.265301 ], "pop" : 2084, "state" : "MA" }
{ "zip" : "01053", "city" : "LEEDS", "loc" : [ -72.70340299999999, 42.354292 ], "pop" : 1350, "state" : "MA" }
{ "zip" : "01054", "city" : "LEVERETT", "loc" : [ -72.499334, 42.46823 ], "pop" : 1748, "state" : "MA" }
{ "zip" : "01056", "city" : "LUDLOW", "loc" : [ -72.471012, 42.172823 ], "pop" : 18820, "state" : "MA" }
{ "zip" : "01057", "city" : "MONSON", "loc" : [ -72.31963399999999, 42.101017 ], "pop" : 8194, "state" : "MA" }
{ "zip" : "01060", "city" : "FLORENCE", "loc" : [ -72.654245, 42.324662 ], "pop" : 27939, "state" : "MA" }
{ "zip" : "01068", "city" : "OAKHAM", "loc" : [ -72.051265, 42.348033 ], "pop" : 1503, "state" : "MA" }
{ "zip" : "01069", "city" : "PALMER", "loc" : [ -72.328785, 42.176233 ], "pop" : 9778, "state" : "MA" }
{ "zip" : "01070", "city" : "PLAINFIELD", "loc" : [ -72.918289, 42.514393 ], "pop" : 571, "state" : "MA" }
{ "zip" : "01071", "city" : "RUSSELL", "loc" : [ -72.840343, 42.147063 ], "pop" : 608, "state" : "MA" }
{ "zip" : "01072", "city" : "SHUTESBURY", "loc" : [ -72.421342, 42.481968 ], "pop" : 1533, "state" : "MA" }
{ "zip" : "01073", "city" : "SOUTHAMPTON", "loc" : [ -72.719381, 42.224697 ], "pop" : 4478, "state" : "MA" }
{ "zip" : "01075", "city" : "SOUTH HADLEY", "loc" : [ -72.581137, 42.237537 ], "pop" : 16699, "state" : "MA" }
{ "zip" : "01256", "city" : "SAVOY", "loc" : [ -73.023281, 42.576964 ], "pop" : 632, "state" : "MA" }
{ "zip" : "01257", "city" : "SHEFFIELD", "loc" : [ -73.361091, 42.100102 ], "pop" : 1839, "state" : "MA" }
{ "zip" : "01258", "city" : "SOUTH EGREMONT", "loc" : [ -73.456575, 42.101153 ], "pop" : 135, "state" : "MA" }
{ "zip" : "01259", "city" : "SOUTHFIELD", "loc" : [ -73.26093299999999, 42.078014 ], "pop" : 622, "state" : "MA" }
{ "zip" : "01262", "city" : "STOCKBRIDGE", "loc" : [ -73.32226300000001, 42.30104 ], "pop" : 2200, "state" : "MA" }
{ "zip" : "01266", "city" : "WEST STOCKBRIDGE", "loc" : [ -73.38251, 42.334752 ], "pop" : 1173, "state" : "MA" }
{ "zip" : "01267", "city" : "WILLIAMSTOWN", "loc" : [ -73.20363999999999, 42.708883 ], "pop" : 8220, "state" : "MA" }
{ "zip" : "01270", "city" : "WINDSOR", "loc" : [ -73.04661, 42.509494 ], "pop" : 770, "state" : "MA" }
{ "zip" : "01301", "city" : "LEYDEN", "loc" : [ -72.60184700000001, 42.601222 ], "pop" : 18968, "state" : "MA" }
{ "zip" : "01330", "city" : "ASHFIELD", "loc" : [ -72.810998, 42.523207 ], "pop" : 1535, "state" : "MA" }
{ "zip" : "01331", "city" : "NEW SALEM", "loc" : [ -72.21464400000001, 42.592065 ], "pop" : 14077, "state" : "MA" }
{ "zip" : "01337", "city" : "LEYDEN", "loc" : [ -72.563439, 42.683784 ], "pop" : 2426, "state" : "MA" }
Question
Zip codes in New York City with population more than
100,000 ordered by population in descending order
db.zips.find({state:'NY',city:'NEW YORK',pop:{'$gt':100000}})
.sort({pop:-1})
db.zips.find({state:'NY',city:'NEW YORK',pop:{'$gt':100000}})
.sort({pop:-1}).explain("executionStats")
{
"queryPlanner" : {
"winningPlan" : {
"stage" : "SORT", plan root
"sortPattern" : {
"pop" : -1
},
"inputStage" : {
"stage" : "COLLSCAN",
"filter" : {
"$and" : [
{
"city" : {
"$eq" : "NEW YORK"
}
},
{
"state" : {
"$eq" : "NY"
}
Query Plan and Execution Statistics
db.zips.find({state:'NY',city:'NEW YORK',pop:{'$gt':100000}})
.sort({pop:-1}).explain("executionStats")
{
"queryPlanner" : {
"winningPlan" : {
"stage" : "SORT", plan root
"sortPattern" : {
"pop" : -1
},
"inputStage" : { SORT
"stage" : "COLLSCAN",
"filter" : {
"$and" : [
{
"city" : {
"$eq" : "NEW YORK"
}
},
{
"state" : {
"$eq" : "NY"
}
Query Plan and Execution Statistics
Collection Scan!
db.zips.find({state:'NY',city:'NEW YORK',pop:{'$gt':100000}})
.sort({pop:-1}).explain("executionStats")
{
"queryPlanner" : {
"winningPlan" : {
"stage" : "SORT", plan root
"sortPattern" : {
"pop" : -1
},
"inputStage" : { SORT
"stage" : "COLLSCAN",
"filter" : {
"$and" : [
{
"city" : { COLLSCAN {...} {...} {...} {...} {...} {...} {...} {...} {...}
"needFetch" : 0,
"saveState" : 229,
"restoreState" : 229,
"isEOF" : 1,
"invalidates" : 0,
"sortPattern" : {
"pop" : -1
Single Field Index
db.zips.createIndex({state:1})
db.zips.find({state:'NY',city:'NEW YORK',pop:{'$gt':100000}})
.sort({pop:-1}).explain("executionStats")
{
"queryPlanner": {
"winningPlan": {
"stage": "SORT", plan root
"sortPattern": {
"pop": -1
},
"inputStage": { SORT
"stage": "FETCH",
"filter": {
"$and": [
{
"city": {
"$eq": "NEW YORK"
}
},
{
"pop": {
"$gt": 100000
}
Single Field Index
db.zips.createIndex({state:1})
db.zips.find({state:'NY',city:'NEW YORK',pop:{'$gt':100000}})
.sort({pop:-1}).explain("executionStats")
{
"queryPlanner": {
"winningPlan": {
"stage": "SORT", plan root
"sortPattern": {
"pop": -1
},
"inputStage": { SORT
"stage": "FETCH",
"filter": {
"$and": [
{
"city": { FETCH
"$eq": "NEW YORK"
}
},
{
"pop": {
"$gt": 100000
}
"pop": -1
},
"state": [
"[\"NY\", \"NY\"]"
]
} IXSCAN
}
}
},
},
"indexName": "state_1",
"isMultiKey": false,
Single Field Index
"direction": "forward",
"indexBounds": {
"state": [
"[\"NY\", \"NY\"]"
db.zips.createIndex({state:1})
]
}
}
}
db.zips.find({state:'NY',city:'NEW YORK',pop:{'$gt':100000}})
},
"rejectedPlans": []
.sort({pop:-1}).explain("executionStats")
},
"executionStats": {
"executionSuccess": true,
"nReturned": 2,
"executionTimeMillis": 6, plan root 2 documents returned
"totalKeysExamined": 1595,
"totalDocsExamined": 1595,
"executionStages": {
"stage": "SORT", SORT In-Memory Sort!
"nReturned": 2,
"executionTimeMillisEstimate": 0,
"works": 1600, 1595 documents scanned
"advanced": 2,
"needTime": 1596, FETCH {...} {...} {...} {...} {...} {...} {...} {...} {...}
"needFetch": 0,
"saveState": 12, 1595 index entries scanned
"restoreState": 12,
"isEOF": 1, IXSCAN
"invalidates": 0,
"sortPattern": {
"pop": -1
Compound Index on two fields
db.zips.createIndex({state:1, city:1})
db.zips.find({state:'NY',city:'NEW YORK',pop:{'$gt':100000}})
.sort({pop:-1}).explain("executionStats")
{
"queryPlanner": {
"winningPlan": {
"stage": "SORT",
plan root
"sortPattern": {
"pop": -1
},
"inputStage": {
SORT
"stage": "FETCH",
"filter": {
"pop": {
"$gt": 100000
}
FETCH {...} {...} {...} {...} {...} {...} {...} {...} {...}
},
"inputStage": {
"stage": "IXSCAN",
"keyPattern": {
IXSCAN
"state": 1,
"city": 1
},
{
"queryPlanner": {
"winningPlan": {
Compound Index on two fields
"stage": "SORT",
"sortPattern": {
"pop": -1
},
db.zips.createIndex({state:1, city:1})
"inputStage": {
"stage": "FETCH",
"filter": {
"pop": {
db.zips.find({state:'NY',city:'NEW YORK',pop:{'$gt':100000}})
"$gt": 100000
}
.sort({pop:-1}).explain("executionStats")
},
"inputStage": {
"stage": "IXSCAN",
"keyPattern": {
"state": 1,
plan root
"city": 1
},
"indexName": "state_1_city_1",
"isMultiKey": false,
SORT
"direction": "forward",
"indexBounds": {
"state": [
"[\"NY\", \"NY\"]"
],
FETCH {...} {...} {...} {...} {...} {...} {...} {...} {...}
"city": [
"[\"NEW YORK\", \"NEW YORK
\"]"
]
IXSCAN
}
}
}
"direction": "forward",
"indexBounds": {
"state": [
Compound Index on two fields
"[\"NY\", \"NY\"]"
],
"city": [
"[\"NEW YORK\", \"NEW YORK
db.zips.createIndex({state:1, city:1})
\"]"
]
}
}
db.zips.find({state:'NY',city:'NEW YORK',pop:{'$gt':100000}})
}
}
.sort({pop:-1}).explain("executionStats")
},
"executionStats": {
"executionSuccess": true,
"nReturned": 2,
"executionTimeMillis": 4,
plan root 2 documents returned
"totalKeysExamined": 40,
"totalDocsExamined": 40,
"executionStages": {
"stage": "SORT",
SORT In-Memory Sort!
"nReturned": 2,
"executionTimeMillisEstimate": 4,
"works": 45,
40 documents scanned
"advanced": 2,
"needTime": 41,
FETCH {...} {...} {...} {...} {...} {...} {...} {...} {...}
"needFetch": 0,
"saveState": 0,
40 index entries scanned
"restoreState": 0,
"isEOF": 1,
IXSCAN
"invalidates": 0,
"sortPattern": {
"pop": -1
Compound Index on three fields
db.zips.createIndex({state:1,city:1,pop:1})
db.zips.find({state:'NY',city:'NEW YORK',pop:{'$gt':100000}})
.sort({pop:-1}).explain("executionStats")
{
"queryPlanner": {
"winningPlan": {
"stage": "FETCH",
plan root
"inputStage": {
"stage": "IXSCAN",
"keyPattern": {
"state": 1,
"city": 1,
"pop": 1
FETCH {...} {...} {...} {...} {...} {...} {...} {...} {...}
},
"indexName": "state_1_city_1_pop_1",
"isMultiKey": false,
"direction": "backward",
"indexBounds": {
IXSCAN
"state": [
"[\"NY\", \"NY\"]"
],
"city": [
"[\"NEW YORK\", \"NEW YORK\"]"
"indexBounds": {
"state": [
"[\"NY\", \"NY\"]"
Compound Index on three fields
],
"city": [
"[\"NEW YORK\", \"NEW YORK\"]"
],
db.zips.createIndex({state:1,city:1,pop:1})
"pop": [
"[inf.0, 100000.0)"
]
}
db.zips.find({state:'NY',city:'NEW YORK',pop:{'$gt':100000}})
}
}
.sort({pop:-1}).explain("executionStats")
},
"executionStats": {
"executionSuccess": true,
"nReturned": 2,
"executionTimeMillis": 2,
plan root 2 documents returned
"totalKeysExamined": 2,
"totalDocsExamined": 2,
"executionStages": {
"stage": "FETCH",
2 documents scanned
"nReturned": 2,
"executionTimeMillisEstimate": 1,
FETCH {...} {...} {...} {...} {...} {...} {...} {...} {...}
"works": 3,
"advanced": 2,
2 index entries scanned
"needTime": 0,
"needFetch": 0,
"saveState": 0,
"restoreState": 0,
IXSCAN
"isEOF": 1,
Index used for Sorting!
"invalidates": 0,
"docsExamined": 2,
"alreadyHasObj": 0,
Projection on Index-only Data
db.zips.createIndex({state:1,city:1,pop:1})
db.zips.find({state:'NY',city:'NEW YORK',pop:{'$gt':100000}})
.sort({pop:-1})
{"zip" : "10021", "city" : "NEW YORK", "pop" : 106564, "state" : "NY" }
{"zip" : "10025", "city" : "NEW YORK", "pop" : 100027, "state" : "NY" }
Projection on Index-only Data
db.zips.createIndex({state:1,city:1,pop:1})
db.zips.find({state:'NY',city:'NEW YORK',pop:{'$gt':100000}})
.sort({pop:-1})
Projection on Index-only Data
db.zips.createIndex({state:1,city:1,pop:1})
db.zips.find({state:'NY',city:'NEW YORK’,pop:{‘$gt':100000}},
{state:1, city:1, pop:1})
.sort({pop:-1})
db.zips.find({state:'NY',city:'NEW YORK’,pop:{‘$gt':100000}},
{state:1, city:1, pop:1})
.sort({pop:-1}).explain("executionStats")
{
"queryPlanner": {
"winningPlan": { plan root
"stage": "PROJECTION",
"transformBy": {
"state": 1,
"city": 1,
"pop": 1,
"zip": 0 PROJECTION
},
"inputStage": {
"stage": "IXSCAN",
"keyPattern": {
"state": 1,
"city": 1, IXSCAN
"pop": 1
},
"indexName": "state_1_city_1_pop_1",
"isMultiKey": false,
"direction": "backward",
"indexBounds": {
Projection on Index-only Data
"state": [
"[\"NY\", \"NY\"]"
],
"city": [
db.zips.createIndex({state:1,city:1,pop:1})
"[\"NEW YORK\", \"NEW YORK\"]"
],
"pop": [
"[inf.0, 100000.0)"
db.zips.find({state:'NY',city:'NEW YORK’,pop:{‘$gt':100000}},
]
}
{state:1, city:1, pop:1})
}
}
.sort({pop:-1}).explain("executionStats")
},
"executionStats": {
"executionSuccess": true,
"nReturned": 2,
"executionTimeMillis": 0, plan root 2 documents returned
"totalKeysExamined": 2,
"totalDocsExamined": 0,
"executionStages": {
"stage": "PROJECTION", 0 documents scanned
"nReturned": 2, PROJECTION "Covered Query "
"executionTimeMillisEstimate": 0,
"works": 3,
"advanced": 2,
"needTime": 0, 2 index entries scanned
"needFetch": 0,
"saveState": 0, IXSCAN
"restoreState": 0,
"isEOF": 1,
"invalidates": 0,
Negation
db.zips.createIndex({state:1,city:1,pop:1})
db.zips.find({state:{$ne:’NY'},city:'NEW YORK’,pop:{'$gt':100000}})
.sort({pop:-1})
db.zips.find({state:{$ne:’NY'},
city:{$ne:'NEW YORK’},
pop:{$not:{‘$gt':100000}}})
.sort({pop:-1}).explain("executionStats")
{
"executionStats" : { plan root 27757 documents returned
"executionSuccess" : true,
"nReturned" : 27757,
"executionTimeMillis" : 156, In-Memory Sort!
"totalKeysExamined" : 27759, SORT
"totalDocsExamined" : 27757,
"executionStages" : { 27759 documents scanned
"stage" : "SORT", {...} {...} {...} {...} {...} {...} {...} {...} {...}
"nReturned" : 27757, FETCH
"executionTimeMillisEstimate" : 110,
"works" : 55519, 27757 index entries scanned
"advanced" : 27757,
"needTime" : 27760, IXSCAN
"needFetch" : 0,
"saveState" : 433,
"alreadyHasObj" : 0,
Negation
"inputStage" : {
"stage" : "IXSCAN",
"nReturned" : 27757,
"executionTimeMillisEstimate" : 40,
db.zips.createIndex({state:1,city:1,pop:1})
"works" : 27759,
"advanced" : 27757,
db.zips.find({state:{$ne:’NY'},city:'NEW YORK’,pop:{'$gt':100000}})
"needTime" : 2,
"needFetch" : 0,
.sort({pop:-1})
"saveState" : 433,
"restoreState" : 433,
"isEOF" : 1,
db.zips.find({state:{$ne:’NY'},
"invalidates" : 0,
city:{$ne:'NEW YORK’},
"keyPattern" : {
"state" : 1,
pop:{$not:{‘$gt':100000}}})
"city" : 1,
"pop" : 1
.sort({pop:-1}).explain("executionStats")
},
"indexName" : "state_1_city_1_pop_1",
"isMultiKey" : false,
"direction" : "forward", plan root 27757 documents returned
"indexBounds" : {
"state" : [
"[MinKey, \"NY\")", In-Memory Sort!
"(\"NY\", MaxKey]" SORT
], 27759 documents scanned
"city" : [
{...} {...} {...} {...} {...} {...} {...} {...} {...}
"[MinKey, \"NEW YORK\")",
"(\"NEW YORK\", MaxKey]"
FETCH
], 27757 index entries scanned
"pop" : [
"[MinKey, 100000.0]", IXSCAN
"(inf.0, MaxKey]"
]
Memory Contention
Main Memory (RAM)
⚙
mongod process
Memory Contention
Main Memory (RAM)
⚙
mongod process
Memory Contention
Main Memory (RAM)
⚙
mongod process
Memory Contention
Main Memory (RAM)
⚙
mongod process
Memory Contention
Main Memory (RAM)
⚙
mongod process
Reduce Memory Contention
Remove unneeded indexes
Main Memory (RAM)
db.zips.find({state:'NY',city:'NEW YORK’,pop:{'$gt':100000}})
.sort({pop:-1})
db.zips.dropIndex({state:1, city:1})
db.zips.dropIndex({state:1})
Reduce Memory Contention
Right-Balanced Index Access
The entire index must fit into RAM Amount of Index Data in RAM
is significantly reduced
Reduce Memory Contention
Index compression
#MDBDays
mongodb.com
MongoDB
Performance Measurement Tools
Log files, Profiler, Query Optimizer
mongod
• http://github.com/rueckstiess/mtools
• log file analysis for poorly performing queries
– Show me queries that took more than 1000 ms from 6
am to 6 pm:
$ mlogfilter mongodb.log --from 06:00 --to
18:00 --slow 1000 > mongodb-filtered.log
mtools graphs
% mplotqueries --type histogram --group namespace --bucketSize 3600
Database Profiler
• iostat
• dstat
• mongostat
• mongotop
• mongoperf
Cloud Manager
• Memory usage
• Opcounters
• Lock percentage
• Queues
• Background flush average
• Replication oplog window and lag