public static PlanNodeCostEstimate calculateLocalRepartitionCost(double inputSizeInBytes) { return cpuCost(inputSizeInBytes); }
@Override public PlanNodeCostEstimate visitAssignUniqueId(AssignUniqueId node, Void context) { return cpuCost(getStats(node).getOutputSizeInBytes(ImmutableList.of(node.getIdColumn()), types)); }
private PlanNodeCostEstimate calculateJoinOutputCost(PlanNode join) { PlanNodeStatsEstimate outputStats = getStats(join); double joinOutputSize = outputStats.getOutputSizeInBytes(join.getOutputSymbols(), types); return cpuCost(joinOutputSize); }
@Override public PlanNodeCostEstimate visitTableScan(TableScanNode node, Void context) { // TODO: add network cost, based on input size in bytes? Or let connector provide this cost? return cpuCost(getStats(node).getOutputSizeInBytes(node.getOutputSymbols(), types)); }
@Override public PlanNodeCostEstimate visitProject(ProjectNode node, Void context) { return cpuCost(getStats(node).getOutputSizeInBytes(node.getOutputSymbols(), types)); }
@Override public PlanNodeCostEstimate visitLimit(LimitNode node, Void context) { // This is just a wild guess. First of all, LimitNode is rather rare except as a top node of a query plan, // so proper cost estimation is not that important. Second, since LimitNode can lead to incomplete evaluation // of the source, true cost estimation should be implemented as a "constraint" enforced on a sub-tree and // evaluated in context of actual source node type (and their sources). return cpuCost(getStats(node).getOutputSizeInBytes(node.getOutputSymbols(), types)); }
@Override public PlanNodeCostEstimate visitFilter(FilterNode node, Void context) { return cpuCost(getStats(node.getSource()).getOutputSizeInBytes(node.getOutputSymbols(), types)); }
@Test public void testEvictCostOnReplace() { PlanNode y = node(); PlanNode x = node(y); Memo memo = new Memo(idAllocator, x); int xGroup = memo.getRootGroup(); int yGroup = getChildGroup(memo, memo.getRootGroup()); PlanNodeCostEstimate yCost = PlanNodeCostEstimate.cpuCost(42); PlanNodeCostEstimate xCost = yCost.add(PlanNodeCostEstimate.networkCost(37)); memo.storeCumulativeCost(yGroup, yCost); memo.storeCumulativeCost(xGroup, xCost); assertEquals(memo.getCumulativeCost(yGroup), Optional.of(yCost)); assertEquals(memo.getCumulativeCost(xGroup), Optional.of(xCost)); memo.replace(yGroup, node(), "rule"); assertEquals(memo.getCumulativeCost(yGroup), Optional.empty()); assertEquals(memo.getCumulativeCost(xGroup), Optional.empty()); }
@Test public void testUnion() { TableScanNode ts1 = tableScan("ts1", "orderkey"); TableScanNode ts2 = tableScan("ts2", "orderkey_0"); ImmutableListMultimap.Builder<Symbol, Symbol> outputMappings = ImmutableListMultimap.builder(); outputMappings.put(new Symbol("orderkey_1"), new Symbol("orderkey")); outputMappings.put(new Symbol("orderkey_1"), new Symbol("orderkey_0")); UnionNode union = new UnionNode(new PlanNodeId("union"), ImmutableList.of(ts1, ts2), outputMappings.build(), ImmutableList.of(new Symbol("orderkey_1"))); Map<String, PlanNodeStatsEstimate> stats = ImmutableMap.of( "ts1", statsEstimate(ts1, 4000), "ts2", statsEstimate(ts2, 1000), "union", statsEstimate(ts1, 5000)); Map<String, PlanNodeCostEstimate> costs = ImmutableMap.of( "ts1", cpuCost(1000), "ts2", cpuCost(1000)); Map<String, Type> types = ImmutableMap.of( "orderkey", BIGINT, "orderkey_0", BIGINT, "orderkey_1", BIGINT); assertCost(union, costs, stats, types) .cpu(2000) .memory(0) .network(0); assertCostEstimatedExchanges(union, costs, stats, types) .cpu(2000) .memory(0) .network(5000 * IS_NULL_OVERHEAD); }
@Test public void testAggregation() { TableScanNode tableScan = tableScan("ts", "orderkey"); AggregationNode aggregation = aggregation("agg", tableScan); Map<String, PlanNodeCostEstimate> costs = ImmutableMap.of("ts", cpuCost(6000)); Map<String, PlanNodeStatsEstimate> stats = ImmutableMap.of( "ts", statsEstimate(tableScan, 6000), "agg", statsEstimate(aggregation, 13)); Map<String, Type> types = ImmutableMap.of( "orderkey", BIGINT, "count", BIGINT); assertCost(aggregation, costs, stats, types) .cpu(6000 * IS_NULL_OVERHEAD + 6000) .memory(13 * IS_NULL_OVERHEAD) .network(0); assertCostEstimatedExchanges(aggregation, costs, stats, types) .cpu((6000 + 6000 + 6000) * IS_NULL_OVERHEAD + 6000) .memory(13 * IS_NULL_OVERHEAD) .network(6000 * IS_NULL_OVERHEAD); assertCostFragmentedPlan(aggregation, costs, stats, types) .cpu(6000 + 6000 * IS_NULL_OVERHEAD) .memory(13 * IS_NULL_OVERHEAD) .network(0 * IS_NULL_OVERHEAD); assertCostHasUnknownComponentsForUnknownStats(aggregation, types); }
@Test public void testProject() { TableScanNode tableScan = tableScan("ts", "orderkey"); PlanNode project = project("project", tableScan, "string", new Cast(new SymbolReference("orderkey"), "STRING")); Map<String, PlanNodeCostEstimate> costs = ImmutableMap.of("ts", cpuCost(1000)); Map<String, PlanNodeStatsEstimate> stats = ImmutableMap.of( "project", statsEstimate(project, 4000), "ts", statsEstimate(tableScan, 1000)); Map<String, Type> types = ImmutableMap.of( "orderkey", BIGINT, "string", VARCHAR); assertCost(project, costs, stats, types) .cpu(1000 + 4000 * OFFSET_AND_IS_NULL_OVERHEAD) .memory(0) .network(0); assertCostEstimatedExchanges(project, costs, stats, types) .cpu(1000 + 4000 * OFFSET_AND_IS_NULL_OVERHEAD) .memory(0) .network(0); assertCostFragmentedPlan(project, costs, stats, types) .cpu(1000 + 4000 * OFFSET_AND_IS_NULL_OVERHEAD) .memory(0) .network(0); assertCostHasUnknownComponentsForUnknownStats(project, types); }