提交 96b77248 authored 作者: Evgenij Ryazanov's avatar Evgenij Ryazanov

Merge branch 'master' into misc

......@@ -397,7 +397,7 @@ public abstract class Query extends Prepared {
}
fireBeforeSelectTriggers();
if (noCache || !session.getDatabase().getOptimizeReuseResults() ||
session.isLazyQueryExecution()) {
(session.isLazyQueryExecution() && !neverLazy)) {
return queryWithoutCacheLazyCheck(limit, target);
}
Value[] params = getParameterValues();
......
......@@ -29,6 +29,7 @@ import org.h2.expression.condition.ConditionAndOr;
import org.h2.index.Cursor;
import org.h2.index.Index;
import org.h2.index.IndexType;
import org.h2.index.ViewIndex;
import org.h2.message.DbException;
import org.h2.result.LazyResult;
import org.h2.result.LocalResult;
......@@ -43,6 +44,7 @@ import org.h2.table.IndexColumn;
import org.h2.table.JoinBatch;
import org.h2.table.Table;
import org.h2.table.TableFilter;
import org.h2.table.TableType;
import org.h2.table.TableView;
import org.h2.util.ColumnNamer;
import org.h2.util.StatementBuilder;
......@@ -722,6 +724,8 @@ public class Select extends Query {
@Override
protected ResultInterface queryWithoutCache(int maxRows, ResultTarget target) {
disableLazyForJoinSubqueries(topTableFilter);
int limitRows = maxRows == 0 ? -1 : maxRows;
if (limitExpr != null) {
Value v = limitExpr.getValue(session);
......@@ -865,6 +869,22 @@ public class Select extends Query {
return null;
}
private void disableLazyForJoinSubqueries(final TableFilter top) {
if (session.isLazyQueryExecution()) {
top.visit(new TableFilter.TableFilterVisitor() {
@Override
public void accept(TableFilter f) {
if (f != top && f.getTable().getTableType() == TableType.VIEW) {
ViewIndex idx = (ViewIndex) f.getIndex();
if (idx != null && idx.getQuery() != null) {
idx.getQuery().setNeverLazy(true);
}
}
}
});
}
}
/**
* Reset the batch-join after the query result is closed.
*/
......
......@@ -222,6 +222,7 @@ import org.h2.test.unit.TestSort;
import org.h2.test.unit.TestStreams;
import org.h2.test.unit.TestStringCache;
import org.h2.test.unit.TestStringUtils;
import org.h2.test.unit.TestSubqueryPerformanceOnLazyExecutionMode;
import org.h2.test.unit.TestTimeStampWithTimeZone;
import org.h2.test.unit.TestTools;
import org.h2.test.unit.TestTraceSystem;
......@@ -926,6 +927,7 @@ kill -9 `jps -l | grep "org.h2.test." | cut -d " " -f 1`
addTest(new TestDefrag());
addTest(new TestTools());
addTest(new TestSampleApps());
addTest(new TestSubqueryPerformanceOnLazyExecutionMode());
runAddedTests(1);
}
......
/*
* Copyright 2004-2018 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.unit;
import org.h2.command.dml.SetTypes;
import org.h2.test.TestBase;
import org.h2.test.TestDb;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
/**
* Test subquery performance with lazy query execution mode {@link SetTypes#LAZY_QUERY_EXECUTION}.
*/
public class TestSubqueryPerformanceOnLazyExecutionMode extends TestDb {
/** Rows count. */
private static final int ROWS = 5000;
/** Test repeats when unexpected failure. */
private static final int FAIL_REPEATS = 5;
/**
* 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 {
deleteDb("lazySubq");
try (Connection conn = getConnection("lazySubq")) {
try (Statement stmt = conn.createStatement()) {
stmt.execute("CREATE TABLE one (x INTEGER, y INTEGER )");
try (PreparedStatement prep = conn.prepareStatement("insert into one values (?,?)")) {
for (int row = 0; row < ROWS; row++) {
prep.setInt(1, row / 100);
prep.setInt(2, row);
prep.execute();
}
}
testSubqueryInCondition(stmt);
testSubqueryInJoin(stmt);
testSubqueryInJoinFirst(stmt);
testJoinTwoSubqueries(stmt);
testSubqueryInNestedJoin(stmt);
}
}
finally {
deleteDb("lazySubq");
}
}
private void testSubqueryInCondition(Statement stmt) throws Exception {
String sql = "SELECT COUNT (*) FROM one WHERE x IN (SELECT y FROM one WHERE y < 50)";
checkExecutionTime(stmt, sql);
}
private void testSubqueryInJoin(Statement stmt) throws Exception {
String sql =
"SELECT COUNT (one.x) FROM one " +
"JOIN (SELECT y AS val FROM one WHERE y < 50) AS subq ON subq.val=one.x";
checkExecutionTime(stmt, sql);
}
private void testSubqueryInJoinFirst(Statement stmt) throws Exception {
String sql =
"SELECT COUNT (one.x) FROM " +
"(SELECT y AS val FROM one WHERE y < 50) AS subq " +
"JOIN one ON subq.val=one.x";
checkExecutionTime(stmt, sql);
}
private void testJoinTwoSubqueries(Statement stmt) throws Exception {
String sql =
"SELECT COUNT (one_sub.x) FROM " +
"(SELECT y AS val FROM one WHERE y < 50) AS subq " +
"JOIN (SELECT x FROM one) AS one_sub ON subq.val=one_sub.x";
checkExecutionTime(stmt, sql);
}
private void testSubqueryInNestedJoin(Statement stmt) throws Exception {
String sql =
"SELECT COUNT (one.x) FROM one " +
"LEFT JOIN (SELECT 1 AS val_1) AS subq0 " +
"JOIN (SELECT y AS val FROM one WHERE y < 30) AS subq1 ON subq0.val_1 < subq1.val " +
"ON one.x = subq1.val " +
"WHERE one.x < 30";
checkExecutionTime(stmt, sql, 3000);
}
private void checkExecutionTime(Statement stmt, String sql) throws Exception {
checkExecutionTime(stmt, sql, ROWS);
}
/**
* Compare execution time when lazy execution mode is disabled and enabled.
* The execution time must be almost the same.
*/
private void checkExecutionTime(Statement stmt, String sql, int expected) throws Exception {
long totalNotLazy = 0;
long totalLazy = 0;
int successCnt = 0;
int failCnt = 0;
for (int i = 0; i < FAIL_REPEATS; ++i) {
long tLazy = executeAndCheckResult(stmt, sql, true, expected);
long tNotLazy = executeAndCheckResult(stmt, sql, false, expected);
totalNotLazy += tNotLazy;
totalLazy += tLazy;
if (tNotLazy * 2 > tLazy) {
successCnt++;
if (i == 0) {
break;
}
} else {
failCnt++;
}
}
if (failCnt > successCnt) {
fail("Lazy execution too slow. Avg lazy time: "
+ (totalLazy / FAIL_REPEATS) + ", avg not lazy time: " + (totalNotLazy / FAIL_REPEATS));
}
}
/**
* @return Time of the query execution.
*/
private long executeAndCheckResult(Statement stmt, String sql, boolean lazy, int expected) throws SQLException {
if (lazy) {
stmt.execute("SET LAZY_QUERY_EXECUTION 1");
}
else {
stmt.execute("SET LAZY_QUERY_EXECUTION 0");
}
long t0 = System.currentTimeMillis();
try (ResultSet rs = stmt.executeQuery(sql)) {
rs.next();
assertEquals(expected, rs.getInt(1));
}
return System.currentTimeMillis() - t0;
}
}
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论