```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.
auto & at(size_t pos) { return data.at(pos); }
        auto & operator[](size_t pos) { return data[pos]; }
        void clear() { data.clear(); }
        void reserve(size_t size_) { data.reserve(size_); }
        void addStream(OutputPort * port, size_t port_max_parallel_streams)
        {
            data.push_back(port);
            max_parallel_streams = std::max<size_t>(max_parallel_streams + port_max_parallel_streams, data.size());
        }
        void addStreams(Streams & other)
        {
            data.insert(data.end(), other.begin(), other.end());
            max_parallel_streams = std::max<size_t>(max_parallel_streams + other.max_parallel_streams, data.size());
        }
        void assign(std::initializer_list<OutputPort *> list)
        {
            data = list;
            max_parallel_streams = std::max<size_t>(max_parallel_streams, data.size());
        }
        size_t maxParallelStreams() const { return max_parallel_streams; }
    private:
        std::vector<OutputPort *> data;
        
        
        
        
        size_t max_parallel_streams = 0;
    };
public:
    QueryPipeline() = default;