public bool Equals(JoinCondition joinCondition) { if (ReferenceEquals(this, joinCondition)) return true; if (joinCondition.Op != _op) return false; if (joinCondition.LeftTable == _leftTable && joinCondition.RightTable == _rightTable) { if (!joinCondition.LeftExpression.IsStructuralEqualTo(_leftExpression)) return false; if (!joinCondition.RightExpression.IsStructuralEqualTo(_rightExpression)) return false; return true; } else if (joinCondition.LeftTable == _rightTable && joinCondition.RightTable == _leftTable) { if (!joinCondition.LeftExpression.IsStructuralEqualTo(_rightExpression)) return false; if (!joinCondition.RightExpression.IsStructuralEqualTo(_leftExpression)) return false; return true; } return false; }
public JoinCondition Clone() { JoinCondition joinCondition = new JoinCondition(); joinCondition.Op = _op; joinCondition.LeftExpression = _leftExpression; joinCondition.LeftTable = _leftTable; joinCondition.RightExpression = _rightExpression; joinCondition.RightTable = _rightTable; return joinCondition; }
private static JoinOrder GetBestJoinOrder(TableRefBinding[] tables, JoinCondition[] joinConditions, ICollection<ExpressionNode> andParts) { // Compute all join orders JoinOrderGenerator generator = new JoinOrderGenerator(joinConditions, tables); JoinOrder[] allJoinOrders = generator.GenerateAll(); // Compute best join order JoinOrder bestJoinOrder = GetBestJoinOrder(allJoinOrders, andParts, tables); return bestJoinOrder; }
public bool Equals(JoinCondition joinCondition) { if (ReferenceEquals(this, joinCondition)) { return(true); } if (joinCondition.Op != _op) { return(false); } if (joinCondition.LeftTable == _leftTable && joinCondition.RightTable == _rightTable) { if (!joinCondition.LeftExpression.IsStructuralEqualTo(_leftExpression)) { return(false); } if (!joinCondition.RightExpression.IsStructuralEqualTo(_rightExpression)) { return(false); } return(true); } else if (joinCondition.LeftTable == _rightTable && joinCondition.RightTable == _leftTable) { if (!joinCondition.LeftExpression.IsStructuralEqualTo(_rightExpression)) { return(false); } if (!joinCondition.RightExpression.IsStructuralEqualTo(_leftExpression)) { return(false); } return(true); } return(false); }
private static JoinCondition ConvertToJoinCondition(IDictionary <RowBufferEntry, ColumnRefBinding> rowBufferColumnDictionary, ExpressionNode expression) { BinaryExpression binaryExpression = expression as BinaryExpression; if (binaryExpression == null) { return(null); } JoinOperator joinOperator = JoinOperatorFromBinaryOperator(binaryExpression.Op); if (joinOperator == JoinOperator.None) { return(null); } TableRefBinding[] leftTableReferences = GetTableReferences(rowBufferColumnDictionary, binaryExpression.Left); TableRefBinding[] rightTableReferences = GetTableReferences(rowBufferColumnDictionary, binaryExpression.Right); if (leftTableReferences.Length == 1 && rightTableReferences.Length == 1) { if (leftTableReferences[0] != rightTableReferences[0]) { // Both expressions depend on extactly one table reference but they are not refering to the same table. // // That means we found a join condition. JoinCondition joinCondition = new JoinCondition(); joinCondition.Op = joinOperator; joinCondition.LeftExpression = binaryExpression.Left; joinCondition.LeftTable = leftTableReferences[0]; joinCondition.RightExpression = binaryExpression.Right; joinCondition.RightTable = rightTableReferences[0]; return(joinCondition); } } return(null); }
public override AlgebraNode VisitJoinAlgebraNode(JoinAlgebraNode node) { // Check if node only consists of INNER join nodes and simple table reference nodes. // This algorithm assumes that the table references have been lineraized so that // // - JoinedTableReference appear on the LHS only (the last one must be NamedTableReference ovbiviously) // - NamedTableReference appear on the RHS only // // While scanning the node's children we create a list of all JoinedTableReferences and // NamedTableReferences. InnerJoinTableExtractor innerJoinTableExtractor = new InnerJoinTableExtractor(); innerJoinTableExtractor.Visit(node); if (!innerJoinTableExtractor.ConsistsOnlyOfInnerJoinsFiltersAndTables) { node.Left = VisitAlgebraNode(node.Left); node.Right = VisitAlgebraNode(node.Right); return(node); } else { TableAlgebraNode[] algebraNodes = innerJoinTableExtractor.GetTableNodes(); Dictionary <TableRefBinding, TableAlgebraNode> tableRefToNodeDictionary = new Dictionary <TableRefBinding, TableAlgebraNode>(); List <TableRefBinding> tableList = new List <TableRefBinding>(); foreach (TableAlgebraNode algebraNode in algebraNodes) { tableRefToNodeDictionary.Add(algebraNode.TableRefBinding, algebraNode); tableList.Add(algebraNode.TableRefBinding); } // Create a mapping RowBufferEntry -> ColumnRefBinding Dictionary <RowBufferEntry, ColumnRefBinding> rowBufferColumnDictionary = new Dictionary <RowBufferEntry, ColumnRefBinding>(); foreach (TableRefBinding tableRefBinding in tableList) { foreach (ColumnRefBinding columnRefBinding in tableRefBinding.ColumnRefs) { rowBufferColumnDictionary.Add(columnRefBinding.ValueDefinition.Target, columnRefBinding); } } // Create list of all possible join conditions and remaining AND-parts. List <JoinCondition> joinConditionList = new List <JoinCondition>(); List <ExpressionNode> andPartList = new List <ExpressionNode>(); ExpressionNode filter = AstUtil.CombineConditions(LogicalOperator.And, innerJoinTableExtractor.GetFilters()); foreach (ExpressionNode andPart in AstUtil.SplitCondition(LogicalOperator.And, filter)) { JoinCondition joinCondition = ConvertToJoinCondition(rowBufferColumnDictionary, andPart); if (joinCondition != null) { joinConditionList.Add(joinCondition); } else { andPartList.Add(andPart); } } // After creating the list of all join conditions and AND-parts we have all we need to create // an optimimal join order between all tables of this part of the table tree. JoinOrder bestJoinOrder = GetBestJoinOrder(tableList.ToArray(), joinConditionList.ToArray(), andPartList.ToArray()); // Get all tables that are introduced by this join order Dictionary <RowBufferEntry, ColumnValueDefinition> introducedColumns = GetIntroducedColumns(bestJoinOrder); // Combine AND-part list with all unused join conditions. andPartList.AddRange(bestJoinOrder.UnusedConditions); // Now we will re-create this part of the tree using the this join order. AlgebraNode lastAlgebraNode = null; for (int joinIndex = 0; joinIndex < bestJoinOrder.Joins.Length; joinIndex++) { Join join = bestJoinOrder.Joins[joinIndex]; AlgebraNode tableInput; TableAlgebraNode tableNode = tableRefToNodeDictionary[join.TableRefBinding]; ExpressionNode tableFilter = ExtractConditionsApplicableToTable(introducedColumns, andPartList, join.TableRefBinding); if (tableFilter == null) { tableInput = tableNode; } else { FilterAlgebraNode filterAlgebraNode = new FilterAlgebraNode(); filterAlgebraNode.Input = tableNode; filterAlgebraNode.Predicate = tableFilter; tableInput = filterAlgebraNode; } if (lastAlgebraNode == null) { // This was the first one. lastAlgebraNode = tableInput; } else { // Not the first one, we can create a join with the current table reference // and last table reference. // Get all AND-parts that can be applied to the tables already joined. // This expression is merged to one condition. ExpressionNode[] applicableAndParts = GetAndPartsApplicableToJoin(introducedColumns, bestJoinOrder, joinIndex, andPartList, true); ExpressionNode condition = AstUtil.CombineConditions(LogicalOperator.And, applicableAndParts); ExpressionNode joinCondition; if (join.JoinCondition == null) { joinCondition = null; } else { joinCondition = join.JoinCondition.ToExpression(); } ExpressionNode completeCondition = AstUtil.CombineConditions(LogicalOperator.And, condition, joinCondition); JoinAlgebraNode joinAlgebraNode = new JoinAlgebraNode(); joinAlgebraNode.Op = JoinAlgebraNode.JoinOperator.InnerJoin; joinAlgebraNode.Left = lastAlgebraNode; joinAlgebraNode.Right = tableInput; joinAlgebraNode.Predicate = completeCondition; // Next time this newly created join is the last table reference. lastAlgebraNode = joinAlgebraNode; } } return(lastAlgebraNode); } }
private void Join(TableRefBinding table, JoinCondition joinCondition) { _usedTableList.Add(table); _usedJoinConditionList.Add(joinCondition); if (_usedTableList.Count == _tables.Length) { // We have joined all tables, create the join order. // // First we create a list of the join conditions we used. List<Join> joinList = new List<Join>(); for (int i = 0; i < _usedTableList.Count; i++) { TableRefBinding usedTable = _usedTableList[i]; JoinCondition usedJoinCondition = _usedJoinConditionList[i]; // The first entry will be null, since we do not join from anywhere if (usedJoinCondition != null) { // Since we swapping the join sides according to the direction // we are joining from we need to create a clone. The clone // is a flat copy meaning that the tables and expressions // themselves are not cloned. usedJoinCondition = usedJoinCondition.Clone(); // If the right table is not the table we are joining to // swap the join sides. if (usedJoinCondition.RightTable != usedTable) usedJoinCondition.SwapSides(); } Join join = new Join(); join.JoinCondition = usedJoinCondition; join.TableRefBinding = usedTable; joinList.Add(join); } // Secondly and very important: We also have to create a list of all // join conditions NOT used. Later theses conditions will be combined // with the and-parts since they must also be checked. List<ExpressionNode> unusedConditionList = new List<ExpressionNode>(); foreach (JoinCondition jc in _joinConditions) { if (!_usedJoinConditionList.Contains(jc)) unusedConditionList.Add(jc.ToExpression()); } JoinOrder joinOrder = new JoinOrder(); joinOrder.Joins = joinList.ToArray(); joinOrder.UnusedConditions = unusedConditionList.ToArray(); _joinOrderList.Add(joinOrder); } else { // We are not yet finished with all tables. Find next table // to join with. bool hasJoin = false; foreach (JoinCondition nextJoin in _joinConditions) { if (!_usedJoinConditionList.Contains(nextJoin)) { TableRefBinding nextTable; if (_usedTableList.Contains(nextJoin.LeftTable)) { nextTable = nextJoin.RightTable; } else if (_usedTableList.Contains(nextJoin.RightTable)) { nextTable = nextJoin.LeftTable; } else { continue; } if (_usedTableList.Contains(nextTable)) continue; Join(nextTable, nextJoin); hasJoin = true; } } if (!hasJoin) { foreach (TableRefBinding t in _tables) { if (!_usedTableList.Contains(t)) Join(t, null); } } } _usedJoinConditionList.RemoveAt(_usedJoinConditionList.Count - 1); _usedTableList.RemoveAt(_usedTableList.Count - 1); }
public JoinOrderGenerator(JoinCondition[] joinConditions, TableRefBinding[] tables) { _joinConditions = joinConditions; _tables = tables; }
private void Join(TableRefBinding table, JoinCondition joinCondition) { _usedTableList.Add(table); _usedJoinConditionList.Add(joinCondition); if (_usedTableList.Count == _tables.Length) { // We have joined all tables, create the join order. // // First we create a list of the join conditions we used. List <Join> joinList = new List <Join>(); for (int i = 0; i < _usedTableList.Count; i++) { TableRefBinding usedTable = _usedTableList[i]; JoinCondition usedJoinCondition = _usedJoinConditionList[i]; // The first entry will be null, since we do not join from anywhere if (usedJoinCondition != null) { // Since we swapping the join sides according to the direction // we are joining from we need to create a clone. The clone // is a flat copy meaning that the tables and expressions // themselves are not cloned. usedJoinCondition = usedJoinCondition.Clone(); // If the right table is not the table we are joining to // swap the join sides. if (usedJoinCondition.RightTable != usedTable) { usedJoinCondition.SwapSides(); } } Join join = new Join(); join.JoinCondition = usedJoinCondition; join.TableRefBinding = usedTable; joinList.Add(join); } // Secondly and very important: We also have to create a list of all // join conditions NOT used. Later theses conditions will be combined // with the and-parts since they must also be checked. List <ExpressionNode> unusedConditionList = new List <ExpressionNode>(); foreach (JoinCondition jc in _joinConditions) { if (!_usedJoinConditionList.Contains(jc)) { unusedConditionList.Add(jc.ToExpression()); } } JoinOrder joinOrder = new JoinOrder(); joinOrder.Joins = joinList.ToArray(); joinOrder.UnusedConditions = unusedConditionList.ToArray(); _joinOrderList.Add(joinOrder); } else { // We are not yet finished with all tables. Find next table // to join with. bool hasJoin = false; foreach (JoinCondition nextJoin in _joinConditions) { if (!_usedJoinConditionList.Contains(nextJoin)) { TableRefBinding nextTable; if (_usedTableList.Contains(nextJoin.LeftTable)) { nextTable = nextJoin.RightTable; } else if (_usedTableList.Contains(nextJoin.RightTable)) { nextTable = nextJoin.LeftTable; } else { continue; } if (_usedTableList.Contains(nextTable)) { continue; } Join(nextTable, nextJoin); hasJoin = true; } } if (!hasJoin) { foreach (TableRefBinding t in _tables) { if (!_usedTableList.Contains(t)) { Join(t, null); } } } } _usedJoinConditionList.RemoveAt(_usedJoinConditionList.Count - 1); _usedTableList.RemoveAt(_usedTableList.Count - 1); }
private static JoinCondition ConvertToJoinCondition(IDictionary<RowBufferEntry, ColumnRefBinding> rowBufferColumnDictionary, ExpressionNode expression) { BinaryExpression binaryExpression = expression as BinaryExpression; if (binaryExpression == null) return null; JoinOperator joinOperator = JoinOperatorFromBinaryOperator(binaryExpression.Op); if (joinOperator == JoinOperator.None) return null; TableRefBinding[] leftTableReferences = GetTableReferences(rowBufferColumnDictionary, binaryExpression.Left); TableRefBinding[] rightTableReferences = GetTableReferences(rowBufferColumnDictionary, binaryExpression.Right); if (leftTableReferences.Length == 1 && rightTableReferences.Length == 1) { if (leftTableReferences[0] != rightTableReferences[0]) { // Both expressions depend on extactly one table reference but they are not refering to the same table. // // That means we found a join condition. JoinCondition joinCondition = new JoinCondition(); joinCondition.Op = joinOperator; joinCondition.LeftExpression = binaryExpression.Left; joinCondition.LeftTable = leftTableReferences[0]; joinCondition.RightExpression = binaryExpression.Right; joinCondition.RightTable = rightTableReferences[0]; return joinCondition; } } return null; }