Mongodb的逻辑优化过程

来源:互联网 发布:餐饮收银软件 编辑:程序博客网 时间:2024/06/06 13:19

逻辑优化过程在关系型数据库里面, 是一个非常复杂的过程, 幸运的是, 在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 对象的设定是否有不正确的地方。

原创粉丝点击