Unverified 提交 28bfe550 authored 作者: Noel Grandin's avatar Noel Grandin 提交者: GitHub

Merge pull request #1571 from isuruperera/master

Optimizing ConditionAndOr queries
......@@ -159,8 +159,7 @@ public class ConditionAndOr extends Condition {
}
}
}
// TODO optimization: convert ((A=1 AND B=2) OR (A=1 AND B=3)) to
// (A=1 AND (B=2 OR B=3))
if (andOrType == OR &&
session.getDatabase().getSettings().optimizeOr) {
// try to add conditions (A=B AND B=1: add A=1)
......@@ -201,6 +200,14 @@ public class ConditionAndOr extends Condition {
if (added != null) {
return added.optimize(session);
}
} else if (left instanceof ConditionAndOr &&
right instanceof ConditionAndOr ){
ConditionAndOr condAORight = (ConditionAndOr)right;
ConditionAndOr condAORLeft = (ConditionAndOr)left;
Expression reduced = optimizeConditionAndOr(condAORLeft,condAORight);
if(reduced != null){
return reduced.optimize(session);
}
}
}
// TODO optimization: convert .. OR .. to UNION if the cost is lower
......@@ -304,4 +311,34 @@ public class ConditionAndOr extends Condition {
}
}
/**
* Optimize query according to the given condition. Example:
* (A AND B) OR (C AND B), the new condition B AND (A OR C) is returned
*
* @param left the session
* @param right the second condition
* @return null or the third condition
*/
private Expression optimizeConditionAndOr(ConditionAndOr left, ConditionAndOr right) {
if (left.andOrType != AND || right.andOrType != AND) {
return null;
}
Expression commonExpressionLeft = left.getSubexpression(0);
Expression commonExpressionRight = left.getSubexpression(1);
Expression combinedExpression;
if (left.getSubexpression(0).getSQL().equals(right.getSubexpression(0).getSQL())) {
combinedExpression = new ConditionAndOr(OR, left.getSubexpression(1), right.getSubexpression(1));
return new ConditionAndOr(AND, commonExpressionLeft, combinedExpression);
} else if (left.getSubexpression(0).getSQL().equals(right.getSubexpression(1).getSQL())) {
combinedExpression = new ConditionAndOr(OR, left.getSubexpression(1), right.getSubexpression(0));
return new ConditionAndOr(AND, commonExpressionLeft, combinedExpression);
} else if (left.getSubexpression(1).getSQL().equals(right.getSubexpression(0).getSQL())) {
combinedExpression = new ConditionAndOr(OR, left.getSubexpression(0), right.getSubexpression(1));
return new ConditionAndOr(AND, commonExpressionRight, combinedExpression);
} else if (left.getSubexpression(1).getSQL().equals(right.getSubexpression(1).getSQL())) {
combinedExpression = new ConditionAndOr(OR, left.getSubexpression(0), right.getSubexpression(0));
return new ConditionAndOr(AND, commonExpressionRight, combinedExpression);
}
return null;
}
}
......@@ -84,6 +84,7 @@ public class TestOptimizations extends TestDb {
testOrderedIndexes();
testIndexUseDespiteNullsFirst();
testConvertOrToIn();
testConditionAndOrDistributiveLaw();
deleteDb("optimizations");
}
......@@ -1177,4 +1178,30 @@ public class TestOptimizations extends TestDb {
assertContains(rs.getString(1), "/* PUBLIC.TABLE_B_IDX");
conn.close();
}
private void testConditionAndOrDistributiveLaw() throws SQLException {
deleteDb("optimizations");
Connection conn = getConnection("optimizations");
Statement stat = conn.createStatement();
stat.execute("CREATE TABLE IF NOT EXISTS TABLE_A (" +
"id int(10) NOT NULL AUTO_INCREMENT, " +
"name VARCHAR(30) NOT NULL," +
"occupation VARCHAR(20)," +
"age int(10)," +
"salary int(10)," +
"PRIMARY KEY(id))");
stat.execute("INSERT INTO TABLE_A (name,occupation,age,salary) VALUES" +
"('mark', 'doctor',25,5000)," +
"('kevin', 'artist',20,4000)," +
"('isuru', 'engineer',25,5000)," +
"('josaph', 'businessman',30,7000)," +
"('sajeewa', 'analyst',24,5000)," +
"('randil', 'engineer',25,5000)," +
"('ashan', 'developer',24,5000)");
ResultSet rs = stat.executeQuery("SELECT * FROM TABLE_A WHERE (salary = 5000 AND name = 'isuru') OR" +
"(age = 25 AND name = 'isuru') ");
rs.next();
assertTrue("engineer".equals(rs.getString("occupation")));
conn.close();
}
}
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论