/** * Estimate the cardinality of a join. The cardinality of a join is the number of tuples produced * by the join. * * @param j A LogicalJoinNode representing the join operation being performed. * @param card1 Cardinality of the left-hand table in the join * @param card2 Cardinality of the right-hand table in the join * @param t1pkey Is the left-hand table a primary-key table? * @param t2pkey Is the right-hand table a primary-key table? * @param stats The table stats, referenced by table names, not alias * @return The cardinality of the join */ public int estimateJoinCardinality( LogicalJoinNode j, int card1, int card2, boolean t1pkey, boolean t2pkey, Map<String, TableStats> stats) { if (j instanceof LogicalSubplanJoinNode) { // A LogicalSubplanJoinNode represents a subquery. // You do not need to implement proper support for these for Project 3. return card1; } else { return estimateTableJoinCardinality( j.p, j.t1Alias, j.t2Alias, j.f1PureName, j.f2PureName, card1, card2, t1pkey, t2pkey, stats, p.getTableAliasToIdMapping()); } }
/** * Estimate the cardinality of a join. The cardinality of a join is the number of tuples produced * by the join. * * @param j A LogicalJoinNode representing the join operation being performed. * @param card1 Cardinality of the left-hand table in the join * @param card2 Cardinality of the right-hand table in the join * @param t1pkey Is the left-hand table a primary-key table? * @param t2pkey Is the right-hand table a primary-key table? * @param stats The table stats, referenced by table names, not alias * @return The cardinality of the join */ public int estimateJoinCardinality( LogicalJoinNode j, int card1, int card2, boolean t1pkey, boolean t2pkey, Map<String, TableStats> stats) { if (j instanceof LogicalSubplanJoinNode) { // A LogicalSubplanJoinNode represents a subquery. // Don't worry about implementing a more sophisticated estimate than the one below. return card1; } else { return estimateTableJoinCardinality( j.p, j.t1Alias, j.t2Alias, j.f1PureName, j.f2PureName, card1, card2, t1pkey, t2pkey, stats, p.getTableAliasToIdMapping()); } }
/** Adds an expression and returns a reference name. */ public String addExpr(Expr expr) throws PlanningException { if (idToExprBiMap.inverse().containsKey(expr)) { int refId = idToExprBiMap.inverse().get(expr); return idToNamesMap.get(refId).get(0); } String generatedName = plan.generateUniqueColumnName(expr); return addExpr(expr, generatedName); }
/** * Helper function to display a Swing window with a tree representation of the specified list of * joins. See {@link #orderJoins}, which may want to call this when the analyze flag is true. * * @param js the join plan to visualize * @param pc the PlanCache accumulated whild building the optimal plan * @param stats table statistics for base tables * @param selectivities the selectivities of the filters over each of the tables (where tables are * indentified by their alias or name if no alias is given) */ private void printJoins( Vector<LogicalJoinNode> js, PlanCache pc, HashMap<String, TableStats> stats, HashMap<String, Double> selectivities) { JFrame f = new JFrame("Join Plan for " + p.getQuery()); // Set the default close operation for the window, // or else the program won't exit when clicking close button f.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); f.setVisible(true); f.setSize(300, 500); HashMap<String, DefaultMutableTreeNode> m = new HashMap<String, DefaultMutableTreeNode>(); // int numTabs = 0; // int k; DefaultMutableTreeNode root = null, treetop = null; HashSet<LogicalJoinNode> pathSoFar = new HashSet<LogicalJoinNode>(); boolean neither; System.out.println(js); for (LogicalJoinNode j : js) { pathSoFar.add(j); System.out.println("PATH SO FAR = " + pathSoFar); String table1Name = Database.getCatalog().getTableName(this.p.getTableId(j.t1Alias)); String table2Name = Database.getCatalog().getTableName(this.p.getTableId(j.t2Alias)); // Double c = pc.getCost(pathSoFar); neither = true; root = new DefaultMutableTreeNode( "Join " + j + " (Cost =" + pc.getCost(pathSoFar) + ", card = " + pc.getCard(pathSoFar) + ")"); DefaultMutableTreeNode n = m.get(j.t1Alias); if (n == null) { // never seen this table before n = new DefaultMutableTreeNode( j.t1Alias + " (Cost = " + stats.get(table1Name).estimateScanCost() + ", card = " + stats.get(table1Name).estimateTableCardinality(selectivities.get(j.t1Alias)) + ")"); root.add(n); } else { // make left child root n root.add(n); neither = false; } m.put(j.t1Alias, root); n = m.get(j.t2Alias); if (n == null) { // never seen this table before n = new DefaultMutableTreeNode( j.t2Alias == null ? "Subplan" : (j.t2Alias + " (Cost = " + stats.get(table2Name).estimateScanCost() + ", card = " + stats .get(table2Name) .estimateTableCardinality(selectivities.get(j.t2Alias)) + ")")); root.add(n); } else { // make right child root n root.add(n); neither = false; } m.put(j.t2Alias, root); // unless this table doesn't join with other tables, // all tables are accessed from root if (!neither) { for (String key : m.keySet()) { m.put(key, root); } } treetop = root; } JTree tree = new JTree(treetop); JScrollPane treeView = new JScrollPane(tree); tree.setShowsRootHandles(true); // Set the icon for leaf nodes. ImageIcon leafIcon = new ImageIcon("join.jpg"); DefaultTreeCellRenderer renderer = new DefaultTreeCellRenderer(); renderer.setOpenIcon(leafIcon); renderer.setClosedIcon(leafIcon); tree.setCellRenderer(renderer); f.setSize(300, 500); f.add(treeView); for (int i = 0; i < tree.getRowCount(); i++) { tree.expandRow(i); } if (js.size() == 0) { f.add(new JLabel("No joins in plan.")); } f.pack(); }
/** * Return true if field is a primary key of the specified table, false otherwise * * @param tableAlias The alias of the table in the query * @param field The pure name of the field */ private boolean isPkey(String tableAlias, String field) { int tid1 = p.getTableId(tableAlias); String pkey1 = Database.getCatalog().getPrimaryKey(tid1); return pkey1.equals(field); }