MongoDB-索引的使用和索引类型
目录
- 简介
- 创建索引的方式
- 索引的种类
- 单列索引
- 复合索引(多列索引)
- 多键索引
- 地理空间索引
- 文本搜索索引
- Hash索引
- 索引属性
简介
- MongoDB的索引种类还是不少的,因为它是个文档数据库,存储的数据种类杂七杂八的,针对MongoDB的索引大致可以分为,唯一索引、单列索引、多列索引(复合索引)、多键索引(数组字段索引)、文本搜索索引、地理空间索引,等。但其实非特殊业务,一般情况下使用到的索引也就单列索引和多列索引,以及唯一索引比较多。
- MongoDB的索引使用B+Tree数据库结构,与MySQL的B+tree类似,如有兴趣可以在我另外一篇文章中查看B+tree的底层原理,这里就不再啰嗦了。
- MongoDB在创建集合时,默认会对_id字段创建唯一索引,如果插入数据不指定_id字段,默认会随机生成一串字符作为_id列。
B+tree与B-Tree数据结构的不同处:链接: https://blog.csdn.net/h_3369/article/details/141357887?spm=1001.2014.3001.5502
创建索引的方式
- MongoDB使用 db.collection.createIndex()语句进行创建索引。
- 索引名称默认没有自定义的话,使用列名称加索引降序还是升序进行命名例如name_-1表示在name列上创建了一个降序的索引
- 可以通过db.collection.getIndexes()查看某个集合上的索引情况。索引一旦创建后无法重命名,除非删除索引重新创建。
db.collection.createIndex( <key and index type specification>, <options> )
### 以下实例在name列创建一个降序索引,其中的-1表示降序,如果是1表示升序
db.collection.createIndex( { name: -1 } )
###对sid列创建一个升序索引,并自定义索引名为collection_sid_idx_1
db.zips.createIndex( { sid: 1 },{name:'collection_sid_idx_1'} )
###查询索引是否创建成功
db.collection.getIndexes()
###删除索引的方式
db.zips.dropIndex( "index_name" )
索引的种类
- MongoDB索引的种类分为很多种,下面我们根据单个字段、多个字段、多键索引、地理空间索引、文本搜索索引、哈希索引、通配符索引这几个种类。进行介绍和使用。
单列索引
- 顾名思义,就是我们集合中,某个列单独创建一个索引。基本上是对于这个列查询需求较高,重复值也不是太高的列,进行创建索引。其中每一个集合中,我们的_id字段就是单列索引,只是不同的是,他是个单列唯一索引。
- MongoDB根据B-tree数据结构,在创建索引时,索引中可存储某个特定字段或多个字段的值,会对创建索引列的值进行排序,索引项的排序支持高效的等值匹配和基于范围的查询操作。此外,MongoDB 还可使用索引中的顺序来返回排序后的结果。
1.创建测试数据,使用MongoDB官方的测试数据。后面这个测试数据集合,还会用到,在另一给文档有详细的导入介绍,这里不再介绍导入方式了。
测试数据地址:https://media.mongodb.org/zips.json
导入方式:https://blog.csdn.net/h_3369/article/details/141923194?spm=1001.2014.3001.5501
2.对pop列创建一个升序索引,自定义名称为zips_pop_1
db.zips.createIndex( { pop: 1 },{name:'zips_pop_1'} )
###查询创建是否成功
db.zips.getIndexes()
[
{ v: 2, key: { _id: 1 }, name: '_id_' },
{ v: 2, key: { pop: 1 }, name: 'zips_pop_1' }
]
3.对嵌入式字段创建索引,也就是字段中的字段。
###插入数据
db.schools.insertOne(
{
"_id": ObjectId("570c04a4ad233577f97dc459"),
"studentsEnrolled": 1034,
"location": { state: "NY", city: "New York" }
}
)
###为嵌入式字段state创建索引
db.zips.createIndex( { "location.state": 1 },{name:'schools_location_statte_1'} )
###查看索引
db.schools.getIndexes()
[
{ v: 2, key: { _id: 1 }, name: '_id_' },
{
v: 2,
key: { 'location.state': 1 },
name: 'schools_location_statte_1'
}
]
复合索引(多列索引)
- 复合索引,也叫多列索引,也可以说是联合索引,和MySQL联合索引一样,是将>=2列以上的值合在一起做索引,一半用于多条件查询语句,或者是单个字段重复值过高。
- MongoDB复合索引的限制最多为32个列。
- 单列索引的排序不是很重要,因为就一个列,但是复合索引的排序就很重要了,直接关系到了查询的性能,根据B+tree的规则,多列索引排序方式为,按照第一个字段排序,如果第一个字段的值相同按照第二个字段排序。而MongoDB的排序方式又有略微不同,MongoDB分为降序-1和升序1进行排序,所以当复合索引排序时,首先按照userid进行升序排列,在遇到相同的userid时再根据score降序排列。所以当复合索引的第一个列相同时,第二个列的值就是相同有序的。否则第二个列就不是有序的如下图。
创建复合索引
db.zips.createIndex( { "city": 1, "pop": 1 } )
###查询索引类型
[
{ v: 2, key: { _id: 1 }, name: '_id_' },
{ v: 2, key: { city: 1, pop: 1 }, name: 'city_1_pop_1' }
]
- 复合索引的查询前缀:上方支持使用find( { city: “xxx” } )或者find( { city: “xxxx”, pop: { $gt: xx } } ),也就是说MongoDB的索引依然需要遵循最左原则。
多键索引
- 多建索引是在数组列上,为数组列中的值进行创建的。MongoDB会为每个数组中的唯一元素,创建索引,但是如果数组中有多个值相同,那么索引中也只会保留他们其中的一个元素。
- 如果创建索引时,字段是数组类型,MongoDB会自动创建多键索引,无需额外指定多键索引的类型。
- 多建索引包含、多键唯一索引、多键复合索引、以及多键单列索引。
创建单列多键索引
- 多建单列索引语法
db.coll.createIndex( { <field>: < 1 or -1 > } )
- 多键复合索引语法
db.coll.createIndex( { <field>: < 1 or -1 > , <field>: < 1 or -1 >} )
- 多键唯一索引语法
db.coll.createIndex( { <field>: < 1 or -1 >},{ unique: true } )
请注意:创建多键复合索引时,不可以是两个数组字段。如a:[1,2,3],b:[1,2,3],a和b两个列都是数组,无法一起创建多键索引。
地理空间索引
- 地理空间索引,用于加速地理空间数据的查询,MongoDB将我们的省份、城市、经纬等信息进行创建索引,例如通过省份范围查找城市、区域等,运用到实际生活中,就是通过地图查找附近5公里内的餐厅等信息。
- MongoDB通过R-tree数据结构存储地理空间索引,R树是一种多维的索引结构,适合存储多个维度的数据。与B-tree最大的不同点,是R-tree的数据节点的每个数据,都包含多个指向不同的数据的指针。而B-tree只是指向左右两条数据的指针。根绝R-tree这种矩阵式指针的特性,是比较适合做地理空间索引的。
- MongoDB的地理空间索引分为两种,2dsphere和2d
- 2d主要用于处理二维平面上的点,适用于需要在二维平面上进行空间查询的场景。它不考虑地球的曲率,因此更适合用于平面地图或时间连续数据等不需要考虑地球曲率的场景。
- 2dsphere,则考虑了地球的曲率,适用于地球表面类型的地图。它允许使用GeoJSON格式指定点、线和多边形,提供了更准确的距离处理,如计算两个城市之间的距离。2dsphere索引基于WGS84基准,将地球表面模拟成一个扁球体,因此在两极地区会比较扁。这种索引考虑了地球的形状,提供了比2d索引更准确的距离计算。
- 语法介绍
db.collection.createIndex( { <location field> : "2dsphere" } )
db.collection.createIndex( { <location field> : "2d" } )
创建地理空间索引
1.插入一批测试数据
db.places.insertMany( [
{
name: "Central Park",
location: { type: "Point", coordinates: [ -73.97, 40.77 ] },
category: "Parks"
},
{
name: "Sara D. Roosevelt Park",
location: { type: "Point", coordinates: [ -73.9928, 40.7193 ] },
category: "Parks"
},
{
name: "Polo Grounds",
location: { type: "Point", coordinates: [ -73.9375, 40.8303 ] },
category: "Stadiums"
}
] )
2.根据location创建一个2dsphere地理空间索引
db.places.createIndex( { location: "2dsphere" } )
Enterprise mongodb_test> db.places.getIndexes()
[
{ v: 2, key: { _id: 1 }, name: '_id_' },
{
v: 2,
key: { location: '2dsphere' },
name: 'location_2dsphere',
'2dsphereIndexVersion': 3
}
]
3.使用near操作符,返回指定地址,1km–5km范围内的数据。
db.places.find(
{
location:
{ $near:
{
$geometry: { type: "Point", coordinates: [ -73.9667, 40.78 ] },
$minDistance: 1000,
$maxDistance: 5000
}
}
}
)
- 对location字段进行过滤,过滤使用到near操作符
- near表示指定地理空间查询要按从最近到最远的顺序为其返回文档的点。$near 操作符可以指定一个 GeoJSON 点或旧版坐标点。
- near中通过geometry,返回指定范围的数据,minDistance表示最小为1000米,maxDistance表示最大为5000米
4.根据一个地址的经纬,查询category为"Parks" 的值,从近到远的数据有哪些,并且输出距离
db.places.aggregate( [
{
$geoNear: {
near: { type: "Point", coordinates: [ -73.9667, 40.78 ] },
spherical: true,
query: { category: "Parks" },
distanceField: "calcDistance"
}
}
] )
...
[
{
_id: ObjectId('66ea72311106849c315e739c'),
name: 'Central Park',
location: { type: 'Point', coordinates: [ -73.97, 40.77 ] },
category: 'Parks',
calcDistance: 1147.4220523120937
},
{
_id: ObjectId('66ea72311106849c315e739d'),
name: 'Sara D. Roosevelt Park',
location: { type: 'Point', coordinates: [ -73.9928, 40.7193 ] },
category: 'Parks',
calcDistance: 7106.506152782792
}
]
- geoNear按距离指定点最近到最远的顺序输出文档。
- near指定一个位置信息
- spherical为true表示MongoDB 使用 $nearSphere 语义,并使用球面几何计算距离。为flase表示MongoDB 使用 $near 语义:2dsphere 索引用于球面,2d 索引用于平面。
- query过滤条件为category字段为Parks的数据
- distanceField表示,指定包含计算出的距离的字段。
文本搜索索引
- 文本搜索索引(text),顾名思义,就是类似ES数据库的文本搜索,也可以进行分词搜索。
- 一个集合上面只能存在一个文本索引( MongoDB Atlas 可以多个)
- 文本搜索索引,通过$text操作符进行查询搜索数据,但是通配符索引不支持使用text操作符,虽然通配符文本索引和通配符索引共享通配符$**字段模式,但它们是不同的索引类型。 只有通配符文本索引支持$text操作符
- 语法介绍
###创建索引
db.collection.createIndex( { <field1> : "text" , <field2> : "text" } )
###搜索数据
{
$text: {
$search: <string>,
$language: <string>,
$caseSensitive: <boolean>,
$diacriticSensitive: <boolean>
}
}
###在多个字段创建文本索引,使用通配符创建
db.collection.createIndex( { "$**": "text" } )
Hash索引
- hash索引只支持等值查询,不支持范围查询。并且不能增加唯一性的限制。
- 可以在同一个列上,额外创建一个非hash索引,这样MongoDB对于范围查询时自动选择非hash索引了。
- 一般情况在使用MongoDB分片的时候,可以使用到Hash索引。
- 语法介绍
db.collection.createIndex( { _id: "hashed" } )
###复合hash索引
db.collection.createIndex( { "fieldA" : 1, "fieldB" : "hashed", "fieldC" : -1 } )
索引属性
- 上面介绍完了索引的种类,索引还分为几种属性,分别是唯一索引、部分索引、稀疏索引、TTL索引、以及隐藏索引(4.4版本以后)
索引属性 | 索引属性介绍 | 属性关键字 | 属性的值 |
---|---|---|---|
唯一索引 | 唯一索引顾名思义,当对唯一索引字段插入重复数据时,会被MongoDB所拒绝,MongoDB唯一索引也是可以存在null值得,在插入数据时唯一索引字段为空,唯一索引字段会为这行文档增加一个null值,但是整个集合也就允许这一个null值,下次再遇到null值就不符合唯一索引得约束,所以会被MongoDB拒绝 | unique | 默认值:false,可选值:true |
部分索引 | 部分索引,仅对集合中符合指定过滤条件得文档,进行创建索引,因此部分索引得存储要求更低,索引创建和维护得成本也就更低。 | partialFilterExpression | 指定语句得过滤条件:如:db.restaurants.createIndex( { cuisine: 1, name: 1 }, { partialFilterExpression: { rating: { $gt: 5 } } }) |
稀疏索引 | 稀疏索引会跳过所有不包含索引键得文档,如果索引字段得值为空,那么会为他存储一个null值。 | sparse | 默认值:flase,可选择值:true |
TTL索引 | TTL是一个特殊得索引属性,可以通过设置指定得过期时间,文档在达到过期事件后MongoDB,会自动删除这个文档。 | expireAfterSeconds | [0-2147483647]秒,到达指定秒树后文档删除,0表示永远不过期 |
隐藏索引 | 隐藏索引对查询规划期不可见,也无法使用这个索引,通过向规划期隐藏索引,用户可以评估在不删除索引的情况下,看出删除索引后的潜在影响,如果一旦需要这个索引,取消隐藏即可,无需重新创建。 | hidden,ratings | hidden在创建索引时指定隐藏索引,值为true表示隐藏; ratings表示对已有索引进行隐藏, 使用语句db.restaurants.hideIndex( { borough: 1, ratings: 1 } )隐藏borough列这个索引 |