Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/mysql/68.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
MongoDB聚合查询与MySQL从表中选择字段1_Mysql_Mongodb_Aggregate - Fatal编程技术网

MongoDB聚合查询与MySQL从表中选择字段1

MongoDB聚合查询与MySQL从表中选择字段1,mysql,mongodb,aggregate,Mysql,Mongodb,Aggregate,我是MongoDB的新手,我想比较NoSQL数据模型相对于其关系数据库计数器部分的查询性能。我把这个写进了MongoDB shell // Make 10 businesses // Each business has 10 locations // Each location has 10 departments // Each department has 10 teams // Each team has 100 employees (new Array(10)).fill(0).forE

我是MongoDB的新手,我想比较NoSQL数据模型相对于其关系数据库计数器部分的查询性能。我把这个写进了MongoDB shell

// Make 10 businesses
// Each business has 10 locations
// Each location has 10 departments
// Each department has 10 teams
// Each team has 100 employees
(new Array(10)).fill(0).forEach(_=>
    db.businesses.insert({
        "name":"Business Name",
        "locations":(new Array(10)).fill(0).map(_=>({
            "name":"Office Location",
            "departments":(new Array(10)).fill(0).map(_=>({
                "name":"Department",
                "teams":(new Array(10)).fill(0).map(_=>({
                    "name":"Team Name",
                    "employees":(new Array(100)).fill(0).map(_=>({
                        "age":Math.floor(Math.random()*100)
                    }))
                }))
            }))
        }))
    })
);
然后,我尝试从年龄>=50 ORDER BY age DESC的员工那里使用MySQL的
EXPLAIN SELECT age、name(和一些其他字段)来解释以下语句:

db.businesses.aggregate([
    { $unwind: "$locations" },
    { $unwind: "$locations.departments" },
    { $unwind: "$locations.departments.teams" },
    { $unwind: "$locations.departments.teams.employees" },
    { $project: { _id: 0, age: "$locations.departments.teams.employees.age" } },
    { $match: { "age": { $gte: 50 }} },
    { $sort: {"age" : -1}}
]).explain("executionStats")
结果是:

“errmsg”:“排序超出了104857600字节的内存限制,但未超过。” 选择加入外部排序。正在中止操作。传递allowDiskUse:true 选择加入。”

因此,我删除了sort子句,并尝试获取一个
explain
。但结果是:

TypeError:db.Businesss.aggregate(…).explain不是函数

