提交 80398809 authored 作者: Noel Grandin's avatar Noel Grandin

Fix heavy CPU usage caused by query planner enhancement in 1.4.191

上级 a9322688
...@@ -21,6 +21,8 @@ Change Log ...@@ -21,6 +21,8 @@ Change Log
<h2>Next Version (unreleased)</h2> <h2>Next Version (unreleased)</h2>
<ul> <ul>
<li>Fix extra CPU usage caused by query planner enhancement in 1.4.191
</li>
<li>improve performance of queries that use LIKE 'foo%' - 10x in the case of one of my queries <li>improve performance of queries that use LIKE 'foo%' - 10x in the case of one of my queries
</li> </li>
<li>Issue #231: Possible infinite loop when initializing the ObjectDataType class <li>Issue #231: Possible infinite loop when initializing the ObjectDataType class
......
...@@ -12,6 +12,7 @@ import org.h2.engine.Right; ...@@ -12,6 +12,7 @@ import org.h2.engine.Right;
import org.h2.engine.Session; import org.h2.engine.Session;
import org.h2.engine.UndoLogRecord; import org.h2.engine.UndoLogRecord;
import org.h2.expression.Expression; import org.h2.expression.Expression;
import org.h2.expression.ExpressionVisitor;
import org.h2.result.ResultInterface; import org.h2.result.ResultInterface;
import org.h2.result.Row; import org.h2.result.Row;
import org.h2.result.RowList; import org.h2.result.RowList;
...@@ -130,7 +131,9 @@ public class Delete extends Prepared { ...@@ -130,7 +131,9 @@ public class Delete extends Prepared {
condition = condition.optimize(session); condition = condition.optimize(session);
condition.createIndexConditions(session, tableFilter); condition.createIndexConditions(session, tableFilter);
} }
PlanItem item = tableFilter.getBestPlanItem(session, new TableFilter[]{tableFilter}, 0); TableFilter[] filters = new TableFilter[] { tableFilter };
PlanItem item = tableFilter.getBestPlanItem(session, filters, 0,
ExpressionVisitor.allColumnsForTableFilters(filters));
tableFilter.setPlanItem(item); tableFilter.setPlanItem(item);
tableFilter.prepare(); tableFilter.prepare();
} }
......
...@@ -20,7 +20,6 @@ import java.util.Collection; ...@@ -20,7 +20,6 @@ import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.Comparator; import java.util.Comparator;
import java.util.Set; import java.util.Set;
import org.h2.api.ErrorCode; import org.h2.api.ErrorCode;
import org.h2.command.CommandInterface; import org.h2.command.CommandInterface;
import org.h2.command.Parser; import org.h2.command.Parser;
...@@ -389,7 +388,7 @@ public class ScriptCommand extends ScriptBase { ...@@ -389,7 +388,7 @@ public class ScriptCommand extends ScriptBase {
} }
private int generateInsertValues(int count, Table table) throws IOException { private int generateInsertValues(int count, Table table) throws IOException {
PlanItem plan = table.getBestPlanItem(session, null, null, -1, null); PlanItem plan = table.getBestPlanItem(session, null, null, -1, null, null);
Index index = plan.getIndex(); Index index = plan.getIndex();
Cursor cursor = index.find(session, null, null); Cursor cursor = index.find(session, null, null);
Column[] columns = table.getColumns(); Column[] columns = table.getColumns();
......
...@@ -7,7 +7,6 @@ package org.h2.command.dml; ...@@ -7,7 +7,6 @@ package org.h2.command.dml;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import org.h2.api.ErrorCode; import org.h2.api.ErrorCode;
import org.h2.api.Trigger; import org.h2.api.Trigger;
import org.h2.command.CommandInterface; import org.h2.command.CommandInterface;
...@@ -15,6 +14,7 @@ import org.h2.command.Prepared; ...@@ -15,6 +14,7 @@ import org.h2.command.Prepared;
import org.h2.engine.Right; import org.h2.engine.Right;
import org.h2.engine.Session; import org.h2.engine.Session;
import org.h2.expression.Expression; import org.h2.expression.Expression;
import org.h2.expression.ExpressionVisitor;
import org.h2.expression.Parameter; import org.h2.expression.Parameter;
import org.h2.expression.ValueExpression; import org.h2.expression.ValueExpression;
import org.h2.message.DbException; import org.h2.message.DbException;
...@@ -191,7 +191,9 @@ public class Update extends Prepared { ...@@ -191,7 +191,9 @@ public class Update extends Prepared {
e.mapColumns(tableFilter, 0); e.mapColumns(tableFilter, 0);
expressionMap.put(c, e.optimize(session)); expressionMap.put(c, e.optimize(session));
} }
PlanItem item = tableFilter.getBestPlanItem(session, new TableFilter[] {tableFilter}, 0); TableFilter[] filters = new TableFilter[] { tableFilter };
PlanItem item = tableFilter.getBestPlanItem(session, filters, 0,
ExpressionVisitor.allColumnsForTableFilters(filters));
tableFilter.setPlanItem(item); tableFilter.setPlanItem(item);
tableFilter.prepare(); tableFilter.prepare();
} }
......
...@@ -10,6 +10,8 @@ import org.h2.engine.DbObject; ...@@ -10,6 +10,8 @@ import org.h2.engine.DbObject;
import org.h2.table.Column; import org.h2.table.Column;
import org.h2.table.ColumnResolver; import org.h2.table.ColumnResolver;
import org.h2.table.Table; import org.h2.table.Table;
import org.h2.table.TableFilter;
import org.h2.util.New;
/** /**
* The visitor pattern is used to iterate through all expressions of a query * The visitor pattern is used to iterate through all expressions of a query
...@@ -286,4 +288,15 @@ public class ExpressionVisitor { ...@@ -286,4 +288,15 @@ public class ExpressionVisitor {
return type; return type;
} }
public static HashSet<Column> allColumnsForTableFilters(TableFilter[] filters) {
HashSet<Column> allColumnsSet = New.hashSet();
for (int i = 0; i < filters.length; i++) {
if (filters[i].getSelect() != null) {
filters[i].getSelect().isEverything(ExpressionVisitor.getColumnsVisitor(allColumnsSet));
}
}
return allColumnsSet;
}
} }
...@@ -5,15 +5,12 @@ ...@@ -5,15 +5,12 @@
*/ */
package org.h2.index; package org.h2.index;
import java.util.Arrays;
import java.util.HashSet; import java.util.HashSet;
import org.h2.api.ErrorCode; import org.h2.api.ErrorCode;
import org.h2.engine.Constants; import org.h2.engine.Constants;
import org.h2.engine.DbObject; import org.h2.engine.DbObject;
import org.h2.engine.Mode; import org.h2.engine.Mode;
import org.h2.engine.Session; import org.h2.engine.Session;
import org.h2.expression.ExpressionVisitor;
import org.h2.message.DbException; import org.h2.message.DbException;
import org.h2.message.Trace; import org.h2.message.Trace;
import org.h2.result.Row; import org.h2.result.Row;
...@@ -25,7 +22,6 @@ import org.h2.table.IndexColumn; ...@@ -25,7 +22,6 @@ import org.h2.table.IndexColumn;
import org.h2.table.Table; import org.h2.table.Table;
import org.h2.table.TableFilter; import org.h2.table.TableFilter;
import org.h2.util.MathUtils; import org.h2.util.MathUtils;
import org.h2.util.New;
import org.h2.util.StatementBuilder; import org.h2.util.StatementBuilder;
import org.h2.util.StringUtils; import org.h2.util.StringUtils;
import org.h2.value.Value; import org.h2.value.Value;
...@@ -164,7 +160,7 @@ public abstract class BaseIndex extends SchemaObjectBase implements Index { ...@@ -164,7 +160,7 @@ public abstract class BaseIndex extends SchemaObjectBase implements Index {
*/ */
protected final long getCostRangeIndex(int[] masks, long rowCount, protected final long getCostRangeIndex(int[] masks, long rowCount,
TableFilter[] filters, int filter, SortOrder sortOrder, TableFilter[] filters, int filter, SortOrder sortOrder,
boolean isScanIndex) { boolean isScanIndex, HashSet<Column> allColumnsSet) {
rowCount += Constants.COST_ROW_OFFSET; rowCount += Constants.COST_ROW_OFFSET;
int totalSelectivity = 0; int totalSelectivity = 0;
long rowsCost = rowCount; long rowsCost = rowCount;
...@@ -244,27 +240,28 @@ public abstract class BaseIndex extends SchemaObjectBase implements Index { ...@@ -244,27 +240,28 @@ public abstract class BaseIndex extends SchemaObjectBase implements Index {
} }
} }
// If we have two indexes with the same cost, and one of the indexes can // If we have two indexes with the same cost, and one of the indexes can
// satisfy the query without needing to read from the primary table, // satisfy the query without needing to read from the primary table (scan index),
// make that one slightly lower cost. // make that one slightly lower cost.
boolean needsToReadFromScanIndex = true; boolean needsToReadFromScanIndex = true;
if (!isScanIndex) { if (!isScanIndex && allColumnsSet != null && !allColumnsSet.isEmpty()) {
HashSet<Column> set1 = New.hashSet(); boolean foundAllColumnsWeNeed = true;
for (int i = 0; i < filters.length; i++) { for (Column c : allColumnsSet) {
if (filters[i].getSelect() != null) { if (c.getTable() == getTable()) {
filters[i].getSelect().isEverything(ExpressionVisitor.getColumnsVisitor(set1)); boolean found = false;
} for (Column c2 : columns) {
} if (c == c2) {
if (!set1.isEmpty()) { found = true;
HashSet<Column> set2 = New.hashSet(); break;
for (Column c : set1) { }
if (c.getTable() == getTable()) { }
set2.add(c); if (!found) {
foundAllColumnsWeNeed = false;
break;
} }
} }
set2.removeAll(Arrays.asList(columns)); }
if (set2.isEmpty()) { if (foundAllColumnsWeNeed) {
needsToReadFromScanIndex = false; needsToReadFromScanIndex = false;
}
} }
} }
long rc; long rc;
......
...@@ -5,11 +5,13 @@ ...@@ -5,11 +5,13 @@
*/ */
package org.h2.index; package org.h2.index;
import java.util.HashSet;
import org.h2.engine.Session; import org.h2.engine.Session;
import org.h2.message.DbException; import org.h2.message.DbException;
import org.h2.result.Row; import org.h2.result.Row;
import org.h2.result.SearchRow; import org.h2.result.SearchRow;
import org.h2.result.SortOrder; import org.h2.result.SortOrder;
import org.h2.table.Column;
import org.h2.table.FunctionTable; import org.h2.table.FunctionTable;
import org.h2.table.IndexColumn; import org.h2.table.IndexColumn;
import org.h2.table.TableFilter; import org.h2.table.TableFilter;
...@@ -53,7 +55,8 @@ public class FunctionIndex extends BaseIndex { ...@@ -53,7 +55,8 @@ public class FunctionIndex extends BaseIndex {
@Override @Override
public double getCost(Session session, int[] masks, public double getCost(Session session, int[] masks,
TableFilter[] filters, int filter, SortOrder sortOrder) { TableFilter[] filters, int filter, SortOrder sortOrder,
HashSet<Column> allColumnsSet) {
if (masks != null) { if (masks != null) {
throw DbException.getUnsupportedException("ALIAS"); throw DbException.getUnsupportedException("ALIAS");
} }
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
*/ */
package org.h2.index; package org.h2.index;
import java.util.HashSet;
import org.h2.engine.Session; import org.h2.engine.Session;
import org.h2.message.DbException; import org.h2.message.DbException;
import org.h2.result.Row; import org.h2.result.Row;
...@@ -114,7 +115,8 @@ public class HashIndex extends BaseIndex { ...@@ -114,7 +115,8 @@ public class HashIndex extends BaseIndex {
@Override @Override
public double getCost(Session session, int[] masks, public double getCost(Session session, int[] masks,
TableFilter[] filters, int filter, SortOrder sortOrder) { TableFilter[] filters, int filter, SortOrder sortOrder,
HashSet<Column> allColumnsSet) {
for (Column column : columns) { for (Column column : columns) {
int index = column.getColumnId(); int index = column.getColumnId();
int mask = masks[index]; int mask = masks[index];
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
*/ */
package org.h2.index; package org.h2.index;
import java.util.HashSet;
import org.h2.engine.Session; import org.h2.engine.Session;
import org.h2.result.Row; import org.h2.result.Row;
import org.h2.result.SearchRow; import org.h2.result.SearchRow;
...@@ -87,7 +88,7 @@ public interface Index extends SchemaObject { ...@@ -87,7 +88,7 @@ public interface Index extends SchemaObject {
* @return the estimated cost * @return the estimated cost
*/ */
double getCost(Session session, int[] masks, TableFilter[] filters, int filter, double getCost(Session session, int[] masks, TableFilter[] filters, int filter,
SortOrder sortOrder); SortOrder sortOrder, HashSet<Column> allColumnsSet);
/** /**
* Remove the index. * Remove the index.
......
...@@ -8,6 +8,7 @@ package org.h2.index; ...@@ -8,6 +8,7 @@ package org.h2.index;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashSet;
import org.h2.engine.Constants; import org.h2.engine.Constants;
import org.h2.engine.Session; import org.h2.engine.Session;
import org.h2.message.DbException; import org.h2.message.DbException;
...@@ -142,9 +143,10 @@ public class LinkedIndex extends BaseIndex { ...@@ -142,9 +143,10 @@ public class LinkedIndex extends BaseIndex {
@Override @Override
public double getCost(Session session, int[] masks, public double getCost(Session session, int[] masks,
TableFilter[] filters, int filter, SortOrder sortOrder) { TableFilter[] filters, int filter, SortOrder sortOrder,
HashSet<Column> allColumnsSet) {
return 100 + getCostRangeIndex(masks, rowCount + return 100 + getCostRangeIndex(masks, rowCount +
Constants.COST_ROW_OFFSET, filters, filter, sortOrder, false); Constants.COST_ROW_OFFSET, filters, filter, sortOrder, false, allColumnsSet);
} }
@Override @Override
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
package org.h2.index; package org.h2.index;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashSet;
import org.h2.engine.Session; import org.h2.engine.Session;
import org.h2.message.DbException; import org.h2.message.DbException;
import org.h2.result.Row; import org.h2.result.Row;
...@@ -53,12 +54,13 @@ public class MetaIndex extends BaseIndex { ...@@ -53,12 +54,13 @@ public class MetaIndex extends BaseIndex {
@Override @Override
public double getCost(Session session, int[] masks, public double getCost(Session session, int[] masks,
TableFilter[] filters, int filter, SortOrder sortOrder) { TableFilter[] filters, int filter, SortOrder sortOrder,
HashSet<Column> allColumnsSet) {
if (scan) { if (scan) {
return 10 * MetaTable.ROW_COUNT_APPROXIMATION; return 10 * MetaTable.ROW_COUNT_APPROXIMATION;
} }
return getCostRangeIndex(masks, MetaTable.ROW_COUNT_APPROXIMATION, return getCostRangeIndex(masks, MetaTable.ROW_COUNT_APPROXIMATION,
filters, filter, sortOrder, false); filters, filter, sortOrder, false, allColumnsSet);
} }
@Override @Override
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
package org.h2.index; package org.h2.index;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashSet;
import org.h2.api.ErrorCode; import org.h2.api.ErrorCode;
import org.h2.engine.Database; import org.h2.engine.Database;
import org.h2.engine.DbObject; import org.h2.engine.DbObject;
...@@ -141,8 +142,9 @@ public class MultiVersionIndex implements Index { ...@@ -141,8 +142,9 @@ public class MultiVersionIndex implements Index {
@Override @Override
public double getCost(Session session, int[] masks, public double getCost(Session session, int[] masks,
TableFilter[] filters, int filter, SortOrder sortOrder) { TableFilter[] filters, int filter, SortOrder sortOrder,
return base.getCost(session, masks, filters, filter, sortOrder); HashSet<Column> allColumnsSet) {
return base.getCost(session, masks, filters, filter, sortOrder, allColumnsSet);
} }
@Override @Override
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
package org.h2.index; package org.h2.index;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashSet;
import org.h2.engine.Session; import org.h2.engine.Session;
import org.h2.message.DbException; import org.h2.message.DbException;
import org.h2.result.Row; import org.h2.result.Row;
...@@ -131,7 +132,8 @@ public class NonUniqueHashIndex extends BaseIndex { ...@@ -131,7 +132,8 @@ public class NonUniqueHashIndex extends BaseIndex {
@Override @Override
public double getCost(Session session, int[] masks, public double getCost(Session session, int[] masks,
TableFilter[] filters, int filter, SortOrder sortOrder) { TableFilter[] filters, int filter, SortOrder sortOrder,
HashSet<Column> allColumnsSet) {
for (Column column : columns) { for (Column column : columns) {
int index = column.getColumnId(); int index = column.getColumnId();
int mask = masks[index]; int mask = masks[index];
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
*/ */
package org.h2.index; package org.h2.index;
import java.util.HashSet;
import org.h2.api.ErrorCode; import org.h2.api.ErrorCode;
import org.h2.engine.Constants; import org.h2.engine.Constants;
import org.h2.engine.Session; import org.h2.engine.Session;
...@@ -218,9 +219,10 @@ public class PageBtreeIndex extends PageIndex { ...@@ -218,9 +219,10 @@ public class PageBtreeIndex extends PageIndex {
@Override @Override
public double getCost(Session session, int[] masks, public double getCost(Session session, int[] masks,
TableFilter[] filters, int filter, SortOrder sortOrder) { TableFilter[] filters, int filter, SortOrder sortOrder,
HashSet<Column> allColumnsSet) {
return 10 * getCostRangeIndex(masks, tableData.getRowCount(session), return 10 * getCostRangeIndex(masks, tableData.getRowCount(session),
filters, filter, sortOrder, false); filters, filter, sortOrder, false, allColumnsSet);
} }
@Override @Override
......
...@@ -310,7 +310,8 @@ public class PageDataIndex extends PageIndex { ...@@ -310,7 +310,8 @@ public class PageDataIndex extends PageIndex {
@Override @Override
public double getCost(Session session, int[] masks, public double getCost(Session session, int[] masks,
TableFilter[] filters, int filter, SortOrder sortOrder) { TableFilter[] filters, int filter, SortOrder sortOrder,
HashSet<Column> allColumnsSet) {
long cost = 10 * (tableData.getRowCountApproximation() + long cost = 10 * (tableData.getRowCountApproximation() +
Constants.COST_ROW_OFFSET); Constants.COST_ROW_OFFSET);
return cost; return cost;
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
*/ */
package org.h2.index; package org.h2.index;
import java.util.HashSet;
import org.h2.engine.Session; import org.h2.engine.Session;
import org.h2.message.DbException; import org.h2.message.DbException;
import org.h2.result.Row; import org.h2.result.Row;
...@@ -97,9 +98,10 @@ public class PageDelegateIndex extends PageIndex { ...@@ -97,9 +98,10 @@ public class PageDelegateIndex extends PageIndex {
@Override @Override
public double getCost(Session session, int[] masks, public double getCost(Session session, int[] masks,
TableFilter[] filters, int filter, SortOrder sortOrder) { TableFilter[] filters, int filter, SortOrder sortOrder,
HashSet<Column> allColumnsSet) {
return 10 * getCostRangeIndex(masks, mainIndex.getRowCount(session), return 10 * getCostRangeIndex(masks, mainIndex.getRowCount(session),
filters, filter, sortOrder, false); filters, filter, sortOrder, false, allColumnsSet);
} }
@Override @Override
......
...@@ -5,11 +5,13 @@ ...@@ -5,11 +5,13 @@
*/ */
package org.h2.index; package org.h2.index;
import java.util.HashSet;
import org.h2.engine.Session; import org.h2.engine.Session;
import org.h2.message.DbException; import org.h2.message.DbException;
import org.h2.result.Row; import org.h2.result.Row;
import org.h2.result.SearchRow; import org.h2.result.SearchRow;
import org.h2.result.SortOrder; import org.h2.result.SortOrder;
import org.h2.table.Column;
import org.h2.table.IndexColumn; import org.h2.table.IndexColumn;
import org.h2.table.RangeTable; import org.h2.table.RangeTable;
import org.h2.table.TableFilter; import org.h2.table.TableFilter;
...@@ -63,7 +65,8 @@ public class RangeIndex extends BaseIndex { ...@@ -63,7 +65,8 @@ public class RangeIndex extends BaseIndex {
@Override @Override
public double getCost(Session session, int[] masks, public double getCost(Session session, int[] masks,
TableFilter[] filters, int filter, SortOrder sortOrder) { TableFilter[] filters, int filter, SortOrder sortOrder,
HashSet<Column> allColumnsSet) {
return 1; return 1;
} }
......
...@@ -11,7 +11,6 @@ import java.util.HashMap; ...@@ -11,7 +11,6 @@ import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import org.h2.api.ErrorCode; import org.h2.api.ErrorCode;
import org.h2.engine.Constants; import org.h2.engine.Constants;
import org.h2.engine.Session; import org.h2.engine.Session;
...@@ -175,7 +174,8 @@ public class ScanIndex extends BaseIndex { ...@@ -175,7 +174,8 @@ public class ScanIndex extends BaseIndex {
@Override @Override
public double getCost(Session session, int[] masks, public double getCost(Session session, int[] masks,
TableFilter[] filters, int filter, SortOrder sortOrder) { TableFilter[] filters, int filter, SortOrder sortOrder,
HashSet<Column> allColumnsSet) {
return tableData.getRowCountApproximation() + Constants.COST_ROW_OFFSET; return tableData.getRowCountApproximation() + Constants.COST_ROW_OFFSET;
} }
......
...@@ -5,8 +5,8 @@ ...@@ -5,8 +5,8 @@
*/ */
package org.h2.index; package org.h2.index;
import java.util.HashSet;
import java.util.Iterator; import java.util.Iterator;
import org.h2.engine.Constants; import org.h2.engine.Constants;
import org.h2.engine.Session; import org.h2.engine.Session;
import org.h2.message.DbException; import org.h2.message.DbException;
...@@ -24,7 +24,6 @@ import org.h2.table.TableFilter; ...@@ -24,7 +24,6 @@ import org.h2.table.TableFilter;
import org.h2.value.Value; import org.h2.value.Value;
import org.h2.value.ValueGeometry; import org.h2.value.ValueGeometry;
import org.h2.value.ValueNull; import org.h2.value.ValueNull;
import com.vividsolutions.jts.geom.Envelope; import com.vividsolutions.jts.geom.Envelope;
import com.vividsolutions.jts.geom.Geometry; import com.vividsolutions.jts.geom.Geometry;
...@@ -203,7 +202,8 @@ public class SpatialTreeIndex extends BaseIndex implements SpatialIndex { ...@@ -203,7 +202,8 @@ public class SpatialTreeIndex extends BaseIndex implements SpatialIndex {
@Override @Override
public double getCost(Session session, int[] masks, public double getCost(Session session, int[] masks,
TableFilter[] filters, int filter, SortOrder sortOrder) { TableFilter[] filters, int filter, SortOrder sortOrder,
HashSet<Column> allColumnsSet) {
return getCostRangeIndex(masks, table.getRowCountApproximation(), columns); return getCostRangeIndex(masks, table.getRowCountApproximation(), columns);
} }
......
...@@ -5,12 +5,14 @@ ...@@ -5,12 +5,14 @@
*/ */
package org.h2.index; package org.h2.index;
import java.util.HashSet;
import org.h2.engine.Session; import org.h2.engine.Session;
import org.h2.engine.SysProperties; import org.h2.engine.SysProperties;
import org.h2.message.DbException; import org.h2.message.DbException;
import org.h2.result.Row; import org.h2.result.Row;
import org.h2.result.SearchRow; import org.h2.result.SearchRow;
import org.h2.result.SortOrder; import org.h2.result.SortOrder;
import org.h2.table.Column;
import org.h2.table.IndexColumn; import org.h2.table.IndexColumn;
import org.h2.table.RegularTable; import org.h2.table.RegularTable;
import org.h2.table.TableFilter; import org.h2.table.TableFilter;
...@@ -319,9 +321,9 @@ public class TreeIndex extends BaseIndex { ...@@ -319,9 +321,9 @@ public class TreeIndex extends BaseIndex {
@Override @Override
public double getCost(Session session, int[] masks, TableFilter[] filters, int filter, public double getCost(Session session, int[] masks, TableFilter[] filters, int filter,
SortOrder sortOrder) { SortOrder sortOrder, HashSet<Column> allColumnsSet) {
return getCostRangeIndex(masks, tableData.getRowCountApproximation(), return getCostRangeIndex(masks, tableData.getRowCountApproximation(),
filters, filter, sortOrder, false); filters, filter, sortOrder, false, allColumnsSet);
} }
@Override @Override
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
package org.h2.index; package org.h2.index;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashSet;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import org.h2.api.ErrorCode; import org.h2.api.ErrorCode;
import org.h2.command.Prepared; import org.h2.command.Prepared;
...@@ -147,7 +148,8 @@ public class ViewIndex extends BaseIndex implements SpatialIndex { ...@@ -147,7 +148,8 @@ public class ViewIndex extends BaseIndex implements SpatialIndex {
@Override @Override
public double getCost(Session session, int[] masks, public double getCost(Session session, int[] masks,
TableFilter[] filters, int filter, SortOrder sortOrder) { TableFilter[] filters, int filter, SortOrder sortOrder,
HashSet<Column> allColumnsSet) {
return recursive ? 1000 : query.getCost(); return recursive ? 1000 : query.getCost();
} }
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
*/ */
package org.h2.mvstore.db; package org.h2.mvstore.db;
import java.util.HashSet;
import java.util.List; import java.util.List;
import org.h2.engine.Session; import org.h2.engine.Session;
import org.h2.index.BaseIndex; import org.h2.index.BaseIndex;
...@@ -89,9 +90,10 @@ public class MVDelegateIndex extends BaseIndex implements MVIndex { ...@@ -89,9 +90,10 @@ public class MVDelegateIndex extends BaseIndex implements MVIndex {
@Override @Override
public double getCost(Session session, int[] masks, public double getCost(Session session, int[] masks,
TableFilter[] filters, int filter, SortOrder sortOrder) { TableFilter[] filters, int filter, SortOrder sortOrder,
HashSet<Column> allColumnsSet) {
return 10 * getCostRangeIndex(masks, mainIndex.getRowCountApproximation(), return 10 * getCostRangeIndex(masks, mainIndex.getRowCountApproximation(),
filters, filter, sortOrder, true); filters, filter, sortOrder, true, allColumnsSet);
} }
@Override @Override
......
...@@ -7,6 +7,7 @@ package org.h2.mvstore.db; ...@@ -7,6 +7,7 @@ package org.h2.mvstore.db;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map.Entry; import java.util.Map.Entry;
...@@ -216,10 +217,11 @@ public class MVPrimaryIndex extends BaseIndex { ...@@ -216,10 +217,11 @@ public class MVPrimaryIndex extends BaseIndex {
@Override @Override
public double getCost(Session session, int[] masks, public double getCost(Session session, int[] masks,
TableFilter[] filters, int filter, SortOrder sortOrder) { TableFilter[] filters, int filter, SortOrder sortOrder,
HashSet<Column> allColumnsSet) {
try { try {
return 10 * getCostRangeIndex(masks, dataMap.sizeAsLongMax(), return 10 * getCostRangeIndex(masks, dataMap.sizeAsLongMax(),
filters, filter, sortOrder, true); filters, filter, sortOrder, true, allColumnsSet);
} catch (IllegalStateException e) { } catch (IllegalStateException e) {
throw DbException.get(ErrorCode.OBJECT_CLOSED, e); throw DbException.get(ErrorCode.OBJECT_CLOSED, e);
} }
......
...@@ -7,6 +7,7 @@ package org.h2.mvstore.db; ...@@ -7,6 +7,7 @@ package org.h2.mvstore.db;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.TreeSet; import java.util.TreeSet;
...@@ -352,10 +353,11 @@ public class MVSecondaryIndex extends BaseIndex implements MVIndex { ...@@ -352,10 +353,11 @@ public class MVSecondaryIndex extends BaseIndex implements MVIndex {
@Override @Override
public double getCost(Session session, int[] masks, public double getCost(Session session, int[] masks,
TableFilter[] filters, int filter, SortOrder sortOrder) { TableFilter[] filters, int filter, SortOrder sortOrder,
HashSet<Column> allColumnsSet) {
try { try {
return 10 * getCostRangeIndex(masks, dataMap.sizeAsLongMax(), return 10 * getCostRangeIndex(masks, dataMap.sizeAsLongMax(),
filters, filter, sortOrder, false); filters, filter, sortOrder, false, allColumnsSet);
} catch (IllegalStateException e) { } catch (IllegalStateException e) {
throw DbException.get(ErrorCode.OBJECT_CLOSED, e); throw DbException.get(ErrorCode.OBJECT_CLOSED, e);
} }
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
*/ */
package org.h2.mvstore.db; package org.h2.mvstore.db;
import java.util.HashSet;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import org.h2.api.ErrorCode; import org.h2.api.ErrorCode;
...@@ -26,6 +27,7 @@ import org.h2.mvstore.rtree.SpatialKey; ...@@ -26,6 +27,7 @@ import org.h2.mvstore.rtree.SpatialKey;
import org.h2.result.Row; import org.h2.result.Row;
import org.h2.result.SearchRow; import org.h2.result.SearchRow;
import org.h2.result.SortOrder; import org.h2.result.SortOrder;
import org.h2.table.Column;
import org.h2.table.IndexColumn; import org.h2.table.IndexColumn;
import org.h2.table.TableFilter; import org.h2.table.TableFilter;
import org.h2.value.Value; import org.h2.value.Value;
...@@ -238,7 +240,8 @@ public class MVSpatialIndex extends BaseIndex implements SpatialIndex, MVIndex { ...@@ -238,7 +240,8 @@ public class MVSpatialIndex extends BaseIndex implements SpatialIndex, MVIndex {
@Override @Override
public double getCost(Session session, int[] masks, TableFilter[] filters, public double getCost(Session session, int[] masks, TableFilter[] filters,
int filter, SortOrder sortOrder) { int filter, SortOrder sortOrder,
HashSet<Column> allColumnsSet) {
return SpatialTreeIndex.getCostRangeIndex(masks, return SpatialTreeIndex.getCostRangeIndex(masks,
table.getRowCountApproximation(), columns); table.getRowCountApproximation(), columns);
} }
......
...@@ -8,6 +8,7 @@ package org.h2.table; ...@@ -8,6 +8,7 @@ package org.h2.table;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet;
import org.h2.engine.Session; import org.h2.engine.Session;
import org.h2.expression.Expression; import org.h2.expression.Expression;
import org.h2.expression.ExpressionVisitor; import org.h2.expression.ExpressionVisitor;
...@@ -112,12 +113,13 @@ public class Plan { ...@@ -112,12 +113,13 @@ public class Plan {
} }
double cost = 1; double cost = 1;
boolean invalidPlan = false; boolean invalidPlan = false;
final HashSet<Column> allColumnsSet = ExpressionVisitor.allColumnsForTableFilters(allFilters);
for (int i = 0; i < allFilters.length; i++) { for (int i = 0; i < allFilters.length; i++) {
TableFilter tableFilter = allFilters[i]; TableFilter tableFilter = allFilters[i];
if (t.isDebugEnabled()) { if (t.isDebugEnabled()) {
t.debug("Plan : for table filter {0}", tableFilter); t.debug("Plan : for table filter {0}", tableFilter);
} }
PlanItem item = tableFilter.getBestPlanItem(session, allFilters, i); PlanItem item = tableFilter.getBestPlanItem(session, allFilters, i, allColumnsSet);
planItems.put(tableFilter, item); planItems.put(tableFilter, item);
if (t.isDebugEnabled()) { if (t.isDebugEnabled()) {
t.debug("Plan : best plan item cost {0} index {1}", t.debug("Plan : best plan item cost {0} index {1}",
......
...@@ -246,12 +246,13 @@ public abstract class Table extends SchemaObjectBase { ...@@ -246,12 +246,13 @@ public abstract class Table extends SchemaObjectBase {
* @param session the session * @param session the session
* @param masks the search mask * @param masks the search mask
* @param filters the table filters * @param filters the table filters
* @param filter the filer index * @param filter the filter index
* @param sortOrder the sort order * @param sortOrder the sort order
* @return the scan index * @return the scan index
*/ */
public Index getScanIndex(Session session, int[] masks, public Index getScanIndex(Session session, int[] masks,
TableFilter[] filters, int filter, SortOrder sortOrder) { TableFilter[] filters, int filter, SortOrder sortOrder,
HashSet<Column> allColumnsSet) {
return getScanIndex(session); return getScanIndex(session);
} }
...@@ -704,10 +705,11 @@ public abstract class Table extends SchemaObjectBase { ...@@ -704,10 +705,11 @@ public abstract class Table extends SchemaObjectBase {
* @return the plan item * @return the plan item
*/ */
public PlanItem getBestPlanItem(Session session, int[] masks, public PlanItem getBestPlanItem(Session session, int[] masks,
TableFilter[] filters, int filter, SortOrder sortOrder) { TableFilter[] filters, int filter, SortOrder sortOrder,
HashSet<Column> allColumnsSet) {
PlanItem item = new PlanItem(); PlanItem item = new PlanItem();
item.setIndex(getScanIndex(session)); item.setIndex(getScanIndex(session));
item.cost = item.getIndex().getCost(session, null, filters, filter, null); item.cost = item.getIndex().getCost(session, null, filters, filter, null, allColumnsSet);
Trace t = session.getTrace(); Trace t = session.getTrace();
if (t.isDebugEnabled()) { if (t.isDebugEnabled()) {
t.debug("Table : potential plan item cost {0} index {1}", t.debug("Table : potential plan item cost {0} index {1}",
...@@ -717,7 +719,7 @@ public abstract class Table extends SchemaObjectBase { ...@@ -717,7 +719,7 @@ public abstract class Table extends SchemaObjectBase {
if (indexes != null && masks != null) { if (indexes != null && masks != null) {
for (int i = 1, size = indexes.size(); i < size; i++) { for (int i = 1, size = indexes.size(); i < size; i++) {
Index index = indexes.get(i); Index index = indexes.get(i);
double cost = index.getCost(session, masks, filters, filter, sortOrder); double cost = index.getCost(session, masks, filters, filter, sortOrder, allColumnsSet);
if (t.isDebugEnabled()) { if (t.isDebugEnabled()) {
t.debug("Table : potential plan item cost {0} index {1}", t.debug("Table : potential plan item cost {0} index {1}",
cost, index.getPlanSQL()); cost, index.getPlanSQL());
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
package org.h2.table; package org.h2.table;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashSet;
import org.h2.command.Parser; import org.h2.command.Parser;
import org.h2.command.dml.Select; import org.h2.command.dml.Select;
import org.h2.engine.Right; import org.h2.engine.Right;
...@@ -186,7 +186,8 @@ public class TableFilter implements ColumnResolver { ...@@ -186,7 +186,8 @@ public class TableFilter implements ColumnResolver {
* @param filter the current table filter index * @param filter the current table filter index
* @return the best plan item * @return the best plan item
*/ */
public PlanItem getBestPlanItem(Session s, TableFilter[] filters, int filter) { public PlanItem getBestPlanItem(Session s, TableFilter[] filters, int filter,
HashSet<Column> allColumnsSet) {
PlanItem item1 = null; PlanItem item1 = null;
SortOrder sortOrder = null; SortOrder sortOrder = null;
if (select != null) { if (select != null) {
...@@ -194,8 +195,8 @@ public class TableFilter implements ColumnResolver { ...@@ -194,8 +195,8 @@ public class TableFilter implements ColumnResolver {
} }
if (indexConditions.size() == 0) { if (indexConditions.size() == 0) {
item1 = new PlanItem(); item1 = new PlanItem();
item1.setIndex(table.getScanIndex(s, null, filters, filter, sortOrder)); item1.setIndex(table.getScanIndex(s, null, filters, filter, sortOrder, allColumnsSet));
item1.cost = item1.getIndex().getCost(s, null, filters, filter, sortOrder); item1.cost = item1.getIndex().getCost(s, null, filters, filter, sortOrder, allColumnsSet);
} }
int len = table.getColumns().length; int len = table.getColumns().length;
int[] masks = new int[len]; int[] masks = new int[len];
...@@ -211,7 +212,7 @@ public class TableFilter implements ColumnResolver { ...@@ -211,7 +212,7 @@ public class TableFilter implements ColumnResolver {
} }
} }
} }
PlanItem item = table.getBestPlanItem(s, masks, filters, filter, sortOrder); PlanItem item = table.getBestPlanItem(s, masks, filters, filter, sortOrder, allColumnsSet);
item.setMasks(masks); item.setMasks(masks);
// The more index conditions, the earlier the table. // The more index conditions, the earlier the table.
// This is to ensure joins without indexes run quickly: // This is to ensure joins without indexes run quickly:
...@@ -224,7 +225,7 @@ public class TableFilter implements ColumnResolver { ...@@ -224,7 +225,7 @@ public class TableFilter implements ColumnResolver {
if (nestedJoin != null) { if (nestedJoin != null) {
setEvaluatable(nestedJoin); setEvaluatable(nestedJoin);
item.setNestedJoinPlan(nestedJoin.getBestPlanItem(s, filters, filter)); item.setNestedJoinPlan(nestedJoin.getBestPlanItem(s, filters, filter, allColumnsSet));
// TODO optimizer: calculate cost of a join: should use separate // TODO optimizer: calculate cost of a join: should use separate
// expected row number and lookup cost // expected row number and lookup cost
item.cost += item.cost * item.getNestedJoinPlan().cost; item.cost += item.cost * item.getNestedJoinPlan().cost;
...@@ -234,7 +235,7 @@ public class TableFilter implements ColumnResolver { ...@@ -234,7 +235,7 @@ public class TableFilter implements ColumnResolver {
do { do {
filter++; filter++;
} while (filters[filter] != join); } while (filters[filter] != join);
item.setJoinPlan(join.getBestPlanItem(s, filters, filter)); item.setJoinPlan(join.getBestPlanItem(s, filters, filter, allColumnsSet));
// TODO optimizer: calculate cost of a join: should use separate // TODO optimizer: calculate cost of a join: should use separate
// expected row number and lookup cost // expected row number and lookup cost
item.cost += item.cost * item.getJoinPlan().cost; item.cost += item.cost * item.getJoinPlan().cost;
......
...@@ -235,7 +235,8 @@ public class TableView extends Table { ...@@ -235,7 +235,8 @@ public class TableView extends Table {
@Override @Override
public PlanItem getBestPlanItem(Session session, int[] masks, public PlanItem getBestPlanItem(Session session, int[] masks,
TableFilter[] filters, int filter, SortOrder sortOrder) { TableFilter[] filters, int filter, SortOrder sortOrder,
HashSet<Column> allColumnsSet) {
final CacheKey cacheKey = new CacheKey(masks, this); final CacheKey cacheKey = new CacheKey(masks, this);
Map<Object, ViewIndex> indexCache = session.getViewIndexCache(topQuery != null); Map<Object, ViewIndex> indexCache = session.getViewIndexCache(topQuery != null);
ViewIndex i = indexCache.get(cacheKey); ViewIndex i = indexCache.get(cacheKey);
...@@ -244,7 +245,7 @@ public class TableView extends Table { ...@@ -244,7 +245,7 @@ public class TableView extends Table {
indexCache.put(cacheKey, i); indexCache.put(cacheKey, i);
} }
PlanItem item = new PlanItem(); PlanItem item = new PlanItem();
item.cost = i.getCost(session, masks, filters, filter, sortOrder); item.cost = i.getCost(session, masks, filters, filter, sortOrder, allColumnsSet);
item.setIndex(i); item.setIndex(i);
return item; return item;
} }
...@@ -439,18 +440,19 @@ public class TableView extends Table { ...@@ -439,18 +440,19 @@ public class TableView extends Table {
@Override @Override
public Index getScanIndex(Session session) { public Index getScanIndex(Session session) {
return getBestPlanItem(session, null, null, -1, null).getIndex(); return getBestPlanItem(session, null, null, -1, null, null).getIndex();
} }
@Override @Override
public Index getScanIndex(Session session, int[] masks, public Index getScanIndex(Session session, int[] masks,
TableFilter[] filters, int filter, SortOrder sortOrder) { TableFilter[] filters, int filter, SortOrder sortOrder,
HashSet<Column> allColumnsSet) {
if (createException != null) { if (createException != null) {
String msg = createException.getMessage(); String msg = createException.getMessage();
throw DbException.get(ErrorCode.VIEW_IS_INVALID_2, throw DbException.get(ErrorCode.VIEW_IS_INVALID_2,
createException, getSQL(), msg); createException, getSQL(), msg);
} }
PlanItem item = getBestPlanItem(session, masks, filters, filter, sortOrder); PlanItem item = getBestPlanItem(session, masks, filters, filter, sortOrder, allColumnsSet);
return item.getIndex(); return item.getIndex();
} }
......
...@@ -14,6 +14,7 @@ import java.util.ArrayList; ...@@ -14,6 +14,7 @@ import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.Comparator; import java.util.Comparator;
import java.util.HashSet;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Random; import java.util.Random;
...@@ -40,6 +41,7 @@ import org.h2.message.DbException; ...@@ -40,6 +41,7 @@ import org.h2.message.DbException;
import org.h2.result.Row; import org.h2.result.Row;
import org.h2.result.SearchRow; import org.h2.result.SearchRow;
import org.h2.result.SortOrder; import org.h2.result.SortOrder;
import org.h2.table.Column;
import org.h2.table.IndexColumn; import org.h2.table.IndexColumn;
import org.h2.table.SubQueryInfo; import org.h2.table.SubQueryInfo;
import org.h2.table.Table; import org.h2.table.Table;
...@@ -901,7 +903,8 @@ public class TestTableEngines extends TestBase { ...@@ -901,7 +903,8 @@ public class TestTableEngines extends TestBase {
@Override @Override
public double getCost(Session session, int[] masks, public double getCost(Session session, int[] masks,
TableFilter[] filters, int filter, SortOrder sortOrder) { TableFilter[] filters, int filter, SortOrder sortOrder,
HashSet<Column> allColumnsSet) {
return 0; return 0;
} }
...@@ -1157,10 +1160,11 @@ public class TestTableEngines extends TestBase { ...@@ -1157,10 +1160,11 @@ public class TestTableEngines extends TestBase {
IndexColumn.wrap(getColumns()), IndexType.createScan(false)) { IndexColumn.wrap(getColumns()), IndexType.createScan(false)) {
@Override @Override
public double getCost(Session session, int[] masks, public double getCost(Session session, int[] masks,
TableFilter[] filters, int filter, SortOrder sortOrder) { TableFilter[] filters, int filter, SortOrder sortOrder,
HashSet<Column> allColumnsSet) {
doTests(session); doTests(session);
return getCostRangeIndex(masks, getRowCount(session), filters, return getCostRangeIndex(masks, getRowCount(session), filters,
filter, sortOrder, true); filter, sortOrder, true, allColumnsSet);
} }
}; };
...@@ -1505,9 +1509,9 @@ public class TestTableEngines extends TestBase { ...@@ -1505,9 +1509,9 @@ public class TestTableEngines extends TestBase {
@Override @Override
public double getCost(Session session, int[] masks, public double getCost(Session session, int[] masks,
TableFilter[] filters, int filter, SortOrder sortOrder) { TableFilter[] filters, int filter, SortOrder sortOrder, HashSet<Column> allColumnsSet) {
doTests(session); doTests(session);
return getCostRangeIndex(masks, set.size(), filters, filter, sortOrder, false); return getCostRangeIndex(masks, set.size(), filters, filter, sortOrder, false, allColumnsSet);
} }
@Override @Override
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论