package com.taobao.tddl.optimizer.costbased.after;
import java.util.List;
import java.util.Map;
import com.taobao.tddl.common.jdbc.ParameterContext;
import com.taobao.tddl.common.model.ExtraCmd;
import com.taobao.tddl.common.utils.GeneralUtil;
import com.taobao.tddl.optimizer.core.ASTNodeFactory;
import com.taobao.tddl.optimizer.core.plan.IDataNodeExecutor;
import com.taobao.tddl.optimizer.core.plan.IQueryTree;
import com.taobao.tddl.optimizer.core.plan.query.IJoin;
import com.taobao.tddl.optimizer.core.plan.query.IJoin.JoinStrategy;
import com.taobao.tddl.optimizer.core.plan.query.IMerge;
import com.taobao.tddl.optimizer.core.plan.query.IQuery;
/**
* 如果设置了MergeConcurrent 并且值为True,则将所有的Merge变为并行
*
* @since 5.0.0
*/
public class MergeJoinMergeOptimizer implements QueryPlanOptimizer {
/**
* 如果设置了MergeConcurrent 并且值为True,则将所有的Merge变为并行
*/
@Override
public IDataNodeExecutor optimize(IDataNodeExecutor dne, Map<Integer, ParameterContext> parameterSettings,
Map<String, Object> extraCmd) {
if (isMergeExpand(extraCmd)) {
return this.findEveryJoin(dne, true, true);
} else {
return dne;
}
}
private IDataNodeExecutor findEveryJoin(IDataNodeExecutor dne, boolean isExpandLeft, boolean isExpandRight) {
if (dne instanceof IMerge) {
List<IDataNodeExecutor> subs = ((IMerge) dne).getSubNode();
for (int i = 0; i < subs.size(); i++) {
subs.set(i, this.findEveryJoin(subs.get(i), isExpandLeft, isExpandRight));
}
((IMerge) dne).setSubNode(subs);
return dne;
} else if (dne instanceof IQuery) {
return dne;
} else if (dne instanceof IJoin) {
((IJoin) dne).setLeftNode((IQueryTree) this.findEveryJoin(((IJoin) dne).getLeftNode(),
isExpandLeft,
isExpandRight));
((IJoin) dne).setRightNode((IQueryTree) this.findEveryJoin(((IJoin) dne).getRightNode(),
isExpandLeft,
isExpandRight));
return this.processJoin((IJoin) dne, isExpandLeft, isExpandRight);
}
return dne;
}
private IQueryTree processJoin(IJoin j, boolean isExpandLeft, boolean isExpandRight) {
// 如果一个节点包含limit,group by,order by等条件,则不能展开
if (!canExpand(j)) {
// join节点可能自己存在limit
isExpandLeft = false;
isExpandRight = false;
} else if (!canExpand(j.getLeftNode())) {
isExpandLeft = false;
} else if (!canExpand(j.getRightNode())) {
isExpandRight = false;
}
if (isExpandLeft && isExpandRight) {
return this.cartesianProduct(j);
} else if (isExpandLeft) {
return this.expandLeft(j);
} else if (isExpandRight) {
return this.expandRight(j);
}
return this.mergeJoinMerge(j);
}
private IJoin mergeJoinMerge(IJoin j) {
// j.setJoinType(JoinType.SORT_MERGE_JOIN);
return j;
}
private boolean canExpand(IQueryTree query) {
// 如果一个节点包含limit,group by,order by等条件
if (query.getLimitFrom() != null || query.getLimitTo() != null || query.getGroupBys() != null
|| query.getOrderBys() != null) {
return false;
} else {
return true;
}
}
/**
* 将左边的merge展开,依次和右边做join
*/
public IQueryTree expandLeft(IJoin j) {
if (!(j.getLeftNode() instanceof IMerge)) {
j.setJoinStrategy(JoinStrategy.SORT_MERGE_JOIN);
return j;
}
IMerge left = (IMerge) j.getLeftNode();
IMerge newMerge = ASTNodeFactory.getInstance().createMerge();
for (IDataNodeExecutor leftChild : left.getSubNode()) {
IJoin newJoin = (IJoin) j.copy();
newJoin.setJoinStrategy(JoinStrategy.SORT_MERGE_JOIN);
newJoin.setLeftNode((IQueryTree) leftChild);
newJoin.setRightNode(j.getRightNode());
newJoin.executeOn(j.getDataNode());
newMerge.addSubNode(newJoin);
}
newMerge.setAlias(j.getAlias());
newMerge.setColumns(j.getColumns());
newMerge.setConsistent(j.getConsistent());
newMerge.setGroupBys(j.getGroupBys());
newMerge.setLimitFrom(j.getLimitFrom());
newMerge.setLimitTo(j.getLimitTo());
newMerge.setOrderBys(j.getOrderBys());
newMerge.setQueryConcurrency(j.getQueryConcurrency());
newMerge.setValueFilter(j.getValueFilter());
newMerge.executeOn(j.getDataNode());
return newMerge;
}
/**
* 将右边的merge展开,依次和左边做join
*
* @param j
* @return
*/
public IQueryTree expandRight(IJoin j) {
// merge的大小大于1时,才会展开
if (!(j.getRightNode() instanceof IMerge && ((IMerge) j.getRightNode()).getSubNode().size() > 1)) {
return j;
}
IMerge right = (IMerge) j.getRightNode();
IMerge newMerge = ASTNodeFactory.getInstance().createMerge();
for (IDataNodeExecutor rightChild : right.getSubNode()) {
IJoin newJoin = (IJoin) j.copy();
newJoin.setLeftNode(j.getLeftNode());
((IQueryTree) rightChild).setAlias(right.getAlias());
newJoin.setRightNode((IQueryTree) rightChild);
newJoin.executeOn(j.getDataNode());
newMerge.addSubNode(newJoin);
}
newMerge.setAlias(j.getAlias());
newMerge.setColumns(j.getColumns());
newMerge.setConsistent(j.getConsistent());
newMerge.setGroupBys(j.getGroupBys());
newMerge.setLimitFrom(j.getLimitFrom());
newMerge.setLimitTo(j.getLimitTo());
newMerge.setOrderBys(j.getOrderBys());
newMerge.setQueryConcurrency(j.getQueryConcurrency());
newMerge.setValueFilter(j.getValueFilter());
newMerge.executeOn(j.getDataNode());
return newMerge;
}
/**
* 左右都展开做笛卡尔积
*
* @param j
* @return
*/
public IQueryTree cartesianProduct(IJoin j) {
if (j.getLeftNode() instanceof IMerge && !(j.getRightNode() instanceof IMerge)) {
return this.expandLeft(j);
}
if (!(j.getLeftNode() instanceof IMerge) && (j.getRightNode() instanceof IMerge)) {
return this.expandRight(j);
}
if (!(j.getLeftNode() instanceof IMerge) && !(j.getRightNode() instanceof IMerge)) {
return j;
}
IMerge leftMerge = (IMerge) j.getLeftNode();
IMerge rightMerge = (IMerge) j.getRightNode();
IMerge newMerge = ASTNodeFactory.getInstance().createMerge();
for (IDataNodeExecutor leftChild : leftMerge.getSubNode()) {
for (IDataNodeExecutor rightChild : rightMerge.getSubNode()) {
IJoin newJoin = (IJoin) j.copy();
newJoin.setLeftNode((IQueryTree) leftChild);
newJoin.setRightNode((IQueryTree) rightChild);
newJoin.executeOn(leftChild.getDataNode());
newMerge.addSubNode(newJoin);
}
}
newMerge.setAlias(j.getAlias());
newMerge.setColumns(j.getColumns());
newMerge.setConsistent(j.getConsistent());
newMerge.setGroupBys(j.getGroupBys());
newMerge.setLimitFrom(j.getLimitFrom());
newMerge.setLimitTo(j.getLimitTo());
newMerge.setOrderBys(j.getOrderBys());
newMerge.setQueryConcurrency(j.getQueryConcurrency());
newMerge.setValueFilter(j.getValueFilter());
newMerge.executeOn(j.getDataNode());
return newMerge;
}
private static boolean isMergeExpand(Map<String, Object> extraCmd) {
return GeneralUtil.getExtraCmdBoolean(extraCmd, ExtraCmd.MERGE_EXPAND, false);
}
}