提交 58425db8 authored 作者: S.Vladykin's avatar S.Vladykin

plan and tests

上级 233ddba8
...@@ -7,6 +7,7 @@ package org.h2.command; ...@@ -7,6 +7,7 @@ package org.h2.command;
import java.util.ArrayList; import java.util.ArrayList;
import org.h2.api.DatabaseEventListener; import org.h2.api.DatabaseEventListener;
import org.h2.command.dml.Explain;
import org.h2.command.dml.Query; import org.h2.command.dml.Query;
import org.h2.expression.Parameter; import org.h2.expression.Parameter;
import org.h2.expression.ParameterInterface; import org.h2.expression.ParameterInterface;
...@@ -47,8 +48,18 @@ public class CommandContainer extends Command { ...@@ -47,8 +48,18 @@ public class CommandContainer extends Command {
@Override @Override
public void prepareJoinBatch() { public void prepareJoinBatch() {
if (session.isJoinBatchEnabled() && prepared.isQuery()) { if (session.isJoinBatchEnabled()) {
((Query) prepared).prepareJoinBatch(); prepareJoinBatch(prepared);
}
}
private static void prepareJoinBatch(Prepared prepared) {
if (prepared.isQuery()) {
if (prepared.getType() == CommandInterface.SELECT) {
((Query) prepared).prepareJoinBatch();
} else if (prepared.getType() == CommandInterface.EXPLAIN) {
prepareJoinBatch(((Explain) prepared).getCommand());
}
} }
} }
......
...@@ -294,6 +294,9 @@ public class AlterTableAddConstraint extends SchemaCommand { ...@@ -294,6 +294,9 @@ public class AlterTableAddConstraint extends SchemaCommand {
} }
private static Index getUniqueIndex(Table t, IndexColumn[] cols) { private static Index getUniqueIndex(Table t, IndexColumn[] cols) {
if (t.getIndexes() == null) {
return null;
}
for (Index idx : t.getIndexes()) { for (Index idx : t.getIndexes()) {
if (canUseUniqueIndex(idx, t, cols)) { if (canUseUniqueIndex(idx, t, cols)) {
return idx; return idx;
...@@ -303,6 +306,9 @@ public class AlterTableAddConstraint extends SchemaCommand { ...@@ -303,6 +306,9 @@ public class AlterTableAddConstraint extends SchemaCommand {
} }
private static Index getIndex(Table t, IndexColumn[] cols, boolean moreColumnOk) { private static Index getIndex(Table t, IndexColumn[] cols, boolean moreColumnOk) {
if (t.getIndexes() == null) {
return null;
}
for (Index idx : t.getIndexes()) { for (Index idx : t.getIndexes()) {
if (canUseIndex(idx, t, cols, moreColumnOk)) { if (canUseIndex(idx, t, cols, moreColumnOk)) {
return idx; return idx;
......
...@@ -132,7 +132,7 @@ public class Delete extends Prepared { ...@@ -132,7 +132,7 @@ public class Delete extends Prepared {
} }
PlanItem item = tableFilter.getBestPlanItem(session, new TableFilter[]{tableFilter}, 0); PlanItem item = tableFilter.getBestPlanItem(session, new TableFilter[]{tableFilter}, 0);
tableFilter.setPlanItem(item); tableFilter.setPlanItem(item);
tableFilter.prepare(); tableFilter.prepare(false);
} }
@Override @Override
......
...@@ -40,6 +40,10 @@ public class Explain extends Prepared { ...@@ -40,6 +40,10 @@ public class Explain extends Prepared {
this.command = command; this.command = command;
} }
public Prepared getCommand() {
return command;
}
@Override @Override
public void prepare() { public void prepare() {
command.prepare(); command.prepare();
......
...@@ -24,11 +24,6 @@ public class NoOperation extends Prepared { ...@@ -24,11 +24,6 @@ public class NoOperation extends Prepared {
return 0; return 0;
} }
@Override
public boolean isQuery() {
return false;
}
@Override @Override
public boolean isTransactional() { public boolean isTransactional() {
return true; return true;
......
...@@ -1010,9 +1010,7 @@ public class Select extends Query { ...@@ -1010,9 +1010,7 @@ public class Select extends Query {
setEvaluatableRecursive(topTableFilter); setEvaluatableRecursive(topTableFilter);
if (!parse) { topTableFilter.prepare(parse);
topTableFilter.prepare();
}
return planCost; return planCost;
} }
......
...@@ -189,7 +189,7 @@ public class Update extends Prepared { ...@@ -189,7 +189,7 @@ public class Update extends Prepared {
} }
PlanItem item = tableFilter.getBestPlanItem(session, new TableFilter[] {tableFilter}, 0); PlanItem item = tableFilter.getBestPlanItem(session, new TableFilter[] {tableFilter}, 0);
tableFilter.setPlanItem(item); tableFilter.setPlanItem(item);
tableFilter.prepare(); tableFilter.prepare(false);
} }
@Override @Override
......
...@@ -51,6 +51,13 @@ public interface IndexLookupBatch { ...@@ -51,6 +51,13 @@ public interface IndexLookupBatch {
*/ */
List<Future<Cursor>> find(); List<Future<Cursor>> find();
/**
* Get plan for EXPLAIN.
*
* @return plan
*/
String getPlanSQL();
/** /**
* Reset this batch to clear state. This method will be called before each query execution. * Reset this batch to clear state. This method will be called before each query execution.
*/ */
......
...@@ -95,16 +95,6 @@ public final class JoinBatch { ...@@ -95,16 +95,6 @@ public final class JoinBatch {
this.additionalFilter = additionalFilter; this.additionalFilter = additionalFilter;
} }
/**
* Check if the index at the given table filter really supports batching in this query.
*
* @param joinFilterId joined table filter id
* @return {@code true} if index really supports batching in this query
*/
public boolean isBatchedIndex(int joinFilterId) {
return filters[joinFilterId].isBatched();
}
/** /**
* Get the lookup batch for the given table filter. * Get the lookup batch for the given table filter.
* *
...@@ -413,7 +403,6 @@ public final class JoinBatch { ...@@ -413,7 +403,6 @@ public final class JoinBatch {
private final TableFilter filter; private final TableFilter filter;
private final JoinFilter join; private final JoinFilter join;
private final int id; private final int id;
private final boolean fakeBatch;
private final IndexLookupBatch lookupBatch; private final IndexLookupBatch lookupBatch;
...@@ -421,16 +410,16 @@ public final class JoinBatch { ...@@ -421,16 +410,16 @@ public final class JoinBatch {
this.filter = filter; this.filter = filter;
this.id = filter.getJoinFilterId(); this.id = filter.getJoinFilterId();
this.join = join; this.join = join;
fakeBatch = lookupBatch == null; if (lookupBatch == null && id != 0) {
this.lookupBatch = fakeBatch ? new FakeLookupBatch(filter) : lookupBatch; lookupBatch = new FakeLookupBatch(filter);
} }
this.lookupBatch = lookupBatch;
private boolean isBatched() {
return !fakeBatch;
} }
private void reset() { private void reset() {
lookupBatch.reset(); if (lookupBatch != null) {
lookupBatch.reset();
}
} }
private Row getNullRow() { private Row getNullRow() {
...@@ -657,6 +646,11 @@ public final class JoinBatch { ...@@ -657,6 +646,11 @@ public final class JoinBatch {
this.filter = filter; this.filter = filter;
} }
@Override
public String getPlanSQL() {
return "fake";
}
@Override @Override
public void reset() { public void reset() {
full = false; full = false;
...@@ -722,29 +716,36 @@ public final class JoinBatch { ...@@ -722,29 +716,36 @@ public final class JoinBatch {
private abstract static class ViewIndexLookupBatchBase<R extends QueryRunnerBase> private abstract static class ViewIndexLookupBatchBase<R extends QueryRunnerBase>
implements IndexLookupBatch { implements IndexLookupBatch {
protected final ViewIndex viewIndex; protected final ViewIndex viewIndex;
protected final ArrayList<Future<Cursor>> result = New.arrayList(); private final ArrayList<Future<Cursor>> result = New.arrayList();
protected int resultSize; private int resultSize;
private boolean findCalled;
protected ViewIndexLookupBatchBase(ViewIndex viewIndex) { protected ViewIndexLookupBatchBase(ViewIndex viewIndex) {
this.viewIndex = viewIndex; this.viewIndex = viewIndex;
} }
@Override
public String getPlanSQL() {
return "view";
}
protected abstract boolean collectSearchRows(R r); protected abstract boolean collectSearchRows(R r);
protected abstract R newQueryRunner(); protected abstract R newQueryRunner();
protected abstract void startQueryRunners(); protected abstract void startQueryRunners(int resultSize);
protected final boolean resetAfterFind() { protected final boolean resetAfterFind() {
if (resultSize < 0) { if (!findCalled) {
// method find was called, we need to reset futures to initial state for reuse return false;
for (int i = 0, size = -resultSize; i < size; i++) {
queryRunner(i).reset();
}
resultSize = 0;
return true;
} }
return false; findCalled = false;
// method find was called, we need to reset futures to initial state for reuse
for (int i = 0; i < resultSize; i++) {
queryRunner(i).reset();
}
resultSize = 0;
return true;
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
...@@ -790,12 +791,9 @@ public final class JoinBatch { ...@@ -790,12 +791,9 @@ public final class JoinBatch {
if (resultSize == 0) { if (resultSize == 0) {
return Collections.emptyList(); return Collections.emptyList();
} }
startQueryRunners(); findCalled = true;
List<Future<Cursor>> list = resultSize == result.size() ? startQueryRunners(resultSize);
result : result.subList(0, resultSize); return resultSize == result.size() ? result : result.subList(0, resultSize);
// mark that method find was called
resultSize = -resultSize;
return list;
} }
} }
...@@ -852,17 +850,16 @@ public final class JoinBatch { ...@@ -852,17 +850,16 @@ public final class JoinBatch {
@Override @Override
public boolean isBatchFull() { public boolean isBatchFull() {
assert resultSize >= 0;
return top.isBatchFull(); return top.isBatchFull();
} }
@Override @Override
protected void startQueryRunners() { protected void startQueryRunners(int resultSize) {
// we do batched find only for top table filter and then lazily run the ViewIndex query // we do batched find only for top table filter and then lazily run the ViewIndex query
// for each received top future cursor // for each received top future cursor
List<Future<Cursor>> topFutureCursors = top.find(); List<Future<Cursor>> topFutureCursors = top.find();
if (topFutureCursors.size() != resultSize) { if (topFutureCursors.size() != resultSize) {
throw DbException.throwInternalError("Unexpected result size: " + result.size() + throw DbException.throwInternalError("Unexpected result size: " + topFutureCursors.size() +
", expected :" + resultSize); ", expected :" + resultSize);
} }
for (int i = 0; i < resultSize; i++) { for (int i = 0; i < resultSize; i++) {
...@@ -976,15 +973,18 @@ public final class JoinBatch { ...@@ -976,15 +973,18 @@ public final class JoinBatch {
} }
@Override @Override
protected void startQueryRunners() { protected void startQueryRunners(int resultSize) {
for (int i = 0; i < filters.size(); i++) { for (int f = 0; f < filters.size(); f++) {
List<Future<Cursor>> topFutureCursors = filters.get(i).find(); List<Future<Cursor>> topFutureCursors = filters.get(f).find();
for (int j = 0, k = 0; j < resultSize; j++) { int r = 0, c = 0;
Future<Cursor>[] cs = queryRunner(j).topFutureCursors; for (; r < resultSize; r++) {
if (cs[j] == null) { Future<Cursor>[] cs = queryRunner(r).topFutureCursors;
cs[j] = topFutureCursors.get(k++); if (cs[f] == null) {
cs[f] = topFutureCursors.get(c++);
} }
} }
assert r == resultSize;
assert c == topFutureCursors.size();
} }
} }
} }
......
...@@ -269,8 +269,10 @@ public class TableFilter implements ColumnResolver { ...@@ -269,8 +269,10 @@ public class TableFilter implements ColumnResolver {
/** /**
* Prepare reading rows. This method will remove all index conditions that * Prepare reading rows. This method will remove all index conditions that
* can not be used, and optimize the conditions. * can not be used, and optimize the conditions.
*
* @param parse if we are parsing sub-query
*/ */
public void prepare() { public void prepare(boolean parse) {
// forget all unused index conditions // forget all unused index conditions
// the indexConditions list may be modified here // the indexConditions list may be modified here
for (int i = 0; i < indexConditions.size(); i++) { for (int i = 0; i < indexConditions.size(); i++) {
...@@ -289,19 +291,21 @@ public class TableFilter implements ColumnResolver { ...@@ -289,19 +291,21 @@ public class TableFilter implements ColumnResolver {
if (SysProperties.CHECK && nestedJoin == this) { if (SysProperties.CHECK && nestedJoin == this) {
DbException.throwInternalError("self join"); DbException.throwInternalError("self join");
} }
nestedJoin.prepare(); nestedJoin.prepare(parse);
} }
if (join != null) { if (join != null) {
if (SysProperties.CHECK && join == this) { if (SysProperties.CHECK && join == this) {
DbException.throwInternalError("self join"); DbException.throwInternalError("self join");
} }
join.prepare(); join.prepare(parse);
} }
if (filterCondition != null) { if (!parse) {
filterCondition = filterCondition.optimize(session); if (filterCondition != null) {
} filterCondition = filterCondition.optimize(session);
if (joinCondition != null) { }
joinCondition = joinCondition.optimize(session); if (joinCondition != null) {
joinCondition = joinCondition.optimize(session);
}
} }
} }
...@@ -784,11 +788,16 @@ public class TableFilter implements ColumnResolver { ...@@ -784,11 +788,16 @@ public class TableFilter implements ColumnResolver {
buff.append('\n'); buff.append('\n');
StatementBuilder planBuff = new StatementBuilder(); StatementBuilder planBuff = new StatementBuilder();
if (joinBatch != null) { if (joinBatch != null) {
if (joinBatch.isBatchedIndex(joinFilterId)) { IndexLookupBatch lookupBatch = joinBatch.getLookupBatch(joinFilterId);
planBuff.append("batched:true "); if (lookupBatch == null) {
} else if (joinFilterId != 0) { if (joinFilterId != 0) {
// top table filter does not need to fake batching, it works as usual in this case throw DbException.throwInternalError();
planBuff.append("batched:fake "); }
} else {
planBuff.append("batched:");
String batchPlan = lookupBatch.getPlanSQL();
planBuff.append(batchPlan);
planBuff.append(" ");
} }
} }
planBuff.append(index.getPlanSQL()); planBuff.append(index.getPlanSQL());
......
...@@ -24,6 +24,7 @@ import java.util.concurrent.ExecutorService; ...@@ -24,6 +24,7 @@ import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.concurrent.Future; import java.util.concurrent.Future;
import java.util.concurrent.ThreadFactory; import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;
import org.h2.api.TableEngine; import org.h2.api.TableEngine;
import org.h2.command.ddl.CreateTableData; import org.h2.command.ddl.CreateTableData;
import org.h2.command.dml.OptimizerHints; import org.h2.command.dml.OptimizerHints;
...@@ -36,6 +37,7 @@ import org.h2.index.Index; ...@@ -36,6 +37,7 @@ import org.h2.index.Index;
import org.h2.index.IndexLookupBatch; import org.h2.index.IndexLookupBatch;
import org.h2.index.IndexType; import org.h2.index.IndexType;
import org.h2.index.SingleRowCursor; import org.h2.index.SingleRowCursor;
import org.h2.jdbc.JdbcConnection;
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;
...@@ -383,10 +385,24 @@ public class TestTableEngines extends TestBase { ...@@ -383,10 +385,24 @@ public class TestTableEngines extends TestBase {
deleteDb("testSubQueryInfo"); deleteDb("testSubQueryInfo");
} }
private void setBatchingEnabled(Statement stat, boolean enabled) throws SQLException {
stat.execute("SET BATCH_JOINS " + enabled);
if (!config.networked) {
Session s = (Session) ((JdbcConnection) stat.getConnection()).getSession();
assertEquals(enabled, s.isJoinBatchEnabled());
}
}
private void testBatchedJoin() throws SQLException { private void testBatchedJoin() throws SQLException {
deleteDb("tableEngine"); deleteDb("testBatchedJoin");
Connection conn = getConnection("tableEngine;OPTIMIZE_REUSE_RESULTS=0"); Connection conn = getConnection("testBatchedJoin;OPTIMIZE_REUSE_RESULTS=0;BATCH_JOINS=1");
Statement stat = conn.createStatement(); Statement stat = conn.createStatement();
if (!config.networked) {
Session s = (Session) ((JdbcConnection) conn).getSession();
assertTrue(s.isJoinBatchEnabled());
}
setBatchingEnabled(stat, false);
setBatchingEnabled(stat, true);
TreeSetIndex.exec = Executors.newFixedThreadPool(8, new ThreadFactory() { TreeSetIndex.exec = Executors.newFixedThreadPool(8, new ThreadFactory() {
@Override @Override
...@@ -399,6 +415,9 @@ public class TestTableEngines extends TestBase { ...@@ -399,6 +415,9 @@ public class TestTableEngines extends TestBase {
enableJoinReordering(false); enableJoinReordering(false);
try { try {
doTestBatchedJoinSubQueryUnion(stat);
TreeSetIndex.lookupBatches.set(0);
doTestBatchedJoin(stat, 1, 0, 0); doTestBatchedJoin(stat, 1, 0, 0);
doTestBatchedJoin(stat, 0, 1, 0); doTestBatchedJoin(stat, 0, 1, 0);
doTestBatchedJoin(stat, 0, 0, 1); doTestBatchedJoin(stat, 0, 0, 1);
...@@ -429,11 +448,13 @@ public class TestTableEngines extends TestBase { ...@@ -429,11 +448,13 @@ public class TestTableEngines extends TestBase {
doTestBatchedJoin(stat, 0, 0, 5); doTestBatchedJoin(stat, 0, 0, 5);
doTestBatchedJoin(stat, 0, 8, 1); doTestBatchedJoin(stat, 0, 8, 1);
doTestBatchedJoin(stat, 0, 2, 1); doTestBatchedJoin(stat, 0, 2, 1);
assertTrue(TreeSetIndex.lookupBatches.get() > 0);
} finally { } finally {
enableJoinReordering(true); enableJoinReordering(true);
TreeSetIndex.exec.shutdownNow(); TreeSetIndex.exec.shutdownNow();
} }
deleteDb("tableEngine"); deleteDb("testBatchedJoin");
} }
/** /**
...@@ -447,7 +468,64 @@ public class TestTableEngines extends TestBase { ...@@ -447,7 +468,64 @@ public class TestTableEngines extends TestBase {
} }
OptimizerHints.set(hints); OptimizerHints.set(hints);
} }
private void checkPlan(Statement stat, String sql) throws SQLException {
ResultSet rs = stat.executeQuery("EXPLAIN " + sql);
assertTrue(rs.next());
String plan = rs.getString(1);
assertEquals(normalize(sql), normalize(plan));
}
private static String normalize(String sql) {
sql = sql.replace('\n', ' ');
return sql.replaceAll("\\s+", " ").trim();
}
private void doTestBatchedJoinSubQueryUnion(Statement stat) throws SQLException {
String engine = '"' + TreeSetIndexTableEngine.class.getName() + '"';
stat.execute("CREATE TABLE t (a int, b int) ENGINE " + engine);
TreeSetTable t = TreeSetIndexTableEngine.created;
stat.execute("CREATE INDEX T_IDX_A ON t(a)");
stat.execute("CREATE INDEX T_IDX_B ON t(b)");
setBatchSize(t, 3);
for (int i = 0; i < 20; i++) {
stat.execute("insert into t values (" + i + "," + i + ")");
}
stat.execute("CREATE TABLE u (a int, b int) ENGINE " + engine);
TreeSetTable u = TreeSetIndexTableEngine.created;
stat.execute("CREATE INDEX U_IDX_A ON u(a)");
stat.execute("CREATE INDEX U_IDX_B ON u(b)");
setBatchSize(u, 0);
for (int i = 0; i < 20; i++) {
stat.execute("insert into u values (" + i + "," + i + ")");
}
checkPlan(stat, "SELECT 1 FROM PUBLIC.T T1 /* PUBLIC.\"scan\" */ "
+ "INNER JOIN PUBLIC.T T2 /* batched:test PUBLIC.T_IDX_B: B = T1.A */ "
+ "ON 1=1 WHERE T1.A = T2.B");
checkPlan(stat, "SELECT 1 FROM PUBLIC.T T1 /* PUBLIC.\"scan\" */ "
+ "INNER JOIN PUBLIC.T T2 /* batched:test PUBLIC.T_IDX_B: B = T1.A */ "
+ "ON 1=1 /* WHERE T1.A = T2.B */ "
+ "INNER JOIN PUBLIC.T T3 /* batched:test PUBLIC.T_IDX_B: B = T2.A */ "
+ "ON 1=1 WHERE (T2.A = T3.B) AND (T1.A = T2.B)");
checkPlan(stat, "SELECT 1 FROM PUBLIC.T T1 /* PUBLIC.\"scan\" */ "
+ "INNER JOIN PUBLIC.U /* batched:fake PUBLIC.U_IDX_A: A = T1.A */ "
+ "ON 1=1 /* WHERE T1.A = U.A */ "
+ "INNER JOIN PUBLIC.T T2 /* batched:test PUBLIC.T_IDX_B: B = U.B */ "
+ "ON 1=1 WHERE (T1.A = U.A) AND (U.B = T2.B)");
checkPlan(stat, "SELECT 1 FROM ( SELECT A FROM PUBLIC.T ) Z "
+ "/* SELECT A FROM PUBLIC.T /++ PUBLIC.\"scan\" ++/ */ "
+ "INNER JOIN PUBLIC.T /* batched:test PUBLIC.T_IDX_B: B = Z.A */ "
+ "ON 1=1 WHERE Z.A = T.B");
checkPlan(stat, "SELECT 1 FROM PUBLIC.T /* PUBLIC.\"scan\" */ "
+ "INNER JOIN ( SELECT A FROM PUBLIC.T ) Z "
+ "/* batched:view SELECT A FROM PUBLIC.T /++ batched:test PUBLIC.T_IDX_A: A IS ?1 ++/ "
+ "WHERE A IS ?1: A = T.B */ ON 1=1 WHERE Z.A = T.B");
stat.execute("DROP TABLE T");
stat.execute("DROP TABLE U");
}
private void doTestBatchedJoin(Statement stat, int... batchSizes) throws SQLException { private void doTestBatchedJoin(Statement stat, int... batchSizes) throws SQLException {
ArrayList<TreeSetTable> tables = New.arrayList(batchSizes.length); ArrayList<TreeSetTable> tables = New.arrayList(batchSizes.length);
...@@ -501,6 +579,9 @@ public class TestTableEngines extends TestBase { ...@@ -501,6 +579,9 @@ public class TestTableEngines extends TestBase {
fail(); fail();
} }
} }
for (int i = 0; i < batchSizes.length; i++) {
stat.executeUpdate("DROP TABLE IF EXISTS T" + i);
}
} }
private static void assert0(boolean condition, String message) { private static void assert0(boolean condition, String message) {
...@@ -512,7 +593,15 @@ public class TestTableEngines extends TestBase { ...@@ -512,7 +593,15 @@ public class TestTableEngines extends TestBase {
private static void setBatchSize(ArrayList<TreeSetTable> tables, int... batchSizes) { private static void setBatchSize(ArrayList<TreeSetTable> tables, int... batchSizes) {
for (int i = 0; i < batchSizes.length; i++) { for (int i = 0; i < batchSizes.length; i++) {
int batchSize = batchSizes[i]; int batchSize = batchSizes[i];
for (Index idx : tables.get(i).getIndexes()) { setBatchSize(tables.get(i), batchSize);
}
}
private static void setBatchSize(TreeSetTable t, int batchSize) {
if (t.getIndexes() == null) {
t.scan.preferedBatchSize = batchSize;
} else {
for (Index idx : t.getIndexes()) {
((TreeSetIndex) idx).preferedBatchSize = batchSize; ((TreeSetIndex) idx).preferedBatchSize = batchSize;
} }
} }
...@@ -1115,6 +1204,8 @@ public class TestTableEngines extends TestBase { ...@@ -1115,6 +1204,8 @@ public class TestTableEngines extends TestBase {
* An index that internally uses a tree set. * An index that internally uses a tree set.
*/ */
private static class TreeSetIndex extends BaseIndex implements Comparator<SearchRow> { private static class TreeSetIndex extends BaseIndex implements Comparator<SearchRow> {
private static AtomicInteger lookupBatches = new AtomicInteger();
/** /**
* Executor service to test batched joins. * Executor service to test batched joins.
*/ */
...@@ -1145,9 +1236,18 @@ public class TestTableEngines extends TestBase { ...@@ -1145,9 +1236,18 @@ public class TestTableEngines extends TestBase {
public IndexLookupBatch createLookupBatch(final TableFilter filter) { public IndexLookupBatch createLookupBatch(final TableFilter filter) {
assert filter.getMasks() != null || "scan".equals(getName()); assert filter.getMasks() != null || "scan".equals(getName());
final int preferedSize = preferedBatchSize; final int preferedSize = preferedBatchSize;
return preferedSize == 0 ? null : new IndexLookupBatch() { if (preferedSize == 0) {
return null;
}
lookupBatches.incrementAndGet();
return new IndexLookupBatch() {
List<SearchRow> searchRows = New.arrayList(); List<SearchRow> searchRows = New.arrayList();
@Override
public String getPlanSQL() {
return "test";
}
@Override public boolean isBatchFull() { @Override public boolean isBatchFull() {
return searchRows.size() >= preferedSize * 2; return searchRows.size() >= preferedSize * 2;
} }
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论