package com.taobao.tddl.optimizer.costbased.after;
import java.util.Map;
import com.taobao.tddl.common.TddlConstants;
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.expression.IBindVal;
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.IMerge;
import com.taobao.tddl.optimizer.core.plan.query.IQuery;
/**
* streaming模式处理
*
* <pre>
* 几种情况需要使用streaming
* 1. merge节点中带limit,需要设置子节点为streaming模式
* 2. join节点+不可下推,需要设置左右节点为streaming模式
* 3. query节点+不可下推,需要设置子节点为streaming模式
* </pre>
*
* @author Whisper
* @author <a href="jianghang.loujh@taobao.com">jianghang</a>
*/
public class StreamingOptimizer implements QueryPlanOptimizer {
public StreamingOptimizer(){
}
@Override
public IDataNodeExecutor optimize(IDataNodeExecutor dne, Map<Integer, ParameterContext> parameterSettings,
Map<String, Object> extraCmd) {
if (dne instanceof IQueryTree) {
this.findQueryOptimizeStreaming(dne, false, extraCmd);
}
return dne;
}
private void findQueryOptimizeStreaming(IDataNodeExecutor dne, boolean isNeedStreaming, Map<String, Object> extraCmd) {
if (!(dne instanceof IQueryTree)) {
return;
}
boolean streaming = isNeedStreaming | isNeedStreaming((IQueryTree) dne, extraCmd);
if (dne instanceof IMerge) {
for (IDataNodeExecutor child : ((IMerge) dne).getSubNode()) {
if (streaming) {
child.setStreaming(true);
}
// 让子节点递归进行计算
this.findQueryOptimizeStreaming(child, streaming, extraCmd);
}
} else if (dne instanceof IJoin) {
if (streaming) {
// 如果父节点要求其为straming,让左右节点为streaming
// 如果是join节点存在limit,让左右节点为streaming
// 如果整个join节点可下推,执行节点只会在join上,不会到left/right节点,此时streaming无效,所以不用做这判断
((IJoin) dne).getLeftNode().setStreaming(true);
((IJoin) dne).getRightNode().setStreaming(true);
}
this.findQueryOptimizeStreaming(((IJoin) dne).getLeftNode(), streaming, extraCmd);
this.findQueryOptimizeStreaming(((IJoin) dne).getRightNode(), streaming, extraCmd);
} else if (dne instanceof IQuery) {
if (streaming) {
// 如果父节点要求其为straming,让其子节点为streaming
// 如果是query节点存在limit,让其子节点为streaming
((IQuery) dne).getSubQuery().setStreaming(true);
}
if (((IQuery) dne).getSubQuery() != null) {
this.findQueryOptimizeStreaming(((IQuery) dne).getSubQuery(), streaming, extraCmd);
}
}
}
private static boolean isNeedStreaming(IQueryTree query, Map<String, Object> extraCmd) {
Comparable from = query.getLimitFrom();
Comparable to = query.getLimitTo();
boolean useStreaming = false;
if ((from instanceof IBindVal) || (to instanceof IBindVal)) {
useStreaming = true;
}
if (from instanceof Long && isNeedStreaming((Long) from, extraCmd)
|| (to instanceof Long && isNeedStreaming((Long) to, extraCmd))) {
useStreaming = true;
}
return useStreaming;
}
private static boolean isNeedStreaming(Long limit, Map<String, Object> extraCmd) {
return limit > GeneralUtil.getExtraCmdLong(extraCmd,
ExtraCmd.STREAMI_THRESHOLD,
TddlConstants.DEFAULT_STREAM_THRESOLD);
}
}