您的位置:首页 > 数据库 > Mongodb

Mongodb的逻辑优化过程

2017-10-07 16:53 127 查看
逻辑优化过程在关系型数据库里面, 是一个非常复杂的过程, 幸运的是, 在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中操作符进行, not和elemMatch 是针对其subnode 调用normalizeTree, and和or 递归的吧子节点提升为父节点的兄弟节点。

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 对象的设定是否有不正确的地方。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  mongodb 查询引擎