package com.taobao.tddl.optimizer.costbased.chooser; import java.util.ArrayList; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.apache.commons.lang.StringUtils; import com.taobao.tddl.common.exception.NotSupportException; 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.OptimizerContext; import com.taobao.tddl.optimizer.config.table.ColumnMeta; import com.taobao.tddl.optimizer.config.table.TableMeta; import com.taobao.tddl.optimizer.core.ASTNodeFactory; import com.taobao.tddl.optimizer.core.ast.ASTNode; import com.taobao.tddl.optimizer.core.ast.DMLNode; import com.taobao.tddl.optimizer.core.ast.QueryTreeNode; import com.taobao.tddl.optimizer.core.ast.dml.DeleteNode; import com.taobao.tddl.optimizer.core.ast.dml.InsertNode; import com.taobao.tddl.optimizer.core.ast.dml.PutNode; import com.taobao.tddl.optimizer.core.ast.dml.UpdateNode; import com.taobao.tddl.optimizer.core.ast.query.JoinNode; import com.taobao.tddl.optimizer.core.ast.query.KVIndexNode; import com.taobao.tddl.optimizer.core.ast.query.MergeNode; import com.taobao.tddl.optimizer.core.ast.query.QueryNode; import com.taobao.tddl.optimizer.core.ast.query.TableNode; import com.taobao.tddl.optimizer.core.expression.IBooleanFilter; import com.taobao.tddl.optimizer.core.expression.IFilter; import com.taobao.tddl.optimizer.core.expression.IFilter.OPERATION; import com.taobao.tddl.optimizer.core.expression.ILogicalFilter; import com.taobao.tddl.optimizer.core.expression.ISelectable; import com.taobao.tddl.optimizer.core.plan.query.IJoin.JoinStrategy; import com.taobao.tddl.optimizer.costbased.esitimater.Cost; import com.taobao.tddl.optimizer.costbased.esitimater.CostEsitimaterFactory; import com.taobao.tddl.optimizer.exceptions.EmptyResultFilterException; import com.taobao.tddl.optimizer.exceptions.OptimizerException; import com.taobao.tddl.optimizer.exceptions.QueryException; import com.taobao.tddl.optimizer.utils.FilterUtils; import com.taobao.tddl.optimizer.utils.OptimizerUtils; import com.taobao.tddl.rule.model.Field; import com.taobao.tddl.rule.model.TargetDB; import com.taobao.tddl.common.utils.logger.Logger; import com.taobao.tddl.common.utils.logger.LoggerFactory; /** * <pre> * 1. 根据Rule计算分库分表,并设置执行计划的executeOn() * 2. 如果存在多个执行目标库,构造为Merge查询树 * * </pre> * * @since 5.0.0 */ public class DataNodeChooser { private static final String LOCAL = "localhost"; private static Pattern suffixPattern = Pattern.compile("\\d+$"); // 提取字符串最后的数字 private static final Logger logger = LoggerFactory.getLogger(DataNodeChooser.class); public static ASTNode shard(ASTNode dne, Map<Integer, ParameterContext> parameterSettings, Map<String, Object> extraCmd) throws QueryException { if (dne instanceof DMLNode) { if (dne instanceof InsertNode) { return shardInsert((InsertNode) dne, parameterSettings, extraCmd); } if (dne instanceof UpdateNode) { return shardUpdate((UpdateNode) dne, parameterSettings, extraCmd); } if (dne instanceof DeleteNode) { return shardDelete((DeleteNode) dne, parameterSettings, extraCmd); } if (dne instanceof PutNode) { return shardPut((PutNode) dne, parameterSettings, extraCmd); } } if (dne instanceof QueryTreeNode) { return shardQuery((QueryTreeNode) dne, parameterSettings, extraCmd); } return dne; } private static QueryTreeNode shardQuery(QueryTreeNode qtn, Map<Integer, ParameterContext> parameterSettings, Map<String, Object> extraCmd) throws QueryException { if (qtn instanceof QueryNode) { QueryNode query = (QueryNode) qtn; QueryTreeNode child = query.getChild(); child = shardQuery(child, parameterSettings, extraCmd); if (child instanceof MergeNode && !child.isExistAggregate()) { return buildMergeQuery(query, (MergeNode) child); } else { query.setChild(child); query.setBroadcast(child.isBroadcast());// 传递一下 query.executeOn(child.getDataNode()); query.setExistAggregate(child.isExistAggregate()); return query; } } else if (qtn instanceof TableNode) { // 此时经过join处理后,已经全部转化为kv结构的查询了 KVIndexNode query = (KVIndexNode) qtn; // 构造filter IFilter f = FilterUtils.and(query.getKeyFilter(), query.getResultFilter()); f = FilterUtils.and(f, query.getOtherJoinOnFilter()); List<TargetDB> dataNodeChoosed = shard(query.getIndexName(), f, true); return buildMergeTable(query, dataNodeChoosed); } else if (qtn instanceof JoinNode) { // Join节点应该在数据量大的一段进行 boolean isPartitionOnPartition = false; JoinNode join = (JoinNode) qtn; QueryTreeNode left = join.getLeftNode(); QueryTreeNode right = join.getRightNode(); /* * 如果是分库键join分库键,并且规则相同,则优化成join merge join */ if (chooseJoinMergeJoinForce(extraCmd)) { isPartitionOnPartition = true;// 强制开启 } else if (chooseJoinMergeJoinByRule(extraCmd)) { isPartitionOnPartition = isJoinOnPartition(join).flag; // 根据规则判断 } // 处理子节点 left = shardQuery(left, parameterSettings, extraCmd); right = shardQuery(right, parameterSettings, extraCmd); if (isPartitionOnPartition) { // 尝试构建join merge join,可能会构建失败 // 失败原因 : // 1. 人肉强制开启join merge join的选项 // 2. 涉及index kv的join查询结构,index的数据和原始数据的分区方式可能不一致 QueryTreeNode joinMergeJOin = buildJoinMergeJoin(join, left, right); if (joinMergeJOin != null) { return joinMergeJOin; } } // 不做join merge join join.setLeftNode(left); // NestedLoop情况下 // 如果右边是多个表,则分库需要再执行层根据左边的结果做 if (!(right instanceof MergeNode && (join.getJoinStrategy() == JoinStrategy.INDEX_NEST_LOOP || join.getJoinStrategy() == JoinStrategy.NEST_LOOP_JOIN))) { join.setRightNode(right); } else { if (right.isSubQuery()) { // 子表会采取BLOCK_LOOP_JOIN模式,一次性取完结果 join.setRightNode(right); } else { right = new MergeNode(); // 右边运行时计算 ((MergeNode) right).merge(join.getRightNode()); ((MergeNode) right).setSharded(false); join.getRightNode().executeOn("undecided"); right.setBroadcast(false); right.build(); join.setRightNode(right); } } String dataNode = join.getLeftNode().getDataNode(); // 对于未决的IndexNestedLoop,join应该在左节点执行 if (right instanceof MergeNode && !((MergeNode) right).isSharded()) { join.executeOn(dataNode); right.executeOn(join.getDataNode()); } else { // 选择一个执行代价最小的节点 Cost leftCost = CostEsitimaterFactory.estimate(left); Cost rightCost = CostEsitimaterFactory.estimate(right); dataNode = leftCost.getRowCount() > rightCost.getRowCount() ? join.getLeftNode().getDataNode() : join.getRightNode() .getDataNode(); join.executeOn(dataNode); } join.setBroadcast(left.isBroadcast() && right.isBroadcast()); return join; } else if (qtn instanceof MergeNode) { // 一个query出现or可能会走到index merge,会拆分为merge合并两个请求 // 为merge选择执行节点 // 很多方案... // 两路归并? // 都发到一台机器上? // 目前的方案是都发到一台机器上 // 对Merge的每个子节点的rowCount进行排序 // 找出rowCount最大的子节点 // merge应该在该机器上执行,其他机器的数据都发送给它 MergeNode merge = (MergeNode) qtn; List<ASTNode> subNodes = merge.getChildren(); merge = new MergeNode(); merge.setUnion(((MergeNode) qtn).isUnion()); long maxRowCount = 0; String maxRowCountDataNode = subNodes.get(0).getDataNode(); for (int i = 0; i < subNodes.size(); i++) { QueryTreeNode child = (QueryTreeNode) subNodes.get(i); child = shardQuery(child, parameterSettings, extraCmd); subNodes.set(i, child); Cost childCost = CostEsitimaterFactory.estimate(child); if (childCost.getRowCount() > maxRowCount) { maxRowCount = childCost.getRowCount(); maxRowCountDataNode = child.getDataNode(); } } if (maxRowCountDataNode == null) { maxRowCountDataNode = subNodes.get(0).getDataNode(); } merge.executeOn(maxRowCountDataNode); merge.merge(subNodes); merge.setSharded(true); merge.setBroadcast(false); merge.build(); return merge; } return qtn; } private static ASTNode shardInsert(InsertNode dne, Map<Integer, ParameterContext> parameterSettings, Map<String, Object> extraCmd) { String indexName = null; if (dne.getNode() instanceof KVIndexNode) { indexName = ((KVIndexNode) dne.getNode()).getIndexName(); } else { indexName = dne.getNode().getTableMeta().getPrimaryIndex().getName(); } // 根据规则计算 IFilter insertFilter = createFilter(dne.getColumns(), dne.getValues()); List<TargetDB> dataNodeChoosed = shard(indexName, insertFilter, true); TargetDB itarget = dataNodeChoosed.get(0); dne.executeOn(itarget.getDbIndex()); if (dataNodeChoosed.size() == 1 && itarget.getTableNameMap() != null && itarget.getTableNameMap().size() == 1) { KVIndexNode query = new KVIndexNode(indexName); // 设置为物理的表 query.executeOn(itarget.getDbIndex()); query.setActualTableName(itarget.getTableNameMap().keySet().iterator().next()); dne = query.insert(dne.getColumns(), dne.getValues()); dne.executeOn(query.getDataNode()); dne.build(); return dne; } else { throw new OptimizerException("insert not support muti tables"); } } private static ASTNode shardUpdate(UpdateNode dne, Map<Integer, ParameterContext> parameterSettings, Map<String, Object> extraCmd) throws QueryException { QueryTreeNode qtn = shardQuery(dne.getNode(), parameterSettings, extraCmd); List<ASTNode> subs = new ArrayList(); if (qtn instanceof MergeNode) { subs.addAll(qtn.getChildren()); } else { subs.add(qtn); } if (subs.size() == 1) { return buildOneQueryUpdate((QueryTreeNode) subs.get(0), dne.getColumns(), dne.getValues()); } MergeNode updateMerge = new MergeNode(); for (ASTNode sub : subs) { updateMerge.merge(buildOneQueryUpdate((QueryTreeNode) sub, dne.getColumns(), dne.getValues())); } updateMerge.executeOn(updateMerge.getChild().getDataNode()); return updateMerge; } private static ASTNode shardDelete(DeleteNode dne, Map<Integer, ParameterContext> parameterSettings, Map<String, Object> extraCmd) throws QueryException { QueryTreeNode qtn = shardQuery(dne.getNode(), parameterSettings, extraCmd); List<ASTNode> subs = new ArrayList(); if (qtn instanceof MergeNode) { subs.addAll(qtn.getChildren()); } else { subs.add(qtn); } if (subs.size() == 1) { return buildOneQueryDelete((QueryTreeNode) subs.get(0)); } MergeNode deleteMerge = new MergeNode(); for (ASTNode sub : subs) { deleteMerge.merge(buildOneQueryDelete((QueryTreeNode) sub)); } deleteMerge.executeOn(deleteMerge.getChild().getDataNode()); return deleteMerge; } private static ASTNode shardPut(PutNode dne, Map<Integer, ParameterContext> parameterSettings, Map<String, Object> extraCmd) { String indexName = null; if (dne.getNode() instanceof KVIndexNode) { indexName = ((KVIndexNode) dne.getNode()).getIndexName(); } else { indexName = dne.getNode().getTableMeta().getPrimaryIndex().getName(); } IFilter insertFilter = createFilter(dne.getColumns(), dne.getValues()); List<TargetDB> dataNodeChoosed = shard(indexName, insertFilter, true); TargetDB itarget = dataNodeChoosed.get(0); dne.executeOn(itarget.getDbIndex()); if (dataNodeChoosed.size() == 1 && itarget.getTableNameMap() != null && itarget.getTableNameMap().size() == 1) { KVIndexNode query = new KVIndexNode(indexName); query.executeOn(itarget.getDbIndex()); query.setActualTableName(itarget.getTableNameMap().keySet().iterator().next()); dne = query.put(dne.getColumns(), dne.getValues()); dne.executeOn(query.getDataNode()); dne.build(); return dne; } else { throw new OptimizerException("insert not support muti tables"); } } // =============== helper method ================= /** * 根据逻辑表名和执行条件计算出执行节点 */ private static List<TargetDB> shard(String logicalName, IFilter f, boolean isWrite) { boolean isTraceSource = true; if (f != null && f instanceof ILogicalFilter) { if (f.getOperation().equals(OPERATION.OR)) { f = null; isTraceSource = false; } } if (logger.isDebugEnabled()) { logger.warn("shard debug:\n"); logger.warn("logicalName:" + logicalName); logger.warn("filter:" + f); logger.warn("isTraceSource:" + isTraceSource); logger.warn("isWrite:" + isWrite); } String tableName = logicalName.split("\\.")[0]; OptimizerContext.getContext().getSchemaManager().getTable(tableName); // 验证下表是否存在 List<TargetDB> dataNodeChoosed = OptimizerContext.getContext().getRule().shard(logicalName, f, isWrite); if (dataNodeChoosed == null || dataNodeChoosed.isEmpty()) { throw new EmptyResultFilterException("无对应执行节点"); } return dataNodeChoosed; } private static class OneDbNodeWithCount { List<QueryTreeNode> subs = new ArrayList(); long totalRowCount = 0; } /** * 根据执行的目标节点,构建MergeNode */ private static QueryTreeNode buildMergeTable(TableNode table, List<TargetDB> dataNodeChoosed) { long maxRowCount = 0; String maxRowCountDataNode = dataNodeChoosed.get(0).getDbIndex(); List<List<QueryTreeNode>> subs = new ArrayList(); // 单库单表是大多数场景,此时无需复制执行计划 boolean needCopy = true; if (dataNodeChoosed != null && dataNodeChoosed.size() == 1 && dataNodeChoosed.get(0).getTableNameMap().size() == 1) { needCopy = false; } for (TargetDB target : dataNodeChoosed) { OneDbNodeWithCount oneDbNodeWithCount = buildMergeTableInOneDB(table, target, needCopy); if (!oneDbNodeWithCount.subs.isEmpty()) { subs.add(oneDbNodeWithCount.subs); } if (oneDbNodeWithCount.totalRowCount > maxRowCount) { maxRowCount = oneDbNodeWithCount.totalRowCount; maxRowCountDataNode = target.getDbIndex(); } } if (subs.isEmpty()) { throw new EmptyResultFilterException("无对应执行节点"); } else if (subs.size() == 1 && subs.get(0).size() == 1) { return subs.get(0).get(0); // 只有单库 } else { // 多库执行 MergeNode merge = new MergeNode(); merge.executeOn(LOCAL);// 随意的一个名字 merge.setAlias(table.getAlias()); merge.setSubQuery(table.isSubQuery()); merge.setSubAlias(table.getSubAlias()); merge.executeOn(maxRowCountDataNode); for (List<QueryTreeNode> subList : subs) { for (QueryTreeNode sub : subList) { merge.merge(sub); } } merge.setBroadcast(false);// merge不可能是广播表 merge.build();// build过程中会复制子节点的信息 return merge; } } /** * 构建单库的执行节点 */ private static OneDbNodeWithCount buildMergeTableInOneDB(TableNode table, TargetDB targetDB, boolean needCopy) { long totalRowCount = 0; OneDbNodeWithCount oneDbNodeWithCount = new OneDbNodeWithCount(); Map<String, Field> tabMap = targetDB.getTableNameMap(); for (String targetTable : tabMap.keySet()) { TableNode node = null; if (needCopy) { node = table.copy(); } else { node = table; } // tddl的traceSource在分库不分表,和全表扫描时无法使用 mengshi if (tabMap.get(targetTable) != null && tabMap.get(targetTable).getSourceKeys() != null) { if (node.getKeyFilter() != null) { IFilter keyFilterAfterTraceSource = (IFilter) node.getKeyFilter().copy(); traceSourceInFilter(keyFilterAfterTraceSource, tabMap.get(targetTable).getSourceKeys()); node.setKeyFilter(keyFilterAfterTraceSource); } if (node.getResultFilter() != null) { IFilter valueFilterAfterTraceSource = (IFilter) node.getResultFilter().copy(); traceSourceInFilter(valueFilterAfterTraceSource, tabMap.get(targetTable).getSourceKeys()); node.setResultFilter(valueFilterAfterTraceSource); } } node.setActualTableName(targetTable); node.executeOn(targetDB.getDbIndex()); node.setExtra(getIdentifierExtra((KVIndexNode) node));// 设置标志 // 暂时先用逻辑表名,以后可能是索引名 String indexName = null; if (node instanceof KVIndexNode) { indexName = ((KVIndexNode) node).getKvIndexName(); } else { indexName = node.getTableMeta().getPrimaryIndex().getName(); } node.setBroadcast(OptimizerContext.getContext().getRule().isBroadCast(indexName)); totalRowCount += CostEsitimaterFactory.estimate(node).getRowCount(); oneDbNodeWithCount.subs.add(node); } oneDbNodeWithCount.totalRowCount = totalRowCount; return oneDbNodeWithCount; } /** * 更新in操作的values */ private static void traceSourceInFilter(IFilter filter, Map<String, Set<Object>> sourceKeys) { if (sourceKeys == null || filter == null) { return; } if (filter instanceof IBooleanFilter) { if (filter.getOperation().equals(OPERATION.IN)) { ISelectable s = (ISelectable) ((IBooleanFilter) filter).getColumn(); Set<Object> sourceKey = sourceKeys.get(s.getColumnName()); if (sourceKey != null && !sourceKey.isEmpty()) { ((IBooleanFilter) filter).setValues(new ArrayList(sourceKey)); } } } else if (filter instanceof ILogicalFilter) { for (IFilter subFilter : ((ILogicalFilter) filter).getSubFilter()) { if (subFilter.getOperation().equals(OPERATION.IN)) { ISelectable s = (ISelectable) ((IBooleanFilter) subFilter).getColumn(); Set<Object> sourceKey = sourceKeys.get(s.getColumnName()); if (sourceKey != null && !sourceKey.isEmpty()) {// 走了规则,在in中有sourceTrace ((IBooleanFilter) subFilter).setValues(new ArrayList(sourceKey)); } } } } } private static UpdateNode buildOneQueryUpdate(QueryTreeNode sub, List columns, List values) { if (sub instanceof TableNode) { UpdateNode update = ((TableNode) sub).update(columns, values); update.executeOn(sub.getDataNode()); return update; } else { throw new NotSupportException("update中暂不支持按照索引进行查询"); } } private static DeleteNode buildOneQueryDelete(QueryTreeNode sub) { if (sub instanceof TableNode) { DeleteNode delete = ((TableNode) sub).delete(); delete.executeOn(sub.getDataNode()); return delete; } else { throw new NotSupportException("delete中暂不支持按照索引进行查询"); } } private static QueryTreeNode buildMergeQuery(QueryNode query, MergeNode mergeNode) { List<QueryNode> mergeQuerys = new LinkedList<QueryNode>(); for (ASTNode child : mergeNode.getChildren()) { // 在未做shard之前就有存在mergeNode的可能,要识别出来 // 比如OR条件,可能会被拆分为两个Query的Merge,这个经过build之后,会是Merge套Merge或者是Merge套Query if (!(child instanceof MergeNode) && child.getExtra() != null) { QueryNode newQuery = query.copy(); newQuery.setChild((QueryTreeNode) child); newQuery.executeOn(child.getDataNode()); newQuery.setExtra(child.getExtra()); newQuery.setBroadcast(child.isBroadcast()); mergeQuerys.add(newQuery); } } if (mergeQuerys.size() > 1) { MergeNode merge = new MergeNode(); merge.setAlias(query.getAlias()); merge.setSubQuery(query.isSubQuery()); merge.setSubAlias(query.getSubAlias()); for (QueryNode q : mergeQuerys) { merge.merge(q); } merge.executeOn(mergeQuerys.get(0).getDataNode()).setExtra(mergeQuerys.get(0).getExtra()); merge.build(); return merge; } else if (mergeQuerys.size() == 1) { return mergeQuerys.get(0); } else { return query; } } private static boolean chooseJoinMergeJoinByRule(Map<String, Object> extraCmd) { return GeneralUtil.getExtraCmdBoolean(extraCmd, ExtraCmd.JOIN_MERGE_JOIN_JUDGE_BY_RULE, true); } private static boolean chooseJoinMergeJoinForce(Map<String, Object> extraCmd) { return GeneralUtil.getExtraCmdBoolean(extraCmd, ExtraCmd.JOIN_MERGE_JOIN, false); } private static class PartitionJoinResult { List<IBooleanFilter> joinFilters; String joinGroup; boolean broadcast = false; boolean flag = false; // 成功还是失败 } /** * 找到join条件完全是分区键的filter,返回null代表没找到,否则返回join条件 */ private static PartitionJoinResult isJoinOnPartition(JoinNode join) { QueryTreeNode left = join.getLeftNode(); QueryTreeNode right = join.getRightNode(); PartitionJoinResult leftResult = isJoinOnPartitionOneSide(join.getLeftKeys(), left); if (!leftResult.flag) { return leftResult; } PartitionJoinResult rightResult = isJoinOnPartitionOneSide(join.getRightKeys(), right); if (!rightResult.flag) { return rightResult; } PartitionJoinResult result = new PartitionJoinResult(); result.broadcast = leftResult.broadcast || rightResult.broadcast; result.flag = StringUtils.equalsIgnoreCase(leftResult.joinGroup, rightResult.joinGroup) || result.broadcast; result.joinGroup = leftResult.joinGroup; result.joinFilters = join.getJoinFilter(); return result; } /** * 判断一个joinNode的左或则右节点的joinColumns是否和当前节点的分区键完全匹配 */ private static PartitionJoinResult isJoinOnPartitionOneSide(List<ISelectable> joinColumns, QueryTreeNode qtn) { PartitionJoinResult result = new PartitionJoinResult(); // 递归拿左边的树 if (qtn instanceof JoinNode) { result = isJoinOnPartition((JoinNode) qtn); if (!result.flag) {// 递归失败,直接返回 result.flag = false; return result; } List<IBooleanFilter> joinOnPatitionFilters = result.joinFilters; if (joinOnPatitionFilters == null) {// 底下不满足,直接退出 result.flag = false; return result; } else { for (ISelectable joinColumn : joinColumns) { ISelectable select = qtn.findColumn(joinColumn); if (!isMatchJoinFilter(joinOnPatitionFilters, select)) { result.flag = false; return result; } } result.flag = true; return result; } } else if (qtn instanceof QueryNode) { // 转一次为query中的select字段 List<ISelectable> newJoinColumns = new LinkedList<ISelectable>(); for (ISelectable joinColumn : joinColumns) { ISelectable newColumn = qtn.findColumn(joinColumn); if (newColumn == null) { return null; } else { newJoinColumns.add(newColumn); } } // 获取当前表的分区字段 return isJoinOnPartitionOneSide(newJoinColumns, (QueryTreeNode) qtn.getChild()); } else if (qtn instanceof MergeNode) { result.flag = false; return result; // 直接返回,不处理 } else { if (OptimizerContext.getContext().getRule().isBroadCast(((KVIndexNode) qtn).getKvIndexName())) { result.flag = true; result.broadcast = true; return result; } // KVIndexNode List<String> shardColumns = OptimizerContext.getContext() .getRule() .getSharedColumns(((KVIndexNode) qtn).getKvIndexName()); List<ColumnMeta> columns = new ArrayList<ColumnMeta>(); TableMeta tableMeta = ((KVIndexNode) qtn).getTableMeta(); for (String shardColumn : shardColumns) { columns.add(tableMeta.getColumn(shardColumn)); } String tableName = ((KVIndexNode) qtn).getTableName(); if (qtn.getAlias() != null) { tableName = qtn.getAlias(); } List<ISelectable> partitionColumns = OptimizerUtils.columnMetaListToIColumnList(columns, tableName); if (partitionColumns.isEmpty()) { result.flag = false;// 没有分库键 return result; } // 要求joinColumns必须包含所有的partitionColumns for (ISelectable partitionColumn : partitionColumns) { boolean isFound = false; for (ISelectable joinColumn : joinColumns) { if (joinColumn.getColumnName().equals(partitionColumn.getColumnName())) {// partition无别名 isFound = true; break; } } if (!isFound) { result.flag = false;// 没有分库键 return result; } } result.flag = true; String indexName = ((KVIndexNode) qtn).getKvIndexName(); result.joinGroup = OptimizerContext.getContext().getRule().getJoinGroup(indexName); return result; } } /** * 判断是否是join条件中的一个字段,可能是左表或右边的字段 */ private static boolean isMatchJoinFilter(List<IBooleanFilter> joinFilters, ISelectable column) { for (IBooleanFilter joinFilter : joinFilters) { ISelectable leftJoinColumn = (ISelectable) joinFilter.getColumn(); ISelectable rightJoinColumn = (ISelectable) joinFilter.getValue(); if (leftJoinColumn.equals(column) || rightJoinColumn.equals(column)) { return true; } } return false; } private static QueryTreeNode buildJoinMergeJoin(JoinNode join, QueryTreeNode left, QueryTreeNode right) { // 根据表名的后缀来判断两个表是不是对应的表 // 底下的节点已经被优先处理 // 1. 如果是KvIndexNode,没必要转化为join merge join,直接join即可 // 2. 如果是QueryNode,底下已经将其转化为merge下套query+child // 所以,只要处理MergeNode即可 Map<String, QueryTreeNode> leftIdentifierExtras = new HashMap<String, QueryTreeNode>(); List<JoinNode> joins = new ArrayList(); List<QueryTreeNode> rights = new ArrayList(); List<QueryTreeNode> lefts = new ArrayList(); boolean leftBroadCast = false; boolean rightBroadCast = false; if (left instanceof MergeNode) { for (ASTNode child : left.getChildren()) { leftIdentifierExtras.put((String) child.getExtra(), (QueryTreeNode) child); lefts.add((QueryTreeNode) child); } } else { // 可能是广播表 leftBroadCast = left.isBroadcast(); } if (right instanceof MergeNode) { for (ASTNode child : right.getChildren()) { rights.add((QueryTreeNode) child); } } else { // 可能是广播表 rightBroadCast = right.isBroadcast(); } if (leftBroadCast && rightBroadCast) { return join;// 两个广播表之间的join,直接返回 } else if (leftBroadCast) {// 左边是广播表 for (QueryTreeNode r : rights) { if (r.isExistAggregate()) {// 存在聚合计算,不能展开 return null; } JoinNode newj = join.copy(); QueryTreeNode newL = left.copy(); setExecuteOn(newL, r.getDataNode());// 广播表的执行节点跟着右边走 newj.setLeftNode(newL); newj.setRightNode(r); newj.executeOn(r.getDataNode()); newj.setExtra(r.getExtra()); joins.add(newj); } } else if (rightBroadCast) { for (QueryTreeNode l : lefts) { if (l.isExistAggregate()) {// 存在聚合计算,不能展开 return null; } QueryTreeNode newR = right.copy(); setExecuteOn(newR, l.getDataNode());// 广播表的执行节点跟着右边走 JoinNode newj = join.copy(); newj.setLeftNode(l); newj.setRightNode(newR); newj.executeOn(l.getDataNode()); newj.setExtra(l.getExtra()); joins.add(newj); } } else { // 根据后缀,找到匹配的表,生成join for (QueryTreeNode r : rights) { QueryTreeNode l = leftIdentifierExtras.get(r.getExtra()); if (l == null) { return null; // 转化失败,直接退回merge join merge的处理 } if (l.isExistAggregate() || r.isExistAggregate()) {// 存在聚合计算,不能展开 return null; } JoinNode newj = join.copy(); newj.setLeftNode(l); newj.setRightNode(r); newj.executeOn(l.getDataNode()); newj.setExtra(l.getExtra()); // 因为left/right的extra相同,只要选择一个即可 joins.add(newj); } } if (joins.size() > 1) { MergeNode merge = new MergeNode(); for (JoinNode j : joins) { merge.merge(j); } merge.executeOn(joins.get(0).getDataNode()).setExtra(joins.get(0).getExtra()); merge.build(); return merge; } else if (joins.size() == 1) { return joins.get(0); } return null; } /** * 递归设置executeOn */ private static void setExecuteOn(QueryTreeNode qtn, String dataNode) { for (ASTNode node : qtn.getChildren()) { setExecuteOn((QueryTreeNode) node, dataNode); } qtn.executeOn(dataNode); } /** * 根据表名提取唯一标识 * * <pre> * 1. tddl中的分库分表时,比如分16个库,每个库128张表,总共1024张表. 表的顺序为递增,从0000-1023, * 此时executeNode就是库名,表名可通过后缀获取,两者结合可以唯一确定一张表 * 2. cobar中的分库分表,只会分库,不分表,每个库中的表名都一样. * 此时executeNode就是库名,已经可以唯一确定一张表 * </pre> */ private static String getIdentifierExtra(KVIndexNode child) { String tableName = child.getActualTableName(); if (tableName == null) { tableName = child.getIndexName(); } Matcher matcher = suffixPattern.matcher(tableName); if (matcher.find()) { return (child.getDataNode() + "_" + matcher.group()); } else { return child.getDataNode(); } } private static IFilter createFilter(List<ISelectable> columns, List<Object> values) { IFilter insertFilter = null; if (columns.size() == 1) { IBooleanFilter f = ASTNodeFactory.getInstance().createBooleanFilter(); f.setOperation(OPERATION.EQ); f.setColumn(columns.get(0)); f.setValue(values.get(0)); insertFilter = f; } else { ILogicalFilter and = ASTNodeFactory.getInstance().createLogicalFilter(); and.setOperation(OPERATION.AND); for (int i = 0; i < columns.size(); i++) { Comparable c = columns.get(i); IBooleanFilter f = ASTNodeFactory.getInstance().createBooleanFilter(); f.setOperation(OPERATION.EQ); f.setColumn(c); f.setValue(values.get(i)); and.addSubFilter(f); } insertFilter = and; } return insertFilter; } }