提交 929b8335 authored 作者: Thomas Mueller's avatar Thomas Mueller

In version 1.3.172, a performance regression was introduced when fixing the…

In version 1.3.172, a performance regression was introduced when fixing the issue 389 (when there is a multi-column primary key, H2 does not seem to always pick the right index). This was related to boosting an index that matches the "order by" column list (the wrong index was used in some cases).
上级 5b3b638c
...@@ -479,7 +479,7 @@ public abstract class Query extends Prepared { ...@@ -479,7 +479,7 @@ public abstract class Query extends Prepared {
} }
sortType[i] = type; sortType[i] = type;
} }
return new SortOrder(session.getDatabase(), index, sortType); return new SortOrder(session.getDatabase(), index, sortType, orderList);
} }
public void setOffset(Expression offset) { public void setOffset(Expression offset) {
......
...@@ -372,7 +372,7 @@ public class ScriptCommand extends ScriptBase { ...@@ -372,7 +372,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); PlanItem plan = table.getBestPlanItem(session, null, 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();
......
...@@ -775,12 +775,7 @@ public class Select extends Query { ...@@ -775,12 +775,7 @@ public class Select extends Query {
} }
// map columns in select list and condition // map columns in select list and condition
for (TableFilter f : filters) { for (TableFilter f : filters) {
for (Expression expr : expressions) { mapColumns(f, 0);
expr.mapColumns(f, 0);
}
if (condition != null) {
condition.mapColumns(f, 0);
}
} }
if (havingIndex >= 0) { if (havingIndex >= 0) {
Expression expr = expressions.get(havingIndex); Expression expr = expressions.get(havingIndex);
...@@ -1133,6 +1128,11 @@ public class Select extends Query { ...@@ -1133,6 +1128,11 @@ public class Select extends Query {
if (condition != null) { if (condition != null) {
condition.mapColumns(resolver, level); condition.mapColumns(resolver, level);
} }
if (orderList != null) {
for (SelectOrderBy order : orderList) {
order.expression.mapColumns(resolver, level);
}
}
} }
@Override @Override
......
...@@ -216,7 +216,7 @@ public class Aggregate extends Expression { ...@@ -216,7 +216,7 @@ public class Aggregate extends Expression {
int order = o.descending ? SortOrder.DESCENDING : SortOrder.ASCENDING; int order = o.descending ? SortOrder.DESCENDING : SortOrder.ASCENDING;
sortType[i] = order; sortType[i] = order;
} }
return new SortOrder(session.getDatabase(), index, sortType); return new SortOrder(session.getDatabase(), index, sortType, null);
} }
@Override @Override
......
...@@ -148,10 +148,11 @@ public abstract class BaseIndex extends SchemaObjectBase implements Index { ...@@ -148,10 +148,11 @@ public abstract class BaseIndex extends SchemaObjectBase implements Index {
* *
* @param masks the search mask * @param masks the search mask
* @param rowCount the number of rows in the index * @param rowCount the number of rows in the index
* @param filter the table filter
* @param sortOrder the sort order * @param sortOrder the sort order
* @return the estimated cost * @return the estimated cost
*/ */
protected long getCostRangeIndex(int[] masks, long rowCount, SortOrder sortOrder) { protected long getCostRangeIndex(int[] masks, long rowCount, TableFilter filter, SortOrder sortOrder) {
rowCount += Constants.COST_ROW_OFFSET; rowCount += Constants.COST_ROW_OFFSET;
long cost = rowCount; long cost = rowCount;
long rows = rowCount; long rows = rowCount;
...@@ -191,36 +192,72 @@ public abstract class BaseIndex extends SchemaObjectBase implements Index { ...@@ -191,36 +192,72 @@ public abstract class BaseIndex extends SchemaObjectBase implements Index {
// if the ORDER BY clause matches the ordering of this index, // if the ORDER BY clause matches the ordering of this index,
// it will be cheaper than another index, so adjust the cost accordingly // it will be cheaper than another index, so adjust the cost accordingly
if (sortOrder != null) { if (sortOrder != null) {
int[] columnIndexes = new int[ indexColumns.length ];
int[] columnSortTypes = new int[ indexColumns.length ];
for (int i = 0, len = indexColumns.length; i < len; i++) {
columnIndexes[i] = indexColumns[i].column.getColumnId();
columnSortTypes[i] = indexColumns[i].sortType;
}
boolean sortOrderMatches = true; boolean sortOrderMatches = true;
int[] sortOrderQueryColumnIndexes = sortOrder.getQueryColumnIndexes();
int coveringCount = 0; int coveringCount = 0;
int[] sortTypes = sortOrder.getSortTypes();
int theFollowingNeedsToBeFixedAndTested; for (int i = 0, len = sortTypes.length; i < len; i++) {
// see also the method Select.getSortIndex() if (i >= indexColumns.length) {
for (int i = 0, len = sortOrderQueryColumnIndexes.length; i < len; i++) { // we can still use this index if we are sorting by more
if (i >= columnIndexes.length) { // than it's columns, it's just that the coveringCount
// we can still use this index if we are sorting by more than it's columns // is lower than with an index that contains
// more of the order by columns
break;
}
Column col = sortOrder.getColumn(i, filter);
if (col == null) {
sortOrderMatches = false;
break; break;
} }
if (columnIndexes[i] != sortOrderQueryColumnIndexes[i] || columnSortTypes[i] != sortOrder.getSortTypes()[i]) { IndexColumn indexCol = indexColumns[i];
if (col != indexCol.column) {
sortOrderMatches = false;
break;
}
int sortType = sortTypes[i];
if (sortType != indexCol.sortType) {
sortOrderMatches = false; sortOrderMatches = false;
break; break;
} }
coveringCount++; coveringCount++;
} }
if (sortOrderMatches) { if (sortOrderMatches) {
// "coveringCount" makes sure that when we have two // "coveringCount" makes sure that when we have two
// or more covering indexes, we choose the one // or more covering indexes, we choose the one
// that covers more // that covers more
cost -= coveringCount; cost -= coveringCount;
} }
//
// int[] columnIndexes = new int[indexColumns.length];
// int[] columnSortTypes = new int[indexColumns.length];
// for (int i = 0, len = indexColumns.length; i < len; i++) {
// columnIndexes[i] = indexColumns[i].column.getColumnId();
// columnSortTypes[i] = indexColumns[i].sortType;
// }
// boolean sortOrderMatches = true;
// int[] sortOrderQueryColumnIndexes = sortOrder.getQueryColumnIndexes();
// int coveringCount = 0;
//
// int theFollowingNeedsToBeFixedAndTested;
// // see also the method Select.getSortIndex()
// for (int i = 0, len = sortOrderQueryColumnIndexes.length; i < len; i++) {
// if (i >= columnIndexes.length) {
// // we can still use this index if we are sorting by more than it's columns
// break;
// }
// if (columnIndexes[i] != sortOrderQueryColumnIndexes[i] || columnSortTypes[i] != sortOrder.getSortTypes()[i]) {
// sortOrderMatches = false;
// break;
// }
// coveringCount++;
// }
//
// if (sortOrderMatches) {
// // "coveringCount" makes sure that when we have two
// // or more covering indexes, we choose the one
// // that covers more
// cost -= coveringCount;
// }
} }
return cost; return cost;
} }
......
...@@ -13,6 +13,7 @@ import org.h2.result.SearchRow; ...@@ -13,6 +13,7 @@ import org.h2.result.SearchRow;
import org.h2.result.SortOrder; import org.h2.result.SortOrder;
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;
/** /**
* An index for a function that returns a result set. This index can only scan * An index for a function that returns a result set. This index can only scan
...@@ -51,7 +52,7 @@ public class FunctionIndex extends BaseIndex { ...@@ -51,7 +52,7 @@ public class FunctionIndex extends BaseIndex {
} }
@Override @Override
public double getCost(Session session, int[] masks, SortOrder sortOrder) { public double getCost(Session session, int[] masks, TableFilter filter, SortOrder sortOrder) {
if (masks != null) { if (masks != null) {
throw DbException.getUnsupportedException("ALIAS"); throw DbException.getUnsupportedException("ALIAS");
} }
......
...@@ -14,6 +14,7 @@ import org.h2.result.SortOrder; ...@@ -14,6 +14,7 @@ import org.h2.result.SortOrder;
import org.h2.table.Column; 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.util.ValueHashMap; import org.h2.util.ValueHashMap;
import org.h2.value.Value; import org.h2.value.Value;
...@@ -112,7 +113,7 @@ public class HashIndex extends BaseIndex { ...@@ -112,7 +113,7 @@ public class HashIndex extends BaseIndex {
} }
@Override @Override
public double getCost(Session session, int[] masks, SortOrder sortOrder) { public double getCost(Session session, int[] masks, TableFilter filter, SortOrder sortOrder) {
for (Column column : columns) { for (Column column : columns) {
int index = column.getColumnId(); int index = column.getColumnId();
int mask = masks[index]; int mask = masks[index];
......
...@@ -80,10 +80,11 @@ public interface Index extends SchemaObject { ...@@ -80,10 +80,11 @@ public interface Index extends SchemaObject {
* @param session the session * @param session the session
* @param masks per-column comparison bit masks, null means 'always false', * @param masks per-column comparison bit masks, null means 'always false',
* see constants in IndexCondition * see constants in IndexCondition
* @param filter the table filter
* @param sortOrder the sort order * @param sortOrder the sort order
* @return the estimated cost * @return the estimated cost
*/ */
double getCost(Session session, int[] masks, SortOrder sortOrder); double getCost(Session session, int[] masks, TableFilter filter, SortOrder sortOrder);
/** /**
* Remove the index. * Remove the index.
......
...@@ -17,6 +17,7 @@ import org.h2.result.SearchRow; ...@@ -17,6 +17,7 @@ import org.h2.result.SearchRow;
import org.h2.result.SortOrder; import org.h2.result.SortOrder;
import org.h2.table.Column; import org.h2.table.Column;
import org.h2.table.IndexColumn; import org.h2.table.IndexColumn;
import org.h2.table.TableFilter;
import org.h2.table.TableLink; import org.h2.table.TableLink;
import org.h2.util.New; import org.h2.util.New;
import org.h2.util.StatementBuilder; import org.h2.util.StatementBuilder;
...@@ -140,8 +141,8 @@ public class LinkedIndex extends BaseIndex { ...@@ -140,8 +141,8 @@ public class LinkedIndex extends BaseIndex {
} }
@Override @Override
public double getCost(Session session, int[] masks, SortOrder sortOrder) { public double getCost(Session session, int[] masks, TableFilter filter, SortOrder sortOrder) {
return 100 + getCostRangeIndex(masks, rowCount + Constants.COST_ROW_OFFSET, sortOrder); return 100 + getCostRangeIndex(masks, rowCount + Constants.COST_ROW_OFFSET, filter, sortOrder);
} }
@Override @Override
......
...@@ -15,6 +15,7 @@ import org.h2.result.SortOrder; ...@@ -15,6 +15,7 @@ import org.h2.result.SortOrder;
import org.h2.table.Column; import org.h2.table.Column;
import org.h2.table.IndexColumn; import org.h2.table.IndexColumn;
import org.h2.table.MetaTable; import org.h2.table.MetaTable;
import org.h2.table.TableFilter;
/** /**
* The index implementation for meta data tables. * The index implementation for meta data tables.
...@@ -52,11 +53,11 @@ public class MetaIndex extends BaseIndex { ...@@ -52,11 +53,11 @@ public class MetaIndex extends BaseIndex {
} }
@Override @Override
public double getCost(Session session, int[] masks, SortOrder sortOrder) { public double getCost(Session session, int[] masks, TableFilter filter, SortOrder sortOrder) {
if (scan) { if (scan) {
return 10 * MetaTable.ROW_COUNT_APPROXIMATION; return 10 * MetaTable.ROW_COUNT_APPROXIMATION;
} }
return getCostRangeIndex(masks, MetaTable.ROW_COUNT_APPROXIMATION, sortOrder); return getCostRangeIndex(masks, MetaTable.ROW_COUNT_APPROXIMATION, filter, sortOrder);
} }
@Override @Override
......
...@@ -138,8 +138,8 @@ public class MultiVersionIndex implements Index { ...@@ -138,8 +138,8 @@ public class MultiVersionIndex implements Index {
} }
@Override @Override
public double getCost(Session session, int[] masks, SortOrder sortOrder) { public double getCost(Session session, int[] masks, TableFilter filter, SortOrder sortOrder) {
return base.getCost(session, masks, sortOrder); return base.getCost(session, masks, filter, sortOrder);
} }
@Override @Override
......
...@@ -15,6 +15,7 @@ import org.h2.result.SortOrder; ...@@ -15,6 +15,7 @@ import org.h2.result.SortOrder;
import org.h2.table.Column; 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.util.New; import org.h2.util.New;
import org.h2.util.ValueHashMap; import org.h2.util.ValueHashMap;
import org.h2.value.Value; import org.h2.value.Value;
...@@ -129,7 +130,7 @@ public class NonUniqueHashIndex extends BaseIndex { ...@@ -129,7 +130,7 @@ public class NonUniqueHashIndex extends BaseIndex {
} }
@Override @Override
public double getCost(Session session, int[] masks, SortOrder sortOrder) { public double getCost(Session session, int[] masks, TableFilter filter, SortOrder sortOrder) {
for (Column column : columns) { for (Column column : columns) {
int index = column.getColumnId(); int index = column.getColumnId();
int mask = masks[index]; int mask = masks[index];
......
...@@ -20,6 +20,7 @@ import org.h2.store.PageStore; ...@@ -20,6 +20,7 @@ import org.h2.store.PageStore;
import org.h2.table.Column; 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.util.MathUtils; import org.h2.util.MathUtils;
import org.h2.value.Value; import org.h2.value.Value;
import org.h2.value.ValueNull; import org.h2.value.ValueNull;
...@@ -214,8 +215,8 @@ public class PageBtreeIndex extends PageIndex { ...@@ -214,8 +215,8 @@ public class PageBtreeIndex extends PageIndex {
} }
@Override @Override
public double getCost(Session session, int[] masks, SortOrder sortOrder) { public double getCost(Session session, int[] masks, TableFilter filter, SortOrder sortOrder) {
return 10 * getCostRangeIndex(masks, tableData.getRowCount(session), sortOrder); return 10 * getCostRangeIndex(masks, tableData.getRowCount(session), filter, sortOrder);
} }
@Override @Override
......
...@@ -25,6 +25,7 @@ import org.h2.store.PageStore; ...@@ -25,6 +25,7 @@ import org.h2.store.PageStore;
import org.h2.table.Column; 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.util.MathUtils; import org.h2.util.MathUtils;
import org.h2.util.New; import org.h2.util.New;
import org.h2.value.Value; import org.h2.value.Value;
...@@ -307,7 +308,7 @@ public class PageDataIndex extends PageIndex { ...@@ -307,7 +308,7 @@ public class PageDataIndex extends PageIndex {
} }
@Override @Override
public double getCost(Session session, int[] masks, SortOrder sortOrder) { public double getCost(Session session, int[] masks, TableFilter filter, SortOrder sortOrder) {
long cost = 10 * (tableData.getRowCountApproximation() + Constants.COST_ROW_OFFSET); long cost = 10 * (tableData.getRowCountApproximation() + Constants.COST_ROW_OFFSET);
return cost; return cost;
} }
......
...@@ -15,6 +15,7 @@ import org.h2.store.PageStore; ...@@ -15,6 +15,7 @@ import org.h2.store.PageStore;
import org.h2.table.Column; 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;
/** /**
* An index that delegates indexing to the page data index. * An index that delegates indexing to the page data index.
...@@ -94,8 +95,8 @@ public class PageDelegateIndex extends PageIndex { ...@@ -94,8 +95,8 @@ public class PageDelegateIndex extends PageIndex {
} }
@Override @Override
public double getCost(Session session, int[] masks, SortOrder sortOrder) { public double getCost(Session session, int[] masks, TableFilter filter, SortOrder sortOrder) {
return 10 * getCostRangeIndex(masks, mainIndex.getRowCount(session), sortOrder); return 10 * getCostRangeIndex(masks, mainIndex.getRowCount(session), filter, sortOrder);
} }
@Override @Override
......
...@@ -13,6 +13,7 @@ import org.h2.result.SearchRow; ...@@ -13,6 +13,7 @@ import org.h2.result.SearchRow;
import org.h2.result.SortOrder; import org.h2.result.SortOrder;
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;
/** /**
* An index for the SYSTEM_RANGE table. * An index for the SYSTEM_RANGE table.
...@@ -60,7 +61,7 @@ public class RangeIndex extends BaseIndex { ...@@ -60,7 +61,7 @@ public class RangeIndex extends BaseIndex {
} }
@Override @Override
public double getCost(Session session, int[] masks, SortOrder sortOrder) { public double getCost(Session session, int[] masks, TableFilter filter, SortOrder sortOrder) {
return 1; return 1;
} }
......
...@@ -23,6 +23,7 @@ import org.h2.result.SortOrder; ...@@ -23,6 +23,7 @@ import org.h2.result.SortOrder;
import org.h2.table.Column; 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.util.New; import org.h2.util.New;
/** /**
...@@ -170,7 +171,7 @@ public class ScanIndex extends BaseIndex { ...@@ -170,7 +171,7 @@ public class ScanIndex extends BaseIndex {
} }
@Override @Override
public double getCost(Session session, int[] masks, SortOrder sortOrder) { public double getCost(Session session, int[] masks, TableFilter filter, SortOrder sortOrder) {
return tableData.getRowCountApproximation() + Constants.COST_ROW_OFFSET; return tableData.getRowCountApproximation() + Constants.COST_ROW_OFFSET;
} }
......
...@@ -170,7 +170,7 @@ public class SpatialTreeIndex extends BaseIndex implements SpatialIndex { ...@@ -170,7 +170,7 @@ public class SpatialTreeIndex extends BaseIndex implements SpatialIndex {
} }
@Override @Override
protected long getCostRangeIndex(int[] masks, long rowCount, SortOrder sortOrder) { protected long getCostRangeIndex(int[] masks, long rowCount, TableFilter filter, SortOrder sortOrder) {
rowCount += Constants.COST_ROW_OFFSET; rowCount += Constants.COST_ROW_OFFSET;
long cost = rowCount; long cost = rowCount;
long rows = rowCount; long rows = rowCount;
...@@ -188,8 +188,8 @@ public class SpatialTreeIndex extends BaseIndex implements SpatialIndex { ...@@ -188,8 +188,8 @@ public class SpatialTreeIndex extends BaseIndex implements SpatialIndex {
} }
@Override @Override
public double getCost(Session session, int[] masks, SortOrder sortOrder) { public double getCost(Session session, int[] masks, TableFilter filter, SortOrder sortOrder) {
return getCostRangeIndex(masks, tableData.getRowCountApproximation(), sortOrder); return getCostRangeIndex(masks, tableData.getRowCountApproximation(), filter, sortOrder);
} }
@Override @Override
......
...@@ -318,8 +318,8 @@ public class TreeIndex extends BaseIndex { ...@@ -318,8 +318,8 @@ public class TreeIndex extends BaseIndex {
} }
@Override @Override
public double getCost(Session session, int[] masks, SortOrder sortOrder) { public double getCost(Session session, int[] masks, TableFilter filter, SortOrder sortOrder) {
return getCostRangeIndex(masks, tableData.getRowCountApproximation(), sortOrder); return getCostRangeIndex(masks, tableData.getRowCountApproximation(), filter, sortOrder);
} }
@Override @Override
......
...@@ -22,6 +22,7 @@ import org.h2.result.SearchRow; ...@@ -22,6 +22,7 @@ import org.h2.result.SearchRow;
import org.h2.result.SortOrder; import org.h2.result.SortOrder;
import org.h2.table.Column; import org.h2.table.Column;
import org.h2.table.IndexColumn; import org.h2.table.IndexColumn;
import org.h2.table.TableFilter;
import org.h2.table.TableView; import org.h2.table.TableView;
import org.h2.util.IntArray; import org.h2.util.IntArray;
import org.h2.util.New; import org.h2.util.New;
...@@ -114,7 +115,7 @@ public class ViewIndex extends BaseIndex { ...@@ -114,7 +115,7 @@ public class ViewIndex extends BaseIndex {
} }
@Override @Override
public synchronized double getCost(Session session, int[] masks, SortOrder sortOrder) { public synchronized double getCost(Session session, int[] masks, TableFilter filter, SortOrder sortOrder) {
if (recursive) { if (recursive) {
return 1000; return 1000;
} }
......
...@@ -16,6 +16,7 @@ import org.h2.result.SearchRow; ...@@ -16,6 +16,7 @@ import org.h2.result.SearchRow;
import org.h2.result.SortOrder; import org.h2.result.SortOrder;
import org.h2.table.Column; import org.h2.table.Column;
import org.h2.table.IndexColumn; import org.h2.table.IndexColumn;
import org.h2.table.TableFilter;
/** /**
* An index that delegates indexing to another index. * An index that delegates indexing to another index.
...@@ -73,8 +74,8 @@ public class MVDelegateIndex extends BaseIndex { ...@@ -73,8 +74,8 @@ public class MVDelegateIndex extends BaseIndex {
} }
@Override @Override
public double getCost(Session session, int[] masks, SortOrder sortOrder) { public double getCost(Session session, int[] masks, TableFilter filter, SortOrder sortOrder) {
return 10 * getCostRangeIndex(masks, mainIndex.getRowCountApproximation(), sortOrder); return 10 * getCostRangeIndex(masks, mainIndex.getRowCountApproximation(), filter, sortOrder);
} }
@Override @Override
......
...@@ -25,6 +25,7 @@ import org.h2.result.SearchRow; ...@@ -25,6 +25,7 @@ import org.h2.result.SearchRow;
import org.h2.result.SortOrder; import org.h2.result.SortOrder;
import org.h2.table.Column; import org.h2.table.Column;
import org.h2.table.IndexColumn; import org.h2.table.IndexColumn;
import org.h2.table.TableFilter;
import org.h2.value.Value; import org.h2.value.Value;
import org.h2.value.ValueArray; import org.h2.value.ValueArray;
import org.h2.value.ValueLong; import org.h2.value.ValueLong;
...@@ -195,7 +196,7 @@ public class MVPrimaryIndex extends BaseIndex { ...@@ -195,7 +196,7 @@ public class MVPrimaryIndex extends BaseIndex {
} }
@Override @Override
public double getCost(Session session, int[] masks, SortOrder sortOrder) { public double getCost(Session session, int[] masks, TableFilter filter, SortOrder sortOrder) {
try { try {
long cost = 10 * (dataMap.map.getSize() + Constants.COST_ROW_OFFSET); long cost = 10 * (dataMap.map.getSize() + Constants.COST_ROW_OFFSET);
return cost; return cost;
......
...@@ -24,6 +24,7 @@ import org.h2.result.SearchRow; ...@@ -24,6 +24,7 @@ import org.h2.result.SearchRow;
import org.h2.result.SortOrder; import org.h2.result.SortOrder;
import org.h2.table.Column; import org.h2.table.Column;
import org.h2.table.IndexColumn; import org.h2.table.IndexColumn;
import org.h2.table.TableFilter;
import org.h2.util.New; import org.h2.util.New;
import org.h2.value.Value; import org.h2.value.Value;
import org.h2.value.ValueArray; import org.h2.value.ValueArray;
...@@ -162,9 +163,9 @@ public class MVSecondaryIndex extends BaseIndex { ...@@ -162,9 +163,9 @@ public class MVSecondaryIndex extends BaseIndex {
} }
@Override @Override
public double getCost(Session session, int[] masks, SortOrder sortOrder) { public double getCost(Session session, int[] masks, TableFilter filter, SortOrder sortOrder) {
try { try {
return 10 * getCostRangeIndex(masks, dataMap.map.getSize(), sortOrder); return 10 * getCostRangeIndex(masks, dataMap.map.getSize(), filter, sortOrder);
} catch (IllegalStateException e) { } catch (IllegalStateException e) {
throw DbException.get(ErrorCode.OBJECT_CLOSED); throw DbException.get(ErrorCode.OBJECT_CLOSED);
} }
......
...@@ -9,9 +9,14 @@ package org.h2.result; ...@@ -9,9 +9,14 @@ package org.h2.result;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.Comparator; import java.util.Comparator;
import org.h2.command.dml.SelectOrderBy;
import org.h2.constant.SysProperties; import org.h2.constant.SysProperties;
import org.h2.engine.Database; import org.h2.engine.Database;
import org.h2.expression.Expression; import org.h2.expression.Expression;
import org.h2.expression.ExpressionColumn;
import org.h2.table.Column;
import org.h2.table.TableFilter;
import org.h2.util.StatementBuilder; import org.h2.util.StatementBuilder;
import org.h2.util.StringUtils; import org.h2.util.StringUtils;
import org.h2.util.Utils; import org.h2.util.Utils;
...@@ -57,7 +62,15 @@ public class SortOrder implements Comparator<Value[]> { ...@@ -57,7 +62,15 @@ public class SortOrder implements Comparator<Value[]> {
*/ */
private final int[] queryColumnIndexes; private final int[] queryColumnIndexes;
/**
* The sort type bit mask (DESCENDING, NULLS_FIRST, NULLS_LAST).
*/
private final int[] sortTypes; private final int[] sortTypes;
/**
* The order list.
*/
private final ArrayList<SelectOrderBy> orderList;
/** /**
* Construct a new sort order object. * Construct a new sort order object.
...@@ -65,11 +78,13 @@ public class SortOrder implements Comparator<Value[]> { ...@@ -65,11 +78,13 @@ public class SortOrder implements Comparator<Value[]> {
* @param database the database * @param database the database
* @param queryColumnIndexes the column index list * @param queryColumnIndexes the column index list
* @param sortType the sort order bit masks * @param sortType the sort order bit masks
* @param orderList the original query order list (if this is a query)
*/ */
public SortOrder(Database database, int[] queryColumnIndexes, int[] sortType) { public SortOrder(Database database, int[] queryColumnIndexes, int[] sortType, ArrayList<SelectOrderBy> orderList) {
this.database = database; this.database = database;
this.queryColumnIndexes = queryColumnIndexes; this.queryColumnIndexes = queryColumnIndexes;
this.sortTypes = sortType; this.sortTypes = sortType;
this.orderList = orderList;
} }
/** /**
...@@ -204,6 +219,33 @@ public class SortOrder implements Comparator<Value[]> { ...@@ -204,6 +219,33 @@ public class SortOrder implements Comparator<Value[]> {
public int[] getQueryColumnIndexes() { public int[] getQueryColumnIndexes() {
return queryColumnIndexes; return queryColumnIndexes;
} }
/**
* Get the column for the given table filter, if the sort column is for this filter.
*
* @param index the column index (0-based)
* @param filter the table filter
* @return the column, or null
*/
public Column getColumn(int index, TableFilter filter) {
if (orderList == null) {
return null;
}
SelectOrderBy order = orderList.get(index);
Expression expr = order.expression;
expr = expr.getNonAliasExpression();
if (expr.isConstant()) {
return null;
}
if (!(expr instanceof ExpressionColumn)) {
return null;
}
ExpressionColumn exprCol = (ExpressionColumn) expr;
if (exprCol.getTableFilter() != filter) {
return null;
}
return exprCol.getColumn();
}
/** /**
* Get the sort order bit masks. * Get the sort order bit masks.
......
...@@ -631,18 +631,19 @@ public abstract class Table extends SchemaObjectBase { ...@@ -631,18 +631,19 @@ public abstract class Table extends SchemaObjectBase {
* @param session the session * @param session the session
* @param masks per-column comparison bit masks, null means 'always false', * @param masks per-column comparison bit masks, null means 'always false',
* see constants in IndexCondition * see constants in IndexCondition
* @param filter the table filter
* @param sortOrder the sort order * @param sortOrder the sort order
* @return the plan item * @return the plan item
*/ */
public PlanItem getBestPlanItem(Session session, int[] masks, SortOrder sortOrder) { public PlanItem getBestPlanItem(Session session, int[] masks, TableFilter filter, SortOrder sortOrder) {
PlanItem item = new PlanItem(); PlanItem item = new PlanItem();
item.setIndex(getScanIndex(session)); item.setIndex(getScanIndex(session));
item.cost = item.getIndex().getCost(session, null, null); item.cost = item.getIndex().getCost(session, null, null, null);
ArrayList<Index> indexes = getIndexes(); ArrayList<Index> indexes = getIndexes();
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, sortOrder); double cost = index.getCost(session, masks, filter, sortOrder);
if (cost < item.cost) { if (cost < item.cost) {
item.cost = cost; item.cost = cost;
item.setIndex(index); item.setIndex(index);
......
...@@ -161,7 +161,7 @@ public class TableFilter implements ColumnResolver { ...@@ -161,7 +161,7 @@ public class TableFilter implements ColumnResolver {
if (indexConditions.size() == 0) { if (indexConditions.size() == 0) {
item = new PlanItem(); item = new PlanItem();
item.setIndex(table.getScanIndex(s)); item.setIndex(table.getScanIndex(s));
item.cost = item.getIndex().getCost(s, null, null); item.cost = item.getIndex().getCost(s, null, null, null);
} else { } else {
int len = table.getColumns().length; int len = table.getColumns().length;
int[] masks = new int[len]; int[] masks = new int[len];
...@@ -181,7 +181,7 @@ public class TableFilter implements ColumnResolver { ...@@ -181,7 +181,7 @@ public class TableFilter implements ColumnResolver {
if (select != null) { if (select != null) {
sortOrder = select.getSortOrder(); sortOrder = select.getSortOrder();
} }
item = table.getBestPlanItem(s, masks, sortOrder); item = table.getBestPlanItem(s, masks, this, sortOrder);
// 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:
// x (x.a=10); y (x.b=y.b) - see issue 113 // x (x.a=10); y (x.b=y.b) - see issue 113
......
...@@ -202,9 +202,9 @@ public class TableView extends Table { ...@@ -202,9 +202,9 @@ public class TableView extends Table {
} }
@Override @Override
public synchronized PlanItem getBestPlanItem(Session session, int[] masks, SortOrder sortOrder) { public synchronized PlanItem getBestPlanItem(Session session, int[] masks, TableFilter filter, SortOrder sortOrder) {
PlanItem item = new PlanItem(); PlanItem item = new PlanItem();
item.cost = index.getCost(session, masks, sortOrder); item.cost = index.getCost(session, masks, filter, sortOrder);
IntArray masksArray = new IntArray(masks == null ? Utils.EMPTY_INT_ARRAY : masks); IntArray masksArray = new IntArray(masks == null ? Utils.EMPTY_INT_ARRAY : masks);
SynchronizedVerifier.check(indexCache); SynchronizedVerifier.check(indexCache);
ViewIndex i2 = indexCache.get(masksArray); ViewIndex i2 = indexCache.get(masksArray);
...@@ -374,7 +374,7 @@ public class TableView extends Table { ...@@ -374,7 +374,7 @@ public class TableView extends Table {
String msg = createException.getMessage(); String msg = createException.getMessage();
throw DbException.get(ErrorCode.VIEW_IS_INVALID_2, createException, getSQL(), msg); throw DbException.get(ErrorCode.VIEW_IS_INVALID_2, createException, getSQL(), msg);
} }
PlanItem item = getBestPlanItem(session, null, null); PlanItem item = getBestPlanItem(session, null, null, null);
return item.getIndex(); return item.getIndex();
} }
......
...@@ -86,10 +86,7 @@ public class TestOptimizations extends TestBase { ...@@ -86,10 +86,7 @@ public class TestOptimizations extends TestBase {
"explain select name from test where name='Hello' order by name"); "explain select name from test where name='Hello' order by name");
rs.next(); rs.next();
String plan = rs.getString(1); String plan = rs.getString(1);
assertContains(plan, "tableScan");
int todoNeedsToBeFixed;
// assertTrue(plan, plan.indexOf("tableScan") >= 0);
stat.execute("drop table test"); stat.execute("drop table test");
conn.close(); conn.close();
} }
...@@ -837,9 +834,10 @@ public class TestOptimizations extends TestBase { ...@@ -837,9 +834,10 @@ public class TestOptimizations extends TestBase {
Connection conn = getConnection("optimizations"); Connection conn = getConnection("optimizations");
Statement stat = conn.createStatement(); Statement stat = conn.createStatement();
stat.execute("CREATE TABLE my_table(K1 INT, K2 INT, VAL VARCHAR, PRIMARY KEY(K1,K2))"); stat.execute("CREATE TABLE my_table(K1 INT, K2 INT, VAL VARCHAR, PRIMARY KEY(K1, K2))");
stat.execute("CREATE INDEX my_index ON my_table(K1,VAL);"); stat.execute("CREATE INDEX my_index ON my_table(K1, VAL)");
ResultSet rs = stat.executeQuery("EXPLAIN PLAN FOR SELECT * FROM my_table WHERE K1=7 ORDER BY K1,VAL"); ResultSet rs = stat.executeQuery(
"EXPLAIN PLAN FOR SELECT * FROM my_table WHERE K1=7 ORDER BY K1, VAL");
rs.next(); rs.next();
assertContains(rs.getString(1), "/* PUBLIC.MY_INDEX: K1 = 7 */"); assertContains(rs.getString(1), "/* PUBLIC.MY_INDEX: K1 = 7 */");
...@@ -848,9 +846,10 @@ public class TestOptimizations extends TestBase { ...@@ -848,9 +846,10 @@ public class TestOptimizations extends TestBase {
// where we have two covering indexes, make sure // where we have two covering indexes, make sure
// we choose the one that covers more // we choose the one that covers more
stat.execute("CREATE TABLE my_table(K1 INT, K2 INT, VAL VARCHAR)"); stat.execute("CREATE TABLE my_table(K1 INT, K2 INT, VAL VARCHAR)");
stat.execute("CREATE INDEX my_index1 ON my_table(K1,K2);"); stat.execute("CREATE INDEX my_index1 ON my_table(K1, K2)");
stat.execute("CREATE INDEX my_index2 ON my_table(K1,K2,VAL);"); stat.execute("CREATE INDEX my_index2 ON my_table(K1, K2, VAL)");
rs = stat.executeQuery("EXPLAIN PLAN FOR SELECT * FROM my_table WHERE K1=7 ORDER BY K1,K2,VAL"); rs = stat.executeQuery(
"EXPLAIN PLAN FOR SELECT * FROM my_table WHERE K1=7 ORDER BY K1, K2, VAL");
rs.next(); rs.next();
assertContains(rs.getString(1), "/* PUBLIC.MY_INDEX2: K1 = 7 */"); assertContains(rs.getString(1), "/* PUBLIC.MY_INDEX2: K1 = 7 */");
......
...@@ -210,7 +210,7 @@ public class TestTableEngines extends TestBase { ...@@ -210,7 +210,7 @@ public class TestTableEngines extends TestBase {
} }
@Override @Override
public double getCost(Session session, int[] masks, SortOrder sortOrder) { public double getCost(Session session, int[] masks, TableFilter filter, SortOrder sortOrder) {
return 0; return 0;
} }
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论