MongoDB索引

MongoDB索引

一、Mongo语句分析

为集合选择合适的索引是提高性能的途径之一,但是在搞明白如何正确使用索引之前必须知道一条Mongo语句是如何被执行的。

使用 db.collection.find().explain() 可以查看MongoDB在查询过程中做的事情。该语句并不会真的去执行Mongo语句,而是针对语句进行执行计划分析并选出最优计划。

  • 栗子
db.order_data.find().explain()
{
	"queryPlanner" : {
		"plannerVersion" : 1,
		"namespace" : "order_data.order_data",
		"indexFilterSet" : false,
		"parsedQuery" : {
			
		},
		"winningPlan" : {
			"stage" : "COLLSCAN",
			"direction" : "forward"
		},
		"rejectedPlans" : [ ]
	},
	"serverInfo" : {
		"host" : "localhost",
		"port" : 27017,
		"version" : "4.0.9",
		"gitVersion" : "fc525e2d9b0e4bceff5c2201457e564362909765"
	},
	"ok" : 1
}
可以看到这个查询分析大致分为三个部分
{
    "queryPlanner" : {},
    "serverInfo" : {},
    "ok" : 1
}
参数含义描述
queryPlanner查询计划
queryPlanner.plannerVersion查询计划版本
queryPlanner.namespace要查询的集合
queryPlanner.indexFilterSet是否使用索引过滤器
queryPlanner.parsedQuery解析查询由于本例未指定查询条件故为空
queryPlanner.winningPlan查询优化器选择的查询计划一般来说一个索引能精确匹配一个查询,那么查询优化器就会使用这个索引,即该参数描述的是查询优化器最终选择的查询计划
queryPlanner.winningPlan.stage最优查询计划的阶段这个翻译有些生硬,但是我们看到这个参数的值就不难理解了,本例中为"COLLSCAN",即全集合扫描(一看就不是什么好stage),这个值非常重要并且拥有多个模式,将在后文中进行详解
queryPlanner.winningPlan.direction语句查询顺序本例子未指定升序/降序,默认为升序(修改时间)
queryPlanner.rejectedPlans查询优化器放弃的查询计划如果好几个索引适合一条查询,那么查询优化器会并行这些查询计划,最早返回100个结果的即为优胜的查询计划,其他计划即为rejectedPlans,本例中没有被终止的查询计划所以为空
serverInfo服务器信息
serverInfo.host主机
serverInfo.port端口号
serverInfo.versionMongoDB版本号
serverInfo.gitVersiongit版本信息
ok说明这个查询计划是没毛病的

db.collection.find().explain()有三个参数(默认是queryPlanner),分别是

  • queryPlanner 概要模式

  • executionStats 执行状态模式

  • allPlansExecution 所有信息模式

  • 栗子

db.order_data.find().explain('queryPlanner')
重点关注下条语句
db.order_data.find().explain('executionStats')
{
	"queryPlanner" : {
		"plannerVersion" : 1,
		"namespace" : "order_data.order_data",
		"indexFilterSet" : false,
		"parsedQuery" : {
			
		},
		"winningPlan" : {
			"stage" : "COLLSCAN",
			"direction" : "forward"
		},
		"rejectedPlans" : [ ]
	},
	"executionStats" : {
		"executionSuccess" : true,
		"nReturned" : 61759,
		"executionTimeMillis" : 26,
		"totalKeysExamined" : 0,
		"totalDocsExamined" : 61759,
		"executionStages" : {
			"stage" : "COLLSCAN",
			"nReturned" : 61759,
			"executionTimeMillisEstimate" : 20,
			"works" : 61761,
			"advanced" : 61759,
			"needTime" : 1,
			"needYield" : 0,
			"saveState" : 482,
			"restoreState" : 482,
			"isEOF" : 1,
			"invalidates" : 0,
			"direction" : "forward",
			"docsExamined" : 61759
		}
	},
	"serverInfo" : {
		"host" : "localhost",
		"port" : 27017,
		"version" : "4.0.9",
		"gitVersion" : "fc525e2d9b0e4bceff5c2201457e564362909765"
	},
	"ok" : 1
}

