Mongodb的逻辑优化过程

本文介绍MongoDB中的查询优化过程,主要包括三个步骤:规范化树(Normoralizetree)、排序树(sorttree)和验证树(validatetree)。规范化树通过优化AND与OR表达式减少查询复杂度;排序树对查询条件进行排序,提高索引使用效率;验证树检查查询的有效性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

逻辑优化过程在关系型数据库里面, 是一个非常复杂的过程, 幸运的是, 在Mongodb里面, 到目前为止, 相对来说, 其实现还是比较简单的。该过程主要通过 CanonicalQuery 类来实现。
该过程主要包含三个方面的优化:
1、Normoralize tree;
2、sort tree;
3、 validate tree;

我们分别来看看这3个方面的优化的实现。

1. Normoralize tree

 该过程主要是针对 AND, OR的子对象的类型也是AND, OR的情况, 把他们从子节点提升到父节点。

 已如下的AND的为例子:
db.inventory.find( {
    $and : [
        { $and : [ { price : 0.99 }, { count : 99 } ] },
        { $and : [ { sale : true }, { qty : 20} ] }
    ]
} )

此时的MatchExpression, 应该为如下的结构:
这里写图片描述
经过Normalize以后, 应该把AND of AND类型的节点提升到父节点的兄弟节点, 如下:
这里写图片描述
从上面两幅图的对比, 比较直观的看到, 节点数变少, 层数也变少了。 我们看一下代码:

MatchExpression* CanonicalQuery::normalizeTree(MatchExpression* root) {
    // root->isLogical() is true now.  We care about AND, OR, and NOT. NOR currently scares us.
    if (MatchExpression::AND == root->matchType() || MatchExpression::OR == root->matchType()) {
        // We could have AND of AND of AND.  Make sure we clean up our children before merging
        // them.
        // UNITTEST 11738048
        for (size_t i = 0; i < root->getChildVector()->size(); ++i) {
            (*root->getChildVector())[i] = normalizeTree(root->getChild(i));
        }

        // If any of our children are of the same logical operator that we are, we remove the
        // child's children and append them to ourselves after we examine all children.
        std::vector<MatchExpression*> absorbedChildren;

        for (size_t i = 0; i < root->numChildren();) {
            MatchExpression* child = root->getChild(i);
            if (child->matchType() == root->matchType()) {
                // AND of an AND or OR of an OR.  Absorb child's children into ourself.
                for (size_t j = 0; j < child->numChildren(); ++j) {
                    absorbedChildren.push_back(child->getChild(j));
                }
                // TODO(opt): this is possibly n^2-ish
                root->getChildVector()->erase(root->getChildVector()->begin() + i);
                child->getChildVector()->clear();
                // Note that this only works because we cleared the child's children
                delete child;
                // Don't increment 'i' as the current child 'i' used to be child 'i+1'
            } else {
                ++i;
            }
        }

        root->getChildVector()->insert(
            root->getChildVector()->end(), absorbedChildren.begin(), absorbedChildren.end());

        // AND of 1 thing is the thing, OR of 1 thing is the thing.
        if (1 == root->numChildren()) {
            MatchExpression* ret = root->getChild(0);
            root->getChildVector()->clear();
            delete root;
            return ret;
        }
    } else if (MatchExpression::NOT == root->matchType()) {
        // Normalize the rest of the tree hanging off this NOT node.
        NotMatchExpression* nme = static_cast<NotMatchExpression*>(root);
        MatchExpression* child = nme->releaseChild();
        // normalizeTree(...) takes ownership of 'child', and then
        // transfers ownership of its return value to 'nme'.
        nme->resetChild(normalizeTree(child));
    } else if (MatchExpression::ELEM_MATCH_VALUE == root->matchType()) {
        // Just normalize our children.
        for (size_t i = 0; i < root->getChildVector()->size(); ++i) {
            (*root->getChildVector())[i] = normalizeTree(root->getChild(i));
        }
    }

    return root;
}

这里, 采用了递归的调用方式, 针对and,or, not,elemMatch 4中操作符进行, notelemMatch 是针对其subnode 调用normalizeTree, andor 递归的吧子节点提升为父节点的兄弟节点。

2. sort tree

sort tree 主要是对MatchExpression的各个子树进行排序, 排序之后的好处就是对于index查询, 如果某个字段的index被分成了几段, 我们的查询用到其中的2段, 就可以做到对于索引的查找只需要一次就能完成。其具体的排序的顺序:
1) operator type (MatchExpression::MatchType)
2) path name (MatchExpression::path())
3) sort order of children
4) number of children (MatchExpression::numChildren())
代码的实现就比较简单, 按照上面的4中比较方式以及优先级。
这里写图片描述

3. validate tree

主要是判断由MatchExpression产生的LiteParsedQuery 对象的设定是否有不正确的地方。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值