package com.taobao.tddl.optimizer.costbased.esitimater; import com.taobao.tddl.optimizer.core.ast.QueryTreeNode; import com.taobao.tddl.optimizer.core.ast.query.JoinNode; import com.taobao.tddl.optimizer.core.plan.query.IJoin.JoinStrategy; import com.taobao.tddl.optimizer.exceptions.StatisticsUnavailableException; /** * @author Dreamond */ public class JoinNodeCostEstimater implements QueryTreeCostEstimater { public Cost estimate(QueryTreeNode query) throws StatisticsUnavailableException { JoinNode join = (JoinNode) query; Cost leftCost = CostEsitimaterFactory.estimate(join.getLeftNode()); Cost rightCost = CostEsitimaterFactory.estimate(join.getRightNode()); Cost cost = new Cost(); cost.setIsOnFly(true); long rowCount = 0; long networkCost = 0; long scanRowCount = 0; boolean isOnFly = true; // 估算IO开销 if (rightCost.isOnFly()) { cost.setDiskIO(leftCost.getDiskIO() + rightCost.getDiskIO()); } else { cost.setDiskIO(leftCost.getDiskIO() + leftCost.getRowCount()); } // 估算行数 // 现在假定join后的行数为较小表的行数,这个假设对于大多数场景都是成立的 if (leftCost.getRowCount() < rightCost.getRowCount()) { rowCount = (leftCost.getRowCount()); } else { rowCount = (rightCost.getRowCount()); } // 估算网络开销 if (join.getDataNode() != null) { if (!join.getDataNode().equals(join.getLeftNode().getDataNode())) { networkCost += leftCost.getRowCount(); } if (!join.getDataNode().equals(join.getRightNode().getDataNode())) { networkCost += rightCost.getRowCount(); } } // 如果是IndexNestLoop,则数据还在磁盘上 if (join.getJoinStrategy() == JoinStrategy.INDEX_NEST_LOOP) { cost.setDiskIO(leftCost.getRowCount()); isOnFly = false; scanRowCount = leftCost.getScanCount() + rightCost.getScanCount(); } else { // sort merge // 右边的先要拿出数据 // 再要将符合的数据插到临时表 // 所以等于是两次 scanRowCount = leftCost.getScanCount() + rightCost.getScanCount() * 2 + rightCost.getRowCount(); } if (query.getLimitFrom() != null && (query.getLimitFrom() instanceof Long || query.getLimitFrom() instanceof Long) && (Long) query.getLimitFrom() != 0 && query.getLimitTo() != null && (query.getLimitTo() instanceof Long || query.getLimitTo() instanceof Long) && (Long) query.getLimitTo() != 0) { rowCount = ((Long) query.getLimitTo() - (Long) query.getLimitFrom()); } else if (query.getLimitFrom() != null || query.getLimitTo() != null) { rowCount = rowCount / 2; } cost.setNetworkCost(networkCost); cost.setRowCount(rowCount); cost.setIsOnFly(isOnFly); cost.setScanCount(scanRowCount); return cost; } }