package com.taobao.tddl.optimizer.costbased;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import com.taobao.tddl.common.model.ExtraCmd;
import com.taobao.tddl.common.utils.GeneralUtil;
import com.taobao.tddl.optimizer.config.table.IndexMeta;
import com.taobao.tddl.optimizer.core.ast.QueryTreeNode;
import com.taobao.tddl.optimizer.core.ast.QueryTreeNode.FilterType;
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.ISelectable;
import com.taobao.tddl.optimizer.costbased.chooser.IndexChooser;
import com.taobao.tddl.optimizer.exceptions.QueryException;
import com.taobao.tddl.optimizer.utils.FilterUtils;
import com.taobao.tddl.optimizer.utils.OptimizerUtils;
/**
* 条件分离器 简单来说 一个查询 A = 1 and B = 2 <br/>
* 需要分析出哪些是key filter?哪些是 post filter( ResultFilter) <br/>
* 在这里进行分离 key filter就是能走索引的那些filter,post filter就是必须遍历结果集的那些filter
*
* @author Dreamond
* @since 5.0.0
*/
public class FilterSpliter {
/**
* 根据where中的所有条件按照or进行分隔,生成多个query请求. (主要考虑部分存储引擎不支持or语法)
*/
public static List<QueryTreeNode> splitByDNF(TableNode node, Map<String, Object> extraCmd) throws QueryException {
if (node.getWhereFilter() == null) {
return new LinkedList<QueryTreeNode>();
}
if (!FilterUtils.isDNF(node.getWhereFilter())) {
throw new IllegalArgumentException("not dnf!!! fuck!!\n" + node.getWhereFilter());
}
List<QueryTreeNode> subQueries = new LinkedList<QueryTreeNode>();
List<List<IFilter>> DNFNodes = FilterUtils.toDNFNodesArray(node.getWhereFilter());
// 判断是否要处理OR转化为index merge,比如mysql可以push
// 比如hbase/bdb这一类,OR条件目前只能是主键索引,由执行器层面去解决
// 如果涉及多字段时就需要拆分为index merge,同时做uniq
boolean needCopy = (DNFNodes.size() > 1);
if (isOptimizeIndexMerge(extraCmd) || DNFNodes.size() == 1) {
for (List<IFilter> DNFNode : DNFNodes) {
List columns = Arrays.asList(FilterUtils.toColumnFiltersMap(DNFNode).keySet().toArray());
String tablename = node.getTableName();
IndexMeta index = IndexChooser.findBestIndex(node.getTableMeta(), columns, DNFNode, tablename, extraCmd);
if (index == null) {
index = node.getTableMeta().getPrimaryIndex();
}
// 如果找不到对应条件的主键,可能需要全表扫描
TableNode subQuery = node;
if (needCopy) {
subQuery = node.deepCopy();
}
subQuery.useIndex(index);
if (index == null) {// 如果无主键进行全表扫描
subQuery.setFullTableScan(true);
}
Map<FilterType, IFilter> filters = splitByIndex(DNFNode, subQuery);
subQuery.setKeyFilter(filters.get(FilterType.IndexQueryKeyFilter));
subQuery.setIndexQueryValueFilter(filters.get(FilterType.IndexQueryValueFilter));
subQuery.setResultFilter(filters.get(FilterType.ResultFilter));
subQueries.add(subQuery);
}
} else {
node.useIndex(node.getTableMeta().getPrimaryIndex());// 默认选中主键
node.setResultFilter(node.getWhereFilter());
}
return subQueries;
}
/**
* 将一组filter,根据索引信息拆分为key/indexValue/Value几种分组,keyFilter可以下推到叶子节点减少数据返回
*/
public static Map<FilterType, IFilter> splitByIndex(List<IFilter> DNFNode, TableNode table) {
Map<FilterType, IFilter> filters = new HashMap();
Map<Object, List<IFilter>> columnAndItsFilters = FilterUtils.toColumnFiltersMap(DNFNode);
IndexMeta index = table.getIndexUsed();
if (index == null) { // 默认选择主键
index = table.getTableMeta().getPrimaryIndex();
}
List<ISelectable> indexKeyColumns = new ArrayList(0);
List<ISelectable> indexValueColumns = new ArrayList(0);
if (index != null) {
indexKeyColumns = OptimizerUtils.columnMetaListToIColumnList(index.getKeyColumns(), table.getTableName());
indexValueColumns = OptimizerUtils.columnMetaListToIColumnList(index.getValueColumns(),
table.getTableName());
}
List<IFilter> indexQueryKeyFilters = new LinkedList();
List<IFilter> indexQueryValueFilters = new LinkedList();
List<IFilter> resultFilters = new LinkedList(DNFNode);
for (int i = 0; i < indexKeyColumns.size(); i++) {
// 不等于,is null, is not null, like 应该按照valueFilter处理
List<IFilter> fs = columnAndItsFilters.get(indexKeyColumns.get(i));
if (fs != null) {
for (IFilter f : fs) {
// filter右边不是常量的,不能走索引
if (((IBooleanFilter) f).getValue() != null
&& (((IBooleanFilter) f).getValue() instanceof ISelectable)) {
continue;
}
if (f != null && f.getOperation() != OPERATION.NOT_EQ && f.getOperation() != OPERATION.IS_NOT_NULL
&& f.getOperation() != OPERATION.IS_NULL && f.getOperation() != OPERATION.LIKE) {
indexQueryKeyFilters.add(f);
} else {
indexQueryValueFilters.add(f);
}
}
fs.clear();
}
}
for (int i = 0; i < indexValueColumns.size(); i++) {
// 不等于,is null, is not null, like 应该按照valueFilter处理
List<IFilter> fs = columnAndItsFilters.get(indexValueColumns.get(i));
if (fs != null) {
for (IFilter f : fs) {
// filter右边不是常量的,不能走索引
if (((IBooleanFilter) f).getValue() != null
&& (((IBooleanFilter) f).getValue() instanceof ISelectable)) {
continue;
}
indexQueryValueFilters.add(f);
}
fs.clear();
}
}
resultFilters.removeAll(indexQueryKeyFilters);
resultFilters.removeAll(indexQueryValueFilters);
IFilter indexQueryKeyTree = FilterUtils.DNFToAndLogicTree(indexQueryKeyFilters);
IFilter indexQueryValueTree = FilterUtils.DNFToAndLogicTree(indexQueryValueFilters);
IFilter resultTree = FilterUtils.DNFToAndLogicTree(resultFilters);
filters.put(FilterType.IndexQueryKeyFilter, indexQueryKeyTree);
filters.put(FilterType.IndexQueryValueFilter, indexQueryValueTree);
filters.put(FilterType.ResultFilter, resultTree);
return filters;
}
private static boolean isOptimizeIndexMerge(Map<String, Object> extraCmd) {
return GeneralUtil.getExtraCmdBoolean(extraCmd, ExtraCmd.CHOOSE_INDEX_MERGE, false);
}
}