MongoDB:16-MongoDB-索引数组字段和索引子文档字段

来源:互联网 发布:淘宝直播的运营怎么做 编辑:程序博客网 时间:2024/06/06 23:58

  1. MongoDB允许深入文档内部,对嵌套字段和数组建立索引;
  2. 嵌套对象和数组字段可以和复合索引中的顶级字段一起使用,多数情况下与“正常”索引字段的行为也是一致的。
  3. 考虑以下文档集合(user ):

  1. db.user.insertMany(
  2. [
  3. {
  4. "address": {
  5. "province": "HeNan",
  6. "city": "ZhengZhou",
  7. "pincode": "123"
  8. },
  9. "tags": [
  10. "music",
  11. "cricket",
  12. "blogs"
  13. ],
  14. "name": "fly"
  15. },
  16. {
  17. "address": {
  18. "province": "HeBei",
  19. "city": "HanDan",
  20. "pincode": "234"
  21. },
  22. "tags": [
  23. "music",
  24. "basket",
  25. "blogs"
  26. ],
  27. "name": "chen"
  28. },
  29. {
  30. "address": {
  31. "province": "ChongQing",
  32. "city": "ChongQing",
  33. "pincode": "456"
  34. },
  35. "tags": [
  36. "music",
  37. "writing",
  38. "running"
  39. ],
  40. "name": "wang"
  41. }
  42. ]
  43. )

以上文档包含了 address 子文档和 tags 数组。


索引数组字段

  • 假设我们基于标签来检索用户,为此我们需要对集合中的数组 tags 建立索引。
  • 在数组中创建索引,需要对数组中的每个字段依次建立索引。所以在我们为数组 tags 创建索引时,会为 music、cricket、blogs三个值建立单独的索引。


    • 使用以下命令创建数组索引:
  1. db.user.ensureIndex({"tags":1})


    • 创建索引后,我们可以这样检索集合的 tags 字段:
  1. db.user.find({tags:"music"})

    • 为了验证我们使用使用了索引,可以使用 explain 命令:
  1. db.user.find({tags:"music"}).explain()
  1. 执行结果
  2. /* 1 */
  3. {
  4. "queryPlanner" : {
  5. "plannerVersion" : 1,
  6. "namespace" : "mongotest.user",
  7. "indexFilterSet" : false,
  8. "parsedQuery" : {
  9. "tags" : {
  10. "$eq" : "music"
  11. }
  12. },
  13. "winningPlan" : {
  14. "stage" : "FETCH",
  15. "inputStage" : {
  16. "stage" : "IXSCAN",
  17. "keyPattern" : {
  18. "tags" : 1.0
  19. },
  20. "indexName" : "tags_1",
  21. "isMultiKey" : true,
  22. "multiKeyPaths" : {
  23. "tags" : [
  24. "tags"
  25. ]
  26. },
  27. "isUnique" : false,
  28. "isSparse" : false,
  29. "isPartial" : false,
  30. "indexVersion" : 2,
  31. "direction" : "forward",
  32. "indexBounds" : {
  33. "tags" : [
  34. "[\"music\", \"music\"]"
  35. ]
  36. }
  37. }
  38. },
  39. "rejectedPlans" : []
  40. },
  41. "serverInfo" : {
  42. "host" : "kf-PC",
  43. "port" : 27017,
  44. "version" : "3.4.9",
  45. "gitVersion" : "876ebee8c7dd0e2d992f36a848ff4dc50ee6603e"
  46. },
  47. "ok" : 1.0
  48. }

  • 以上命令执行结果中会显示 "stage":"FETCH",,则表示已经使用了索引。
    1. stage的类型的意义
    2. mongodb的文档中列出了前4种类型,还有一些没有列出来,但是会比较常见,这里一并解释一下。
    3. COLLSCAN :全表扫描
    4. IXSCAN:索引扫描
    5. FETCH::根据索引去检索指定document
    6. SHARD_MERGE:各个分片返回数据进行merge
    7. SORT:表明在内存中进行了排序(与前期版本的scanAndOrder:true一致)
    8. SORT_MERGE:表明在内存中进行了排序后再合并
    9. LIMIT:使用limit限制返回数
    10. SKIP:使用skip进行跳过
    11. IDHACK:针对_id进行查询
    12. SHARDING_FILTER:通过mongos对分片数据进行查询
    13. COUNT:利用db.coll.count()之类进行count运算
    14. COUNTSCANcount不使用用Index进行count时的stage返回
    15. COUNT_SCANcount使用了Index进行count时的stage返回
    16. SUBPLA:未使用到索引的$or查询的stage返回
    17. TEXT:使用全文索引进行查询时候的stage返回
    18. 附:explain查询结果解析官方文档:
    19. https://docs.mongodb.org/v3.0/reference/explain-results/
  • 具体参考:http://blog.csdn.net/fly910905/article/details/78184302
  1. 数组上的索引
  2. 1)可以看得出在数组字段上建立索引的代价比较大,因为每次的删除,更新都会对每一个索引进行刷新,太消耗服务器的资源;
  3. 2可以针对数组字段中的某一个元素做具体的单独索引,减少索引的数量;
  • 例如,在数组字段tags中的第1个元素中的music上建立索引:
  1. db.user.ensureIndex({"tags.0.music":1})
  • 同样,只有精确匹配tags.0.music查询,上述索引才会起到索引的作用。
  1. 多键索引
  2. 如果在数组字段上创建索引,那么这个索引称为多键索引( multikey)。
  3. 多键索引用explain函数中可以看到“isMultikey”字段的值为true,多键索引比非多键索引要慢一些;


