package com.taobao.tddl.optimizer.costbased.esitimater; import java.util.HashMap; import java.util.List; import java.util.Map; import com.taobao.tddl.common.exception.NotSupportException; import com.taobao.tddl.optimizer.config.table.ColumnMeta; import com.taobao.tddl.optimizer.config.table.IndexMeta; import com.taobao.tddl.optimizer.core.ast.QueryTreeNode; import com.taobao.tddl.optimizer.core.ast.query.JoinNode; 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.IColumn; import com.taobao.tddl.optimizer.core.expression.IFilter; import com.taobao.tddl.optimizer.core.expression.IFilter.OPERATION; import com.taobao.tddl.optimizer.costbased.esitimater.stat.KVIndexStat; import com.taobao.tddl.optimizer.exceptions.StatisticsUnavailableException; /** * 计算结构树的cost * * @since 5.0.0 */ public class CostEsitimaterFactory { private static JoinNodeCostEstimater joinNodeCostEstimater = new JoinNodeCostEstimater(); private static MergeNodeCostEstimater mergeNodeCostEstimater = new MergeNodeCostEstimater(); private static QueryNodeCostEstimater queryNodeCostEstimater = new QueryNodeCostEstimater(); public static Cost estimate(QueryTreeNode query) throws StatisticsUnavailableException { if (query instanceof JoinNode) { return joinNodeCostEstimater.estimate(query); } else if (query instanceof MergeNode) { return mergeNodeCostEstimater.estimate(query); } else if (query instanceof QueryNode || query instanceof TableNode) { return queryNodeCostEstimater.estimate(query); } else { throw new NotSupportException(); } } /** * 根据索引和查询的filter条件,估算记录数 * * @param tableRowCount 表记录数 * @param filters 查询条件 * @param index 选择的索引 * @param indexStat 索引的统计信息,如果为null则按照经验值预算 * @return */ public static long estimateRowCount(long tableRowCount, List<IFilter> filters, IndexMeta index, KVIndexStat indexStat) { // indexMeta if (filters == null || filters.isEmpty()) { return tableRowCount; } Map<String, Double> columnAndColumnCountItSelectivity = new HashMap(); if (index != null && indexStat != null) { Double columnCountEveryKeyColumnSelect = ((double) index.getKeyColumns().size()) * (1.0 / indexStat.getDistinctKeys()); for (ColumnMeta cm : index.getKeyColumns()) { columnAndColumnCountItSelectivity.put(cm.getName(), columnCountEveryKeyColumnSelect); } } long count = tableRowCount; // 每出现一个运算符,都把现在的行数乘上一个系数 for (IFilter f : filters) { if (f == null) { break; } IBooleanFilter filter = (IBooleanFilter) f; Double selectivity = null; if (filter.getColumn() instanceof IColumn) { String columnName = ((IColumn) filter.getColumn()).getColumnName(); if (columnAndColumnCountItSelectivity.containsKey(columnName)) { selectivity = columnAndColumnCountItSelectivity.get(columnName); } } if (selectivity == null) { selectivity = CostEsitimaterFactory.selectivity(filter.getOperation()); } count *= selectivity; } return count; } /** * 参考derby数据库实现 */ private static double selectivity(OPERATION operator) { if (operator == OPERATION.EQ) { return 0.1; } if (operator == OPERATION.GT || operator == OPERATION.GT_EQ) { return 0.33; } if (operator == OPERATION.LT || operator == OPERATION.LT_EQ) { return 0.33; } if (operator == OPERATION.NOT_EQ) { return 0.9; } if (operator == OPERATION.IS_NULL) { return 0.1; } if (operator == OPERATION.IS_NOT_NULL) { return 0.9; } if (operator == OPERATION.LIKE) { return 0.9; } if (operator == OPERATION.IN) { return 0.2; } return 0.5; } }