最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

$ lookup中其他连接条件(使用管道)的性能严重下降

网站源码admin17浏览0评论

$ lookup中其他连接条件(使用管道)的性能严重下降

$ lookup中其他连接条件(使用管道)的性能严重下降

因此,在进行一些代码审查时,我决定通过改进这样的聚合来提高现有查询的性能:

    .aggregate([
        //difference starts here
        {
            "$lookup": {
                "from": "sessions",
                "localField": "_id",
                "foreignField": "_client",
                "as": "sessions"
            }
        },
        {
            $unwind: "$sessions"
        },
        {
            $match: {
                "sessions.deleted_at": null
            }
        },
        //difference ends here
        {
            $project: {
                name: client_name_concater,
                email: '$email',
                phone: '$phone',
                address: addressConcater,
                updated_at: '$updated_at',
            }
        }
    ]);

至此:

    .aggregate([
    //difference starts here
    {
        $lookup: {
            from: 'sessions',
            let: {
                id: "$_id"
            },
            pipeline: [
                {
                    $match: {
                        $expr: {
                            $and:
                                [
                                    {
                                        $eq: ["$_client", "$$id"]
                                    }, {
                                    $eq: ["$deleted_at", null]
                                },
                                ]
                        }
                    }
                }
            ],
            as: 'sessions'
        }
    },
    {
        $match: {
            "sessions": {$ne: []}
        }
    },
    //difference ends here
        {
            $project: {
                name: client_name_concater,
                email: '$email',
                phone: '$phone',
                address: addressConcater,
                updated_at: '$updated_at',
            }
        }
    ]);

我认为第二个选项应该更好,因为我们的阶段要少一些,但是性能上的差异却是相反的,第一个查询的平均运行时间约为40ms,另一个查询的运行时间为3.5-5秒, 100倍以上。另一个集合(会话)约有120个文档,而这个集合约有152个文档,但是即使由于数据大小而可以接受,但为什么这两者之间的区别基本上不是同一件事,我们只是添加管道中的连接条件与连接的其他主要条件。我想念什么吗?

包括的某些函数或变量大多是静态或串联的,不应影响$ lookup部分。

谢谢

编辑:

为版本1添加了查询计划:

{
        "stages": [
            {
                "$cursor": {
                    "query": {
                        "$and": [
                            {
                                "deleted_at": null
                            },
                            {}
                        ]
                    },
                    "fields": {
                        "email": 1,
                        "phone": 1,
                        "updated_at": 1,
                        "_id": 1
                    },
                    "queryPlanner": {
                        "plannerVersion": 1,
                        "namespace": "test.clients",
                        "indexFilterSet": false,
                        "parsedQuery": {
                            "deleted_at": {
                                "$eq": null
                            }
                        },
                        "winningPlan": {
                            "stage": "COLLSCAN",
                            "filter": {
                                "deleted_at": {
                                    "$eq": null
                                }
                            },
                            "direction": "forward"
                        },
                        "rejectedPlans": []
                    }
                }
            },
            {
                "$lookup": {
                    "from": "sessions",
                    "as": "sessions",
                    "localField": "_id",
                    "foreignField": "_client",
                    "unwinding": {
                        "preserveNullAndEmptyArrays": false
                    }
                }
            },
            {
                "$project": {
                    "_id": true,
                    "email": "$email",
                    "phone": "$phone",
                    "updated_at": "$updated_at"
                }
            }
        ],
        "ok": 1
    }

对于版本2:

{
        "stages": [
            {
                "$cursor": {
                    "query": {
                        "deleted_at": null
                    },
                    "fields": {
                        "email": 1,
                        "phone": 1,
                        "sessions": 1,
                        "updated_at": 1,
                        "_id": 1
                    },
                    "queryPlanner": {
                        "plannerVersion": 1,
                        "namespace": "test.clients",
                        "indexFilterSet": false,
                        "parsedQuery": {
                            "deleted_at": {
                                "$eq": null
                            }
                        },
                        "winningPlan": {
                            "stage": "COLLSCAN",
                            "filter": {
                                "deleted_at": {
                                    "$eq": null
                                }
                            },
                            "direction": "forward"
                        },
                        "rejectedPlans": []
                    }
                }
            },
            {
                "$lookup": {
                    "from": "sessions",
                    "as": "sessions",
                    "let": {
                        "id": "$_id"
                    },
                    "pipeline": [
                        {
                            "$match": {
                                "$expr": {
                                    "$and": [
                                        {
                                            "$eq": [
                                                "$_client",
                                                "$$id"
                                            ]
                                        },
                                        {
                                            "$eq": [
                                                "$deleted_at",
                                                null
                                            ]
                                        }
                                    ]
                                }
                            }
                        }
                    ]
                }
            },
            {
                "$match": {
                    "sessions": {
                        "$not": {
                            "$eq": []
                        }
                    }
                }
            },
            {
                "$project": {
                    "_id": true,
                    "email": "$email",
                    "phone": "$phone",
                    "updated_at": "$updated_at"
                }
            }
        ],
        "ok": 1
    }

注意,加入的会话集合具有某些属性,这些属性具有非常大的数据(某些导入的数据),所以我认为由于这些数据,它可能以某种方式影响查询的大小?但是,为什么两个$ lookup版本之间有区别呢?

回答如下:

第二个版本添加了聚合流水线执行对于连接的集合中的每个文档

The documentation说:

指定要在加入的集合上运行的管道。管道从联接的集合中确定生成的文档。要返回所有文档,请指定一个空管道[]。

将对集合中的每个文档而不是每个匹配的文档执行管道。

取决于集合的大小(文档数量和文档大小),这可能会花费相当长的时间。

删除限制后,管道版本跳到10秒钟以上

有道理-由于删除了限制,所有其他文档也必须为其执行聚集管道。

[聚合管道的每个文档执行可能未达到最佳化。例如,如果为每个文档设置并拆除了管道,则与[$ match]条件相比,that中的开销可能会更大。

使用一个或另一个时有没有情况?

每个加入的文档执行聚合管道可提供额外的灵活性。如果您需要这种灵活性,尽管需要考虑性能,但执行管道可能是有意义的。如果您不这样做,则使用更高效的方法是明智的。

发布评论

评论列表(0)

  1. 暂无评论