提交 5b5a787a authored 作者: Thomas Mueller's avatar Thomas Mueller

The optimization to group using an index didn't work.

上级 2c6cde93
...@@ -18,7 +18,9 @@ Change Log ...@@ -18,7 +18,9 @@ Change Log
<h1>Change Log</h1> <h1>Change Log</h1>
<h2>Next Version (unreleased)</h2> <h2>Next Version (unreleased)</h2>
<ul><li>OSGi meta data is included in the manifest file. <ul><li>The optimization to group using an index didn't work in some cases in version 1.1
(see also system property h2.optimizeGroupSorted).
</li><li>OSGi meta data is included in the manifest file.
An OSGi BundleActivator is included: it loads the database driver when starting the bundle, An OSGi BundleActivator is included: it loads the database driver when starting the bundle,
and unloads it when stopping the bundle. and unloads it when stopping the bundle.
</li><li>The default value for MAX_MEMORY_UNDO to 50000. </li><li>The default value for MAX_MEMORY_UNDO to 50000.
......
...@@ -249,8 +249,11 @@ public class Select extends Query { ...@@ -249,8 +249,11 @@ public class Select extends Query {
} }
private boolean isGroupSortedIndex(Index index) { private boolean isGroupSortedIndex(Index index) {
// check that all the GROUP BY expressions are part of the index
Column[] indexColumns = index.getColumns(); Column[] indexColumns = index.getColumns();
outerLoop: // also check that the first columns in the index are grouped
boolean[] grouped = new boolean[indexColumns.length];
outerLoop:
for (int i = 0; i < expressions.size(); i++) { for (int i = 0; i < expressions.size(); i++) {
if (!groupByExpression[i]) { if (!groupByExpression[i]) {
continue; continue;
...@@ -262,13 +265,22 @@ public class Select extends Query { ...@@ -262,13 +265,22 @@ public class Select extends Query {
ExpressionColumn exprCol = (ExpressionColumn) expr; ExpressionColumn exprCol = (ExpressionColumn) expr;
for (int j = 0; j < indexColumns.length; ++j) { for (int j = 0; j < indexColumns.length; ++j) {
if (indexColumns[j].equals(exprCol.getColumn())) { if (indexColumns[j].equals(exprCol.getColumn())) {
grouped[j] = true;
continue outerLoop; continue outerLoop;
} }
} }
// We didn't find a matching index column for the group by // We didn't find a matching index column
// expression // for one group by expression
return false; return false;
} }
// check that the first columns in the index are grouped
// good: index(a, b, c); group by b, a
// bad: index(a, b, c); group by a, c
for (int i = 1; i < grouped.length; i++) {
if (!grouped[i - 1] && grouped[i]) {
return false;
}
}
return true; return true;
} }
......
...@@ -10,8 +10,12 @@ import java.io.InputStream; ...@@ -10,8 +10,12 @@ import java.io.InputStream;
import java.sql.Connection; import java.sql.Connection;
import java.sql.DriverManager; import java.sql.DriverManager;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.Statement; import java.sql.Statement;
import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
import org.h2.util.JdbcDriverUtils; import org.h2.util.JdbcDriverUtils;
...@@ -30,7 +34,12 @@ public class Db { ...@@ -30,7 +34,12 @@ public class Db {
private Statement stat; private Statement stat;
private HashMap prepared = new HashMap(); private HashMap prepared = new HashMap();
private Db(Connection conn) { /**
* Create a database object using the given connection.
*
* @param conn the database connection
*/
public Db(Connection conn) {
try { try {
this.conn = conn; this.conn = conn;
stat = conn.createStatement(); stat = conn.createStatement();
...@@ -88,6 +97,31 @@ public class Db { ...@@ -88,6 +97,31 @@ public class Db {
throw convert(e); throw convert(e);
} }
} }
/**
* Execute a SQL statement.
*
* @param sql the SQL statement
* @return a list of maps
*/
public List query(String sql) {
try {
List list = new ArrayList();
ResultSet rs = stat.executeQuery(sql);
ResultSetMetaData meta = rs.getMetaData();
int columnCount = meta.getColumnCount();
while (rs.next()) {
HashMap map = new HashMap();
for (int i = 0; i < columnCount; i++) {
map.put(meta.getColumnLabel(i+1), rs.getObject(i+1));
}
list.add(map);
}
return list;
} catch (Exception e) {
throw convert(e);
}
}
/** /**
* Close the database connection. * Close the database connection.
......
/*
* Copyright 2004-2008 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.test.synth;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;
import java.util.Random;
import org.h2.test.TestBase;
import org.h2.test.db.Db;
import org.h2.test.db.Db.Prepared;
/**
* This test executes random SQL statements to test if optimizations are working
* correctly.
*/
public class TestOptimizations extends TestBase {
private Connection conn;
/**
* Run just this test.
*
* @param a ignored
*/
public static void main(String[] a) throws Exception {
TestBase.createCaller().init().test();
}
public void test() throws Exception {
deleteDb("optimizations");
conn = getConnection("optimizations");
testGroupSorted();
conn.close();
}
private void testGroupSorted() throws SQLException {
Db db = new Db(conn);
db.execute("CREATE TABLE TEST(A INT, B INT, C INT)");
Random random = new Random();
long seed = random.nextLong();
println("seed: " + seed);
for (int i = 0; i < 100; i++) {
Prepared p = db.prepare("INSERT INTO TEST VALUES(?, ?, ?)");
p.set(new String[] { null, "0", "1", "2" }[random.nextInt(4)]);
p.set(new String[] { null, "0", "1", "2" }[random.nextInt(4)]);
p.set(new String[] { null, "0", "1", "2" }[random.nextInt(4)]);
p.execute();
}
int len = getSize(1000, 10000);
for (int i = 0; i < len / 10; i++) {
db.execute("CREATE TABLE TEST_INDEXED AS SELECT * FROM TEST");
int jLen = 1 + random.nextInt(2);
for (int j = 0; j < jLen; j++) {
String x = "CREATE INDEX IDX" + j + " ON TEST_INDEXED(";
int kLen = 1 + random.nextInt(2);
for (int k = 0; k < kLen; k++) {
if (k > 0) {
x += ",";
}
x += new String[] { "A", "B", "C" }[random.nextInt(3)];
}
db.execute(x + ")");
}
for (int j = 0; j < 10; j++) {
String x = "SELECT ";
for (int k = 0; k < 3; k++) {
if (k > 0) {
x += ",";
}
x += new String[] { "SUM(A)", "MAX(B)", "AVG(C)", "COUNT(B)" }[random.nextInt(4)];
x += " S" + k;
}
x += " FROM ";
String group = " GROUP BY ";
int kLen = 1 + random.nextInt(2);
for (int k = 0; k < kLen; k++) {
if (k > 0) {
group += ",";
}
group += new String[] { "A", "B", "C" }[random.nextInt(3)];
}
group += " ORDER BY 1, 2, 3";
List a = db.query(x + "TEST" + group);
List b = db.query(x + "TEST_INDEXED" + group);
assertTrue(a.equals(b));
}
db.execute("DROP TABLE TEST_INDEXED");
}
}
}
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论