MongoDB
of the index of MySql
the index of 061c20820efa42 and the principles to be optimized are basically similar. The MySql
can be basically divided into:
- Single key index-joint index
- Primary key index (clustered index)-non-primary key index (non-clustered index)
In MongoDB
, there are also some special index types, such as: array index | sparse index | geospatial index | TTL index, etc.
In order to facilitate the test below, we use the script to insert the following data
for(var i = 0;i < 100000;i++){
db.users.insertOne({
username: "user"+i,
age: Math.random() * 100,
sex: i % 2,
phone: 18468150001+i
});
}
Single key index
A single-key index means that there is only one field in the index, which is the most basic indexing method.
username
field in the collection to create a single-key index, MongoDB
will automatically name this index username_1
db.users.createIndex({username:1})
'username_1'
After creating the index, look at the query plan username
stage
is IXSCAN
, which means that the index scan is used.
db.users.find({username:"user40001"}).explain()
{
queryPlanner:
{
winningPlan:
{
......
stage: 'FETCH',
inputStage:
{
stage: 'IXSCAN',
keyPattern: { username: 1 },
indexName: 'username_1',
......
}
}
rejectedPlans: [] ,
},
......
ok: 1
}
Among the principles of index optimization, there is a very important principle that the index should be built on a field with a high cardinality. The so-called cardinality is the number of non-repeated values on a field, that is, the value of the age when users
0-99
then age
this field will have 100 unique values, namely age
base field is 100, and sex
this field will only appear 0 | 1
the two values, namely sex
underlying field is 2, which is a fairly low Cardinality, in this case, the efficiency of the index is not high and will cause the index to fail.
Below is a sex
field index on the ship. When you query the execution plan, you will find that the full table scan is used when the query is performed, and the relevant index is not used.
db.users.createIndex({sex:1})
'sex_1'
db.users.find({sex:1}).explain()
{
queryPlanner:
{
......
winningPlan:
{
stage: 'COLLSCAN',
filter: { sex: { '$eq': 1 } },
direction: 'forward'
},
rejectedPlans: []
},
......
ok: 1
}
Joint index
The joint index means that there will be multiple fields on the index. Below, use the age
and sex
create an index
db.users.createIndex({age:1,sex:1})
'age_1_sex_1'
Then we use these two fields to perform a query, view the execution plan, and successfully go through this index
db.users.find({age:23,sex:1}).explain()
{
queryPlanner:
{
......
winningPlan:
{
stage: 'FETCH',
inputStage:
{
stage: 'IXSCAN',
keyPattern: { age: 1, sex: 1 },
indexName: 'age_1_sex_1',
.......
indexBounds: { age: [ '[23, 23]' ], sex: [ '[1, 1]' ] }
}
},
rejectedPlans: [],
},
......
ok: 1
}
Array index
The array index is to create an index on the array field, also called a multi-value index. The following is to add a part of the array field to the data in the users
db.users.updateOne({username:"user1"},{$set:{hobby:["唱歌","篮球","rap"]}})
......
Create an array index and view its execution isMultiKey: true
that 061c20820efc87 indicates that the index used is a multi-value index.
db.users.createIndex({hobby:1})
'hobby_1'
db.users.find({hobby:{$elemMatch:{$eq:"钓鱼"}}}).explain()
{
queryPlanner:
{
......
winningPlan:
{
stage: 'FETCH',
filter: { hobby: { '$elemMatch': { '$eq': '钓鱼' } } },
inputStage:
{
stage: 'IXSCAN',
keyPattern: { hobby: 1 },
indexName: 'hobby_1',
isMultiKey: true,
multiKeyPaths: { hobby: [ 'hobby' ] },
......
indexBounds: { hobby: [ '["钓鱼", "钓鱼"]' ] } }
},
rejectedPlans: []
},
......
ok: 1
}
The array index is compared to other index entries and index volume necessarily increases exponentially, for example, the average of each document hobby
array size
is 10, then the set hobby
number of entries in the array index would be 10 times normal index.
associative array index
Joint array index is a joint index containing array fields. This kind of index does not support multiple array fields in an index, that is, there can be at most one array field in an index. This is to avoid the explosive growth of index entries. Suppose an index There are two array fields in the index, then the number of index entries will be n*m times the normal index
Geospatial index
Add some geographic information to the original users
for(var i = 0;i < 100000;i++){
db.users.updateOne(
{username:"user"+i},
{
$set:{
location:{
type: "Point",
coordinates: [100+Math.random() * 4,40+Math.random() * 3]
}
}
});
}
Create a two-dimensional spatial index
db.users.createIndex({location:"2dsphere"})
'location_2dsphere'
//查询500米内的人
db.users.find({
location:{
$near:{
$geometry:{type:"Point",coordinates:[102,41.5]},
$maxDistance:500
}
}
})
type
geospatial index contains many Ponit (point) |
LineString (line) |
Polygon (polygon), etc.
TTL index
The full spelling of TTL is time to live
, which is mainly used for the automatic deletion of expired data. To use this index, you need to declare a time type field in the document, and then you need to set a expireAfterSeconds
expiration time unit when creating a TTL index for this field. Seconds, after the creation is completed, MongoDB
will periodically check the data in the collection. When it appears:
$$ 当前时间 - TTL索引字段时间 > expireAfterSrconds $$
MongoDB
will automatically delete these documents. This index has the following requirements:
- TTL index can only have one field, there is no joint TTL index
- TTL cannot be used for fixed collections
- After the TTL index is traversed one by one, it is found that the
delete
function will be used to delete if the deletion conditions are met, which is not efficient
First add or subtract a time field on our document
for(var i = 90000;i < 100000;i++){
db.users.updateOne(
{username:"user"+i},
{
$set:{
createdDate:new Date()
}
});
}
Create a TTL index and set the expiration time to 60s. After 60s, you will find that the data no longer exists.
db.users.createIndex({createdDate:1},{expireAfterSeconds:60})
'createdDate_1'
In addition, you can use the CollMod
command to change the expiration time of the TTL index
db.runCommand({
collMod:"users",
index:{
keyPattern:{createdDate:1},
expireAfterSeconds:120
}
})
{ expireAfterSeconds_old: 60, expireAfterSeconds_new: 120, ok: 1 }
Condition index
Conditional index is also called partial index (partial), only the data that meets the condition is indexed.
Only 50-year-old user
be established username_1
index, view the execution plan will find isPartial
this field will become true
db.users.createIndex({username:1},{partialFilterExpression:{
age:{$gt:50}
}})
'username_1'
db.users.find({$and:[{username:"user4"},{age:60}]}).explain()
{
queryPlanner:
{
......
winningPlan:
{
stage: 'FETCH',
filter: { age: { '$eq': 60 } },
inputStage:
{
stage: 'IXSCAN',
keyPattern: { username: 1 },
indexName: 'username_1',
......
isPartial: true,
......
}
},
rejectedPlans: []
},
......
ok: 1
}
Sparse index
The general index will create an index for the entire collection based on a certain field.Even if a certain document does not store this field, then the index will use this field of the document as null
built in the index.
A sparse index will not index a field that does not exist in the document.If this field exists but is null
, an index will be created.
Let's create a sparse index for part of the data in the users
for(var i = 5000;i < 10000;i++){
if(i < 9000){
db.users.updateOne(
{username:"user"+i},
{ $set:{email:(120000000+i)+"@qq.email"}}
)
}else{
db.users.updateOne(
{username:"user"+i},
{ $set:{email:null}}
)
}
}
{email:null}
condition without indexing, we will find that the detected documents contain documents without the email
field
db.users.find({email:null})
{
_id: ObjectId("61bdc01ba59136670f6536fd"),
username: 'user0',
age: 64.41483801726282,
sex: 0,
phone: 18468150001,
location:
{
type: 'Point',
coordinates: [ 101.42490900320335, 42.2576650823515 ]
}
}
......
Then email
this field to create a sparse index using {email:null}
conditions query, the query to find all documents email
field exists and is null
document.
db.users.createIndex({email:1},{sparse:true});
'email_1'
db.users.find({email:null}).hint({email:1})
{
_id: ObjectId("61bdc12ca59136670f655a25"),
username: 'user9000',
age: 94.18397576757012,
sex: 0,
phone: 18468159001,
hobby: [ '钓鱼', '乒乓球' ],
location:
{
type: 'Point',
coordinates: [ 101.25903151863596, 41.38450145025062 ]
},
email: null
}
......
Text index
The text index will perform word segmentation on the indexed document field first and then search, but currently does not support Chinese word segmentation.
Add two text fields below to create a joint text index
db.blog.insertMany([
{title:"hello world",content:"mongodb is the best database"},
{title:"index",content:"efficient data structure"}
])
//创建索引
db.blog.createIndex({title:"text",content:"text"})
'title_text_content_text'
//使用文本索引查询
db.blog.find({$text:{$search:"hello data"}})
{
_id: ObjectId("61c092268c4037d17827d977"),
title: 'index',
content: 'efficient data structure'
},
{
_id: ObjectId("61c092268c4037d17827d976"),
title: 'hello world',
content: 'mongodb is the best database'
}
Unique index
The unique index means that no duplicate elements can appear in the field where the index is created. In addition to the single-field unique index, there are joint unique indexes and array unique indexes (that is, there can be no element intersection between )
//对title字段创建唯一索引
db.blog.createIndex({title:1},{unique:true})
'title_1'
//插入一个已经存在的title值
db.blog.insertOne({title:"hello world",content:"mongodb is the best database"})
MongoServerError: E11000 duplicate key error collection: mock.blog index: title_1 dup key: { : "hello world" }
//查看一下执行计划,isUnique为true
db.blog.find({"title":"index"}).explain()
{
queryPlanner:
{
......
winningPlan:
{
stage: 'FETCH',
inputStage:
{
stage: 'IXSCAN',
keyPattern: { title: 1 },
indexName: 'title_1',
isMultiKey: false,
multiKeyPaths: { title: [] },
isUnique: true,
......
}
},
rejectedPlans: []
},
.......
ok: 1
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。