```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.
limits.speed_limits.min_execution_bps = settings.min_execution_speed_bytes;
        }
        limits.speed_limits.max_execution_rps = settings.max_execution_speed;
        limits.speed_limits.max_execution_bps = settings.max_execution_speed_bytes;
        limits.speed_limits.timeout_before_checking_execution_speed = settings.timeout_before_checking_execution_speed;
        auto quota = context->getQuota();
        for (auto & pipe : pipes)
        {
            if (!options.ignore_limits)
                pipe.setLimits(limits);
            if (!options.ignore_quota && (options.to_stage == QueryProcessingStage::Complete))
                pipe.setQuota(quota);
        }
    }
    if (pipes.size() == 1)
        pipeline->setMaxThreads(1);
    for (auto & pipe : pipes)
        pipe.enableQuota();
    pipeline->init(std::move(pipes));
    pipeline->addInterpreterContext(std::move(context));
    pipeline->addStorageHolder(std::move(storage));
    output_stream = DataStream{.header = pipeline->getHeader(), .has_single_port = pipeline->getNumStreams() == 1};
}
ReadFromStorageStep::~ReadFromStorageStep() = default;
QueryPipelinePtr ReadFromStorageStep::updatePipeline(QueryPipelines)
{
    return std::move(pipeline);
}
}