参数含义描述
executionStats查询计划
executionStats.executionSuccess语句执行结果
executionStats.nReturned返回的集合数量
executionStats.executionTimeMillis执行耗时(单位:毫秒)
executionStats.totalKeysExamined扫描的总索引条目数
executionStats.totalDocsExamined查询执行期间检查的总文档数
executionStats.executionStages最优查询计划完成执行细节阶段树
executionStats.executionStages.stage最优查询计划的阶段
executionStats.executionStages.nReturned返回的集合数量
executionStats.executionStages.executionTimeMillisEstimate预估执行耗时(单位:毫秒)
executionStats.executionStages.works查询执行阶段执行的“工作单元”的数量查询执行阶段将其工作分为小的“工作单元”。“工作单元”可能包括检查单个索引键,从集合中提取单个文档,将投影应用于单个文档或执行内部记账。
executionStats.executionStages.advanced返回到父阶段的结果数
executionStats.executionStages.needTime未将中间结果推进到其父级的工作循环数
executionStats.executionStages.needYield本次查询暂停的次数为了能让写入的请求顺利执行,查询会周期性地释放它的锁,本例中没有写入,所以查询没有暂停过
executionStats.executionStages.saveState查询阶段挂起处理并保存其当前执行状态的次数
executionStats.executionStages.restoreState查询阶段恢复保存的执行状态的次数
executionStats.executionStages.isEOF执行阶段是否已到达流的结尾
executionStats.executionStages.invalidates我猜是在查询期间被删除的文档
executionStats.executionStages.direction语句查询顺序
executionStats.executionStages.docsExamined指定在查询执行阶段扫描的文档数
db.order_data.find().explain('allPlansExecution')
{
	"queryPlanner" : {
		"plannerVersion" : 1,
		"namespace" : "order_data.order_data",
		"indexFilterSet" : false,
		"parsedQuery" : {
			
		},
		"winningPlan" : {
			"stage" : "COLLSCAN",
			"direction" : "forward"
		},
		"rejectedPlans" : [ ]
	},
	"executionStats" : {
		"executionSuccess" : true,
		"nReturned" : 62162,
		"executionTimeMillis" : 27,
		"totalKeysExamined" : 0,
		"totalDocsExamined" : 62162,
		"executionStages" : {
			"stage" : "COLLSCAN",
			"nReturned" : 62162,
			"executionTimeMillisEstimate" : 20,
			"works" : 62164,
			"advanced" : 62162,
			"needTime" : 1,
			"needYield" : 0,
			"saveState" : 485,
			"restoreState" : 485,
			"isEOF" : 1,
			"invalidates" : 0,
			"direction" : "forward",
			"docsExamined" : 62162
		},
		"allPlansExecution" : [ ]
	},
	"serverInfo" : {
		"host" : "localhost",
		"port" : 27017,
		"version" : "4.0.9",
		"gitVersion" : "fc525e2d9b0e4bceff5c2201457e564362909765"
	},
	"ok" : 1
}
参数含义描述
executionStats.executionStats.allPlansExecution所有查询计划执行情况本例中没有被终止的查询计划
这里我们截取几个对性能分析比较直观的参数
  • executionStats.executionTimeMillis 执行耗时(单位:毫秒)
  • executionStats.totalKeysExamined 扫描的总索引条目数
  • executionStats.totalDocsExamined 查询执行期间检查的总文档数
  • executionStats.executionStages.stage
我们可以用以下方式直接查询我们需要的参数
db.order_data.find().explain('executionStats').executionStats.executionTimeMillis
30

二、MongoDB索引

1、索引操作

使用 db.collection.getIndexes() 可以查看该集合中建立了哪些索引
  • 栗子
db.order_data.getIndexes()
[
	{
		"v" : 2,
		"key" : {
			"_id" : 1
		},
		"name" : "_id_",
		"ns" : "order_data.order_data"
	},
	{
		"v" : 2,
		"key" : {
			"hotel_id" : 1
		},
		"name" : "hotel_id_1",
		"ns" : "order_data.order_data",
		"background" : true
	},
	{
		"v" : 2,
		"key" : {
			"channel_id" : 1
		},
		"name" : "channel_id_1",
		"ns" : "order_data.order_data",
		"background" : true
	},
	{
		"v" : 2,
		"key" : {
			"check_in_date" : -1
		},
		"name" : "check_in_date_-1",
		"ns" : "order_data.order_data",
		"background" : true
	},
	{
		"v" : 2,
		"key" : {
			"check_out_date" : -1
		},
		"name" : "check_out_date_-1",
		"ns" : "order_data.order_data",
		"background" : true
	},
	{
		"v" : 2,
		"key" : {
			"newest" : 1
		},
		"name" : "newest_1",
		"ns" : "order_data.order_data",
		"background" : true
	},
	{
		"v" : 2,
		"key" : {
			"book_flow" : 1
		},
		"name" : "book_flow_1",
		"ns" : "order_data.order_data",
		"background" : true
	},
	{
		"v" : 2,
		"key" : {
			"order_id" : 1
		},
		"name" : "order_id_1",
		"ns" : "order_data.order_data",
		"background" : true
	},
	{
		"v" : 2,
		"key" : {
			"order_status_key" : 1
		},
		"name" : "order_status_key_1",
		"ns" : "order_data.order_data",
		"background" : true
	},
	{
		"v" : 2,
		"key" : {
			"num_person" : 1
		},
		"name" : "num_person_1",
		"ns" : "order_data.order_data",
		"background" : true
	},
	{
		"v" : 2,
		"key" : {
			"rent_price" : 1
		},
		"name" : "rent_price_1",
		"ns" : "order_data.order_data",
		"background" : true
	}
]

