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

Optimizer: the expected runtime calculation was incorrect.

上级 c77c145a
...@@ -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>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>Connection.isValid is a bit faster.
</li><li>H2 Console: The autocomplete feature has been improved a bit. It can now better </li><li>H2 Console: The autocomplete feature has been improved a bit. It can now better
parse conditions. parse conditions.
......
...@@ -6,7 +6,6 @@ ...@@ -6,7 +6,6 @@
*/ */
package org.h2.command.dml; package org.h2.command.dml;
import java.math.BigInteger;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.BitSet; import java.util.BitSet;
import java.util.Random; import java.util.Random;
...@@ -16,7 +15,6 @@ import org.h2.expression.Expression; ...@@ -16,7 +15,6 @@ import org.h2.expression.Expression;
import org.h2.table.Plan; import org.h2.table.Plan;
import org.h2.table.PlanItem; import org.h2.table.PlanItem;
import org.h2.table.TableFilter; import org.h2.table.TableFilter;
import org.h2.util.MathUtils;
import org.h2.util.ObjectUtils; import org.h2.util.ObjectUtils;
import org.h2.util.Permutations; import org.h2.util.Permutations;
...@@ -27,12 +25,12 @@ import org.h2.util.Permutations; ...@@ -27,12 +25,12 @@ import org.h2.util.Permutations;
public class Optimizer { public class Optimizer {
private static final int MAX_BRUTE_FORCE_FILTERS = 7; 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 static final int MAX_GENETIC = 500;
private long start; private long start;
private BitSet switched; private BitSet switched;
// possible plans for filters: // possible plans for filters, if using brute force:
// 1 filter 1 plan // 1 filter 1 plan
// 2 filters 2 plans // 2 filters 2 plans
// 3 filters 6 plans // 3 filters 6 plans
...@@ -43,10 +41,6 @@ public class Optimizer { ...@@ -43,10 +41,6 @@ public class Optimizer {
// 8 filters 40320 plan // 8 filters 40320 plan
// 9 filters 362880 plans // 9 filters 362880 plans
// 10 filters 3628800 filters // 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 TableFilter[] filters;
private Expression condition; private Expression condition;
...@@ -63,12 +57,21 @@ public class Optimizer { ...@@ -63,12 +57,21 @@ public class Optimizer {
this.session = session; this.session = session;
} }
private int getMaxBruteForceFilters(int filterCount) { /**
int i = 0, j = filterCount; * How many filter to calculate using brute force. The remaining filters are
BigInteger total = new BigInteger("" + filterCount); * selected using a greedy algorithm which has a runtime of (1 + 2 + ... +
while (j > 0 && total.compareTo(MAX_BRUTE_FORCE) < 0) { * 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--; j--;
total = total.multiply(MathUtils.factorial(j)); total *= j;
i++; i++;
} }
return i; return i;
......
...@@ -7,7 +7,6 @@ ...@@ -7,7 +7,6 @@
package org.h2.util; package org.h2.util;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.math.BigInteger;
import java.sql.SQLException; import java.sql.SQLException;
import org.h2.engine.Constants; import org.h2.engine.Constants;
...@@ -179,29 +178,4 @@ public class MathUtils { ...@@ -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 @@ ...@@ -6,10 +6,9 @@
*/ */
package org.h2.test.unit; package org.h2.test.unit;
import java.math.BigInteger;
import java.sql.SQLException; import java.sql.SQLException;
import org.h2.test.TestBase; import org.h2.test.TestBase;
import org.h2.util.MathUtils;
/** /**
* Tests math utility methods. * Tests math utility methods.
...@@ -26,17 +25,47 @@ public class TestMathUtils extends TestBase { ...@@ -26,17 +25,47 @@ public class TestMathUtils extends TestBase {
} }
public void test() throws SQLException { public void test() throws SQLException {
testFactorial();
}
private void testFactorial() {
try { try {
MathUtils.factorial(-1); factorial(-1);
fail(); fail();
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
// ignore // ignore
} }
assertEquals("1", MathUtils.factorial(0).toString()); assertEquals("1", factorial(0).toString());
assertEquals("1", MathUtils.factorial(1).toString()); assertEquals("1", factorial(1).toString());
assertEquals("2", MathUtils.factorial(2).toString()); assertEquals("2", factorial(2).toString());
assertEquals("6", MathUtils.factorial(3).toString()); assertEquals("6", factorial(3).toString());
assertEquals("3628800", MathUtils.factorial(10).toString()); assertEquals("3628800", factorial(10).toString());
assertEquals("2432902008176640000", MathUtils.factorial(20).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 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论