因此,我的问题是:

  • 首先,我想知道与MongoDB的聚合查询计数器部分相比,
    SELECT age与age>=50 ORDER BY age DESC的员工的性能差异。差不多吧?其中一个会比另一个更快或性能更好吗

  • 或者,我如何修复MongoDB查询,以便获得性能详细信息,与MySQL查询计数器部分进行比较


  • 通过如下修改查询,我能够在1.5秒内获得结果,而无需任何索引:

    db.businesss.aggregate([
    {
    $展开:“$位置”
    },
    {
    $展开:“$位置.部门”
    },
    {
    $unwind:“$地点、部门、团队”
    },
    {
    $REWIND:“$地点、部门、团队、员工”
    },
    {
    $match:{
    “地点、部门、团队、员工、年龄”:{
    $gte:50
    }
    }
    },
    {
    $项目:{
    _id:0,
    年龄:“$地点、部门、团队、员工、年龄”
    }
    },
    {
    $group:{
    _id:“$age”
    }
    },
    {
    $项目:{
    _id:0,
    年龄:“$\u id”
    }
    },
    {
    $sort:{
    “年龄”:-1
    }
    }
    ], {
    解释:错
    })
    
    员工是单一实体;因此,您可能不想在部门、地点和团队的丰富结构中对团队成员的年龄进行如此深入的建模。有一个单独的
    员工
    集合,只需执行以下操作即可:

    db.businesses.aggregate([
    {$match: {"age": {$gt: 50} }}
    ,{$sort: {"age": -1} }
    ]);
    
    深入您的
    业务
    收藏,您可以拥有:

    { teams: [ {name: "T1", employees: [ "E1", "E34" ]} ] }
    
    或者,尝试以下方法:

    db.businesses.aggregate([ your pipeline] ,{allowDiskUse:true});
    
    OP设置为10个业务->10个loc->10个部门->10个团队->100个EMP。前3次展开会产生10000x的数据爆炸,但最后一次是100x。我们可以使用
    $filter
    缩小命中率:

    db.businesses.aggregate([
    { $unwind: "$locations" },
    { $unwind: "$locations.departments" },
    { $unwind: "$locations.departments.teams" },
    
    {$project: {
            XX: {$filter: {
                        input: "$locations.departments.teams.employees",
                        as: "z",
                        cond: {$gte: [ "$$z.age", 50] }
                }}
        }}
    ,{$unwind: "$XX"}
    ,{$sort: {"XX.age":-1}}])
    

    您最好将
    $match
    移动到第一个管道,因为聚合框架在第一个管道之后会丢失索引,而且我猜您不需要解开这些数组。

    还有另一种方法可以解决整个问题,尽管OP问题并非完全一致。目标是找到所有年龄大于等于50岁的人并进行排序。下面是一个“几乎”这样做的例子,如果您想知道如何获得它,也会抛出
    loc、dept、team
    ,但您可以取出行来获得
    emp
    。现在,这是未排序的——但可以提出一个论点,即DB引擎在排序方面不会比客户端做得更好,而且所有数据都必须通过连接。客户机可以使用更复杂的编码技巧来挖掘
    age
    字段并对其进行排序

    c = db.foo.aggregate([
    {$project: {XX:
      {$map: {input: "$locations", as:"z", in:
              {$map: {input: "$$z.departments", as:"z2", in:
                      {$map: {input: "$$z2.teams", as:"z3", in:
                              {loc: "$$z.name",  // remove if you want
                               dept: "$$z2.name", // remove if you want
                               team: "$$z3.name",  // remove if you want
                               emps: {$filter: {input: "$$z3.employees",
                                         as: "z4",
                                         cond: {$gt: [ "$$z4.age", 50] }
                                        }}
                              }
                          }}
                  }}
          }}
        }}
    ]);
    
    ages = [];
    
    c.forEach(function(biz) {
        biz['XX'].forEach(function(locs) {
            locs.forEach(function(depts) {
                depts.forEach(function(teams) {
                    teams['emps'].forEach(function(emp) {
                        ages.push(emp['age']);
                                        });
                                });
                        });
                });
        });
    
    print( ages.sort(function(a, b){return b-a}) );
    
    99,98,97,96,95,94,92,92,84,81,78,77,76,72,71,67,66,65,65,64,63,62,62,61,59,59,57,57,57,56,55,54,52,51
    
    
    在运行MongoDB 4.0的MacBook Pro上,我们看到的系列如下:

    Collection            Count   AvgSize          Unz  Xz  +Idx     TotIdx  Idx/doc
    --------------------  ------- -------- -G--M------  --- ---- ---M------  -------
                     foo       10   2238682     22386820  4.0    0      16384    0
    
    
    考虑到0到100之间的随机年龄,每个loc/dept/team的年龄大于等于50,并且返回的字节总数约为一半,这并不奇怪。但是请注意,设置agg的总时间(不是返回所有字节)约为700毫秒

    697 millis to agg; 0.697
    found 10
    tot bytes 11536558
    

    谢谢,
    {$group:{{u id:$age}}
    有效地实现了
    按年龄分组的等效功能,对吗?这意味着,如果我的员工有一个姓名字段,那么我将无法准确地获取该员工的姓名以及他们的年龄(即,
    选择姓名,员工的年龄
    )?当我删除
    {$group:{$id:::$age}
    ,但保留在排序筛选器中时,我的mongo仍然会因内存不足而崩溃。我对MySQL没有同样的问题。在这两种情况下都没有应用索引。在我的MySQL
    选择名称中,年龄>=50的员工按姓名排序DESC
    也需要大约1秒的时间。没有应用任何指数。仍然不能让MongoDB等同于不崩溃……让员工作为单独的实体不会让我回到我最初的问题吗?这就产生了一系列的4-5个问题,让我想到了这个问题。我的实验结果是,当我使用
    {allowDiskUse:true}
    时,mongodb查询花了3秒钟。MySQL
    SELECT age FROM t_employee,其中age=>50 ORDER BY age DESC
    耗时1.2秒。我猜MySQL默认情况下不会启用
    allowDiskUse
    。两种情况下均未应用任何指数。这种情况下会出现这种结果吗?其他人也认为MongoDB比MySQL慢3倍?基于
    map
    的替代方案,以绕过最后100倍于
    employee
    的大爆炸……谢谢,使用过滤方法加上
    {allowDiskUse:true}
    ,MongoDB查询耗时2秒。从3秒开始,这是一个很好的进步!同样在您的计算机上,您的查询性能是否与MySQL相匹配?我只有postgres.:-)我也不知道为SQL建模以提高性能的“最佳”方法。我可以做4路左外连接业务->loc->部门->团队->EMP和年龄>=50的筛选,但我还没有尝试。在我的secnario中,没有连接是必要的,因为我只选择employees表中的字段,不需要引用任何其他表。所以你是