使用 db.collection.createIndex({“key”:1}) 可以创建创建一个普通索引
  • 栗子
db.order_data.createIndex({"order_id":1})
{
	"createdCollectionAutomatically" : false,
	"numIndexesBefore" : 1,
	"numIndexesAfter" : 2,
	"ok" : 1
}
使用 db.collection.dropIndex() 可以删除指定索引
  • 栗子
db.order_data.dropIndex("order_id_1")
{ "nIndexesWas" : 2, "ok" : 1 }
使用 db.collection.dropIndexes() 可以删除所有索引
  • 栗子
db.order_data.dropIndexes()
{
	"nIndexesWas" : 14,
	"msg" : "non-_id indexes dropped for collection",
	"ok" : 1
}
但是无论怎么删都是无法删除_id建立的索引

2、索引类型

普通索引
普通索引也被称为单键索引,是MongoDB索引中最普通的索引,使用方式在索引基本操作中已经介绍了,这里不再赘述。值得一提的是 db.collection.createIndex({“key”:1}) 中key的值,使用"1"代表升序,使用"-1"代表降序。
[
    {
		"v" : 2,
		"key" : {
			"check_in_date" : -1
		},
		"name" : "check_in_date_-1",
		"ns" : "order_data.order_data",
		"background" : true
	},
	{
		"v" : 2,
		"key" : {
			"check_out_date" : -1
		},
		"name" : "check_out_date_-1",
		"ns" : "order_data.order_data",
		"background" : true
	}
]
这是刚才索引操作中的栗子,根据查询订单入离时间建立的倒序普通索引,依照需求,查询的订单往往都是下单时间离现在比较近的,也就是说在大部分场景下的查询倒序可以更快的返回我们需要的结果。
唯一索引
唯一索引顾名思义,可以确保集合中每个文档的指定键都是唯一的,最最典型的就是"_id"字段,可以使用 db.collection.createIndex({“key”:1},{“unique”:true}) 创建。
  • 一个栗子
db.order_data.createIndex({"order_id":1},{"unique":true})
复合索引
使用 db.collection.createIndex({“key1”:1, “key2”:1}) 就创建了复合索引,当然如果加上唯一限制 db.collection.createIndex({“key1”:1, “key2”:1},{“unique”:true}) 就变成了复合唯一索引
  • 栗子(复合索引)
db.order_data.createIndex({"channel":1, "order_id":1})
  • 栗子(复合唯一索引)
db.order_data.createIndex({"channel":1, "order_id":1},{"unique":true})
讲到这里顺便一提隐式索引
如果你创建了一个形如…{“a”:1},{“b”:1},{“c”:1}…的复合索引,那同时你也喜提…{“a”:1}…/…{“a”:1},{“b”:1}…
别问我…{“b”:1},{“c”:1}…和…{“a”:1},{“c”:1}…能不能用,问就不能,除非你建
地理空间索引
MongoDB支持的最常见的地理空间索引是2dsphere索引和2d索引,前者用于地球表面类型的地图(曲面),后者用于平面地图和时间连续的数据(平面),2d索引用于球体表面会出现大量的扭曲变形。
GeoJSON
  • 点,可以用形如 [longitude,latitude] ([经度,纬度])表示
{
    "name":"zhonghe",
    "loc":{
        "type":"Point",
        "coordinates":[50,2]
    }
}
  • 线,可以用一个点的数组表示(两点构成一条直线)
{
    "name":"fu River",
    "loc":{
        "type":"Line",
        "coordinates":[[5,2],[3,2]]
    }
}
  • 面,跟线类似
{
    "name":"chengdu",
    "loc":{
        "type":"Polygon",
        "coordinates":[[5,2],[3,2],[3,9]]
    }
}
建立2dsphre索引
db.city.createIndex({"loc":"2dsphere"})
地理空间查询的类型

