Tips and Tricks
for Avoiding
Common Query Pitfalls
Christian Kurze
CHRISTIAN KURZE
Senior Solutions Architect
MongoDB
Roadmap
• Motivation
• Three items to be aware of:
• Blocking stages
• Using the $or operator
• Case insensitivity
The Power of Query Optimization
• Query tuning results in:
• Improved performance
• Reduced resource utilization
• This may lead to:
• Improved stability and
predictability
• A smaller hardware footprint
Not uncommon to observe
efficiency improvements greater than 99%
The Challenge @ Acme Games, Inc.
Charlie
• DBA at Acme Game, Inc.
• MongoDB Champion
Stakeholders
• Developers
• Leadership
• RDBMS History
Acme Games Introduces…
The Peanuts
Brand new strategy game
Launching November 15th
Stakeholder Concerns
• Game nearly complete
• Developers have learned a lot from Charlie
Stakeholder Concerns
• Game nearly complete
• Developers have learned a lot from Charlie
Indexes support the efficient
execution of queries in MongoDB
Stakeholder Concerns
• Game nearly complete
• Developers have learned a lot from Charlie
Indexes support the efficient
execution of queries in MongoDB
Stakeholder Concerns
• Game nearly complete
• Developers have learned a lot from Charlie
Indexes support the efficient
execution of queries in MongoDB
Ace Bob Sue
… …
Stakeholder Concerns
• Game nearly complete
• Developers have learned a lot from Charlie
• App being stress tested
Stakeholder Concerns
• Game nearly complete
• Developers have learned a lot from Charlie
• App being stress tested
• Concerned over current performance
Stakeholder Concern #1
Developers created index
db.games.createIndex({ gamerTag: 1 })
Stakeholder Concern #1
Developers created index
db.games.createIndex({ gamerTag: 1 })
This query takes several seconds to execute:
db.games.find( { gamerTag: "Ace" } ).sort({score:-1})
Stakeholder Concern #1
Developers created index
db.games.createIndex({ gamerTag: 1 })
This query takes several seconds to execute:
db.games.find( { gamerTag: "Ace" } ).sort({score:-1})
Adding the index on score does not help!
db.games.createIndex({ score: -1 })
Stakeholder Concern #1
Developers created index
db.games.createIndex({ gamerTag: 1 })
This query takes several seconds to execute:
db.games.find( { gamerTag: "Ace" } ).sort({score:-1})
Adding the index on score does not help!
db.games.createIndex({ score: -1 })
“Clearly MongoDB
is not web-scale!”
Blocking Operations
Blocking Operations
● Formally:
■ “An operation which must process all input before it can
begin to produce any output.”
● Opposite of the often desirable “fully pipelined” plan which can
stream results back as soon as they are found.
● Commonly observed when a sort is added to a query
Sorting with blocking
Sorting with blocking
Sorting with blocking
Sorting with blocking
Sorting with blocking
Sorting with blocking
Sorting with blocking
Sorting with blocking
Sorting with blocking
Sorting with blocking
Sorting with blocking
Sorting with blocking
Sorting with blocking
Sorting with blocking
Sorting with blocking
Sorting with blocking
Sorting with blocking
Sorting with blocking
Sorting with blocking
Sorting with blocking
Sorting with blocking
Sorting with blocking
Sorting with blocking
Sorting with blocking
Sorting without blocking
Sorting without blocking
Sorting without blocking
Sorting without blocking
Blocking Stages
• $sort
• In aggregation and find
• $group
• $bucket
• $count
• $facet
Are there any other blocking
operations?
Working with blocking stages
For sorting:
• Add a supporting index
• Worth the overhead in almost all circumstances
For other stages:
• Do you need the blocking stage?
• Offload to secondary member
Stakeholder Concern #1
Performance of
db.games.find( { gamerTag: "Ace" } ).sort({score:-1})
“Clearly MongoDB
is not web-scale!”
Stakeholder Concern #1
Performance of
db.games.find( { gamerTag: "Ace" } ).sort({score:-1})
db.games.createIndex({ gamerTag: 1, score:-1 })
Stakeholder Concern #1
Performance of
db.games.find( { gamerTag: "Ace" } ).sort({score:-1})
db.games.createIndex({ gamerTag: 1, score:-1 })
"That’ll work great!”
Stakeholder Concern #2
The $and version of a query
returns quickly:
db.games.find({
$and : [
{ gamerTag: "Ace" },
{ score: {$gt: 9000} }
]
})
Stakeholder Concern #2
The $and version of a query
returns quickly:
db.games.find({
$and : [
{ gamerTag: "Ace" },
{ score: {$gt: 9000} }
]
})
But the $or version is slow:
db.games.find({
$or : [
{ gamerTag: "Ace" },
{ score: {$gt: 9000} }
]
})
Stakeholder Concern #2
The $and version of a query
returns quickly:
db.games.find({
$and : [
{ gamerTag: "Ace" },
{ score: {$gt: 9000} }
]
})
But the $or version is slow:
db.games.find({
$or : [
{ gamerTag: "Ace" },
{ score: {$gt: 9000} }
]
})
We just created an index with both
those fields… Can’t it be used?
$or
$and example
Query on games:
db.games.find({
$and : [
{ gamerTag: "Ace" },
{ score: {$gt: 9000} }
]
})
Matching games:
{ gamerTag: "Ace", score: 9500 }
Non-matching games:
{ gamerTag: "Ace", score: 500 },
{ gamerTag: "Bob", score: 9500 },
{ gamerTag: "Bob", score: 500 }
Groups of documents
{ gamerTag: "Ace",
score: 9500 }
{ gamerTag: "Ace",
score: 500 }
{ gamerTag: "Bob",
score: 9500 }
{ gamerTag: "Bob",
score: 500 }
Groups of documents
{ gamerTag: "Ace",
score: 9500 }
{ gamerTag: "Ace",
score: 500 }
{ gamerTag: "Bob",
score: 9500 }
{ gamerTag: "Bob",
score: 500 }
gamerTag: "Ace"
Groups of documents
{ gamerTag: "Ace",
score: 9500 }
{ gamerTag: "Ace",
score: 500 }
{ gamerTag: "Bob",
score: 9500 }
{ gamerTag: "Bob",
score: 500 }
gamerTag: "Ace" score: {$gt: 9000}
$and Venn Diagram (logical)
{ gamerTag: "Ace",
score: 9500 }
{ gamerTag: "Ace",
score: 500 }
{ gamerTag: "Bob",
score: 9500 }
{ gamerTag: "Bob",
score: 500 }
db.games.find({
$and : [
{ gamerTag: "Ace" },
{ score: {$gt: 9000} }
]
})gamerTag: "Ace" score: {$gt: 9000}
$and Venn Diagram (logical)
{ gamerTag: "Ace",
score: 9500 }
{ gamerTag: "Ace",
score: 500 }
{ gamerTag: "Bob",
score: 9500 }
{ gamerTag: "Bob",
score: 500 }
db.games.find({
$and : [
{ gamerTag: "Ace" },
{ score: {$gt: 9000} }
]
})gamerTag: "Ace" score: {$gt: 9000}
$and Venn Diagram (logical)
db.games.find({
$and : [
{ gamerTag: "Ace" },
{ score: {$gt: 9000} }
]
})gamerTag: "Ace" score: {$gt: 9000}
$and Venn Diagram (logical)
db.games.find({
$and : [
{ gamerTag: "Ace" },
{ score: {$gt: 9000} }
]
})gamerTag: "Ace" score: {$gt: 9000}
$and Venn Diagram (logical)
db.games.find({
$and : [
{ gamerTag: "Ace" },
{ score: {$gt: 9000} }
]
})gamerTag: "Ace" score: {$gt: 9000}
$and Venn Diagram (logical)
db.games.find({
$and : [
{ gamerTag: "Ace" },
{ score: {$gt: 9000} }
]
})gamerTag: "Ace" score: {$gt: 9000}
$and Venn Diagram (logical)
db.games.find({
$and : [
{ gamerTag: "Ace" },
{ score: {$gt: 9000} }
]
})gamerTag: "Ace" score: {$gt: 9000}
$and Venn Diagram (logical)
db.games.find({
$and : [
{ gamerTag: "Ace" },
{ score: {$gt: 9000} }
]
})
Ace Bob
500
950
0 500
950
0
{gamerTag:1
, score:-1}
$and Venn Diagram (logical)
db.games.find({
$and : [
{ gamerTag: "Ace" },
{ score: {$gt: 9000} }
]
})
Ace Bob
500
950
0 500
950
0
"indexBounds" : {
"gamerTag" : [
"["Ace", "Ace"]"
],
"score" : [
"[inf.0, 9000.0)"
]
}
{gamerTag:1
, score:-1}
$and Venn Diagram (logical)
db.games.find({
$and : [
{ gamerTag: "Ace" },
{ score: {$gt: 9000} }
]
})
Ace Bob
500
950
0 500
950
0
"indexBounds" : {
"gamerTag" : [
"["Ace", "Ace"]"
],
"score" : [
"[inf.0, 9000.0)"
]
}
{gamerTag:1
, score:-1}
$and Venn Diagram (logical)
db.games.find({
$and : [
{ gamerTag: "Ace" },
{ score: {$gt: 9000} }
]
})
Ace Bob
500
950
0 500
950
0
"indexBounds" : {
"gamerTag" : [
"["Ace", "Ace"]"
],
"score" : [
"[inf.0, 9000.0)"
]
}
{gamerTag:1
, score:-1}
$and Venn Diagram (logical)
db.games.find({
$and : [
{ gamerTag: "Ace" },
{ score: {$gt: 9000} }
]
})
Ace Bob
500
950
0 500
950
0
"indexBounds" : {
"gamerTag" : [
"["Ace", "Ace"]"
],
"score" : [
"[inf.0, 9000.0)"
]
}
{gamerTag:1
, score:-1}
$or example
Query on games:
db.games.find({
$or : [
{ gamerTag: "Ace" },
{ score: {$gt: 9000} }
]
})
Matching games:
{ gamerTag: "Ace", score: 9500 },
{ gamerTag: "Ace", score: 500 },
{ gamerTag: "Bob", score: 9500 }
Non-matching games:
{ gamerTag: "Bob", score: 500 }
$or Venn Diagram (logical)
{ gamerTag: "Ace",
score: 9500 }
{ gamerTag: "Ace",
score: 500 }
{ gamerTag: "Bob",
score: 9500 }
{ gamerTag: "Bob",
score: 500 }
db.games.find({
$or : [
{ gamerTag: "Ace" },
{ score: {$gt: 9000} }
]
})gamerTag: "Ace" score: {$gt: 9000}
$or Venn Diagram (logical)
{ gamerTag: "Ace",
score: 9500 }
{ gamerTag: "Ace",
score: 500 }
{ gamerTag: "Bob",
score: 9500 }
{ gamerTag: "Bob",
score: 500 }
db.games.find({
$or : [
{ gamerTag: "Ace" },
{ score: {$gt: 9000} }
]
})gamerTag: "Ace" score: {$gt: 9000}
$or Venn Diagram (logical)
{ gamerTag: "Ace",
score: 9500 }
{ gamerTag: "Ace",
score: 500 }
{ gamerTag: "Bob",
score: 9500 }
{ gamerTag: "Bob",
score: 500 }
db.games.find({
$or : [
{ gamerTag: "Ace" },
{ score: {$gt: 9000} }
]
})gamerTag: "Ace" score: {$gt: 9000}
$or Venn Diagram (logical)
{ gamerTag: "Ace",
score: 9500 }
{ gamerTag: "Ace",
score: 500 }
{ gamerTag: "Bob",
score: 9500 }
{ gamerTag: "Bob",
score: 500 }
db.games.find({
$or : [
{ gamerTag: "Ace" },
{ score: {$gt: 9000} }
]
})gamerTag: "Ace" score: {$gt: 9000}
$or Venn Diagram (logical)
{ gamerTag: "Ace",
score: 9500 }
{ gamerTag: "Ace",
score: 500 }
{ gamerTag: "Bob",
score: 9500 }
{ gamerTag: "Bob",
score: 500 }
db.games.find({
$or : [
{ gamerTag: "Ace" },
{ score: {$gt: 9000} }
]
})gamerTag: "Ace" score: {$gt: 9000}
$or Venn Diagram (logical)
db.games.find({
$or : [
{ gamerTag: "Ace" },
{ score: {$gt: 9000} }
]
})gamerTag: "Ace" score: {$gt: 9000}
$or Venn Diagram (logical)
db.games.find({
$or : [
{ gamerTag: "Ace" },
{ score: {$gt: 9000} }
]
})gamerTag: "Ace" score: {$gt: 9000}
$or Venn Diagram (logical)
db.games.find({
$or : [
{ gamerTag: "Ace" },
{ score: {$gt: 9000} }
]
})gamerTag: "Ace" score: {$gt: 9000}
$or Venn Diagram (logical)
db.games.find({
$or : [
{ gamerTag: "Ace" },
{ score: {$gt: 9000} }
]
})gamerTag: "Ace" score: {$gt: 9000}
$or Venn Diagram (logical)
db.games.find({
$or : [
{ gamerTag: "Ace" },
{ score: {$gt: 9000} }
]
})gamerTag: "Ace" score: {$gt: 9000}
$or (single) Index visualization
Ace Bob
{gamerTag:1
, score:-1}
500
950
0 500
950
0
db.games.find({
$or : [
{ gamerTag: "Ace" },
{ score: {$gt: 9000} }
]
})
$or (single) Index visualization
Ace Bob
{gamerTag:1
, score:-1}
500
950
0 500
950
0
db.games.find({
$or : [
{ gamerTag: "Ace" },
{ score: {$gt: 9000} }
]
})
Expected Index Bounds:
"indexBounds" : {
"gamerTag" : [
"["Ace", "Ace"]"
],
"score" : [
"[inf.0, 9000)"
]
}
$or (single) Index visualization
Ace Bob
{gamerTag:1
, score:-1}
500
950
0 500
950
0
db.games.find({
$or : [
{ gamerTag: "Ace" },
{ score: {$gt: 9000} }
]
})
Expected Index Bounds:
"indexBounds" : {
"gamerTag" : [
"["Ace", "Ace"]"
],
"score" : [
"[inf.0, 9000)"
]
}
$or (single) Index visualization
Ace Bob
{gamerTag:1
, score:-1}
500
950
0 500
950
0
db.games.find({
$or : [
{ gamerTag: "Ace" },
{ score: {$gt: 9000} }
]
})
Expected Index Bounds:
"indexBounds" : {
"gamerTag" : [
"["Ace", "Ace"]"
],
"score" : [
"[inf.0, 9000)"
]
}
$or (single) Index visualization
Ace Bob
{gamerTag:1
, score:-1}
500
950
0 500
950
0
db.games.find({
$or : [
{ gamerTag: "Ace" },
{ score: {$gt: 9000} }
]
})
Expected Index Bounds:
"indexBounds" : {
"gamerTag" : [
"["Ace", "Ace"]"
],
"score" : [
"[inf.0, 9000)"
]
}
$or (single) Index visualization
Ace Bob
{gamerTag:1
, score:-1}
500
950
0 500
950
0
db.games.find({
$or : [
{ gamerTag: "Ace" },
{ score: {$gt: 9000} }
]
})
Expected Index Bounds:
"indexBounds" : {
"gamerTag" : [
"["Ace", "Ace"]"
],
"score" : [
"[inf.0, 9000)"
]
}
$or (single) Index visualization
Ace Bob
{gamerTag:1
, score:-1}
500
950
0 500
950
0
db.games.find({
$or : [
{ gamerTag: "Ace" },
{ score: {$gt: 9000} }
]
})
Expected Index Bounds:
"indexBounds" : {
"gamerTag" : [
"["Ace", "Ace"]"
],
"score" : [
"[inf.0, 9000)"
]
}
$or (single) Index visualization
Ace Bob
{gamerTag:1
, score:-1}
500
950
0 500
950
0
db.games.find({
$or : [
{ gamerTag: "Ace" },
{ score: {$gt: 9000} }
]
})
Expected Index Bounds:
"indexBounds" : {
"gamerTag" : [
"["Ace", "Ace"]"
],
"score" : [
"[inf.0, 9000)"
]
}
Actual (Hinted) Index Bounds:
"indexBounds" : {
"gamerTag" : [
"[MinKey, MaxKey]"
],
"score" : [
"[MaxKey, MinKey]"
]
}
$or (single) Index visualization
Ace Bob
{gamerTag:1
, score:-1}
500
950
0 500
950
0
db.games.find({
$or : [
{ gamerTag: "Ace" },
{ score: {$gt: 9000} }
]
})
Expected Index Bounds:
"indexBounds" : {
"gamerTag" : [
"["Ace", "Ace"]"
],
"score" : [
"[inf.0, 9000)"
]
}
Actual (Hinted) Index Bounds:
"indexBounds" : {
"gamerTag" : [
"[MinKey, MaxKey]"
],
"score" : [
"[MaxKey, MinKey]"
]
}
So is there anything we can do to
improve the performance of this
query?
Recommendations
Use multiple indexes!
db.data.createIndex({gamerTag: 1})
db.data.createIndex({score: 1})
$or (multiple) Index visualization
db.games.find({
$or : [
{ gamerTag: "Ace" },
{ score: {$gt: 9000} }
]
})
$or (multiple) Index visualization
Ace
db.games.find({
$or : [
{ gamerTag: "Ace" },
{ score: {$gt: 9000} }
]
})
$or (multiple) Index visualization
Ace Bob
db.games.find({
$or : [
{ gamerTag: "Ace" },
{ score: {$gt: 9000} }
]
})
$or (multiple) Index visualization
Ace Bob
{gamerTag:1}
db.games.find({
$or : [
{ gamerTag: "Ace" },
{ score: {$gt: 9000} }
]
})
$or (multiple) Index visualization
Ace Bob
{gamerTag:1}
500
db.games.find({
$or : [
{ gamerTag: "Ace" },
{ score: {$gt: 9000} }
]
})
$or (multiple) Index visualization
Ace Bob
{gamerTag:1}
500
950
0
db.games.find({
$or : [
{ gamerTag: "Ace" },
{ score: {$gt: 9000} }
]
})
$or (multiple) Index visualization
Ace Bob
{gamerTag:1}
500
950
0
{score:1}
db.games.find({
$or : [
{ gamerTag: "Ace" },
{ score: {$gt: 9000} }
]
})
$or (multiple) Index visualization
Ace Bob
{gamerTag:1}
500
950
0
{score:1}
"indexBounds" : {
"gamerTag" : [
"["Ace", "Ace"]"
]
}
"indexBounds" : {
"score" : [
"(9000.0, inf.0]"
]
}
db.games.find({
$or : [
{ gamerTag: "Ace" },
{ score: {$gt: 9000} }
]
})
$or (multiple) Index visualization
Ace Bob
{gamerTag:1}
500
950
0
{score:1}
db.games.find({
$or : [
{ gamerTag: "Ace" },
{ score: {$gt: 9000} }
]
})
"indexBounds" : {
"gamerTag" : [
"["Ace", "Ace"]"
]
}
"indexBounds" : {
"score" : [
"(9000.0, inf.0]"
]
}
$or (multiple) Index visualization
Ace Bob
{gamerTag:1}
500
950
0
{score:1}
db.games.find({
$or : [
{ gamerTag: "Ace" },
{ score: {$gt: 9000} }
]
})
"indexBounds" : {
"gamerTag" : [
"["Ace", "Ace"]"
]
}
"indexBounds" : {
"score" : [
"(9000.0, inf.0]"
]
}
$or (multiple) Index visualization
Ace Bob
{gamerTag:1}
500
950
0
{score:1}
db.games.find({
$or : [
{ gamerTag: "Ace" },
{ score: {$gt: 9000} }
]
})
"indexBounds" : {
"gamerTag" : [
"["Ace", "Ace"]"
]
}
"indexBounds" : {
"score" : [
"(9000.0, inf.0]"
]
}
$or (multiple) Index visualization
Ace Bob
{gamerTag:1}
500
950
0
{score:1}
db.games.find({
$or : [
{ gamerTag: "Ace" },
{ score: {$gt: 9000} }
]
})
"indexBounds" : {
"gamerTag" : [
"["Ace", "Ace"]"
]
}
"indexBounds" : {
"score" : [
"(9000.0, inf.0]"
]
}
$or (multiple) Index visualization
Ace Bob
{gamerTag:1}
500
950
0
{score:1}
db.games.find({
$or : [
{ gamerTag: "Ace" },
{ score: {$gt: 9000} }
]
})
"indexBounds" : {
"gamerTag" : [
"["Ace", "Ace"]"
]
}
"indexBounds" : {
"score" : [
"(9000.0, inf.0]"
]
}
Recommendations
Use multiple indexes!
db.data.createIndex({gamerTag: 1})
db.data.createIndex({score: 1})
Recommendations
Use multiple indexes!
db.data.createIndex({gamerTag: 1})
db.data.createIndex({score: 1})
We already have the {gamerTag:1, score:-1}
index, do we need both of these new ones?
Recommendations
Use multiple indexes!
db.data.createIndex({gamerTag: 1})
db.data.createIndex({gamerTag: 1, score: -1}}
db.data.createIndex({score: 1})
We already have the {gamerTag:1, score:-1}
index, do we need both of these new ones?
Recommendations
Use multiple indexes!
db.data.createIndex({gamerTag: 1})
db.data.createIndex({gamerTag: 1, score: -1}}
db.data.createIndex({score: 1})
Rule of thumb for compound indexes: equality, sort, range
Recommendations
Use multiple indexes!
db.data.createIndex({gamerTag: 1})
db.data.createIndex({gamerTag: 1, score: -1}}
db.data.createIndex({score: 1})
Rule of thumb for compound indexes: equality, sort, range
Works with sorting
Generate a SORT_MERGE plan
Stakeholder Concern #2
db.games.find({
$or : [ { gamerTag: "Ace" }, { score: {$gt: 9000} } ]
})
Having the right index is critical
Stakeholder Concern #2
db.games.find({
$or : [ { gamerTag: "Ace" }, { score: {$gt: 9000} } ]
})
Having the right index is critical
Stakeholder Concern #2
db.games.find({
$or : [ { gamerTag: "Ace" }, { score: {$gt: 9000} } ]
})
Having the right index is critical
"Super!!”
Stakeholder Concern #3
“Wait wait wait, we can’t even FIND the gamers!”
A basic search on gamerTag takes several seconds already:
db.games.find({gamerTag: /Ace/i})
“This query is SLOWER with the index than it is without it!”
Case Insensitive
Case Sensitive
db.games.find({
gamerTag: /^Ace$/
})
//equivalent to
db.games.find({
gamerTag: “Ace”
})
Matching games:
{ gamerTag: "Ace", score: 9500 },
Non-matching games:
{ gamerTag: "ACE", score: 500 },
{ gamerTag: "aCe", score: 9500 },
{ gamerTag: "ace", score: 0 },
{ gamerTag: "Bob", score: 500 },
{ gamerTag: "acxyz", score: 9500 },
{ gamerTag: "Ace mdb", score: 9500 }
Case Sensitive
ace aCe
acxy
z
Ace
Ace
mdb
ACE Bob
"indexBounds" : {
"gamerTag" : [
"["Ace", "Acf")",
"[/^Ace$/, /^Ace$/]"
]
}
Matching games:
{ gamerTag: "Ace", score: 9500 },
Non-matching games:
{ gamerTag: "ACE", score: 500 },
{ gamerTag: "aCe", score: 9500 },
{ gamerTag: "ace", score: 0 },
{ gamerTag: "Bob", score: 500 },
{ gamerTag: "acxyz", score: 9500 },
{ gamerTag: "Ace mdb", score: 9500 }
Case insensitive
db.games.find({
gamerTag: /^Ace$/i
})
//equivalent to
db.games.find({
gamerTag: {
$regex: “^Ace$”,
$options: “i”
}
})
//equivalent to
db.games.find({ gamerTag: “Ace”})
.collation({locale:’en’, strength:2})
Matching games:
{ gamerTag: "Ace", score: 9500 },
{ gamerTag: "ACE", score: 500 },
{ gamerTag: "aCe", score: 9500 },
{ gamerTag: "ace", score: 0 }
Non-matching games:
{ gamerTag: "Bob", score: 500 },
{ gamerTag: "acxyz", score: 9500 },
{ gamerTag: "Ace mdb", score: 9500 }
Case insensitive
db.games.find({
gamerTag: /^Ace$/i
})
//equivalent to
db.games.find({
gamerTag: {
$regex: “^Ace$”,
$options: “i”
}
})
//equivalent to
db.games.find({ gamerTag: “Ace”})
.collation({locale:’en’, strength:2})
Matching games:
{ gamerTag: "Ace", score: 9500 },
{ gamerTag: "ACE", score: 500 },
{ gamerTag: "aCe", score: 9500 },
{ gamerTag: "ace", score: 0 }
Non-matching games:
{ gamerTag: "Bob", score: 500 },
{ gamerTag: "acxyz", score: 9500 },
{ gamerTag: "Ace mdb", score: 9500 }
Would a $text search be the same as well?
Case INsensitive
ace aCe
acxy
z
Ace
Ace
mdb
ACE Bob
"indexBounds" : {
"gamerTag" : [
"["", {})",
"[/^Ace$/i, /^Ace$/i]"
]
}
Matching games:
{ gamerTag: "Ace", score: 9500 },
{ gamerTag: "ACE", score: 500 },
{ gamerTag: "aCe", score: 9500 },
{ gamerTag: "ace", score: 0 }
Non-matching games:
{ gamerTag: "Bob", score: 500 },
{ gamerTag: "acxyz", score: 9500 },
{ gamerTag: "Ace mdb", score: 9500 }
Recommendations
Case insensitive index!
Collations available since 3.4
Recommendations
Case insensitive index!
Collations available since 3.4
db.games.createIndex(
{ gamerTag: 1},
{ collation: { locale: 'en', strength: 2 } } )
Recommendations
Case insensitive index!
Collations available since 3.4
db.games.createIndex(
{ gamerTag: 1},
{ collation: { locale: 'en', strength: 2 } } )
> db.games.find( { gamerTag: "Ace"}).collation( { locale: 'en', strength: 2 } )
Recommendations
Case insensitive index!
Collations available since 3.4
db.games.createIndex(
{ gamerTag: 1},
{ collation: { locale: 'en', strength: 2 } } )
> db.games.find( { gamerTag: "Ace"}).collation( { locale: 'en', strength: 2 } )
{ "_id" : ObjectId("5b29dbee6c7d4f531bf73b5d"), "gamerTag" : "Ace", "score" : 9500 }
{ "_id" : ObjectId("5b29dbee6c7d4f531bf73b5e"), "gamerTag" : "ACE", "score" : 500 }
{ "_id" : ObjectId("5b29dbee6c7d4f531bf73b5f"), "gamerTag" : "aCe", "score" : 9500 }
{ "_id" : ObjectId("5b29dbee6c7d4f531bf73b60"), "gamerTag" : "ace", "score" : 0 }
Recommendations
Case insensitive index!
Collations available since 3.4
db.games.createIndex(
{ gamerTag: 1},
{ collation: { locale: 'en', strength: 2 } } )
Store a transformed (eg toLower()) copy of the string
Stakeholder Concern #3
db.games.find({gamerTag: “Ace”})
.collation({locale:'en', strength:2})
Stakeholder Concern #3
db.games.find({gamerTag: “Ace”})
.collation({locale:'en', strength:2})
Stakeholder Concern #3
db.games.find({gamerTag: “Ace”})
.collation({locale:'en', strength:2})
“Wow, MongoDB can do anything!!!”
Summary
Work Smarter Not Harder
• Understand the business logic
• Index appropriately
• Is it the right index to support the query?
• Be aware of:
• Blocking Stages
• Usage of $or
• Case sensitivity
• Leverage the Performance Advisor
Work Smarter Not Harder
• Understand the business logic
• Index appropriately
• Is it the right index to support the query?
• Be aware of:
• Blocking Stages
• Usage of $or
• Case sensitivity
• Leverage the Performance Advisor
Countdown to The Peanuts
Powered by an optimized MongoDB
environment, The Peanuts is sure to be a hit!
Tips and Tricks for Avoiding Common Query Pitfalls Christian Kurze

