MongoDB之三:查询优化

前提:测试数据库有100万条数据,分别存放{"user":"user: 0-1000000","age:"0-100","createAt":new Date()}字段

  • 基于多个字段查询时,尽量将会用于精确查询的字段放在索引前面,范围查询字段放在索引后面。

例如: 查询小于"user: 1080"的user字段并且年龄是40岁的人。

db.foo.find({"user":{"$lt":"user: 1080"},"age":40}).hint({"age":1,"user":1})

×

db.foo.find({"user":{"$lt":"user: 1080"},"age":40}).hint({"user":1,"age":1})
  • 单、多个索引时,多字段排序应该将索引字段放置第一位,排序字段放在末尾。

例如:根据"user"字段升序,"age"字段升序:
(单字段索引)

db.foo.find().sort({"user":1,"age":1}).hint({"user":1})

×

db.foo.find().sort({"user":1,"age":1}).hint({"age":1})

(多字段索引)

db.foo.find({"age":21}).sort({"user":-1}).hint({"age":1,"user":1})

×

db.foo.find({"age":21}).sort({"user":-1}).hint({"user":1,"age":1})
  • MongoDB会对已经添加索引的字段根据你的指示进行排序,查找单个值,根据第二个字段排序不会造成性能影响。

例如:查找年龄为21岁的用户并且根据用户倒序排列:

db.foo.find({"age":21}).sort({"user":-1}).hint({"age":1,"user":1})

该索引里已经是有序的了,即便是倒序,MongoDB也会根据age字段搜索出复合条件的条目然后再逆遍历输出。
PS:db.collection.ensureIndex({"age":1,"user":1})MongoDB索引会先根据age进行升序,然后age的相同条目再会由user进行升序排序。
(-1则是倒序排序)。

  • 根据范围且要排序的查询:
    例如:查询年龄介于15-30之间并且根据user降序处理:

db.foo.find({"age":{"$gt":15,"$lt":30}}).sort({"user":-1}).hint({"age":1,"user":1})//该方法的排序操作在内存中进行。

×

db.foo.find({"age":{"$gt":15,"$ lt":30}}).sort({"user":-1}).hint({"user":1,"age":1})//该方法的排序操作不用在内存中进行。

不在内存中进行排序会慢于将排序放于内存中进行。在内存中进行大量数据排序会牺牲性能,无可厚非,但是如果数据过多(超过32MB),则MongoDB会出错,所以建议不要在内存里面进行排序;并且如果限制查询范围,MongoDB在进行几次匹配之后不再匹配索引,在这种情况下,将排序键放在前面是一个非常好的策略。

  • 根据范围且要排序且限制输出的查询:

db.foo.find({"age":{"$gt":15,"$lt":30}}).sort({"user":-1}).limit(1000).hint({"user":1,"age":1})//该方法的排序操作不在内存中进行。
//executionTimeMillis: 16
//totalKeysExamined: 8693

×

db.foo.find({"age":{"$gt":15,"$lt":30}}).sort({"user":-1}).limit(1000).hint({"age":1,"user":1})//该方法的排序操作在内存中进行。
//executionTimeMillis: 495
//totalKeysExamined: 231689

一旦限制输出条目,则查询效率跟上一个建议出现反转:
不在内存中进行排序的索引查询时间为16ms,匹配的文档为8693条;
在内存中进行排序的时间为495ms,匹配的文档为231689条。
由此可见,如果限制了返回的条目数,则不在内存中进行排序会快得多。
实际应用中,对需要范围查询的数据进行排序一般会取前面的结果,所以推荐使用{"sortKey":1,"queryCriteria":1}这种索引:
把排序键放在索引的前面键,查询条件放在索引的后面键,并且这种索引排序不会在内存中进行,且限制查询条目的时候非常有优势。
当然,如果是需要获取全部数据,使用{"queryCriteria":1,"sortKey":1},这种方式会比较快那么一丢丢,但是注意,这种方式是在内存中进行排序的,注意32MB限制。
一般情况下,推荐使用{"sortKey":1,"queryCriteria":1}索引。


总结

  • 单索引:匹配精确条件。
  • 多索引:
//有范围条件且需要排序的查询(或许还有输出条目限制),先排序再查询 --> {"sortKey":1,"queryCerteria":1}
db.foo.find({"age":{"$gt":15,"$lt":30}}).sort({"user":-1}).limit(1000).hint({"user":1,"age":1})
//精确条件且需要排序的查询,先查询后排序 --> {"queryCerteria":1,"sortKey":1}
db.foo.find({"age":21}).sort("user":-1).hint({age:1,user:1})
  • $nin总是进行全表扫描。
  • $or只有在双方的键上都单独创建了索引才会有效率。
  • {a:1,b:1.....z:1}以后,{a:1},{a:1,b:1},{a:1,b:1,c:1}等会自动生效,但是子集{b:1},{c:1},{d:1}或{a:1,c:1}等不会生效。
  • 取反$ne的效率比较低,因为要进行整个索引条目的扫描,因为除了$ne指定的条目,其他条目一样要全部扫描。
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,684评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,143评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,214评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,788评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,796评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,665评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,027评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,679评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,346评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,664评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,766评论 1 331
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,412评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,015评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,974评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,073评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,501评论 2 343

推荐阅读更多精彩内容

  • 本文包括以下几个方面: –安全措施 – 部署架构 – 系统优化 – 索引设计 – 备份监控 – 模式设计 – 程序...
    张伟科阅读 3,966评论 0 9
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,596评论 18 139
  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,573评论 18 399
  • 原文:https://my.oschina.net/liuyuantao/blog/751438 查询集API 参...
    阳光小镇少爷阅读 3,809评论 0 8
  • 世界太大 我们太小 相遇不易 相知更是万一 不求白首 只求我们相遇在最美的年华 最近在微博游走的时候偶尔发现几张图...
    游弋恶灵阅读 9,821评论 93 394