提交 9d77b433 authored 作者: noelgrandin's avatar noelgrandin

Fix Issue 389: When there is a multi-column primary key, H2 does not seem to…

Fix Issue 389: When there is a multi-column primary key, H2 does not seem to always pick the right index
上级 8635dca5
...@@ -28,6 +28,7 @@ Change Log ...@@ -28,6 +28,7 @@ Change Log
</li><li>Fix issue #453, ABBA race conditions in TABLE LINK connection sharing. </li><li>Fix issue #453, ABBA race conditions in TABLE LINK connection sharing.
</li><li>Fix Issue 449: Postgres Serial data type should not automatically be marked as primary key </li><li>Fix Issue 449: Postgres Serial data type should not automatically be marked as primary key
</li><li>Fix Issue 406: support "SELECT h2version()" </li><li>Fix Issue 406: support "SELECT h2version()"
</li><li>Fix Issue 389: When there is a multi-column primary key, H2 does not seem to always pick the right index
</li></ul> </li></ul>
<h2>Version 1.3.171 (2013-03-17)</h2> <h2>Version 1.3.171 (2013-03-17)</h2>
......
...@@ -366,7 +366,7 @@ public class ScriptCommand extends ScriptBase { ...@@ -366,7 +366,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); PlanItem plan = table.getBestPlanItem(session, 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();
......
...@@ -1273,4 +1273,8 @@ public class Select extends Query { ...@@ -1273,4 +1273,8 @@ public class Select extends Query {
return false; return false;
} }
public SortOrder prepareOrder() {
return sort;
}
} }
...@@ -126,7 +126,7 @@ public abstract class BaseIndex extends SchemaObjectBase implements Index { ...@@ -126,7 +126,7 @@ public abstract class BaseIndex extends SchemaObjectBase implements Index {
* @param rowCount the number of rows in the index * @param rowCount the number of rows in the index
* @return the estimated cost * @return the estimated cost
*/ */
protected long getCostRangeIndex(int[] masks, long rowCount) { protected long getCostRangeIndex(int[] masks, long rowCount, SortOrder sortOrder) {
rowCount += Constants.COST_ROW_OFFSET; rowCount += Constants.COST_ROW_OFFSET;
long cost = rowCount; long cost = rowCount;
long rows = rowCount; long rows = rowCount;
...@@ -163,6 +163,34 @@ public abstract class BaseIndex extends SchemaObjectBase implements Index { ...@@ -163,6 +163,34 @@ public abstract class BaseIndex extends SchemaObjectBase implements Index {
break; break;
} }
} }
// If the query ORDER BY clause matches the ordering of this index, it will be cheaper
// than another index, so adjust the cost accordingly.
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;
int[] sortOrderIndexes = sortOrder.getIndexes();
int coveringCount = 0;
for (int i = 0, len = sortOrderIndexes.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] != sortOrderIndexes[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;
} }
......
...@@ -10,6 +10,7 @@ import org.h2.engine.Session; ...@@ -10,6 +10,7 @@ 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.table.FunctionTable; import org.h2.table.FunctionTable;
import org.h2.table.IndexColumn; import org.h2.table.IndexColumn;
...@@ -45,7 +46,7 @@ public class FunctionIndex extends BaseIndex { ...@@ -45,7 +46,7 @@ public class FunctionIndex extends BaseIndex {
return new FunctionCursor(functionTable.getResult(session)); return new FunctionCursor(functionTable.getResult(session));
} }
public double getCost(Session session, int[] masks) { public double getCost(Session session, int[] masks, SortOrder sortOrder) {
if (masks != null) { if (masks != null) {
throw DbException.getUnsupportedException("ALIAS"); throw DbException.getUnsupportedException("ALIAS");
} }
......
...@@ -10,6 +10,7 @@ import org.h2.engine.Session; ...@@ -10,6 +10,7 @@ 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.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;
...@@ -93,7 +94,7 @@ public class HashIndex extends BaseIndex { ...@@ -93,7 +94,7 @@ public class HashIndex extends BaseIndex {
// nothing to do // nothing to do
} }
public double getCost(Session session, int[] masks) { public double getCost(Session session, int[] masks, 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];
......
...@@ -9,6 +9,7 @@ package org.h2.index; ...@@ -9,6 +9,7 @@ package org.h2.index;
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;
import org.h2.result.SortOrder;
import org.h2.schema.SchemaObject; import org.h2.schema.SchemaObject;
import org.h2.table.Column; import org.h2.table.Column;
import org.h2.table.IndexColumn; import org.h2.table.IndexColumn;
...@@ -81,7 +82,7 @@ public interface Index extends SchemaObject { ...@@ -81,7 +82,7 @@ public interface Index extends SchemaObject {
* see constants in IndexCondition * see constants in IndexCondition
* @return the estimated cost * @return the estimated cost
*/ */
double getCost(Session session, int[] masks); double getCost(Session session, int[] masks, SortOrder sortOrder);
/** /**
* Remove the index. * Remove the index.
......
...@@ -14,6 +14,7 @@ import org.h2.engine.Session; ...@@ -14,6 +14,7 @@ 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.table.Column; import org.h2.table.Column;
import org.h2.table.IndexColumn; import org.h2.table.IndexColumn;
import org.h2.table.TableLink; import org.h2.table.TableLink;
...@@ -134,8 +135,8 @@ public class LinkedIndex extends BaseIndex { ...@@ -134,8 +135,8 @@ public class LinkedIndex extends BaseIndex {
} }
} }
public double getCost(Session session, int[] masks) { public double getCost(Session session, int[] masks, SortOrder sortOrder) {
return 100 + getCostRangeIndex(masks, rowCount + Constants.COST_ROW_OFFSET); return 100 + getCostRangeIndex(masks, rowCount + Constants.COST_ROW_OFFSET, sortOrder);
} }
public void remove(Session session) { public void remove(Session session) {
......
...@@ -11,6 +11,7 @@ import org.h2.engine.Session; ...@@ -11,6 +11,7 @@ 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.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;
...@@ -46,11 +47,11 @@ public class MetaIndex extends BaseIndex { ...@@ -46,11 +47,11 @@ public class MetaIndex extends BaseIndex {
return new MetaCursor(rows); return new MetaCursor(rows);
} }
public double getCost(Session session, int[] masks) { public double getCost(Session session, int[] masks, 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); return getCostRangeIndex(masks, MetaTable.ROW_COUNT_APPROXIMATION, sortOrder);
} }
public void truncate(Session session) { public void truncate(Session session) {
......
...@@ -13,6 +13,7 @@ import org.h2.engine.Session; ...@@ -13,6 +13,7 @@ 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.schema.Schema; import org.h2.schema.Schema;
import org.h2.table.Column; import org.h2.table.Column;
import org.h2.table.IndexColumn; import org.h2.table.IndexColumn;
...@@ -123,8 +124,8 @@ public class MultiVersionIndex implements Index { ...@@ -123,8 +124,8 @@ public class MultiVersionIndex implements Index {
return cursor; return cursor;
} }
public double getCost(Session session, int[] masks) { public double getCost(Session session, int[] masks, SortOrder sortOrder) {
return base.getCost(session, masks); return base.getCost(session, masks, sortOrder);
} }
public boolean needRebuild() { public boolean needRebuild() {
......
...@@ -13,6 +13,7 @@ import org.h2.engine.Session; ...@@ -13,6 +13,7 @@ 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.store.Data; import org.h2.store.Data;
import org.h2.store.Page; import org.h2.store.Page;
import org.h2.store.PageStore; import org.h2.store.PageStore;
...@@ -216,8 +217,8 @@ public class PageBtreeIndex extends PageIndex { ...@@ -216,8 +217,8 @@ public class PageBtreeIndex extends PageIndex {
return cursor; return cursor;
} }
public double getCost(Session session, int[] masks) { public double getCost(Session session, int[] masks, SortOrder sortOrder) {
return 10 * getCostRangeIndex(masks, tableData.getRowCount(session)); return 10 * getCostRangeIndex(masks, tableData.getRowCount(session), sortOrder);
} }
public boolean needRebuild() { public boolean needRebuild() {
......
...@@ -19,6 +19,7 @@ import org.h2.engine.UndoLogRecord; ...@@ -19,6 +19,7 @@ import org.h2.engine.UndoLogRecord;
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.store.Page; import org.h2.store.Page;
import org.h2.store.PageStore; import org.h2.store.PageStore;
import org.h2.table.Column; import org.h2.table.Column;
...@@ -300,7 +301,7 @@ public class PageDataIndex extends PageIndex { ...@@ -300,7 +301,7 @@ public class PageDataIndex extends PageIndex {
return root.getLastKey(); return root.getLastKey();
} }
public double getCost(Session session, int[] masks) { public double getCost(Session session, int[] masks, SortOrder sortOrder) {
long cost = 10 * (tableData.getRowCountApproximation() + Constants.COST_ROW_OFFSET); long cost = 10 * (tableData.getRowCountApproximation() + Constants.COST_ROW_OFFSET);
return cost; return cost;
} }
......
...@@ -10,6 +10,7 @@ import org.h2.engine.Session; ...@@ -10,6 +10,7 @@ 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.store.PageStore; 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;
...@@ -84,8 +85,8 @@ public class PageDelegateIndex extends PageIndex { ...@@ -84,8 +85,8 @@ public class PageDelegateIndex extends PageIndex {
return -1; return -1;
} }
public double getCost(Session session, int[] masks) { public double getCost(Session session, int[] masks, SortOrder sortOrder) {
return 10 * getCostRangeIndex(masks, mainIndex.getRowCount(session)); return 10 * getCostRangeIndex(masks, mainIndex.getRowCount(session), sortOrder);
} }
public boolean needRebuild() { public boolean needRebuild() {
......
...@@ -10,6 +10,7 @@ import org.h2.engine.Session; ...@@ -10,6 +10,7 @@ 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.table.IndexColumn; import org.h2.table.IndexColumn;
import org.h2.table.RangeTable; import org.h2.table.RangeTable;
...@@ -54,7 +55,7 @@ public class RangeIndex extends BaseIndex { ...@@ -54,7 +55,7 @@ public class RangeIndex extends BaseIndex {
return new RangeCursor(start, end); return new RangeCursor(start, end);
} }
public double getCost(Session session, int[] masks) { public double getCost(Session session, int[] masks, SortOrder sortOrder) {
return 1; return 1;
} }
......
...@@ -19,6 +19,7 @@ import org.h2.engine.UndoLogRecord; ...@@ -19,6 +19,7 @@ import org.h2.engine.UndoLogRecord;
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.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;
...@@ -159,7 +160,7 @@ public class ScanIndex extends BaseIndex { ...@@ -159,7 +160,7 @@ public class ScanIndex extends BaseIndex {
return new ScanCursor(session, this, database.isMultiVersion()); return new ScanCursor(session, this, database.isMultiVersion());
} }
public double getCost(Session session, int[] masks) { public double getCost(Session session, int[] masks, SortOrder sortOrder) {
return tableData.getRowCountApproximation() + Constants.COST_ROW_OFFSET; return tableData.getRowCountApproximation() + Constants.COST_ROW_OFFSET;
} }
......
...@@ -11,6 +11,7 @@ import org.h2.engine.Session; ...@@ -11,6 +11,7 @@ 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.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;
...@@ -308,8 +309,8 @@ public class TreeIndex extends BaseIndex { ...@@ -308,8 +309,8 @@ public class TreeIndex extends BaseIndex {
return new TreeCursor(this, x, first, last); return new TreeCursor(this, x, first, last);
} }
public double getCost(Session session, int[] masks) { public double getCost(Session session, int[] masks, SortOrder sortOrder) {
return getCostRangeIndex(masks, tableData.getRowCountApproximation()); return getCostRangeIndex(masks, tableData.getRowCountApproximation(), sortOrder);
} }
public void remove(Session session) { public void remove(Session session) {
......
...@@ -19,6 +19,7 @@ import org.h2.result.LocalResult; ...@@ -19,6 +19,7 @@ import org.h2.result.LocalResult;
import org.h2.result.ResultInterface; import org.h2.result.ResultInterface;
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.table.Column; import org.h2.table.Column;
import org.h2.table.IndexColumn; import org.h2.table.IndexColumn;
import org.h2.table.TableView; import org.h2.table.TableView;
...@@ -108,7 +109,7 @@ public class ViewIndex extends BaseIndex { ...@@ -108,7 +109,7 @@ public class ViewIndex extends BaseIndex {
double cost; double cost;
} }
public synchronized double getCost(Session session, int[] masks) { public synchronized double getCost(Session session, int[] masks, SortOrder sortOrder) {
if (recursive) { if (recursive) {
return 1000; return 1000;
} }
......
...@@ -13,6 +13,7 @@ import org.h2.index.IndexType; ...@@ -13,6 +13,7 @@ import org.h2.index.IndexType;
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.table.Column; import org.h2.table.Column;
import org.h2.table.IndexColumn; import org.h2.table.IndexColumn;
...@@ -65,8 +66,8 @@ public class MVDelegateIndex extends BaseIndex { ...@@ -65,8 +66,8 @@ public class MVDelegateIndex extends BaseIndex {
return -1; return -1;
} }
public double getCost(Session session, int[] masks) { public double getCost(Session session, int[] masks, SortOrder sortOrder) {
return 10 * getCostRangeIndex(masks, mainIndex.getRowCount(session)); return 10 * getCostRangeIndex(masks, mainIndex.getRowCount(session), sortOrder);
} }
public boolean needRebuild() { public boolean needRebuild() {
......
...@@ -177,7 +177,7 @@ public class MVPrimaryIndex extends BaseIndex { ...@@ -177,7 +177,7 @@ public class MVPrimaryIndex extends BaseIndex {
} }
@Override @Override
public double getCost(Session session, int[] masks) { public double getCost(Session session, int[] masks, SortOrder sortOrder) {
TransactionMap<Value, Value> map = getMap(session); TransactionMap<Value, Value> map = getMap(session);
long cost = 10 * (map.getSize() + Constants.COST_ROW_OFFSET); long cost = 10 * (map.getSize() + Constants.COST_ROW_OFFSET);
return cost; return cost;
......
...@@ -171,9 +171,9 @@ public class MVSecondaryIndex extends BaseIndex { ...@@ -171,9 +171,9 @@ public class MVSecondaryIndex extends BaseIndex {
} }
@Override @Override
public double getCost(Session session, int[] masks) { public double getCost(Session session, int[] masks, SortOrder sortOrder) {
TransactionMap<Value, Value> map = getMap(session); TransactionMap<Value, Value> map = getMap(session);
return 10 * getCostRangeIndex(masks, map.getSize()); return 10 * getCostRangeIndex(masks, map.getSize(), sortOrder);
} }
@Override @Override
......
...@@ -29,6 +29,7 @@ import org.h2.result.RowList; ...@@ -29,6 +29,7 @@ import org.h2.result.RowList;
import org.h2.result.SearchRow; import org.h2.result.SearchRow;
import org.h2.result.SimpleRow; import org.h2.result.SimpleRow;
import org.h2.result.SimpleRowValue; import org.h2.result.SimpleRowValue;
import org.h2.result.SortOrder;
import org.h2.schema.Schema; import org.h2.schema.Schema;
import org.h2.schema.SchemaObjectBase; import org.h2.schema.SchemaObjectBase;
import org.h2.schema.Sequence; import org.h2.schema.Sequence;
...@@ -627,15 +628,15 @@ public abstract class Table extends SchemaObjectBase { ...@@ -627,15 +628,15 @@ public abstract class Table extends SchemaObjectBase {
* see constants in IndexCondition * see constants in IndexCondition
* @return the plan item * @return the plan item
*/ */
public PlanItem getBestPlanItem(Session session, int[] masks) { public PlanItem getBestPlanItem(Session session, int[] masks, 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); item.cost = item.getIndex().getCost(session, 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); double cost = index.getCost(session, masks, sortOrder);
if (cost < item.cost) { if (cost < item.cost) {
item.cost = cost; item.cost = cost;
item.setIndex(index); item.setIndex(index);
......
...@@ -23,6 +23,7 @@ import org.h2.index.IndexCursor; ...@@ -23,6 +23,7 @@ import org.h2.index.IndexCursor;
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.util.New; 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;
...@@ -159,7 +160,7 @@ public class TableFilter implements ColumnResolver { ...@@ -159,7 +160,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); item.cost = item.getIndex().getCost(s, null, null);
} else { } else {
int len = table.getColumns().length; int len = table.getColumns().length;
int[] masks = new int[len]; int[] masks = new int[len];
...@@ -175,7 +176,11 @@ public class TableFilter implements ColumnResolver { ...@@ -175,7 +176,11 @@ public class TableFilter implements ColumnResolver {
} }
} }
} }
item = table.getBestPlanItem(s, masks); SortOrder sortOrder = null;
if (select != null) {
sortOrder = select.prepareOrder();
}
item = table.getBestPlanItem(s, masks, 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
......
...@@ -23,6 +23,7 @@ import org.h2.message.DbException; ...@@ -23,6 +23,7 @@ import org.h2.message.DbException;
import org.h2.result.LocalResult; import org.h2.result.LocalResult;
import org.h2.result.ResultInterface; import org.h2.result.ResultInterface;
import org.h2.result.Row; import org.h2.result.Row;
import org.h2.result.SortOrder;
import org.h2.schema.Schema; import org.h2.schema.Schema;
import org.h2.util.IntArray; import org.h2.util.IntArray;
import org.h2.util.New; import org.h2.util.New;
...@@ -200,9 +201,9 @@ public class TableView extends Table { ...@@ -200,9 +201,9 @@ public class TableView extends Table {
return createException != null; return createException != null;
} }
public synchronized PlanItem getBestPlanItem(Session session, int[] masks) { public synchronized PlanItem getBestPlanItem(Session session, int[] masks, SortOrder sortOrder) {
PlanItem item = new PlanItem(); PlanItem item = new PlanItem();
item.cost = index.getCost(session, masks); item.cost = index.getCost(session, masks, 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);
...@@ -352,7 +353,7 @@ public class TableView extends Table { ...@@ -352,7 +353,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); PlanItem item = getBestPlanItem(session, null, null);
return item.getIndex(); return item.getIndex();
} }
......
...@@ -68,6 +68,7 @@ public class TestOptimizations extends TestBase { ...@@ -68,6 +68,7 @@ public class TestOptimizations extends TestBase {
testIn(); testIn();
testMinMaxCountOptimization(true); testMinMaxCountOptimization(true);
testMinMaxCountOptimization(false); testMinMaxCountOptimization(false);
testOrderedIndexes();
deleteDb("optimizations"); deleteDb("optimizations");
} }
...@@ -782,4 +783,28 @@ public class TestOptimizations extends TestBase { ...@@ -782,4 +783,28 @@ public class TestOptimizations extends TestBase {
conn.close(); conn.close();
} }
/** Where there are multiple indices, and we have an ORDER BY, select the index that already has the required ordering. */
private void testOrderedIndexes() throws SQLException {
deleteDb("optimizations");
Connection conn = getConnection("optimizations");
Statement stat = conn.createStatement();
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);");
ResultSet rs = stat.executeQuery("EXPLAIN PLAN FOR SELECT * FROM my_table WHERE K1=7 ORDER BY K1,VAL");
rs.next();
assertContains(rs.getString(1), "/* PUBLIC.MY_INDEX: K1 = 7 */");
stat.execute("DROP TABLE my_table");
// where we have two covering indexes, make sure we choose the one that covers more
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_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.next();
assertContains(rs.getString(1), "/* PUBLIC.MY_INDEX2: K1 = 7 */");
conn.close();
}
} }
...@@ -17,14 +17,15 @@ import org.h2.engine.Session; ...@@ -17,14 +17,15 @@ import org.h2.engine.Session;
import org.h2.expression.Expression; import org.h2.expression.Expression;
import org.h2.index.BaseIndex; import org.h2.index.BaseIndex;
import org.h2.index.Cursor; import org.h2.index.Cursor;
import org.h2.index.SingleRowCursor;
import org.h2.index.Index; import org.h2.index.Index;
import org.h2.index.IndexType; import org.h2.index.IndexType;
import org.h2.index.SingleRowCursor;
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.table.IndexColumn; import org.h2.table.IndexColumn;
import org.h2.table.TableBase;
import org.h2.table.Table; import org.h2.table.Table;
import org.h2.table.TableBase;
import org.h2.table.TableFilter; import org.h2.table.TableFilter;
import org.h2.test.TestBase; import org.h2.test.TestBase;
import org.h2.value.Value; import org.h2.value.Value;
...@@ -176,7 +177,7 @@ public class TestTableEngines extends TestBase { ...@@ -176,7 +177,7 @@ public class TestTableEngines extends TestBase {
return false; return false;
} }
public double getCost(Session session, int[] masks) { public double getCost(Session session, int[] masks, SortOrder sortOrder) {
return 0; return 0;
} }
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论