提交 b694ef8f authored 作者: Thomas Mueller's avatar Thomas Mueller

Merge pull request #183 from svladykin/optimizerHints

Optimizer hints
...@@ -53,6 +53,14 @@ class Optimizer { ...@@ -53,6 +53,14 @@ class Optimizer {
this.session = session; this.session = session;
} }
/**
* @return {@code true} If join reordering is enabled (it can be disabled by hint).
*/
private static boolean isJoinReorderingEnabled() {
OptimizerHints hints = OptimizerHints.get();
return hints == null || hints.joinReorderEnabled;
}
/** /**
* How many filter to calculate using brute force. The remaining filters are * How many filter to calculate using brute force. The remaining filters are
* selected using a greedy algorithm which has a runtime of (1 + 2 + ... + * selected using a greedy algorithm which has a runtime of (1 + 2 + ... +
...@@ -76,7 +84,7 @@ class Optimizer { ...@@ -76,7 +84,7 @@ class Optimizer {
private void calculateBestPlan() { private void calculateBestPlan() {
start = System.currentTimeMillis(); start = System.currentTimeMillis();
cost = -1; cost = -1;
if (filters.length == 1) { if (filters.length == 1 || !isJoinReorderingEnabled()) {
testPlan(filters); testPlan(filters);
} else if (filters.length <= MAX_BRUTE_FORCE_FILTERS) { } else if (filters.length <= MAX_BRUTE_FORCE_FILTERS) {
calculateBruteForceAll(); calculateBruteForceAll();
......
/*
* Copyright 2004-2014 H2 Group. Multiple-Licensed under the MPL 2.0,
* and the EPL 1.0 (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package org.h2.command.dml;
/**
* Thread local hints for H2 query optimizer. All the ongoing queries in the current thread
* will run with respect to these hints, so if they are needed only for a single
* operation it is preferable to setup and drop them in try-finally block.
*
* Currently works only in embedded mode.
*
* @author Sergi Vladykin
*/
public class OptimizerHints {
private static final ThreadLocal<OptimizerHints> HINTS = new ThreadLocal<OptimizerHints>();
boolean joinReorderEnabled = true;
/**
* Set thread local hints or {@code null} to drop any existing hints.
*
* @param hints
*/
public static void set(OptimizerHints hints) {
if (hints != null) {
HINTS.set(hints);
} else {
HINTS.remove();
}
}
/**
* @return Current thread local hints or {@code null} if none.
*/
public static OptimizerHints get() {
return HINTS.get();
}
/**
* Set whether reordering of tables (or anything else in the {@code FROM} clause) is enabled.
* By default is {@code true}.
*
* @param joinReorderEnabled Flag value.
*/
public void setJoinReorderEnabled(boolean joinReorderEnabled) {
this.joinReorderEnabled = joinReorderEnabled;
}
}
/*
* Copyright 2004-2014 H2 Group. Multiple-Licensed under the MPL 2.0,
* and the EPL 1.0 (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package org.h2.test.db;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import org.h2.command.dml.OptimizerHints;
import org.h2.test.TestBase;
/**
* Test for optimizer hints.
*
* @author Sergi Vladykin
*/
public class TestOptimizerHints extends TestBase {
/**
* Run just this test.
*
* @param a ignored
*/
public static void main(String[] a) throws Exception {
TestBase.createCaller().init().test();
}
@Override
public void test() throws Exception {
if (config.networked) {
return;
}
deleteDb("testOptimizerHints");
Connection conn = getConnection("testOptimizerHints");
Statement s = conn.createStatement();
s.execute("create table t1(id int)");
s.execute("create table t2(id int, ref_id int)");
s.execute("insert into t1 values(1),(2),(3)");
s.execute("insert into t2 values(1,2),(2,3),(3,4),(4,6),(5,1),(6,4)");
s.execute("create unique index idx1_id on t1(id)");
s.execute("create index idx2_id on t2(id)");
s.execute("create index idx2_ref_id on t2(ref_id)");
enableJoinReordering(false);
try {
String plan;
plan = plan(s, "select * from t1, t2 where t1.id = t2.ref_id");
assertTrue(plan, plan.contains("INNER JOIN PUBLIC.T2"));
plan = plan(s, "select * from t2, t1 where t1.id = t2.ref_id");
assertTrue(plan, plan.contains("INNER JOIN PUBLIC.T1"));
plan = plan(s, "select * from t2, t1 where t1.id = 1");
assertTrue(plan, plan.contains("INNER JOIN PUBLIC.T1"));
plan = plan(s, "select * from t2, t1 where t1.id = t2.ref_id and t2.id = 1");
assertTrue(plan, plan.contains("INNER JOIN PUBLIC.T1"));
plan = plan(s, "select * from t1, t2 where t1.id = t2.ref_id and t2.id = 1");
assertTrue(plan, plan.contains("INNER JOIN PUBLIC.T2"));
} finally {
enableJoinReordering(true);
}
deleteDb("testOptimizerHints");
}
/**
* @param enable Enabled.
*/
private void enableJoinReordering(boolean enable) {
OptimizerHints hints = new OptimizerHints();
hints.setJoinReorderEnabled(enable);
OptimizerHints.set(hints);
}
/**
* @param s Statement.
* @param query Query.
* @return Plan.
* @throws SQLException If failed.
*/
private String plan(Statement s, String query) throws SQLException {
ResultSet rs = s.executeQuery("explain " + query);
assertTrue(rs.next());
String plan = rs.getString(1);
rs.close();
return plan;
}
}
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论