Search in sources :

Example 1 with TableStats

use of io.crate.statistics.TableStats in project crate by crate.

the class Rename method rewriteToFetch.

@Nullable
@Override
public FetchRewrite rewriteToFetch(TableStats tableStats, Collection<Symbol> usedColumns) {
    IdentityHashMap<Symbol, Symbol> parentToChildMap = new IdentityHashMap<>(outputs.size());
    IdentityHashMap<Symbol, Symbol> childToParentMap = new IdentityHashMap<>(outputs.size());
    for (int i = 0; i < outputs.size(); i++) {
        parentToChildMap.put(outputs.get(i), source.outputs().get(i));
        childToParentMap.put(source.outputs().get(i), outputs.get(i));
    }
    ArrayList<Symbol> mappedUsedColumns = new ArrayList<>();
    for (Symbol usedColumn : usedColumns) {
        SymbolVisitors.intersection(usedColumn, outputs, s -> {
            Symbol childSymbol = parentToChildMap.get(s);
            assert childSymbol != null : "There must be a mapping available for symbol " + s;
            mappedUsedColumns.add(childSymbol);
        });
    }
    FetchRewrite fetchRewrite = source.rewriteToFetch(tableStats, mappedUsedColumns);
    if (fetchRewrite == null) {
        return null;
    }
    LogicalPlan newSource = fetchRewrite.newPlan();
    ArrayList<Symbol> newOutputs = new ArrayList<>();
    for (Symbol output : newSource.outputs()) {
        if (output instanceof FetchMarker) {
            FetchMarker marker = (FetchMarker) output;
            FetchMarker newMarker = new FetchMarker(name, marker.fetchRefs(), marker.fetchId());
            newOutputs.add(newMarker);
            childToParentMap.put(marker, newMarker);
        } else {
            Symbol mappedOutput = requireNonNull(childToParentMap.get(output), () -> "Mapping must exist for output from source. `" + output + "` is missing in " + childToParentMap);
            newOutputs.add(mappedOutput);
        }
    }
    LinkedHashMap<Symbol, Symbol> replacedOutputs = new LinkedHashMap<>();
    Function<Symbol, Symbol> convertChildrenToScopedSymbols = s -> MapBackedSymbolReplacer.convert(s, childToParentMap);
    for (var entry : fetchRewrite.replacedOutputs().entrySet()) {
        Symbol key = entry.getKey();
        Symbol value = entry.getValue();
        Symbol parentSymbolForKey = requireNonNull(childToParentMap.get(key), () -> "Mapping must exist for output from source. `" + key + "` is missing in " + childToParentMap);
        replacedOutputs.put(parentSymbolForKey, convertChildrenToScopedSymbols.apply(value));
    }
    Rename newRename = new Rename(newOutputs, name, fieldResolver, newSource);
    return new FetchRewrite(replacedOutputs, newRename);
}
Also used : IdentityHashMap(java.util.IdentityHashMap) RelationName(io.crate.metadata.RelationName) Collection(java.util.Collection) Set(java.util.Set) FetchMarker(io.crate.expression.symbol.FetchMarker) Function(java.util.function.Function) FieldResolver(io.crate.analyze.relations.FieldResolver) Lists2(io.crate.common.collections.Lists2) SymbolVisitors(io.crate.expression.symbol.SymbolVisitors) ExecutionPlan(io.crate.planner.ExecutionPlan) ArrayList(java.util.ArrayList) LinkedHashMap(java.util.LinkedHashMap) List(java.util.List) OrderBy(io.crate.analyze.OrderBy) TableStats(io.crate.statistics.TableStats) Row(io.crate.data.Row) Symbol(io.crate.expression.symbol.Symbol) PlannerContext(io.crate.planner.PlannerContext) Objects.requireNonNull(java.util.Objects.requireNonNull) ScopedSymbol(io.crate.expression.symbol.ScopedSymbol) Nullable(javax.annotation.Nullable) ProjectionBuilder(io.crate.execution.dsl.projection.builder.ProjectionBuilder) Symbol(io.crate.expression.symbol.Symbol) ScopedSymbol(io.crate.expression.symbol.ScopedSymbol) FetchMarker(io.crate.expression.symbol.FetchMarker) IdentityHashMap(java.util.IdentityHashMap) ArrayList(java.util.ArrayList) LinkedHashMap(java.util.LinkedHashMap) Nullable(javax.annotation.Nullable)

Example 2 with TableStats

use of io.crate.statistics.TableStats in project crate by crate.

the class MoveFilterBeneathWindowAgg method apply.