可以使用多种不同类型的地理空间查询:交集(intersection)、包含(within)以及接近(nearness)。查询时,需要将希望查找的内容指定为形如

{"$geometry" : geoJsonDesc}

的GeoJSON对象。

现在我们试着查询一下
  • 首先造一个GeoJSON对象
var zhonghe = {
    "type":"Polygon",
    "coordinates":[
    [-73.9917900,40.7254100],
    [-73.9913900,40.7211900],
    [-73.9927900,40.7212100],
    [-73.9931100,40.7253300],
    [-73.9952200,40.7251100]
    ]
}
  • 查询和中和有交集的区域
db.city.find({"loc":{"$geoIntersects":{"$geometry":zhonghe}}})
  • 查询完全包含在中和中的区域,例如,中和有什么餐馆
db.city.find({"loc":{"$within":{"$geometry":zhonghe}}})
  • 查询中和附近的区域
db.city.find({"loc":{"$near":{"$geometry":zhonghe}}})
注:“ g e o I n t e r s e c t s " 和 " geoIntersects"和" geoIntersects""within"的使用不需要创建地理空间索引,但是”$near"需要。建议用于表示地理位置的字段都建立地理空间索引来提高查询速度。
复合地理空间索引
  • 地理空间索引可以和其他字段一起使用,例如,中和的商户类型用"tags"字段维护,我们想查询中和的KTV
db.city.createIndex({"tags":1, "location":"2dsphere"})
db.city.find({"loc":{"$within":{"$geometry":zhonghe}},"tags":"KTV"})
如果你想了解更多关于地理空间索引的内容可以点击:http://www.mongoing.com/mongodb-geo-index-1/
多键索引
对于某个索引的键,如果在某个文档中是一个数组,那么这件就会被标记为多键索引
全文索引
使用 db.collection.createIndex({“key1”:“text”}) 可以创建全文索引
使用 db.collection.createIndex({“key1”:“text”,“key2”:“text”}) 可以创建复合全文索引,与复合普通索引不一样,复合全文索引字段顺序并不重要,每个字段都被同等对待,可以为每个字段分配不同权重来控制字段的相对重要性
db.order_data.createIndex({"channel":"text","order_date":"text"},{"weights":{"channel":1,"order_date":2}})
行,这个索引就介绍这么多,主要是不支持中文
TTL索引
TTL(time to live)索引,即具有生命周期的索引,这种索引允许为每一个文档设置一个超时时间,时间一到就会被自动删除,这种索引一般用于解决缓存问题(如会话)。
  • 一个栗子
db.magazine.createIndex({"create_time":1},{"expireAfterSeconds": 3600})
{
	"createdCollectionAutomatically" : false,
	"numIndexesBefore" : 2,
	"numIndexesAfter" : 3,
	"ok" : 1
}
使用时应该注意的问题
  • TTL索引不能基于已存在的索引创建
  • TTL索引不能以非日期字段创建(可以创建成功但不会生效)
  • TTL索引不支持定长集合(固定集合,集合大小是固定的,类似循环队列,如果集合被占满,插入新文档会将最老的文档从集合中移除)
  • TTL索引不支持多字段创建(复合索引)

3、索引属性

覆盖索引
什么是覆盖索引?覆盖索引可以用来干什么?
先思考一个问题?我们使用MySQL的时候常常说不要" SELECT * ",要指定被查询的字段,那么在MongoDB中是否也是如此呢?
语句一:不指定字段
db.order_data.find({"channel_id":4}).explain("executionStats").executionStats.executionTimeMillis
语句二:指定所有字段
db.order_data.find(
	{"channel_id":4},
	{
		"_id" : 1,
		"username" : 1,
		"channel_id" : 1,
		"book_flow" : 1,
		"order_status_key" : 1,
		"hotel_id" : 1,
		"order_id" : 1,
		"landlord_id" : 1,
		"check_in_date" : 1,
		"check_out_date" : 1,
		"order_date" : 1,
		"last_update_time" : 1,
		"total_price" : 1,
		"online_pay_price" : 1,
		"rent_price" : 1,
		"clean_price" : 1,
		"damages_price" : 1,
		"online_service_price" : 1,
		"submit_mobile" : 1,
		"submit_mobile_area_code" : 1,
		"submit_name" : 1,
		"guest_name" : 1,
		"room_num" : 1,
		"num_person" : 1,
		"other_info" : 1,
		"newest" : 1,
		"crawl_time" : 1
	}
).explain("executionStats").executionStats.executionTimeMillis
对比语句一和语句二的执行时间
\语句一执行时间(单位:毫秒)语句二执行时间(单位:毫秒)
14497
24090
34290
44492
547100
64274
73774
84283
93473
103887
平均4186
  • 可以看到在MongoDB中指定字段并没有让查询速度更快,反而更慢了
