/// <summary> /// Estimates the number of rows of each node table in the graph pattern. /// </summary> /// <param name="graph">The graph pattern specified by the MATCH clause</param> private void EstimateRows(MatchGraph graph) { var declareParameter = ""; if (_variables != null) { declareParameter = _variables.Aggregate(declareParameter, (current, parameter) => current + ("DECLARE " + parameter.VariableName.Value + " " + TsqlFragmentToString.DataType(parameter.DataType) + "\r\n")); } var estimator = new TableSizeEstimator(Tx); bool first = true; // Constructs a union-all query in which each sub-query is a selection of // a node table alias plus predicates that can be associated with it. // This query is sent to the SQL DB to get the estimated cardinality of // each node table alias. var estimateQuerySb = new StringBuilder(1024); foreach (var subGraph in graph.ConnectedSubGraphs) { foreach (var node in subGraph.Nodes) { if (first) first = false; else estimateQuerySb.Append("\r\nUNION ALL\r\n"); var currentNode = node.Value; estimateQuerySb.AppendFormat("SELECT GlobalNodeId FROM {0} AS [{1}]", currentNode.NodeTableObjectName, currentNode.NodeAlias); if (currentNode.Predicates != null && currentNode.Predicates.Count > 0) { estimateQuerySb.AppendFormat("\r\nWHERE {0}", currentNode.Predicates[0]); for (int i = 1; i < currentNode.Predicates.Count; i++) { var predicate = currentNode.Predicates[i]; estimateQuerySb.AppendFormat(" AND {0}", predicate); } } } } string nodeEstimationQuery = string.Format("{0}\r\n {1}\r\n", declareParameter, estimateQuerySb); // A list of estimated cardinalities var estimateRows = estimator.GetUnionQueryTableEstimatedRows(nodeEstimationQuery); int j = 0; foreach (var subGraph in graph.ConnectedSubGraphs) { // Update Row Estimation for nodes foreach (var node in subGraph.Nodes) { var currentNode = node.Value; var tableSchema = currentNode.NodeTableObjectName.SchemaIdentifier.Value; var tableName = currentNode.NodeTableObjectName.BaseIdentifier.Value; var tableTuple = WNamedTableReference.SchemaNameToTuple(currentNode.NodeTableObjectName); if (_graphMetaData.NodeViewMapping.ContainsKey(tableTuple)) { var nodeSet = _graphMetaData.NodeViewMapping[tableTuple]; int n = nodeSet.Count; double nodeViewEstRows = 0.0; currentNode.TableRowCount = nodeSet.Aggregate(0, (cur, next) => cur + estimator.GetTableRowCount(tableSchema, next)); bool bug = false; while (n > 0) { n--; if (j > estimateRows.Count - 1) { bug = true; break; } nodeViewEstRows += estimateRows[j]; j++; } currentNode.EstimatedRows = bug ? currentNode.TableRowCount : nodeViewEstRows; } else { currentNode.TableRowCount = estimator.GetTableRowCount(tableSchema, tableName); if (j > estimateRows.Count - 1) currentNode.EstimatedRows = currentNode.TableRowCount; else currentNode.EstimatedRows = estimateRows[j]; j++; } } } }
/// <summary> /// Estimate number of rows of node table in graph. /// </summary> /// <param name="graph">Constructed node graph</param> private void EstimateRows(WSelectQueryBlock query, MatchGraph graph) { var declareParameter = ""; if (_variables != null) { foreach (var parameter in _variables) { declareParameter += "DECLARE " + parameter.VariableName.Value + " " + TsqlFragmentToString.DataType(parameter.DataType) + "\r\n"; } } var estimator = new TableSizeEstimator(Conn); bool first = true; var fromQuerySb = new StringBuilder(1024); foreach (var subGraph in graph.ConnectedSubGraphs) { foreach (var node in subGraph.Nodes) { if (first) first = false; else fromQuerySb.Append(", "); var currentNode = node.Value; fromQuerySb.AppendFormat("{0} AS [{1}] WITH (ForceScan)", currentNode.TableObjectName, currentNode.NodeAlias); } } // Attach proper parts of the where clause into the Estimiation Query var columnTableMapping = _context.GetColumnTableMapping(_columnsOfNodeTables); var attachWhereClauseVisiter = new AttachNodeEdgePredictesVisitor(); var nodeEstimationWhereClause = attachWhereClauseVisiter.Invoke(query.WhereClause, graph, columnTableMapping); string nodeEstimationQuery = string.Format("{0}\r\n SELECT * FROM {1}\r\n", declareParameter, fromQuerySb); if (nodeEstimationWhereClause.SearchCondition != null) nodeEstimationQuery += nodeEstimationWhereClause.ToString(); var estimateRows = estimator.GetQueryTableEstimatedRows(nodeEstimationQuery); foreach (var subGraph in graph.ConnectedSubGraphs) { // Update Row Estimation for nodes foreach (var node in subGraph.Nodes) { var currentNode = node.Value; currentNode.EstimatedRows = estimateRows[node.Key]; var tableSchema = currentNode.TableObjectName.SchemaIdentifier.Value; var tableName = currentNode.TableObjectName.BaseIdentifier.Value; currentNode.TableRowCount = estimator.GetTableRowCount(tableSchema, tableName); } } // Attach predicates to nodes and edges var attachPredicateVisitor = new AttachWhereClauseVisitor(); attachPredicateVisitor.Invoke(query.WhereClause, graph, columnTableMapping); }