github.com/matrixorigin/matrixone@v1.2.0/pkg/sql/plan/associative_law.go (about) 1 // Copyright 2022 Matrix Origin 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package plan 16 17 import "github.com/matrixorigin/matrixone/pkg/pb/plan" 18 19 // for A*(B*C), if C.sel>0.9 and B<C, change this to (A*B)*C 20 func (builder *QueryBuilder) applyAssociativeLawRule1(nodeID int32) int32 { 21 node := builder.qry.Nodes[nodeID] 22 if len(node.Children) > 0 { 23 for i, child := range node.Children { 24 node.Children[i] = builder.applyAssociativeLawRule1(child) 25 } 26 } 27 if node.NodeType != plan.Node_JOIN || node.JoinType != plan.Node_INNER { 28 return nodeID 29 } 30 rightChild := builder.qry.Nodes[node.Children[1]] 31 if rightChild.NodeType != plan.Node_JOIN || rightChild.JoinType != plan.Node_INNER { 32 return nodeID 33 } 34 NodeB := builder.qry.Nodes[rightChild.Children[0]] 35 NodeC := builder.qry.Nodes[rightChild.Children[1]] 36 if NodeC.Stats.Selectivity < 0.9 || NodeB.Stats.Outcnt >= NodeC.Stats.Outcnt { 37 return nodeID 38 } 39 node.Children[1] = NodeB.NodeId 40 determineHashOnPK(node.NodeId, builder) 41 if !node.Stats.HashmapStats.HashOnPK { 42 // a join b must be hash on primary key, or we can not do this change 43 node.Children[1] = rightChild.NodeId 44 return node.NodeId 45 } 46 rightChild.Children[0] = node.NodeId 47 ReCalcNodeStats(rightChild.NodeId, builder, true, false, true) 48 return rightChild.NodeId 49 } 50 51 // for (A*B)*C, if C.sel<0.5, change this to A*(B*C) 52 func (builder *QueryBuilder) applyAssociativeLawRule2(nodeID int32) int32 { 53 node := builder.qry.Nodes[nodeID] 54 if len(node.Children) > 0 { 55 for i, child := range node.Children { 56 node.Children[i] = builder.applyAssociativeLawRule2(child) 57 } 58 } 59 if node.NodeType != plan.Node_JOIN || node.JoinType != plan.Node_INNER { 60 return nodeID 61 } 62 leftChild := builder.qry.Nodes[node.Children[0]] 63 if leftChild.NodeType != plan.Node_JOIN || leftChild.JoinType != plan.Node_INNER { 64 return nodeID 65 } 66 NodeC := builder.qry.Nodes[node.Children[1]] 67 if NodeC.Stats.Selectivity > 0.5 { 68 return nodeID 69 } 70 NodeB := builder.qry.Nodes[leftChild.Children[1]] 71 node.Children[0] = NodeB.NodeId 72 determineHashOnPK(node.NodeId, builder) 73 if !node.Stats.HashmapStats.HashOnPK { 74 // b join c must be hash on primary key, or we can not do this change 75 node.Children[0] = leftChild.NodeId 76 return node.NodeId 77 } 78 leftChild.Children[1] = node.NodeId 79 ReCalcNodeStats(leftChild.NodeId, builder, true, false, true) 80 return leftChild.NodeId 81 } 82 83 // for (A*B)*C, if A.outcnt>C.outcnt and C.sel<B.sel, change this to (A*C)*B 84 func (builder *QueryBuilder) applyAssociativeLawRule3(nodeID int32) int32 { 85 node := builder.qry.Nodes[nodeID] 86 if len(node.Children) > 0 { 87 for i, child := range node.Children { 88 node.Children[i] = builder.applyAssociativeLawRule3(child) 89 } 90 } 91 if node.NodeType != plan.Node_JOIN || node.JoinType != plan.Node_INNER { 92 return nodeID 93 } 94 leftChild := builder.qry.Nodes[node.Children[0]] 95 if leftChild.NodeType != plan.Node_JOIN || leftChild.JoinType != plan.Node_INNER { 96 return nodeID 97 } 98 NodeA := builder.qry.Nodes[leftChild.Children[0]] 99 NodeB := builder.qry.Nodes[leftChild.Children[1]] 100 NodeC := builder.qry.Nodes[node.Children[1]] 101 if NodeA.Stats.Outcnt < NodeC.Stats.Outcnt || NodeC.Stats.Selectivity >= NodeB.Stats.Selectivity { 102 return nodeID 103 } 104 105 node.Children[0] = NodeA.NodeId 106 newSel := NodeC.Stats.Selectivity / getHashColsNDVRatio(node.NodeId, builder) 107 if newSel >= NodeB.Stats.Selectivity { 108 //new selectivity bigger than b.sel, can't do this change 109 node.Children[0] = leftChild.NodeId 110 return node.NodeId 111 } 112 leftChild.Children[0] = node.NodeId 113 ReCalcNodeStats(leftChild.NodeId, builder, true, false, true) 114 return leftChild.NodeId 115 } 116 117 func (builder *QueryBuilder) applyAssociativeLaw(nodeID int32) int32 { 118 if builder.optimizerHints != nil && builder.optimizerHints.joinOrdering != 0 { 119 return nodeID 120 } 121 nodeID = builder.applyAssociativeLawRule1(nodeID) 122 builder.determineBuildAndProbeSide(nodeID, true) 123 nodeID = builder.applyAssociativeLawRule2(nodeID) 124 builder.determineBuildAndProbeSide(nodeID, true) 125 nodeID = builder.applyAssociativeLawRule3(nodeID) 126 builder.determineBuildAndProbeSide(nodeID, true) 127 return nodeID 128 }