@Override
public LogicalPlan apply(Filter filter, Captures captures, TableStats tableStats, TransactionContext txnCtx, NodeContext nodeCtx) {
    WindowAgg windowAgg = captures.get(windowAggCapture);
    WindowDefinition windowDefinition = windowAgg.windowDefinition();
    List<WindowFunction> windowFunctions = windowAgg.windowFunctions();
    Predicate<Symbol> containsWindowFunction = symbol -> symbol instanceof WindowFunction && windowFunctions.contains(symbol);
    Symbol predicate = filter.query();
    List<Symbol> filterParts = AndOperator.split(predicate);
    ArrayList<Symbol> remainingFilterSymbols = new ArrayList<>();
    ArrayList<Symbol> windowPartitionedBasedFilters = new ArrayList<>();
    for (Symbol part : filterParts) {
        if (SymbolVisitors.any(containsWindowFunction, part) == false && windowDefinition.partitions().containsAll(extractColumns(part))) {
            windowPartitionedBasedFilters.add(part);
        } else {
            remainingFilterSymbols.add(part);
        }
    }
    assert remainingFilterSymbols.size() > 0 || windowPartitionedBasedFilters.size() > 0 : "Splitting the filter symbol must result in at least one group";
    /* SELECT ROW_NUMBER() OVER(PARTITION BY id)
         * WHERE `x = 1`
         *
         * `x` is not the window partition column.
         * We cannot push down the filter as it would change the window aggregation value
         *
         */
    if (windowPartitionedBasedFilters.isEmpty()) {
        return null;
    }
    /* SELECT ROW_NUMBER() OVER(PARTITION BY id)
         * WHERE `id = 1`
         * remainingFilterSymbols:                  []
         * windowPartitionedBasedFilters:           [id = 1]
         *
         * Filter
         *  |
         * WindowsAgg
         *
         * transforms to
         *
         * WindowAgg
         *  |
         * Filter (id = 1)
         */
    if (remainingFilterSymbols.isEmpty()) {
        return transpose(filter, windowAgg);
    }
    /* WHERE `ROW_NUMBER() OVER(PARTITION BY id) = 2 AND id = 1`
         * remainingFilterSymbols:                  [ROW_NUMBER() OVER(PARTITION BY id) = 2]
         * windowPartitionedBasedFilters:           [id = 1]
         *
         * Filter
         *  |
         * WindowsAgg
         *
         * transforms to
         *
         * Filter (ROW_NUMBER() OVER(PARTITION BY id) = 2)
         *  |
         * WindowAgg
         *  |
         * Filter (id = 1)
         */
    LogicalPlan newWindowAgg = windowAgg.replaceSources(List.of(new Filter(windowAgg.source(), AndOperator.join(windowPartitionedBasedFilters))));
    return new Filter(newWindowAgg, AndOperator.join(remainingFilterSymbols));
}
Also used : TransactionContext(io.crate.metadata.TransactionContext) NodeContext(io.crate.metadata.NodeContext) LogicalPlanner.extractColumns(io.crate.planner.operators.LogicalPlanner.extractColumns) LogicalPlan(io.crate.planner.operators.LogicalPlan) Captures(io.crate.planner.optimizer.matcher.Captures) Predicate(java.util.function.Predicate) Util.transpose(io.crate.planner.optimizer.rule.Util.transpose) Pattern(io.crate.planner.optimizer.matcher.Pattern) Rule(io.crate.planner.optimizer.Rule) SymbolVisitors(io.crate.expression.symbol.SymbolVisitors) ArrayList(java.util.ArrayList) List(java.util.List) AndOperator(io.crate.expression.operator.AndOperator) TableStats(io.crate.statistics.TableStats) WindowDefinition(io.crate.analyze.WindowDefinition) Symbol(io.crate.expression.symbol.Symbol) Pattern.typeOf(io.crate.planner.optimizer.matcher.Pattern.typeOf) WindowFunction(io.crate.expression.symbol.WindowFunction) Patterns.source(io.crate.planner.optimizer.matcher.Patterns.source) Filter(io.crate.planner.operators.Filter) WindowAgg(io.crate.planner.operators.WindowAgg) Capture(io.crate.planner.optimizer.matcher.Capture) WindowFunction(io.crate.expression.symbol.WindowFunction) WindowAgg(io.crate.planner.operators.WindowAgg) Filter(io.crate.planner.operators.Filter) Symbol(io.crate.expression.symbol.Symbol) ArrayList(java.util.ArrayList) LogicalPlan(io.crate.planner.operators.LogicalPlan) WindowDefinition(io.crate.analyze.WindowDefinition)

Example 3 with TableStats

use of io.crate.statistics.TableStats in project crate by crate.

the class SubSelectIntegrationTest method testSingleRowSubSelectWorksWithJoins.

@Test
public void testSingleRowSubSelectWorksWithJoins() throws Exception {
    execute("create table t (x long primary key)");
    ensureYellow();
    execute("insert into t (x) values (1), (2)");
    execute("refresh table t");
    for (TableStats tableStats : internalCluster().getInstances(TableStats.class)) {
        Map<RelationName, Stats> newStats = new HashMap<>();
        newStats.put(new RelationName(sqlExecutor.getCurrentSchema(), "t"), new Stats(100, 64, Map.of()));
        tableStats.updateTableStats(newStats);
    }
    // Left table is expected to be one row, due to the single row subselect in the where clause.
    execute("select * from t as t1, t as t2 where t1.x = (select 1) order by t2.x");
    assertThat(printedTable(response.rows()), is("1| 1\n1| 2\n"));
    // Left table is expected to be bigger due to the table stats stating it being 100 rows
    execute("select * from t as t2, t as t1 where t1.x = (select 1) order by t2.x");
    assertThat(printedTable(response.rows()), is("1| 1\n2| 1\n"));
}
Also used : HashMap(java.util.HashMap) Stats(io.crate.statistics.Stats) TableStats(io.crate.statistics.TableStats) RelationName(io.crate.metadata.RelationName) TableStats(io.crate.statistics.TableStats) Test(org.junit.Test)