语句三:随意指定一个字段
db.order_data.find(
	{"channel_id":4},
	{
		"_id" : 0,
		"order_date" : 1
	}
).explain("executionStats").executionStats.executionTimeMillis
对比三条语句执行时间对比
\语句一执行时间(单位:毫秒)语句二执行时间(单位:毫秒)语句三执行时间(单位:毫秒)
1449794
2409080
3429082
4449279
54710090
6427498
73774101
84283105
9347395
10388779
平均418690.3
  • 可以看到指定一个字段查询和指定所有字段查询没有什么区别甚至还更慢了
语句四:指定索引字段
db.order_data.find(
	{"channel_id":4},
	{
		"_id" : 0,
		"channel_id" : 1
	}
).explain("executionStats").executionStats.executionTimeMillis
\语句一执行时间(单位:毫秒)语句二执行时间(单位:毫秒)语句三执行时间(单位:毫秒)语句四执行时间(单位:毫秒)
144979426
240908023
342908222
444927923
5471009022
642749822
7377410122
8428310523
934739526
1038877924
平均418690.323.3
  • 可以看到只指定索引字段的查询速度惊人,那么这是为什么呢?
db.order_data.find(
	{"channel_id":4},
	{
		"_id" : 0,
		"channel_id" : 1
	}
).explain("executionStats")
{
	"queryPlanner" : {
		"plannerVersion" : 1,
		"namespace" : "order_data.order_data",
		"indexFilterSet" : false,
		"parsedQuery" : {
			"channel_id" : {
				"$eq" : 4
			}
		},
		"winningPlan" : {
			"stage" : "PROJECTION",
			"transformBy" : {
				"_id" : 0,
				"channel_id" : 1
			},
			"inputStage" : {
				"stage" : "IXSCAN",
				"keyPattern" : {
					"channel_id" : 1
				},
				"indexName" : "channel_id_1",
				"isMultiKey" : false,
				"multiKeyPaths" : {
					"channel_id" : [ ]
				},
				"isUnique" : false,
				"isSparse" : false,
				"isPartial" : false,
				"indexVersion" : 2,
				"direction" : "forward",
				"indexBounds" : {
					"channel_id" : [
						"[4.0, 4.0]"
					]
				}
			}
		},
		"rejectedPlans" : [ ]
	},
	"executionStats" : {
		"executionSuccess" : true,
		"nReturned" : 30722,
		"executionTimeMillis" : 23,
		"totalKeysExamined" : 30722,
		"totalDocsExamined" : 0,
		"executionStages" : {
			"stage" : "PROJECTION",
			"nReturned" : 30722,
			"executionTimeMillisEstimate" : 20,
			"works" : 30723,
			"advanced" : 30722,
			"needTime" : 0,
			"needYield" : 0,
			"saveState" : 240,
			"restoreState" : 240,
			"isEOF" : 1,
			"invalidates" : 0,
			"transformBy" : {
				"_id" : 0,
				"channel_id" : 1
			},
			"inputStage" : {
				"stage" : "IXSCAN",
				"nReturned" : 30722,
				"executionTimeMillisEstimate" : 20,
				"works" : 30723,
				"advanced" : 30722,
				"needTime" : 0,
				"needYield" : 0,
				"saveState" : 240,
				"restoreState" : 240,
				"isEOF" : 1,
				"invalidates" : 0,
				"keyPattern" : {
					"channel_id" : 1
				},
				"indexName" : "channel_id_1",
				"isMultiKey" : false,
				"multiKeyPaths" : {
					"channel_id" : [ ]
				},
				"isUnique" : false,
				"isSparse" : false,
				"isPartial" : false,
				"indexVersion" : 2,
				"direction" : "forward",
				"indexBounds" : {
					"channel_id" : [
						"[4.0, 4.0]"
					]
				},
				"keysExamined" : 30722,
				"seeks" : 1,
				"dupsTested" : 0,
				"dupsDropped" : 0,
				"seenInvalidated" : 0
			}
		}
	},
	"serverInfo" : {
		"host" : "localhost",
		"port" : 27017,
		"version" : "4.0.9",
		"gitVersion" : "fc525e2d9b0e4bceff5c2201457e564362909765"
	},
	"ok" : 1
}
  • 可以看到
