```sql

CREATE MATERIALIZED VIEW player_champ_counts_mv
ENGINE = AggregatingMergeTree() ORDER BY (patch_num, my_account_id, champ_id)
as select patch_num, my_account_id, champ_id, countState() as c_state
from full_info
group by patch_num, my_account_id, champ_id;

create view player_champ_counts as
select patch_num, my_account_id, champ_id, countMerge(c_state) as c
from player_champ_counts_mv
group by patch_num, my_account_id, champ_id;
```

2.4s:
`select * from player_champ_counts`

900ms:
```
select patch_num, my_account_id, champ_id, countMerge(c_state) as c
from player_champ_counts_mv
group by patch_num, my_account_id, champ_id;
```

In other words, just inlining the definition of the view is doing something different than querying the view itself.
"plan header: " + plan_header.dumpStructure() +
                            "step header: " + step_header.dumpStructure(), ErrorCodes::LOGICAL_ERROR);
    }
    for (auto & plan : plans)
        nodes.splice(nodes.end(), std::move(plan.nodes));
    nodes.emplace_back(Node{.step = std::move(step)});
    root = &nodes.back();
    for (auto & plan : plans)
        root->children.emplace_back(plan.root);
    for (auto & plan : plans)
    {
        max_threads = std::max(max_threads, plan.max_threads);
        interpreter_context.insert(interpreter_context.end(),
                                   plan.interpreter_context.begin(), plan.interpreter_context.end());
    }
}
void QueryPlan::addStep(QueryPlanStepPtr step)
{
    checkNotCompleted();
    size_t num_input_streams = step->getInputStreams().size();
    if (num_input_streams == 0)
    {
        if (isInitialized())
            throw Exception("Cannot add step " + step->getName() + " to QueryPlan because "
                            "step has no inputs, but QueryPlan is already initialized", ErrorCodes::LOGICAL_ERROR);
        nodes.emplace_back(Node{.step = std::move(step)});
        root = &nodes.back();
        return;
    }
    if (num_input_streams == 1)