Example 4 with TableStats

use of io.crate.statistics.TableStats in project crate by crate.

the class CollectTest method test_prune_output_of_collect_updates_estimated_row_size.

@Test
public void test_prune_output_of_collect_updates_estimated_row_size() throws Exception {
    var e = SQLExecutor.builder(clusterService).addTable("create table t (x int, y int)").build();
    TableStats tableStats = new TableStats();
    Symbol x = e.asSymbol("x");
    Collect collect = Collect.create(new DocTableRelation(e.resolveTableInfo("t")), List.of(x, e.asSymbol("y")), WhereClause.MATCH_ALL, tableStats, Row.EMPTY);
    assertThat(collect.estimatedRowSize(), is(DataTypes.INTEGER.fixedSize() * 2L));
    LogicalPlan prunedCollect = collect.pruneOutputsExcept(tableStats, List.of(x));
    assertThat(prunedCollect.estimatedRowSize(), is((long) DataTypes.INTEGER.fixedSize()));
}
Also used : Symbol(io.crate.expression.symbol.Symbol) DocTableRelation(io.crate.analyze.relations.DocTableRelation) TableStats(io.crate.statistics.TableStats) Test(org.junit.Test) CrateDummyClusterServiceUnitTest(io.crate.test.integration.CrateDummyClusterServiceUnitTest)

Example 5 with TableStats

use of io.crate.statistics.TableStats in project crate by crate.

the class FetchRewriteTest method test_fetchrewrite_on_eval_with_nested_source_outputs.

@Test
public void test_fetchrewrite_on_eval_with_nested_source_outputs() throws Exception {
    SQLExecutor e = SQLExecutor.builder(clusterService).addTable("create table tbl (x int)").build();
    DocTableInfo tableInfo = e.resolveTableInfo("tbl");
    var x = new AliasSymbol("x_alias", e.asSymbol("x"));
    var relation = new DocTableRelation(tableInfo);
    var collect = new Collect(relation, List.of(x), WhereClause.MATCH_ALL, 1L, DataTypes.INTEGER.fixedSize());
    var eval = new Eval(collect, List.of(x));
    FetchRewrite fetchRewrite = eval.rewriteToFetch(new TableStats(), List.of());
    assertThat(fetchRewrite, Matchers.notNullValue());
    assertThat(fetchRewrite.newPlan(), isPlan("Collect[doc.tbl | [_fetchid] | true]"));
    assertThat(fetchRewrite.replacedOutputs(), Matchers.hasEntry(is(x), isAlias("x_alias", isFetchStub("_doc['x']"))));
}
Also used : DocTableInfo(io.crate.metadata.doc.DocTableInfo) AliasSymbol(io.crate.expression.symbol.AliasSymbol) SQLExecutor(io.crate.testing.SQLExecutor) DocTableRelation(io.crate.analyze.relations.DocTableRelation) TableStats(io.crate.statistics.TableStats) CrateDummyClusterServiceUnitTest(io.crate.test.integration.CrateDummyClusterServiceUnitTest) Test(org.junit.Test)

Aggregations

TableStats (io.crate.statistics.TableStats)23 Test (org.junit.Test)17 CrateDummyClusterServiceUnitTest (io.crate.test.integration.CrateDummyClusterServiceUnitTest)15 Symbol (io.crate.expression.symbol.Symbol)11 RelationName (io.crate.metadata.RelationName)8 Filter (io.crate.planner.operators.Filter)7 LogicalPlan (io.crate.planner.operators.LogicalPlan)7 SQLExecutor (io.crate.testing.SQLExecutor)7 WindowFunction (io.crate.expression.symbol.WindowFunction)6 WindowAgg (io.crate.planner.operators.WindowAgg)6 Stats (io.crate.statistics.Stats)6 DocTableRelation (io.crate.analyze.relations.DocTableRelation)4 PlannerContext (io.crate.planner.PlannerContext)4 ProjectionBuilder (io.crate.execution.dsl.projection.builder.ProjectionBuilder)3 ScopedSymbol (io.crate.expression.symbol.ScopedSymbol)3 ColumnIdent (io.crate.metadata.ColumnIdent)3 Reference (io.crate.metadata.Reference)3 DocTableInfo (io.crate.metadata.doc.DocTableInfo)3 ColumnStats (io.crate.statistics.ColumnStats)3 ArrayList (java.util.ArrayList)3