package com.tesora.dve.sql.transform.strategy; /* * #%L * Tesora Inc. * Database Virtualization Engine * %% * Copyright (C) 2011 - 2014 Tesora Inc. * %% * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * #L% */ import java.util.Arrays; import java.util.Collections; import java.util.List; import com.tesora.dve.sql.transform.constraints.PlanningConstraint; // predicted execution cost // we are interested in: // - how many sites // - how much data // - specific row counts // - cardinality info // // we have several levels of what we can know about the cost, in order from best to worst. // [1] an estimated row count - this would be an upper bound. // [2] existence of a where clause // [3] single or multisite // we always have to keep track of all of it public class ExecutionCost implements Comparable<ExecutionCost> { // may not be that bad if only on one site protected boolean singleSite; // the constraint that rules - for partition queries this is the limiting constraint // once joined, this is the expectation (i.e. not limiting) protected PlanningConstraint constraint; // even if we didn't find a constraint, we might still have a where clause protected boolean whereClause; // roughly, the group score protected int score; // row estimate protected long rowCount; public ExecutionCost(boolean wc, boolean oneSite, PlanningConstraint c, long rowEstimate) { singleSite = oneSite; whereClause = wc; if (c == null && !wc) score = 100; else if (singleSite) score = 1; else score = 10; constraint = c; rowCount = rowEstimate; } public ExecutionCost(boolean wc, boolean oneSite, ExecutionCost basis) { this(wc,oneSite,basis.getConstraint(),basis.getRowCount()); } public ExecutionCost(PlanningConstraint c, long rowEstimate, ExecutionCost...costs) { singleSite = true; score = -1; for(ExecutionCost ec : costs) { if (ec.hasWhereClause()) whereClause = true; if (!ec.singleSite) singleSite = false; if (ec.score > score) score = ec.score; } constraint = c; rowCount = rowEstimate; } public ExecutionCost(ExecutionCost basis, long rowEstimate) { whereClause = basis.whereClause; singleSite = basis.singleSite; score = basis.score; constraint = basis.constraint; rowCount = rowEstimate; } @Override public String toString() { return "Cost(" + score + "): singleSite=" + singleSite + ", constraint=" + constraint + ", wc=" + whereClause; } @Override public int compareTo(ExecutionCost o) { // a row count beats everything - it definitively says that the upper bound on number of rows // will be the number sites * rowCount. if (rowCount > -1 && o.rowCount > -1) { if (rowCount < o.rowCount) return -1; else if (rowCount > o.rowCount) return 1; return 0; } if (constraint != null && o.constraint != null) return constraint.compareTo(o.constraint); else if (constraint == null && o.constraint != null) return 1; else if (constraint != null && o.constraint == null) return -1; else if (score < o.score) return -1; else if (score > o.score) return 1; else if (whereClause && !o.whereClause) return -1; else if (!whereClause && o.whereClause) return 1; else return 0; } public PlanningConstraint getConstraint() { return constraint; } public boolean isSingleSite() { return singleSite; } public void setSingleSite() { singleSite = true; } public boolean hasWhereClause() { return whereClause; } public int getGroupScore() { return score; } public long getRowCount() { return rowCount; } public static ExecutionCost minimize(ExecutionCost[] in) { Arrays.sort(in); return in[0]; } public static ExecutionCost minimize(List<ExecutionCost> in) { Collections.sort(in); return in.get(0); } public static ExecutionCost maximize(List<ExecutionCost> in) { Collections.sort(in); return in.get(in.size() - 1); } }