...
        "totalKeysExamined" : 30722,    // 扫描的索引数量
		"totalDocsExamined" : 0,        // 扫描的文档数量
...
  • 说明这条查询语句仅仅根据索引就返回了查询的结果,并没有查询任何文档
所谓覆盖索引就是无需实际查看文档内部就能匹配查询条件和返回使用相同索引的结果
使用覆盖索引也是有条件的
  • 查询所有的字段是索引的一部分
  • 查询的所有返回字段都在同一个索引中
假设有个需求是根据渠道订单号查询入住人信息,那么给渠道订单编号和入住人信息建立一个复合索引就非常合适了。
稀疏索引
稀疏索引就是只包含有索引字段的文档的条目,跳过索引键不存在的文档
举个栗子。假如你有一张用户表,用户注册后需要实名认证(实名认证必须唯一),但是有部分用户在注册完成之后并没有实名认证,在MongoDB中该字段存储为null,有很多个null导致创建唯一索引失败了,此时使用稀疏索引可以完美解决这个问题。
db.user.createIndex({real_name_authentication:1},{"sparse":true})
后台创建索引
新建索引是一件既费时又费资源的事情,创建索引过程中,MongoDB会阻塞数据库其他操作一直到索引创建完成。如果希望MongoDB在创建索引的同时又能够处理读写请求,可以指定background后台方式创建索引。
db.user.createIndex({"key":1},{"background":true})

3、正确地使用索引

可以参照的stage组合
以下是常见stage(不全)
stagedescription
COLLSCAN集合扫描
IXSCAN索引扫描
FETCH根据索引去检索指定文档
SHARD_MERGE合并分片中结果
SHARDING_FILTER分片中过滤掉孤立文档
LIMIT使用limit 限制返回数
SORT在内存中进行了排序
PROJECTION使用 skip 进行跳过
IDHACK针对_id进行查询
COUNT利用db.coll.explain().count()之类进行count运算
COUNTSCANcount不使用Index进行count时的stage返回
COUNT_SCANcount使用了Index进行count时的stage返回
SUBPLA未使用到索引的$or查询的stage返回
TEXT使用全文索引进行查询时候的stage返回
PROJECTION限定返回字段时候stage的返回
explain() 希望看到的阶段
  • FETCH+IDHACK
  • FETCH+IXSCAN
  • LIMIT+(FETCH+IXSCAN)
  • PROJECTION+IXSCAN
  • SHARDING_FILTER+IXSCAN
  • COUNT_SCAN
explain() 不希望看到的阶段
  • COLLSCAN(全表扫描)
  • SORT(使用sort但是没有使用索引)
  • 不合理的SKIP
  • SUBPLA(不能使用索引的情形)
  • COUNTSCAN
不要使用低效率的操作符
  • 不能使用索引的操作符尽量不要使用,例如,“ w h e r e " 以 及 where"以及 where"nin”(不在什么里)等
  • 不能高效地使用索引的操作符尽量少用,例如,“ e x i s t s " ( 存 在 ) 、 " exists"(存在)、" exists""ne”(取反)、 n o t " ( 不 是 ) 以 及 范 围 查 询 的 操 作 符 ( not"(不是)以及范围查询的操作符( not"()gt,$lte)"等等
一些建议
  • 并没有一个严格的规则告诉我们如何根据数据大小、索引大小和文档大小等等因素判断什么时候使用索引有用,什么时候使用索引没用,非要有个标准可以参照下表, 实际请根据业务情况选择合适的索引
索引适用的情况索引不适用的情况
集合较大集合较小
文档较大文档较小
选择性查询非选择性查询
  • 通常,索引基数(集合中某个字段拥有不同值的数量)高的字段建立索引的价值较高
  • 绝大多数MySQL/Oracle/SQLite索引的技巧也同样适用与MongoDB
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值