Tips and Tricks for Avoiding Common Query Pitfalls Christian Kurze

  • 1.
    Tips and Tricks forAvoiding Common Query Pitfalls Christian Kurze
  • 2.
  • 3.
    Roadmap • Motivation • Threeitems to be aware of: • Blocking stages • Using the $or operator • Case insensitivity
  • 4.
    The Power ofQuery Optimization • Query tuning results in: • Improved performance • Reduced resource utilization • This may lead to: • Improved stability and predictability • A smaller hardware footprint Not uncommon to observe efficiency improvements greater than 99%
  • 5.
    The Challenge @Acme Games, Inc. Charlie • DBA at Acme Game, Inc. • MongoDB Champion Stakeholders • Developers • Leadership • RDBMS History
  • 6.
    Acme Games Introduces… ThePeanuts Brand new strategy game Launching November 15th
  • 7.
    Stakeholder Concerns • Gamenearly complete • Developers have learned a lot from Charlie
  • 8.
    Stakeholder Concerns • Gamenearly complete • Developers have learned a lot from Charlie Indexes support the efficient execution of queries in MongoDB
  • 9.
    Stakeholder Concerns • Gamenearly complete • Developers have learned a lot from Charlie Indexes support the efficient execution of queries in MongoDB
  • 10.
    Stakeholder Concerns • Gamenearly complete • Developers have learned a lot from Charlie Indexes support the efficient execution of queries in MongoDB Ace Bob Sue … …
  • 11.
    Stakeholder Concerns • Gamenearly complete • Developers have learned a lot from Charlie • App being stress tested
  • 12.
    Stakeholder Concerns • Gamenearly complete • Developers have learned a lot from Charlie • App being stress tested • Concerned over current performance
  • 13.
    Stakeholder Concern #1 Developerscreated index db.games.createIndex({ gamerTag: 1 })
  • 14.
    Stakeholder Concern #1 Developerscreated index db.games.createIndex({ gamerTag: 1 }) This query takes several seconds to execute: db.games.find( { gamerTag: "Ace" } ).sort({score:-1})
  • 15.
    Stakeholder Concern #1 Developerscreated index db.games.createIndex({ gamerTag: 1 }) This query takes several seconds to execute: db.games.find( { gamerTag: "Ace" } ).sort({score:-1}) Adding the index on score does not help! db.games.createIndex({ score: -1 })
  • 16.
    Stakeholder Concern #1 Developerscreated index db.games.createIndex({ gamerTag: 1 }) This query takes several seconds to execute: db.games.find( { gamerTag: "Ace" } ).sort({score:-1}) Adding the index on score does not help! db.games.createIndex({ score: -1 }) “Clearly MongoDB is not web-scale!”
  • 17.
  • 18.
    Blocking Operations ● Formally: ■“An operation which must process all input before it can begin to produce any output.” ● Opposite of the often desirable “fully pipelined” plan which can stream results back as soon as they are found. ● Commonly observed when a sort is added to a query
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
    Blocking Stages • $sort •In aggregation and find • $group • $bucket • $count • $facet Are there any other blocking operations?
  • 48.
    Working with blockingstages For sorting: • Add a supporting index • Worth the overhead in almost all circumstances For other stages: • Do you need the blocking stage? • Offload to secondary member
  • 49.
    Stakeholder Concern #1 Performanceof db.games.find( { gamerTag: "Ace" } ).sort({score:-1}) “Clearly MongoDB is not web-scale!”
  • 50.
    Stakeholder Concern #1 Performanceof db.games.find( { gamerTag: "Ace" } ).sort({score:-1}) db.games.createIndex({ gamerTag: 1, score:-1 })
  • 51.
    Stakeholder Concern #1 Performanceof db.games.find( { gamerTag: "Ace" } ).sort({score:-1}) db.games.createIndex({ gamerTag: 1, score:-1 }) "That’ll work great!”
  • 52.
    Stakeholder Concern #2 The$and version of a query returns quickly: db.games.find({ $and : [ { gamerTag: "Ace" }, { score: {$gt: 9000} } ] })
  • 53.
    Stakeholder Concern #2 The$and version of a query returns quickly: db.games.find({ $and : [ { gamerTag: "Ace" }, { score: {$gt: 9000} } ] }) But the $or version is slow: db.games.find({ $or : [ { gamerTag: "Ace" }, { score: {$gt: 9000} } ] })
  • 54.
    Stakeholder Concern #2 The$and version of a query returns quickly: db.games.find({ $and : [ { gamerTag: "Ace" }, { score: {$gt: 9000} } ] }) But the $or version is slow: db.games.find({ $or : [ { gamerTag: "Ace" }, { score: {$gt: 9000} } ] }) We just created an index with both those fields… Can’t it be used?
  • 55.
  • 56.
    $and example Query ongames: db.games.find({ $and : [ { gamerTag: "Ace" }, { score: {$gt: 9000} } ] }) Matching games: { gamerTag: "Ace", score: 9500 } Non-matching games: { gamerTag: "Ace", score: 500 }, { gamerTag: "Bob", score: 9500 }, { gamerTag: "Bob", score: 500 }
  • 57.
    Groups of documents {gamerTag: "Ace", score: 9500 } { gamerTag: "Ace", score: 500 } { gamerTag: "Bob", score: 9500 } { gamerTag: "Bob", score: 500 }
  • 58.
    Groups of documents {gamerTag: "Ace", score: 9500 } { gamerTag: "Ace", score: 500 } { gamerTag: "Bob", score: 9500 } { gamerTag: "Bob", score: 500 } gamerTag: "Ace"
  • 59.
    Groups of documents {gamerTag: "Ace", score: 9500 } { gamerTag: "Ace", score: 500 } { gamerTag: "Bob", score: 9500 } { gamerTag: "Bob", score: 500 } gamerTag: "Ace" score: {$gt: 9000}
  • 60.
    $and Venn Diagram(logical) { gamerTag: "Ace", score: 9500 } { gamerTag: "Ace", score: 500 } { gamerTag: "Bob", score: 9500 } { gamerTag: "Bob", score: 500 } db.games.find({ $and : [ { gamerTag: "Ace" }, { score: {$gt: 9000} } ] })gamerTag: "Ace" score: {$gt: 9000}
  • 61.
    $and Venn Diagram(logical) { gamerTag: "Ace", score: 9500 } { gamerTag: "Ace", score: 500 } { gamerTag: "Bob", score: 9500 } { gamerTag: "Bob", score: 500 } db.games.find({ $and : [ { gamerTag: "Ace" }, { score: {$gt: 9000} } ] })gamerTag: "Ace" score: {$gt: 9000}
  • 62.
    $and Venn Diagram(logical) db.games.find({ $and : [ { gamerTag: "Ace" }, { score: {$gt: 9000} } ] })gamerTag: "Ace" score: {$gt: 9000}
  • 63.
    $and Venn Diagram(logical) db.games.find({ $and : [ { gamerTag: "Ace" }, { score: {$gt: 9000} } ] })gamerTag: "Ace" score: {$gt: 9000}
  • 64.
    $and Venn Diagram(logical) db.games.find({ $and : [ { gamerTag: "Ace" }, { score: {$gt: 9000} } ] })gamerTag: "Ace" score: {$gt: 9000}
  • 65.
    $and Venn Diagram(logical) db.games.find({ $and : [ { gamerTag: "Ace" }, { score: {$gt: 9000} } ] })gamerTag: "Ace" score: {$gt: 9000}
  • 66.
    $and Venn Diagram(logical) db.games.find({ $and : [ { gamerTag: "Ace" }, { score: {$gt: 9000} } ] })gamerTag: "Ace" score: {$gt: 9000}
  • 67.
    $and Venn Diagram(logical) db.games.find({ $and : [ { gamerTag: "Ace" }, { score: {$gt: 9000} } ] }) Ace Bob 500 950 0 500 950 0 {gamerTag:1 , score:-1}
  • 68.
    $and Venn Diagram(logical) db.games.find({ $and : [ { gamerTag: "Ace" }, { score: {$gt: 9000} } ] }) Ace Bob 500 950 0 500 950 0 "indexBounds" : { "gamerTag" : [ "["Ace", "Ace"]" ], "score" : [ "[inf.0, 9000.0)" ] } {gamerTag:1 , score:-1}
  • 69.
    $and Venn Diagram(logical) db.games.find({ $and : [ { gamerTag: "Ace" }, { score: {$gt: 9000} } ] }) Ace Bob 500 950 0 500 950 0 "indexBounds" : { "gamerTag" : [ "["Ace", "Ace"]" ], "score" : [ "[inf.0, 9000.0)" ] } {gamerTag:1 , score:-1}
  • 70.
    $and Venn Diagram(logical) db.games.find({ $and : [ { gamerTag: "Ace" }, { score: {$gt: 9000} } ] }) Ace Bob 500 950 0 500 950 0 "indexBounds" : { "gamerTag" : [ "["Ace", "Ace"]" ], "score" : [ "[inf.0, 9000.0)" ] } {gamerTag:1 , score:-1}
  • 71.
    $and Venn Diagram(logical) db.games.find({ $and : [ { gamerTag: "Ace" }, { score: {$gt: 9000} } ] }) Ace Bob 500 950 0 500 950 0 "indexBounds" : { "gamerTag" : [ "["Ace", "Ace"]" ], "score" : [ "[inf.0, 9000.0)" ] } {gamerTag:1 , score:-1}
  • 72.
    $or example Query ongames: db.games.find({ $or : [ { gamerTag: "Ace" }, { score: {$gt: 9000} } ] }) Matching games: { gamerTag: "Ace", score: 9500 }, { gamerTag: "Ace", score: 500 }, { gamerTag: "Bob", score: 9500 } Non-matching games: { gamerTag: "Bob", score: 500 }
  • 73.
    $or Venn Diagram(logical) { gamerTag: "Ace", score: 9500 } { gamerTag: "Ace", score: 500 } { gamerTag: "Bob", score: 9500 } { gamerTag: "Bob", score: 500 } db.games.find({ $or : [ { gamerTag: "Ace" }, { score: {$gt: 9000} } ] })gamerTag: "Ace" score: {$gt: 9000}
  • 74.
    $or Venn Diagram(logical) { gamerTag: "Ace", score: 9500 } { gamerTag: "Ace", score: 500 } { gamerTag: "Bob", score: 9500 } { gamerTag: "Bob", score: 500 } db.games.find({ $or : [ { gamerTag: "Ace" }, { score: {$gt: 9000} } ] })gamerTag: "Ace" score: {$gt: 9000}
  • 75.
    $or Venn Diagram(logical) { gamerTag: "Ace", score: 9500 } { gamerTag: "Ace", score: 500 } { gamerTag: "Bob", score: 9500 } { gamerTag: "Bob", score: 500 } db.games.find({ $or : [ { gamerTag: "Ace" }, { score: {$gt: 9000} } ] })gamerTag: "Ace" score: {$gt: 9000}
  • 76.
    $or Venn Diagram(logical) { gamerTag: "Ace", score: 9500 } { gamerTag: "Ace", score: 500 } { gamerTag: "Bob", score: 9500 } { gamerTag: "Bob", score: 500 } db.games.find({ $or : [ { gamerTag: "Ace" }, { score: {$gt: 9000} } ] })gamerTag: "Ace" score: {$gt: 9000}
  • 77.
    $or Venn Diagram(logical) { gamerTag: "Ace", score: 9500 } { gamerTag: "Ace", score: 500 } { gamerTag: "Bob", score: 9500 } { gamerTag: "Bob", score: 500 } db.games.find({ $or : [ { gamerTag: "Ace" }, { score: {$gt: 9000} } ] })gamerTag: "Ace" score: {$gt: 9000}
  • 78.
    $or Venn Diagram(logical) db.games.find({ $or : [ { gamerTag: "Ace" }, { score: {$gt: 9000} } ] })gamerTag: "Ace" score: {$gt: 9000}
  • 79.
    $or Venn Diagram(logical) db.games.find({ $or : [ { gamerTag: "Ace" }, { score: {$gt: 9000} } ] })gamerTag: "Ace" score: {$gt: 9000}
  • 80.
    $or Venn Diagram(logical) db.games.find({ $or : [ { gamerTag: "Ace" }, { score: {$gt: 9000} } ] })gamerTag: "Ace" score: {$gt: 9000}
  • 81.
    $or Venn Diagram(logical) db.games.find({ $or : [ { gamerTag: "Ace" }, { score: {$gt: 9000} } ] })gamerTag: "Ace" score: {$gt: 9000}
  • 82.
    $or Venn Diagram(logical) db.games.find({ $or : [ { gamerTag: "Ace" }, { score: {$gt: 9000} } ] })gamerTag: "Ace" score: {$gt: 9000}
  • 83.
    $or (single) Indexvisualization Ace Bob {gamerTag:1 , score:-1} 500 950 0 500 950 0 db.games.find({ $or : [ { gamerTag: "Ace" }, { score: {$gt: 9000} } ] })
  • 84.
    $or (single) Indexvisualization Ace Bob {gamerTag:1 , score:-1} 500 950 0 500 950 0 db.games.find({ $or : [ { gamerTag: "Ace" }, { score: {$gt: 9000} } ] }) Expected Index Bounds: "indexBounds" : { "gamerTag" : [ "["Ace", "Ace"]" ], "score" : [ "[inf.0, 9000)" ] }
  • 85.
    $or (single) Indexvisualization Ace Bob {gamerTag:1 , score:-1} 500 950 0 500 950 0 db.games.find({ $or : [ { gamerTag: "Ace" }, { score: {$gt: 9000} } ] }) Expected Index Bounds: "indexBounds" : { "gamerTag" : [ "["Ace", "Ace"]" ], "score" : [ "[inf.0, 9000)" ] }
  • 86.
    $or (single) Indexvisualization Ace Bob {gamerTag:1 , score:-1} 500 950 0 500 950 0 db.games.find({ $or : [ { gamerTag: "Ace" }, { score: {$gt: 9000} } ] }) Expected Index Bounds: "indexBounds" : { "gamerTag" : [ "["Ace", "Ace"]" ], "score" : [ "[inf.0, 9000)" ] }
  • 87.
    $or (single) Indexvisualization Ace Bob {gamerTag:1 , score:-1} 500 950 0 500 950 0 db.games.find({ $or : [ { gamerTag: "Ace" }, { score: {$gt: 9000} } ] }) Expected Index Bounds: "indexBounds" : { "gamerTag" : [ "["Ace", "Ace"]" ], "score" : [ "[inf.0, 9000)" ] }
  • 88.
    $or (single) Indexvisualization Ace Bob {gamerTag:1 , score:-1} 500 950 0 500 950 0 db.games.find({ $or : [ { gamerTag: "Ace" }, { score: {$gt: 9000} } ] }) Expected Index Bounds: "indexBounds" : { "gamerTag" : [ "["Ace", "Ace"]" ], "score" : [ "[inf.0, 9000)" ] }
  • 89.
    $or (single) Indexvisualization Ace Bob {gamerTag:1 , score:-1} 500 950 0 500 950 0 db.games.find({ $or : [ { gamerTag: "Ace" }, { score: {$gt: 9000} } ] }) Expected Index Bounds: "indexBounds" : { "gamerTag" : [ "["Ace", "Ace"]" ], "score" : [ "[inf.0, 9000)" ] }
  • 90.
    $or (single) Indexvisualization Ace Bob {gamerTag:1 , score:-1} 500 950 0 500 950 0 db.games.find({ $or : [ { gamerTag: "Ace" }, { score: {$gt: 9000} } ] }) Expected Index Bounds: "indexBounds" : { "gamerTag" : [ "["Ace", "Ace"]" ], "score" : [ "[inf.0, 9000)" ] } Actual (Hinted) Index Bounds: "indexBounds" : { "gamerTag" : [ "[MinKey, MaxKey]" ], "score" : [ "[MaxKey, MinKey]" ] }
  • 91.
    $or (single) Indexvisualization Ace Bob {gamerTag:1 , score:-1} 500 950 0 500 950 0 db.games.find({ $or : [ { gamerTag: "Ace" }, { score: {$gt: 9000} } ] }) Expected Index Bounds: "indexBounds" : { "gamerTag" : [ "["Ace", "Ace"]" ], "score" : [ "[inf.0, 9000)" ] } Actual (Hinted) Index Bounds: "indexBounds" : { "gamerTag" : [ "[MinKey, MaxKey]" ], "score" : [ "[MaxKey, MinKey]" ] } So is there anything we can do to improve the performance of this query?
  • 92.
  • 93.
    $or (multiple) Indexvisualization db.games.find({ $or : [ { gamerTag: "Ace" }, { score: {$gt: 9000} } ] })
  • 94.
    $or (multiple) Indexvisualization Ace db.games.find({ $or : [ { gamerTag: "Ace" }, { score: {$gt: 9000} } ] })
  • 95.
    $or (multiple) Indexvisualization Ace Bob db.games.find({ $or : [ { gamerTag: "Ace" }, { score: {$gt: 9000} } ] })
  • 96.
    $or (multiple) Indexvisualization Ace Bob {gamerTag:1} db.games.find({ $or : [ { gamerTag: "Ace" }, { score: {$gt: 9000} } ] })
  • 97.
    $or (multiple) Indexvisualization Ace Bob {gamerTag:1} 500 db.games.find({ $or : [ { gamerTag: "Ace" }, { score: {$gt: 9000} } ] })
  • 98.
    $or (multiple) Indexvisualization Ace Bob {gamerTag:1} 500 950 0 db.games.find({ $or : [ { gamerTag: "Ace" }, { score: {$gt: 9000} } ] })
  • 99.
    $or (multiple) Indexvisualization Ace Bob {gamerTag:1} 500 950 0 {score:1} db.games.find({ $or : [ { gamerTag: "Ace" }, { score: {$gt: 9000} } ] })
  • 100.
    $or (multiple) Indexvisualization Ace Bob {gamerTag:1} 500 950 0 {score:1} "indexBounds" : { "gamerTag" : [ "["Ace", "Ace"]" ] } "indexBounds" : { "score" : [ "(9000.0, inf.0]" ] } db.games.find({ $or : [ { gamerTag: "Ace" }, { score: {$gt: 9000} } ] })
  • 101.
    $or (multiple) Indexvisualization Ace Bob {gamerTag:1} 500 950 0 {score:1} db.games.find({ $or : [ { gamerTag: "Ace" }, { score: {$gt: 9000} } ] }) "indexBounds" : { "gamerTag" : [ "["Ace", "Ace"]" ] } "indexBounds" : { "score" : [ "(9000.0, inf.0]" ] }
  • 102.
    $or (multiple) Indexvisualization Ace Bob {gamerTag:1} 500 950 0 {score:1} db.games.find({ $or : [ { gamerTag: "Ace" }, { score: {$gt: 9000} } ] }) "indexBounds" : { "gamerTag" : [ "["Ace", "Ace"]" ] } "indexBounds" : { "score" : [ "(9000.0, inf.0]" ] }
  • 103.
    $or (multiple) Indexvisualization Ace Bob {gamerTag:1} 500 950 0 {score:1} db.games.find({ $or : [ { gamerTag: "Ace" }, { score: {$gt: 9000} } ] }) "indexBounds" : { "gamerTag" : [ "["Ace", "Ace"]" ] } "indexBounds" : { "score" : [ "(9000.0, inf.0]" ] }
  • 104.
    $or (multiple) Indexvisualization Ace Bob {gamerTag:1} 500 950 0 {score:1} db.games.find({ $or : [ { gamerTag: "Ace" }, { score: {$gt: 9000} } ] }) "indexBounds" : { "gamerTag" : [ "["Ace", "Ace"]" ] } "indexBounds" : { "score" : [ "(9000.0, inf.0]" ] }
  • 105.
    $or (multiple) Indexvisualization Ace Bob {gamerTag:1} 500 950 0 {score:1} db.games.find({ $or : [ { gamerTag: "Ace" }, { score: {$gt: 9000} } ] }) "indexBounds" : { "gamerTag" : [ "["Ace", "Ace"]" ] } "indexBounds" : { "score" : [ "(9000.0, inf.0]" ] }
  • 106.
  • 107.
    Recommendations Use multiple indexes! db.data.createIndex({gamerTag:1}) db.data.createIndex({score: 1}) We already have the {gamerTag:1, score:-1} index, do we need both of these new ones?
  • 108.
    Recommendations Use multiple indexes! db.data.createIndex({gamerTag:1}) db.data.createIndex({gamerTag: 1, score: -1}} db.data.createIndex({score: 1}) We already have the {gamerTag:1, score:-1} index, do we need both of these new ones?
  • 109.
    Recommendations Use multiple indexes! db.data.createIndex({gamerTag:1}) db.data.createIndex({gamerTag: 1, score: -1}} db.data.createIndex({score: 1}) Rule of thumb for compound indexes: equality, sort, range
  • 110.
    Recommendations Use multiple indexes! db.data.createIndex({gamerTag:1}) db.data.createIndex({gamerTag: 1, score: -1}} db.data.createIndex({score: 1}) Rule of thumb for compound indexes: equality, sort, range Works with sorting Generate a SORT_MERGE plan
  • 111.
    Stakeholder Concern #2 db.games.find({ $or: [ { gamerTag: "Ace" }, { score: {$gt: 9000} } ] }) Having the right index is critical
  • 112.
    Stakeholder Concern #2 db.games.find({ $or: [ { gamerTag: "Ace" }, { score: {$gt: 9000} } ] }) Having the right index is critical
  • 113.
    Stakeholder Concern #2 db.games.find({ $or: [ { gamerTag: "Ace" }, { score: {$gt: 9000} } ] }) Having the right index is critical "Super!!”
  • 114.
    Stakeholder Concern #3 “Waitwait wait, we can’t even FIND the gamers!” A basic search on gamerTag takes several seconds already: db.games.find({gamerTag: /Ace/i}) “This query is SLOWER with the index than it is without it!”
  • 115.
  • 116.
    Case Sensitive db.games.find({ gamerTag: /^Ace$/ }) //equivalentto db.games.find({ gamerTag: “Ace” }) Matching games: { gamerTag: "Ace", score: 9500 }, Non-matching games: { gamerTag: "ACE", score: 500 }, { gamerTag: "aCe", score: 9500 }, { gamerTag: "ace", score: 0 }, { gamerTag: "Bob", score: 500 }, { gamerTag: "acxyz", score: 9500 }, { gamerTag: "Ace mdb", score: 9500 }
  • 117.
    Case Sensitive ace aCe acxy z Ace Ace mdb ACEBob "indexBounds" : { "gamerTag" : [ "["Ace", "Acf")", "[/^Ace$/, /^Ace$/]" ] } Matching games: { gamerTag: "Ace", score: 9500 }, Non-matching games: { gamerTag: "ACE", score: 500 }, { gamerTag: "aCe", score: 9500 }, { gamerTag: "ace", score: 0 }, { gamerTag: "Bob", score: 500 }, { gamerTag: "acxyz", score: 9500 }, { gamerTag: "Ace mdb", score: 9500 }
  • 118.
    Case insensitive db.games.find({ gamerTag: /^Ace$/i }) //equivalentto db.games.find({ gamerTag: { $regex: “^Ace$”, $options: “i” } }) //equivalent to db.games.find({ gamerTag: “Ace”}) .collation({locale:’en’, strength:2}) Matching games: { gamerTag: "Ace", score: 9500 }, { gamerTag: "ACE", score: 500 }, { gamerTag: "aCe", score: 9500 }, { gamerTag: "ace", score: 0 } Non-matching games: { gamerTag: "Bob", score: 500 }, { gamerTag: "acxyz", score: 9500 }, { gamerTag: "Ace mdb", score: 9500 }
  • 119.
    Case insensitive db.games.find({ gamerTag: /^Ace$/i }) //equivalentto db.games.find({ gamerTag: { $regex: “^Ace$”, $options: “i” } }) //equivalent to db.games.find({ gamerTag: “Ace”}) .collation({locale:’en’, strength:2}) Matching games: { gamerTag: "Ace", score: 9500 }, { gamerTag: "ACE", score: 500 }, { gamerTag: "aCe", score: 9500 }, { gamerTag: "ace", score: 0 } Non-matching games: { gamerTag: "Bob", score: 500 }, { gamerTag: "acxyz", score: 9500 }, { gamerTag: "Ace mdb", score: 9500 } Would a $text search be the same as well?
  • 120.
    Case INsensitive ace aCe acxy z Ace Ace mdb ACEBob "indexBounds" : { "gamerTag" : [ "["", {})", "[/^Ace$/i, /^Ace$/i]" ] } Matching games: { gamerTag: "Ace", score: 9500 }, { gamerTag: "ACE", score: 500 }, { gamerTag: "aCe", score: 9500 }, { gamerTag: "ace", score: 0 } Non-matching games: { gamerTag: "Bob", score: 500 }, { gamerTag: "acxyz", score: 9500 }, { gamerTag: "Ace mdb", score: 9500 }
  • 121.
  • 122.
    Recommendations Case insensitive index! Collationsavailable since 3.4 db.games.createIndex( { gamerTag: 1}, { collation: { locale: 'en', strength: 2 } } )
  • 123.
    Recommendations Case insensitive index! Collationsavailable since 3.4 db.games.createIndex( { gamerTag: 1}, { collation: { locale: 'en', strength: 2 } } ) > db.games.find( { gamerTag: "Ace"}).collation( { locale: 'en', strength: 2 } )
  • 124.
    Recommendations Case insensitive index! Collationsavailable since 3.4 db.games.createIndex( { gamerTag: 1}, { collation: { locale: 'en', strength: 2 } } ) > db.games.find( { gamerTag: "Ace"}).collation( { locale: 'en', strength: 2 } ) { "_id" : ObjectId("5b29dbee6c7d4f531bf73b5d"), "gamerTag" : "Ace", "score" : 9500 } { "_id" : ObjectId("5b29dbee6c7d4f531bf73b5e"), "gamerTag" : "ACE", "score" : 500 } { "_id" : ObjectId("5b29dbee6c7d4f531bf73b5f"), "gamerTag" : "aCe", "score" : 9500 } { "_id" : ObjectId("5b29dbee6c7d4f531bf73b60"), "gamerTag" : "ace", "score" : 0 }
  • 125.
    Recommendations Case insensitive index! Collationsavailable since 3.4 db.games.createIndex( { gamerTag: 1}, { collation: { locale: 'en', strength: 2 } } ) Store a transformed (eg toLower()) copy of the string
  • 126.
    Stakeholder Concern #3 db.games.find({gamerTag:“Ace”}) .collation({locale:'en', strength:2})
  • 127.
    Stakeholder Concern #3 db.games.find({gamerTag:“Ace”}) .collation({locale:'en', strength:2})
  • 128.
    Stakeholder Concern #3 db.games.find({gamerTag:“Ace”}) .collation({locale:'en', strength:2}) “Wow, MongoDB can do anything!!!”
  • 129.
  • 130.
    Work Smarter NotHarder • Understand the business logic • Index appropriately • Is it the right index to support the query? • Be aware of: • Blocking Stages • Usage of $or • Case sensitivity • Leverage the Performance Advisor
  • 131.
    Work Smarter NotHarder • Understand the business logic • Index appropriately • Is it the right index to support the query? • Be aware of: • Blocking Stages • Usage of $or • Case sensitivity • Leverage the Performance Advisor
  • 132.
    Countdown to ThePeanuts Powered by an optimized MongoDB environment, The Peanuts is sure to be a hit!