索引子文档字段

  • 假设我们需要通过city、state、pincode字段来检索文档,由于这些字段是子文档的字段,所以我们需要对子文档建立索引。
    • 为子文档的三个字段创建索引,命令如下:

  1. db.user.ensureIndex({"address.province":1,"address.city":1,"address.pincode":1})

  1. 利用这种方式可以建立任意深度的索引,例如可以在X.Y.Z.A.B.C上建立索引。
  2. 但是,针对子文档“address”上建立的索引,和建立在子文档的某个字段“address.provincey”上的索引是不同的:
  3. 1)对整个子文档上建立的索引,只会提高整个子文档的的查询速度;
  4. 也就是说只有在完全匹配子文档的查询(包括字段顺序),子文档索引才会起作用;
  5. 2)只有查询address.province字段,索引address.province才会起作用,
  6. 其他情况索引address.province不起作用;

    • 一旦创建索引,我们可以使用子文档的字段来检索数据:
  1. db.user.find({"address.province":"HeNan"})

    • 记住查询表达式必须遵循指定的索引的顺序。所以上面创建的索引将支持以下查询:
  1. db.user.find({"address.province":"HeNan","address.city":"ZhengZhou"})

    • 同样支持以下查询:

  1. db.user.find({"address.province":"HeNan","address.city":"ZhengZhou","address.pincode":"123"})
  1. 查询分析
  2. /* 1 */
  3. {
  4. "queryPlanner" : {
  5. "plannerVersion" : 1,
  6. "namespace" : "mongotest.user",
  7. "indexFilterSet" : false,
  8. "parsedQuery" : {
  9. "$and" : [
  10. {
  11. "address.city" : {
  12. "$eq" : "ZhengZhou"
  13. }
  14. },
  15. {
  16. "address.pincode" : {
  17. "$eq" : "123"
  18. }
  19. },
  20. {
  21. "address.province" : {
  22. "$eq" : "HeNan"
  23. }
  24. }
  25. ]
  26. },
  27. "winningPlan" : {
  28. "stage" : "FETCH",
  29. "inputStage" : {
  30. "stage" : "IXSCAN",
  31. "keyPattern" : {
  32. "address.province" : 1.0,
  33. "address.city" : 1.0,
  34. "address.pincode" : 1.0
  35. },
  36. "indexName" : "address.province_1_address.city_1_address.pincode_1",
  37. "isMultiKey" : false,
  38. "multiKeyPaths" : {
  39. "address.province" : [],
  40. "address.city" : [],
  41. "address.pincode" : []
  42. },
  43. "isUnique" : false,
  44. "isSparse" : false,
  45. "isPartial" : false,
  46. "indexVersion" : 2,
  47. "direction" : "forward",
  48. "indexBounds" : {
  49. "address.province" : [
  50. "[\"HeNan\", \"HeNan\"]"
  51. ],
  52. "address.city" : [
  53. "[\"ZhengZhou\", \"ZhengZhou\"]"
  54. ],
  55. "address.pincode" : [
  56. "[\"123\", \"123\"]"
  57. ]
  58. }
  59. }
  60. },
  61. "rejectedPlans" : []
  62. },
  63. "serverInfo" : {
  64. "host" : "kf-PC",
  65. "port" : 27017,
  66. "version" : "3.4.9",
  67. "gitVersion" : "876ebee8c7dd0e2d992f36a848ff4dc50ee6603e"
  68. },
  69. "ok" : 1.0
  70. }

参考来源: http://www.runoob.com/mongodb/mongodb-advanced-indexing.html

参考来源:http://281816327.blog.51cto.com/907015/1601473