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

Optimizer: the expected runtime calculation was incorrect.

上级 c77c145a
......@@ -18,7 +18,9 @@ Change Log
<h1>Change Log</h1>
<h2>Next Version (unreleased)</h2>
<ul><li>Improved exception message when connecting to a just started server fails.
<ul><li>Optimizer: the expected runtime calculation was incorrect. The fixed calculation
should give slightly better query plans when using many joins.
</li><li>Improved exception message when connecting to a just started server fails.
</li><li>Connection.isValid is a bit faster.
</li><li>H2 Console: The autocomplete feature has been improved a bit. It can now better
parse conditions.
......
......@@ -6,7 +6,6 @@
*/
package org.h2.command.dml;
import java.math.BigInteger;
import java.sql.SQLException;
import java.util.BitSet;
import java.util.Random;
......@@ -16,7 +15,6 @@ import org.h2.expression.Expression;
import org.h2.table.Plan;
import org.h2.table.PlanItem;
import org.h2.table.TableFilter;
import org.h2.util.MathUtils;
import org.h2.util.ObjectUtils;
import org.h2.util.Permutations;
......@@ -27,12 +25,12 @@ import org.h2.util.Permutations;
public class Optimizer {
private static final int MAX_BRUTE_FORCE_FILTERS = 7;
private static final BigInteger MAX_BRUTE_FORCE = new BigInteger("" + 2000);
private static final int MAX_BRUTE_FORCE = 2000;
private static final int MAX_GENETIC = 500;
private long start;
private BitSet switched;
// possible plans for filters:
// possible plans for filters, if using brute force:
// 1 filter 1 plan
// 2 filters 2 plans
// 3 filters 6 plans
......@@ -43,10 +41,6 @@ public class Optimizer {
// 8 filters 40320 plan
// 9 filters 362880 plans
// 10 filters 3628800 filters
// 1 of 1, 2, 3, 4, 5, 6 filters: 1, 2, 3, 4, 5, 6
// 2 of 2, 3, 4, 5, 6 filters: 2, 6, 12, 20, 30
// 3 of 3, 4, 5, 6 filters: 6, 24, 75, 120
// 4 of 4, 5, 6 filters: 24, 120, 260
private TableFilter[] filters;
private Expression condition;
......@@ -63,12 +57,21 @@ public class Optimizer {
this.session = session;
}
private int getMaxBruteForceFilters(int filterCount) {
int i = 0, j = filterCount;
BigInteger total = new BigInteger("" + filterCount);
while (j > 0 && total.compareTo(MAX_BRUTE_FORCE) < 0) {
/**
* How many filter to calculate using brute force. The remaining filters are
* selected using a greedy algorithm which has a runtime of (1 + 2 + ... +
* n) = (n * (n-1) / 2) for n filters. The brute force algorithm has a
* runtime of n * (n-1) * ... * (n-m) when calculating m brute force of n
* total. The combined runtime is (brute force) * (greedy).
*
* @param filterCount the number of filters total
* @return the number of filters to calculate using brute force
*/
private static int getMaxBruteForceFilters(int filterCount) {
int i = 0, j = filterCount, total = filterCount;
while (j > 0 && total * (j * (j - 1) / 2) < MAX_BRUTE_FORCE) {
j--;
total = total.multiply(MathUtils.factorial(j));
total *= j;
i++;
}
return i;
......
......@@ -7,7 +7,6 @@
package org.h2.util;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.sql.SQLException;
import org.h2.engine.Constants;
......@@ -179,29 +178,4 @@ public class MathUtils {
}
}
/**
* Calculate the factorial (n!) of a number.
* This implementation uses a naive multiplication loop, and
* is very slow for large n.
* For n = 1000, it takes about 10 ms.
* For n = 8000, it takes about 800 ms.
*
* @param n the number
* @return the factorial of n
*/
public static BigInteger factorial(int n) {
if (n < 0) {
throw new IllegalArgumentException(n + "<0");
} else if (n < 2) {
return BigInteger.ONE;
}
BigInteger x = new BigInteger("" + n);
BigInteger result = x;
for (int i = n - 1; i >= 2; i--) {
x = x.subtract(BigInteger.ONE);
result = result.multiply(x);
}
return result;
}
}
......@@ -6,10 +6,9 @@
*/
package org.h2.test.unit;
import java.math.BigInteger;
import java.sql.SQLException;
import org.h2.test.TestBase;
import org.h2.util.MathUtils;
/**
* Tests math utility methods.
......@@ -26,17 +25,47 @@ public class TestMathUtils extends TestBase {
}
public void test() throws SQLException {
testFactorial();
}
private void testFactorial() {
try {
MathUtils.factorial(-1);
factorial(-1);
fail();
} catch (IllegalArgumentException e) {
// ignore
}
assertEquals("1", MathUtils.factorial(0).toString());
assertEquals("1", MathUtils.factorial(1).toString());
assertEquals("2", MathUtils.factorial(2).toString());
assertEquals("6", MathUtils.factorial(3).toString());
assertEquals("3628800", MathUtils.factorial(10).toString());
assertEquals("2432902008176640000", MathUtils.factorial(20).toString());
assertEquals("1", factorial(0).toString());
assertEquals("1", factorial(1).toString());
assertEquals("2", factorial(2).toString());
assertEquals("6", factorial(3).toString());
assertEquals("3628800", factorial(10).toString());
assertEquals("2432902008176640000", factorial(20).toString());
}
/**
* Calculate the factorial (n!) of a number.
* This implementation uses a naive multiplication loop, and
* is very slow for large n.
* For n = 1000, it takes about 10 ms.
* For n = 8000, it takes about 800 ms.
*
* @param n the number
* @return the factorial of n
*/
public static BigInteger factorial(int n) {
if (n < 0) {
throw new IllegalArgumentException(n + "<0");
} else if (n < 2) {
return BigInteger.ONE;
}
BigInteger x = new BigInteger("" + n);
BigInteger result = x;
for (int i = n - 1; i >= 2; i--) {
x = x.subtract(BigInteger.ONE);
result = result.multiply(x);
}
return result;
}
}
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论