如何优化mongoDB查询?

 书友73892718 发布于 2023-01-09 13:39

我在mongoDB中有以下示例文档.

  {
    "location" : {
                "language" : null,
                "country" : "null",
                "city" : "null",
                "state" : null,
                "continent" : "null",
                "latitude" : "null",
                "longitude" : "null"
         },
    "request" : [
                 {
                  "referrer" : "direct",
                  "url" : "http://www.google.com/"
                  "title" : "index page"
                  "currentVisit" : "1401282897"
                  "visitedTime" : "1401282905"
                 },

                 {
                 "referrer" : "direct",
                 "url" : "http://www.stackoverflow.com/",
                 "title" : "index page"
                 "currentVisit" : "1401282900"
                 "visitedTime" : "1401282905"
                 },
           ......
               ]
    "uuid" : "109eeee0-e66a-11e3"
}

注意:

    该数据库包含多个10845文档

    每个文档包含几乎100请求(请求数组中的100个对象).

    技术/语言 - node.js

    我不得不setProfiling检查执行时间

    First Query - 13899ms
    Second Query - 9024ms 
    Third Query - 8310ms
    Fourth Query - 6858ms
    

    使用索引没有太大区别

查询:

我正在aggregation queries执行以下操作来获取数据.

 var match = {"request.currentVisit":{$gte:core.getTime()[1].toString(),$lte:core.getTime()[0].toString()}};

For Example: var match = {"request.currentVisit":{$ gte:"1401282905",$ lte:"1401282935"}};

对于第三和第四个查询request.visitedTime而不是request.currentVisit

    第一

    [
        { "$project":{
            "request.currentVisit":1,
            "request.url":1
        }},
       { "$match":{
           "request.1": {$exists:true}
       }},
       { "$unwind": "$request" },
       { "$match": match },
       { "$group": { 
           "_id": {
               "url":"$request.url"
           },
           "count": { "$sum": 1 }
       }},
       { "$sort":{ "count": -1 } }
    ]
    

    第二

    [
        { "$project": {
            "request.currentVisit":1,
            "request.url":1
        }},
        { "$match": {  
            "request":{ "$size": 1 }
        }},
        { "$unwind": "$request" },
        { "$match": match },
        { "$group": {
            "_id":{ 
                "url":"$request.url"
            },
            "count":{ "$sum": 1 }
        }},
        { "$sort": { "count": -1} }
    ]
    

    第三

    [
        { "$project": {
             "request.visitedTime":1,
             "uuid":1
        }},
        { "$match":{
            "request.1": { "$exists": true } 
        }},
        { "$match": match },
        { "$group": {
             "_id": "$uuid",
             "count":{ "$sum": 1 }
        }},
        { "$group": {
            "_id": null,
            "total": { "$sum":"$count" }}
        }}
    ]
    

    向前

    [
        { "$project": {
            "request.visitedTime":1,
            "uuid":1
        }},
        { "$match":{
            "request":{ "$size": 1 }
        }},
        { "$match": match },
        { "$group": {
           "_id":"$uuid",
           "count":{ "$sum": 1 }
       }},
       { "$group": {
           "_id":null,
           "total": { "$sum": "$count" }
       }}
    ]
    

问题:

它不仅仅是38091 ms获取数据.

有没有办法优化查询?

任何建议都将不胜感激.

1 个回答
  • 那么有一些问题,你肯定需要索引,但你不能有复合的.它是您要在索引的数组中查询的"时间戳"值.还建议您将这些转换为数值而不是当前字符串,或者实际转换为BSON日期类型.后一种形式实际上在内部存储为数字时间戳值,因此存在通常的存储大小减少,这也减小了索引大小以及更有效地匹配数值.

    每个查询的一个大问题是,您在处理完后$unwind随后"过滤"匹配时,总是会潜入"数组"内容.虽然这是您想要为结果做的事情,但由于您没有在早期阶段应用相同的过滤器,因此当您在管道中有许多文档与这些条件不匹配时$unwind.结果是在此阶段您不需要处理的"大量"文档.在这里你不能使用索引.

    您需要此匹配的位置是管道阶段的开始.在过滤实际数组之前,这会将文档缩小为"可能的"匹配.

    所以以第一个为例:

    [
       { "$match":{
           { "request.currentVisit":{ 
               "$gte":"1401282905", "$lte": "1401282935"
           }
       }},
       { "$unwind": "$request" },
       { "$match":{
           { "request.currentVisit":{ 
               "$gte":"1401282905", "$lte": "1401282935"
           }
       }},
       { "$group": { 
           "_id": {
               "url":"$request.url"
           },
           "count": { "$sum": 1 }
       }},
       { "$sort":{ "count": -1 } }
    ]
    

    所以有一些变化.$match 管道的头部有一个.这会缩小文档范围并能够使用索引.这是最重要的性能考虑因素.黄金法则,始终 "匹配"第一.

    $project你不得不在有多余的,因为你不能计划"只是"一个数组是尚未解开的领域.还有一种误解,认为人们$project首先要减少管道.如果事实上有一个实际上限制字段的后来$project$group语句,那么效果是非常小的,那么这将是"前向优化的",所以事情确实会从管道处理中取出.$match上面的陈述仍然需要更多优化.

    不需要查看数组是否实际存在于另一个$match阶段,因为您现在在管道开始时"隐式地"执行此操作.如果更多条件使您更舒服,则将它们添加到初始管道阶段.

    其余的保持不变,就像你接下来$unwind的数组一样,$match在继续进行剩余处理之前过滤你真正想要的项目.到目前为止,输入文档已经大大减少或减少了.

    您可以使用MongoDB 2.6及更高版本执行的另一个选择是在您甚至**之前"过滤"数组内容$unwind它.这会产生这样的列表:

    [
       { "$match":{
           { "request.currentVisit":{ 
               "$gte":"1401282905", "$lte": "1401282935"
           }
       }},
       { "$project": {
           "request": {
               "$setDifference": [
                   { 
                       "$map": {
                           "input": "$request",
                           "as": "el",
                           "in": {
                               "$cond"": [
                                   {
                                       "$and":[
                                           { "$gte": [ "1401282905", "$$el.currentVisit" ] },
                                           { "$lt": [ "1401282935", "$$el.currentVisit" ] }
                                       ]
                                   }
                                   "$el",
                                   false
                               ]
                           }
                       }
                   }
                   [false]
               ]
           }
       }}
       { "$unwind": "$request" },
       { "$group": { 
           "_id": {
               "url":"$request.url"
           },
           "count": { "$sum": 1 }
       }},
       { "$sort":{ "count": -1 } }
    ]
    

    这可以通过能够在之前"过滤"数组来节省一些,并且$unwind可能比$match之后更好.

    但这是所有陈述的一般规则.你需要使用的索引,你需要.$match

    您可能会在单个查询中获得您真正想要的实际结果,但就目前而言,您的问题并非如此.尝试按照概述更改处理,您应该看到显着的改进.

    如果你仍然试图接受这可能是单数的方式,那么你总是可以提出另一个问题.

    2023-01-09 13:41 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有