package com.taobao.tddl.optimizer.costbased; import org.junit.Assert; import org.junit.Test; import com.taobao.tddl.optimizer.BaseOptimizerTest; import com.taobao.tddl.optimizer.core.ASTNodeFactory; import com.taobao.tddl.optimizer.core.ast.query.JoinNode; import com.taobao.tddl.optimizer.core.ast.query.MergeNode; import com.taobao.tddl.optimizer.core.ast.query.QueryNode; import com.taobao.tddl.optimizer.core.ast.query.TableNode; import com.taobao.tddl.optimizer.core.expression.IColumn; import com.taobao.tddl.optimizer.core.plan.query.IJoin.JoinStrategy; import com.taobao.tddl.optimizer.costbased.pusher.OrderByPusher; public class OrderByPusherTest extends BaseOptimizerTest { @Test public void test_order条件下推_子表_case1_下推NAME() { TableNode table1 = new TableNode("TABLE1"); table1.alias("A"); table1.orderBy("ID"); QueryNode query = new QueryNode(table1); query.orderBy("A.ID"); query.orderBy("A.NAME"); query.build(); OrderByPusher.optimize(query); Assert.assertEquals(2, table1.getOrderBys().size()); Assert.assertEquals("TABLE1.ID", table1.getOrderBys().get(0).getColumn().toString()); Assert.assertEquals("TABLE1.NAME", table1.getOrderBys().get(1).getColumn().toString()); } @Test public void test_order条件下推_子表_case2_强制下推() { TableNode table1 = new TableNode("TABLE1"); table1.alias("A"); table1.orderBy("ID"); table1.orderBy("NAME"); QueryNode query = new QueryNode(table1); query.orderBy("A.NAME"); query.orderBy("A.SCHOOL"); query.build(); OrderByPusher.optimize(query); Assert.assertEquals(2, table1.getOrderBys().size()); Assert.assertEquals("TABLE1.NAME", table1.getOrderBys().get(0).getColumn().toString()); Assert.assertEquals("TABLE1.SCHOOL", table1.getOrderBys().get(1).getColumn().toString()); } @Test public void test_order条件下推_子表_case3_不下推() { TableNode table1 = new TableNode("TABLE1"); table1.alias("A"); table1.orderBy("ID"); table1.orderBy("NAME"); table1.limit(0, 10); QueryNode query = new QueryNode(table1); query.orderBy("A.NAME"); query.orderBy("A.SCHOOL"); query.build(); OrderByPusher.optimize(query); Assert.assertEquals(2, table1.getOrderBys().size()); Assert.assertEquals("TABLE1.ID", table1.getOrderBys().get(0).getColumn().toString()); Assert.assertEquals("TABLE1.NAME", table1.getOrderBys().get(1).getColumn().toString()); } @Test public void test_order条件下推_子表_case4_下推IDNAME() { TableNode table1 = new TableNode("TABLE1"); table1.alias("A"); QueryNode query = new QueryNode(table1); query.orderBy("A.ID"); query.orderBy("A.NAME"); query.build(); OrderByPusher.optimize(query); Assert.assertEquals(2, query.getOrderBys().size()); Assert.assertEquals("TABLE1.ID", table1.getOrderBys().get(0).getColumn().toString()); Assert.assertEquals("TABLE1.NAME", table1.getOrderBys().get(1).getColumn().toString()); } @Test public void test_order条件下推_子表_case5_不下推函数() { TableNode table1 = new TableNode("TABLE1"); table1.alias("A"); QueryNode query = new QueryNode(table1); query.select("ID AS CID, (NAME+SCHOOL) AS NAME"); query.orderBy("A.CID "); query.orderBy("A.NAME"); // 这里的name为select中的函数 query.build(); OrderByPusher.optimize(query); Assert.assertEquals(0, table1.getOrderBys().size()); } @Test public void test_join条件下推_子表_case1_下推NAME() { TableNode table1 = new TableNode("TABLE1"); TableNode table2 = new TableNode("TABLE2"); table1.alias("A"); table1.orderBy("ID"); table2.alias("B"); JoinNode join = table1.join(table2); join.setJoinStrategy(JoinStrategy.INDEX_NEST_LOOP); join.orderBy("A.ID"); join.orderBy("A.NAME"); join.build(); OrderByPusher.optimize(join); Assert.assertEquals(2, table1.getOrderBys().size()); Assert.assertEquals("TABLE1.ID", table1.getOrderBys().get(0).getColumn().toString()); Assert.assertEquals("TABLE1.NAME", table1.getOrderBys().get(1).getColumn().toString()); } @Test public void test_join条件下推_子表_case2_强制下推() { TableNode table1 = new TableNode("TABLE1"); TableNode table2 = new TableNode("TABLE2"); table1.alias("A"); table1.orderBy("ID"); table1.orderBy("NAME"); table2.alias("B"); JoinNode join = table1.join(table2); join.setJoinStrategy(JoinStrategy.INDEX_NEST_LOOP); join.orderBy("A.NAME"); join.orderBy("A.SCHOOL"); join.build(); OrderByPusher.optimize(join); Assert.assertEquals(2, table1.getOrderBys().size()); Assert.assertEquals("TABLE1.NAME", table1.getOrderBys().get(0).getColumn().toString()); Assert.assertEquals("TABLE1.SCHOOL", table1.getOrderBys().get(1).getColumn().toString()); } @Test public void test_join条件下推_子表_case3_不下推() { TableNode table1 = new TableNode("TABLE1"); TableNode table2 = new TableNode("TABLE2"); table1.alias("A"); QueryNode query = new QueryNode(table1); query.orderBy("ID"); query.orderBy("NAME"); query.limit(0, 10); table2.alias("B"); JoinNode join = query.join(table2); join.setJoinStrategy(JoinStrategy.INDEX_NEST_LOOP); join.orderBy("A.NAME"); join.orderBy("A.SCHOOL"); join.build(); OrderByPusher.optimize(join); Assert.assertEquals(2, query.getOrderBys().size()); Assert.assertEquals("A.ID", query.getOrderBys().get(0).getColumn().toString()); Assert.assertEquals("A.NAME", query.getOrderBys().get(1).getColumn().toString()); } @Test public void test_join条件下推_子表_case4_下推IDNAME() { TableNode table1 = new TableNode("TABLE1"); TableNode table2 = new TableNode("TABLE2"); table1.alias("A"); table2.alias("B"); JoinNode join = table1.join(table2); join.setJoinStrategy(JoinStrategy.INDEX_NEST_LOOP); join.orderBy("A.ID"); join.orderBy("A.NAME"); join.build(); OrderByPusher.optimize(join); Assert.assertEquals(2, table1.getOrderBys().size()); Assert.assertEquals("TABLE1.ID", table1.getOrderBys().get(0).getColumn().toString()); Assert.assertEquals("TABLE1.NAME", table1.getOrderBys().get(1).getColumn().toString()); } @Test public void test_join条件下推_子表_case5_函数不下推() { TableNode table1 = new TableNode("TABLE1"); TableNode table2 = new TableNode("TABLE2"); table1.alias("A"); table2.alias("B"); JoinNode join = table1.join(table2); join.setJoinStrategy(JoinStrategy.INDEX_NEST_LOOP); join.select("A.ID AS CID, (A.NAME + A.SCHOOL) AS NAME"); join.orderBy("CID "); join.orderBy("NAME"); // 这里的name为select中的函数 join.build(); OrderByPusher.optimize(join); Assert.assertEquals(0, table1.getOrderBys().size()); } @Test public void test_orderby多级结构下推() { TableNode table1 = new TableNode("TABLE1"); TableNode table2 = new TableNode("TABLE2"); JoinNode join = table1.join(table2); join.setJoinStrategy(JoinStrategy.INDEX_NEST_LOOP); join.alias("S").select("TABLE1.ID AS ID , TABLE1.NAME AS NAME , TABLE2.SCHOOL AS SCHOOL"); join.build(); QueryNode queryA = new QueryNode(join); queryA.alias("B"); queryA.select("S.ID AS ID,S.NAME AS NAME"); queryA.build(); QueryNode queryB = queryA.deepCopy(); queryB.alias("C"); queryB.select("S.SCHOOL AS SCHOOL"); queryB.build(); JoinNode nextJoin = queryA.join(queryB); nextJoin.setJoinStrategy(JoinStrategy.INDEX_NEST_LOOP); nextJoin.orderBy("B.ID ASC"); nextJoin.orderBy("B.NAME DESC"); nextJoin.build(); OrderByPusher.optimize(nextJoin); // 最左节点会有两个order by push, ID和NAME Assert.assertEquals(2, table1.getOrderBys().size()); } @Test public void test_orderby_SortMerge下推() { TableNode table1 = new TableNode("TABLE1"); TableNode table2 = new TableNode("TABLE2"); JoinNode join = table1.join(table2).addJoinKeys("ID", "ID").addJoinKeys("NAME", "NAME"); join.setOuterJoin().setJoinStrategy(JoinStrategy.SORT_MERGE_JOIN); join.select("TABLE1.ID AS ID , TABLE1.NAME AS NAME , TABLE1.SCHOOL AS SCHOOL"); join.groupBy("NAME").groupBy("SCHOOL").groupBy("ID"); // group by顺序可调整 join.orderBy("ID", false); join.build(); OrderByPusher.optimize(join); // 推出来的结果: // 1. 按照join列先推,ID , NAME的排序 // 2. 按照order by + group by的推成功,最后排序结果为ID,NAME,SCHOOL Assert.assertEquals("TABLE1.ID", join.getLeftNode().getOrderBys().get(0).getColumn().toString()); Assert.assertEquals(false, join.getLeftNode().getOrderBys().get(0).getDirection()); // 逆序 Assert.assertEquals("TABLE1.NAME", join.getLeftNode().getOrderBys().get(1).getColumn().toString()); Assert.assertEquals("TABLE1.SCHOOL", join.getLeftNode().getOrderBys().get(2).getColumn().toString()); Assert.assertEquals("TABLE2.ID", join.getRightNode().getOrderBys().get(0).getColumn().toString()); Assert.assertEquals(false, join.getRightNode().getOrderBys().get(0).getDirection()); // 逆序 Assert.assertEquals("TABLE2.NAME", join.getRightNode().getOrderBys().get(1).getColumn().toString()); Assert.assertEquals("TABLE1.ID as ID", join.getGroupBys().get(0).getColumn().toString()); Assert.assertEquals("TABLE1.NAME as NAME", join.getGroupBys().get(1).getColumn().toString()); Assert.assertEquals("TABLE1.SCHOOL as SCHOOL", join.getGroupBys().get(2).getColumn().toString()); Assert.assertEquals("TABLE1.ID as ID", join.getOrderBys().get(0).getColumn().toString()); Assert.assertEquals(false, join.getOrderBys().get(0).getDirection()); // 逆序 } @Test public void test_orderby_SortMerge下推_只推group() { TableNode table1 = new TableNode("TABLE1"); TableNode table2 = new TableNode("TABLE2"); JoinNode join = table1.join(table2).addJoinKeys("ID", "ID").addJoinKeys("NAME", "NAME"); join.setOuterJoin().setJoinStrategy(JoinStrategy.SORT_MERGE_JOIN); join.select("TABLE1.ID AS ID , TABLE1.NAME AS NAME , TABLE1.SCHOOL AS SCHOOL"); join.groupBy("NAME").groupBy("SCHOOL").groupBy("ID"); // group by顺序可调整 join.orderBy("SCHOOL", false); join.build(); OrderByPusher.optimize(join); // 推出来的结果: // 1. 按照join列先推,ID , NAME的排序 // 2. 按照order by + group by的会推不成功,因为是按照school字段顺序 // 3. 按照group by单独推会成功 Assert.assertEquals("TABLE1.ID", join.getLeftNode().getOrderBys().get(0).getColumn().toString()); Assert.assertEquals("TABLE1.NAME", join.getLeftNode().getOrderBys().get(1).getColumn().toString()); Assert.assertEquals("TABLE1.SCHOOL", join.getLeftNode().getOrderBys().get(2).getColumn().toString()); Assert.assertEquals(false, join.getLeftNode().getOrderBys().get(2).getDirection()); // 逆序 Assert.assertEquals("TABLE2.ID", join.getRightNode().getOrderBys().get(0).getColumn().toString()); Assert.assertEquals("TABLE2.NAME", join.getRightNode().getOrderBys().get(1).getColumn().toString()); Assert.assertEquals("TABLE1.ID as ID", join.getGroupBys().get(0).getColumn().toString()); Assert.assertEquals("TABLE1.NAME as NAME", join.getGroupBys().get(1).getColumn().toString()); Assert.assertEquals("TABLE1.SCHOOL as SCHOOL", join.getGroupBys().get(2).getColumn().toString()); Assert.assertEquals("TABLE1.SCHOOL as SCHOOL", join.getOrderBys().get(0).getColumn().toString()); Assert.assertEquals(false, join.getOrderBys().get(0).getDirection()); // 逆序 } @Test public void test_orderby_SortMerge下推_调整join顺序() { TableNode table1 = new TableNode("TABLE1"); TableNode table2 = new TableNode("TABLE2"); JoinNode join = table1.join(table2).addJoinKeys("ID", "ID").addJoinKeys("NAME", "NAME"); join.setOuterJoin().setJoinStrategy(JoinStrategy.SORT_MERGE_JOIN); join.select("TABLE1.ID AS ID , TABLE1.NAME AS NAME , TABLE1.SCHOOL AS SCHOOL"); join.groupBy("NAME").groupBy("SCHOOL"); // group by顺序可调整 join.orderBy("NAME", false); join.build(); OrderByPusher.optimize(join); // 推出来的结果: // 1. 按照join列先推,ID , NAME的排序 // 2. 按照order by + group by的会推不成功,因为是按照NAME+SCHOOL字段顺序 Assert.assertEquals("TABLE1.NAME", join.getLeftNode().getOrderBys().get(0).getColumn().toString()); Assert.assertEquals("TABLE1.ID", join.getLeftNode().getOrderBys().get(1).getColumn().toString()); Assert.assertEquals(false, join.getLeftNode().getOrderBys().get(0).getDirection()); // 逆序 Assert.assertEquals("TABLE2.NAME", join.getRightNode().getOrderBys().get(0).getColumn().toString()); Assert.assertEquals("TABLE2.ID", join.getRightNode().getOrderBys().get(1).getColumn().toString()); Assert.assertEquals(false, join.getRightNode().getOrderBys().get(0).getDirection()); // 逆序 Assert.assertEquals("TABLE1.NAME as NAME", join.getGroupBys().get(0).getColumn().toString()); Assert.assertEquals(false, join.getGroupBys().get(0).getDirection()); // 逆序 Assert.assertEquals("TABLE1.SCHOOL as SCHOOL", join.getGroupBys().get(1).getColumn().toString()); Assert.assertEquals("TABLE1.NAME as NAME", join.getOrderBys().get(0).getColumn().toString()); Assert.assertEquals(false, join.getOrderBys().get(0).getDirection()); // 逆序 } @Test public void test_orderby_SortMerge下推_多级结构下推() { TableNode table1 = new TableNode("TABLE1"); TableNode table2 = new TableNode("TABLE2"); // 如果底层join的顺序不是ID,NAME的顺序,暂时没法推,要递归做最优,算法太复杂,先简单只考虑一层 JoinNode join = table1.join(table2).addJoinKeys("ID", "ID"); join.setJoinStrategy(JoinStrategy.SORT_MERGE_JOIN); join.alias("S").select("TABLE1.ID AS AID , TABLE1.NAME AS ANAME , TABLE1.SCHOOL AS ASCHOOL"); join.build(); QueryNode queryA = new QueryNode(join); queryA.alias("B"); queryA.select("S.AID AS BID,S.ANAME AS BNAME,S.ASCHOOL AS BSCHOOL"); queryA.build(); QueryNode queryB = queryA.deepCopy(); queryB.alias("C"); queryB.select("S.AID AS CID,S.ANAME AS CNAME,S.ASCHOOL AS CSCHOOL"); queryB.build(); JoinNode nextJoin = queryA.join(queryB).addJoinKeys("BID", "CID").addJoinKeys("BNAME", "CNAME"); nextJoin.setJoinStrategy(JoinStrategy.SORT_MERGE_JOIN); nextJoin.select("C.CID AS ID , C.CNAME AS NAME , C.CSCHOOL AS SCHOOL"); // group by顺序可调整 nextJoin.groupBy("NAME").groupBy("SCHOOL").groupBy("ID"); nextJoin.orderBy("SCHOOL", false); nextJoin.build(); OrderByPusher.optimize(nextJoin); // 推导结果有点深,就不枚举了 // 左子树,ID , NAME Assert.assertEquals(2, ((TableNode) queryA.getChild().getChildren().get(0)).getOrderBys().size()); // 只是id join列 Assert.assertEquals(1, ((TableNode) queryA.getChild().getChildren().get(1)).getOrderBys().size()); // ID , NAME Assert.assertEquals(2, queryA.getOrderBys().size()); // 右子树,ID , NAME , SCHOOL Assert.assertEquals(3, ((TableNode) queryB.getChild().getChildren().get(0)).getOrderBys().size()); // 只是id join列 Assert.assertEquals(1, ((TableNode) queryB.getChild().getChildren().get(1)).getOrderBys().size()); // ID , NAME , SCHOOL Assert.assertEquals(3, queryB.getOrderBys().size()); // ID Assert.assertEquals(1, nextJoin.getOrderBys().size()); // ID , NAME , SCHOOL Assert.assertEquals(3, nextJoin.getGroupBys().size()); } @Test public void test_merge的distinct下推() { TableNode table1 = new TableNode("TABLE1"); TableNode table2 = new TableNode("TABLE2"); IColumn id = ASTNodeFactory.getInstance().createColumn(); id.setColumnName("ID"); id.setDistinct(true); IColumn name = ASTNodeFactory.getInstance().createColumn(); name.setColumnName("NAME"); name.setDistinct(true); IColumn school = ASTNodeFactory.getInstance().createColumn(); school.setColumnName("SCHOOL"); school.setDistinct(true); table1.groupBy("NAME"); table1.orderBy("ID"); MergeNode merge = table1.merge(table2); merge.select(id, name, school); merge.build(); OrderByPusher.optimize(merge); Assert.assertEquals(3, table1.getOrderBys().size()); Assert.assertEquals("TABLE1.NAME", table1.getOrderBys().get(0).getColumn().toString()); } @Test public void test_join的distinct下推() { TableNode table1 = new TableNode("TABLE1"); TableNode table2 = new TableNode("TABLE2"); IColumn id = ASTNodeFactory.getInstance().createColumn(); id.setColumnName("ID"); id.setTableName("TABLE1"); id.setDistinct(true); IColumn name = ASTNodeFactory.getInstance().createColumn(); name.setColumnName("NAME"); name.setTableName("TABLE1"); name.setDistinct(true); IColumn school = ASTNodeFactory.getInstance().createColumn(); school.setColumnName("SCHOOL"); school.setTableName("TABLE1"); school.setDistinct(true); JoinNode join = table1.join(table2); join.select(id, name, school); join.orderBy("NAME"); join.build(); OrderByPusher.optimize(join); Assert.assertEquals(3, table1.getOrderBys().size()); Assert.assertEquals("TABLE1.NAME", table1.getOrderBys().get(0).getColumn().toString()); } }