提交 411255cd authored 作者: Thomas Mueller's avatar Thomas Mueller

Hash indexes now are only used for single column indexes.

上级 62c5f801
/*
* Copyright 2004-2010 H2 Group. Multiple-Licensed under the H2 License,
* Version 1.0, and under the Eclipse Public License, Version 1.0
* (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package org.h2.index;
import org.h2.engine.Session;
import org.h2.message.DbException;
import org.h2.result.SearchRow;
import org.h2.table.Column;
import org.h2.table.IndexColumn;
import org.h2.table.TableData;
import org.h2.value.Value;
import org.h2.value.ValueArray;
/**
* Base of hash indexes.
*/
public abstract class BaseHashIndex extends BaseIndex {
public BaseHashIndex(TableData table, int id, String indexName, IndexColumn[] columns, IndexType indexType) {
initBaseIndex(table, id, indexName, columns, indexType);
}
public void close(Session session) {
// nothing to do
}
public void remove(Session session) {
// nothing to do
}
/**
* Generate the search key from a row. Single column indexes are mapped to
* the value, multi-column indexes are mapped to an value array.
*
* @param row the row
* @return the value
*/
protected Value getKey(SearchRow row) {
if (columns.length == 1) {
Column column = columns[0];
int index = column.getColumnId();
Value v = row.getValue(index);
return v;
}
Value[] list = new Value[columns.length];
for (int i = 0; i < columns.length; i++) {
Column column = columns[i];
int index = column.getColumnId();
list[i] = row.getValue(index);
}
return ValueArray.get(list);
}
public double getCost(Session session, int[] masks) {
for (Column column : columns) {
int index = column.getColumnId();
int mask = masks[index];
if ((mask & IndexCondition.EQUALITY) != IndexCondition.EQUALITY) {
return Long.MAX_VALUE;
}
}
return 2;
}
public void checkRename() {
// ok
}
public boolean needRebuild() {
return true;
}
public boolean canGetFirstOrLast() {
return false;
}
public Cursor findFirstOrLast(Session session, boolean first) {
throw DbException.getUnsupportedException("HASH");
}
}
...@@ -10,33 +10,30 @@ import org.h2.engine.Session; ...@@ -10,33 +10,30 @@ 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.table.Column;
import org.h2.table.IndexColumn; import org.h2.table.IndexColumn;
import org.h2.table.TableData; import org.h2.table.TableData;
import org.h2.util.IntIntHashMap;
import org.h2.util.ValueHashMap; import org.h2.util.ValueHashMap;
import org.h2.value.Value; import org.h2.value.Value;
/** /**
* An unique index based on an in-memory hash map. * An unique index based on an in-memory hash map.
*/ */
public class HashIndex extends BaseHashIndex { public class HashIndex extends BaseIndex {
private ValueHashMap<Integer> rows; protected final int indexColumn;
private IntIntHashMap intMap; private final TableData tableData;
private TableData tableData; private ValueHashMap<Long> rows;
public HashIndex(TableData table, int id, String indexName, IndexColumn[] columns, IndexType indexType) { public HashIndex(TableData table, int id, String indexName, IndexColumn[] columns, IndexType indexType) {
super(table, id, indexName, columns, indexType); initBaseIndex(table, id, indexName, columns, indexType);
this.indexColumn = columns[0].column.getColumnId();
this.tableData = table; this.tableData = table;
reset(); reset();
} }
private void reset() { private void reset() {
if (columns.length == 1 && columns[0].getType() == Value.INT) { rows = ValueHashMap.newInstance(table.getDatabase());
intMap = new IntIntHashMap();
} else {
rows = ValueHashMap.newInstance(table.getDatabase());
}
} }
public void truncate(Session session) { public void truncate(Session session) {
...@@ -44,27 +41,17 @@ public class HashIndex extends BaseHashIndex { ...@@ -44,27 +41,17 @@ public class HashIndex extends BaseHashIndex {
} }
public void add(Session session, Row row) { public void add(Session session, Row row) {
if (intMap != null) { Value key = row.getValue(indexColumn);
int key = row.getValue(columns[0].getColumnId()).getInt(); Object old = rows.get(key);
intMap.put(key, (int) row.getKey()); if (old != null) {
} else { // TODO index duplicate key for hash indexes: is this allowed?
Value key = getKey(row); throw getDuplicateKeyException();
Object old = rows.get(key);
if (old != null) {
// TODO index duplicate key for hash indexes: is this allowed?
throw getDuplicateKeyException();
}
rows.put(getKey(row), (int) row.getKey());
} }
rows.put(key, row.getKey());
} }
public void remove(Session session, Row row) { public void remove(Session session, Row row) {
if (intMap != null) { rows.remove(row.getValue(indexColumn));
int key = row.getValue(columns[0].getColumnId()).getInt();
intMap.remove(key);
} else {
rows.remove(getKey(row));
}
} }
public Cursor find(Session session, SearchRow first, SearchRow last) { public Cursor find(Session session, SearchRow first, SearchRow last) {
...@@ -73,21 +60,11 @@ public class HashIndex extends BaseHashIndex { ...@@ -73,21 +60,11 @@ public class HashIndex extends BaseHashIndex {
throw DbException.throwInternalError(); throw DbException.throwInternalError();
} }
Row result; Row result;
if (intMap != null) { Long pos = rows.get(first.getValue(indexColumn));
int key = first.getValue(columns[0].getColumnId()).getInt(); if (pos == null) {
int pos = intMap.get(key); result = null;
if (pos != IntIntHashMap.NOT_FOUND) {
result = tableData.getRow(session, pos);
} else {
result = null;
}
} else { } else {
Integer pos = rows.get(getKey(first)); result = tableData.getRow(session, pos.intValue());
if (pos == null) {
result = null;
} else {
result = tableData.getRow(session, pos.intValue());
}
} }
return new HashCursor(result); return new HashCursor(result);
} }
...@@ -97,7 +74,51 @@ public class HashIndex extends BaseHashIndex { ...@@ -97,7 +74,51 @@ public class HashIndex extends BaseHashIndex {
} }
public long getRowCountApproximation() { public long getRowCountApproximation() {
return intMap != null ? intMap.size() : rows.size(); return rows.size();
}
public void close(Session session) {
// nothing to do
}
public void remove(Session session) {
// nothing to do
}
/**
* Generate the search key from a row. Only single column indexes are
* supported (multi-column indexes could be mapped to an value array, but
* that is much slower than using a tree based index).
*
* @param row the row
* @return the value
*/
public double getCost(Session session, int[] masks) {
for (Column column : columns) {
int index = column.getColumnId();
int mask = masks[index];
if ((mask & IndexCondition.EQUALITY) != IndexCondition.EQUALITY) {
return Long.MAX_VALUE;
}
}
return 2;
}
public void checkRename() {
// ok
}
public boolean needRebuild() {
return true;
}
public boolean canGetFirstOrLast() {
return false;
}
public Cursor findFirstOrLast(Session session, boolean first) {
throw DbException.getUnsupportedException("HASH");
} }
} }
...@@ -10,6 +10,7 @@ package org.h2.index; ...@@ -10,6 +10,7 @@ package org.h2.index;
* Represents information about the properties of an index * Represents information about the properties of an index
*/ */
public class IndexType { public class IndexType {
private boolean primaryKey, persistent, unique, hash, scan; private boolean primaryKey, persistent, unique, hash, scan;
private boolean belongsToConstraint; private boolean belongsToConstraint;
......
...@@ -6,11 +6,11 @@ ...@@ -6,11 +6,11 @@
*/ */
package org.h2.index; package org.h2.index;
import java.util.ArrayList;
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.table.TableData; import org.h2.table.TableData;
import org.h2.util.IntArray;
/** /**
* Cursor implementation for non-unique hash index * Cursor implementation for non-unique hash index
...@@ -20,12 +20,12 @@ import org.h2.util.IntArray; ...@@ -20,12 +20,12 @@ import org.h2.util.IntArray;
public class NonUniqueHashCursor implements Cursor { public class NonUniqueHashCursor implements Cursor {
private final Session session; private final Session session;
private final IntArray positions; private final ArrayList<Long> positions;
private final TableData tableData; private final TableData tableData;
private int index = -1; private int index = -1;
public NonUniqueHashCursor(Session session, TableData tableData, IntArray positions) { public NonUniqueHashCursor(Session session, TableData tableData, ArrayList<Long> positions) {
this.session = session; this.session = session;
this.tableData = tableData; this.tableData = tableData;
this.positions = positions; this.positions = positions;
......
...@@ -6,13 +6,14 @@ ...@@ -6,13 +6,14 @@
*/ */
package org.h2.index; package org.h2.index;
import java.util.ArrayList;
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.table.IndexColumn; import org.h2.table.IndexColumn;
import org.h2.table.TableData; import org.h2.table.TableData;
import org.h2.util.IntArray; 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;
...@@ -21,9 +22,9 @@ import org.h2.value.Value; ...@@ -21,9 +22,9 @@ import org.h2.value.Value;
* *
* @author Sergi Vladykin * @author Sergi Vladykin
*/ */
public class NonUniqueHashIndex extends BaseHashIndex { public class NonUniqueHashIndex extends HashIndex {
private ValueHashMap<IntArray> rows; private ValueHashMap<ArrayList<Long>> rows;
private TableData tableData; private TableData tableData;
private long rowCount; private long rowCount;
...@@ -43,13 +44,13 @@ public class NonUniqueHashIndex extends BaseHashIndex { ...@@ -43,13 +44,13 @@ public class NonUniqueHashIndex extends BaseHashIndex {
} }
public void add(Session session, Row row) { public void add(Session session, Row row) {
Value key = getKey(row); Value key = row.getValue(indexColumn);
IntArray positions = rows.get(key); ArrayList<Long> positions = rows.get(key);
if (positions == null) { if (positions == null) {
positions = new IntArray(1); positions = New.arrayList();
rows.put(key, positions); rows.put(key, positions);
} }
positions.add((int) row.getKey()); positions.add(row.getKey());
rowCount++; rowCount++;
} }
...@@ -58,13 +59,13 @@ public class NonUniqueHashIndex extends BaseHashIndex { ...@@ -58,13 +59,13 @@ public class NonUniqueHashIndex extends BaseHashIndex {
// last row in table // last row in table
reset(); reset();
} else { } else {
Value key = getKey(row); Value key = row.getValue(indexColumn);
IntArray positions = rows.get(key); ArrayList<Long> positions = rows.get(key);
if (positions.size() == 1) { if (positions.size() == 1) {
// last row with such key // last row with such key
rows.remove(key); rows.remove(key);
} else { } else {
positions.removeValue((int) row.getKey()); positions.remove(row.getKey());
} }
rowCount--; rowCount--;
} }
...@@ -79,7 +80,7 @@ public class NonUniqueHashIndex extends BaseHashIndex { ...@@ -79,7 +80,7 @@ public class NonUniqueHashIndex extends BaseHashIndex {
throw DbException.throwInternalError(); throw DbException.throwInternalError();
} }
} }
IntArray positions = rows.get(getKey(first)); ArrayList<Long> positions = rows.get(first.getValue(indexColumn));
return new NonUniqueHashCursor(session, tableData, positions); return new NonUniqueHashCursor(session, tableData, positions);
} }
......
...@@ -196,7 +196,7 @@ public class TableData extends Table { ...@@ -196,7 +196,7 @@ public class TableData extends Table {
index = new PageBtreeIndex(this, indexId, indexName, cols, indexType, create, session); index = new PageBtreeIndex(this, indexId, indexName, cols, indexType, create, session);
} }
} else { } else {
if (indexType.isHash()) { if (indexType.isHash() && cols.length <= 1) {
if (indexType.isUnique()) { if (indexType.isUnique()) {
index = new HashIndex(this, indexId, indexName, cols, indexType); index = new HashIndex(this, indexId, indexName, cols, indexType);
} else { } else {
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论