Altinity blog 的读者们知道我们喜欢ClickHouse的物化视图 . 物化视图可以实现聚合计算, 从Kafka读取数据, 实现最后点查询(last point queries)以及重组表主键索引和排序顺序. 除了这些功能之外, 物化视图可以在大量节点上很好地扩缩, 并可以处理大型数据集. 它们是ClickHouse的独特功能之一.
在计算领域, 强大的功能至少意味着一点点复杂性. 这篇由两部分组成的文章通过解释物化视图的工作原理来填补空白, 从而使初学者也可以有效地使用它们. 我们将通过几个详细的示例, 您可以根据自己的使用进行调整. 在此过程中, 我们将探索用于创建视图的语法的确切含义, 并让您深入了解ClickHouse在做什么. 示例是完全自包含的, 因此您可以将它们复制/粘贴到clickhouse-client中并自己运行它们.
How Materialized Views Work: Computing Sums ClickHouse物化视图自动在表之间转换数据. 它们类似于触发器, 对插入的行运行查询并将结果存入第二个表. 让我们看一个基本的例子. 假设我们有一个记录用户下载的表, 如下所示.
1 2 3 4 5 6 7 CREATE TABLE download ( when DateTime, userid UInt32, bytes Float32 ) ENGINE =MergeTree PARTITION BY toYYYYMM(when )ORDER BY (userid, when )
我们希望跟踪每个用户的每日下载. 让我们看看如何用一个查询来做到这一点. 首先, 我们需要为单个用户向表中添加一些数据.
1 2 3 4 5 6 7 INSERT INTO download SELECT now () + number * 60 as when , 25 , rand () % 100000000 FROM system.numbers LIMIT 5000
接下来, 让我们运行一个查询来显示该用户的每日下载. 当添加新用户时, 这也将正常工作.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 SELECT toStartOfDay(when) AS day, userid, count() AS downloads, sum(bytes) AS bytes FROM download GROUP BY userid, day ORDER BY userid ASC, day ASC ┌─────────────────day─┬─userid─┬─downloads─┬───────bytes─┐ │ 2020 -08 -18 00 :00 :00 │ 25 │ 736 │ 36722522631 │ │ 2020 -08 -19 00 :00 :00 │ 25 │ 1440 │ 73305428060 │ │ 2020 -08 -20 00 :00 :00 │ 25 │ 1440 │ 73183910537 │ │ 2020 -08 -21 00 :00 :00 │ 25 │ 1384 │ 70059352697 │ └─────────────────────┴────────┴───────────┴─────────────┘
我们可以通过每次运行查询以交互方式为应用程序计算这些每日总数, 但是对于大型表, 提前计算它们将更快, 更节省资源. 因此, 最好将结果放在单独的表格中, 该表格可以连续跟踪每天每个用户的下载总数. 我们可以使用以下物化视图来做到这一点.
1 2 3 4 5 6 7 8 9 10 11 CREATE MATERIALIZED VIEW download_daily_mvENGINE = SummingMergeTreePARTITION BY toYYYYMM(day ) ORDER BY (userid, day )POPULATE AS SELECT toStartOfDay(when ) AS day , userid, count () as downloads, sum (bytes ) AS bytes FROM downloadGROUP BY userid, day
这里有三件重要的事情需要注意. 首先, 物化视图定义允许类似于CREATE TABLE的语法, 这是有意义的, 因为这个命令将实际创建一个隐藏的目标表(.inner表)来保存视图数据. 我们使用的ClickHouse引擎旨在使计算和计数变得简单:SummingMergeTree . 它是用于计算聚合的物化视图的推荐引擎.
其次, 视图定义包含关键字POPULATE. 这告诉ClickHouse将download
表中的现有数据插入物化视图. 我们稍后会更多地讨论automatic population.
需要注意, 在POPULATE
填充历史数据的期间, 新进入的这部分数据会被忽略掉, 所以如果对准确性要求非常高, 应慎用
第三, 视图定义包含一个SELECT语句, 该语句定义在加载视图时如何转换数据. 这个查询在表中的新数据上运行, 以计算每天每个用户id的下载数量和总字节数. 它本质上与我们以交互方式运行的查询相同, 只是在本例中, 结果将放在隐藏的目标表(.inner表)中. 我们可以跳过排序, 因为视图定义已经确保了排序顺序.
现在, 我们从物化视图中查询数据
1 2 3 4 5 6 7 8 9 10 SELECT * FROM download_daily_mv ORDER BY day, userid LIMIT 5 ┌─────────────────day─┬─userid─┬─downloads─┬───────bytes─┐ │ 2020 -08 -18 00 :00 :00 │ 25 │ 736 │ 36722522631 │ │ 2020 -08 -19 00 :00 :00 │ 25 │ 1440 │ 73305428060 │ │ 2020 -08 -20 00 :00 :00 │ 25 │ 1440 │ 73183910537 │ │ 2020 -08 -21 00 :00 :00 │ 25 │ 1384 │ 70059352697 │ └─────────────────────┴────────┴───────────┴─────────────┘
这为我们提供了与先前查询完全相同的答案. 原因是上面介绍的POPULATE关键字. 它确保源表中的现有数据自动加载到视图中. 不过, 有一个重要警告:如果在填充视图时插入了新数据, ClickHouse将会丢失它们. 在本系列的第二部分中, 我们将展示如何手动插入数据并避免数据遗漏的问题.
现在, 尝试使用其他用户向表中添加更多数据.
1 2 3 4 5 6 7 INSERT INTO download SELECT now () + number * 60 as when , 22 , rand () % 100000000 FROM system.numbers LIMIT 5000
如果您从实例化视图中进行选择, 您将看到它现在具有用户ID 22和25的总数. 请注意, 一旦INSERT完成, 将立即填充新数据. 这是ClickHouse实例化视图的重要功能, 这使其对于实时分析非常有用.
下面是查询和新结果.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 SELECT * FROM download_daily_mv ORDER BY userid ASC, day ASC ┌─────────────────day─┬─userid─┬─downloads─┬───────bytes─┐ │ 2020 -08 -18 00 :00 :00 │ 22 │ 416 │ 21063519801 │ │ 2020 -08 -19 00 :00 :00 │ 22 │ 1440 │ 71523929305 │ │ 2020 -08 -20 00 :00 :00 │ 22 │ 1440 │ 70435459582 │ │ 2020 -08 -21 00 :00 :00 │ 22 │ 1440 │ 70725673036 │ │ 2020 -08 -22 00 :00 :00 │ 22 │ 264 │ 13826466067 │ └─────────────────────┴────────┴───────────┴─────────────┘ ┌─────────────────day─┬─userid─┬─downloads─┬────────bytes─┐ │ 2020 -08 -18 00 :00 :00 │ 25 │ 1467 │ 75441118166 │ │ 2020 -08 -19 00 :00 :00 │ 25 │ 2880 │ 144811386193 │ │ 2020 -08 -20 00 :00 :00 │ 25 │ 2880 │ 145138479865 │ │ 2020 -08 -21 00 :00 :00 │ 25 │ 2773 │ 138488485955 │ └─────────────────────┴────────┴───────────┴──────────────┘
作为练习, 您可以对源表运行原始查询, 以确认它与物化视图中的总数相匹配.
作为最后一个示例, 让我们使用物化视图按月汇总. 在本例中, 我们将物化视图视为一个普通表, 按月分组, 如下所示. 我们添加了WITH TOTALS子句, 它打印一个方便的聚合的总和.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 SELECT toStartOfMonth(day ) AS month , userid, sum (downloads), sum (bytes ) FROM download_daily_mvGROUP BY userid, month WITH TOTALS ORDER BY userid ASC , month ASC ┌──────month ─┬─userid─┬─sum (downloads)─┬───sum (bytes )─┐ │ 2020 -08 -01 │ 22 │ 5000 │ 247575047791 │ │ 2020 -08 -01 │ 25 │ 10000 │ 503879470179 │ └────────────┴────────┴────────────────┴──────────────┘ Extremes: ┌──────month ─┬─userid─┬─sum (downloads)─┬───sum (bytes )─┐ │ 0000 -00 -00 │ 0 │ 15000 │ 751454517970 │ └────────────┴────────┴────────────────┴──────────────┘
从前面的示例中, 我们可以清楚地看到实例化视图如何正确地汇总源数据中的数据(how the materialized view correctly summarizes data from the source data). 如上例所示, 我们甚至可以“summarize the summaries”. 那么幕后到底发生了什么? 下图说明了数据的逻辑流.
如图所示, 原表上INSERT的值被转换并应用于隐藏的目标表(.inner表). 要填充视图(To populate the view), 您要做的就是在源表中插入数据.
您可以从隐藏的目标表(.inner表)和物化视图中进行查询. 实际上ClickHouse就是将查询路由到创建物化视图时自动创建的internel表中的.
图中还有另外一件重要的事情需要注意. 物化视图创建一个具有特殊名称私有表来保存数据. 如果您通过输入DROP TABLE download_daily_mv
删除物化视图, 则私有表也会被删除. 如果需要更改视图, 则需要将其删除并使用新数据重新创建
1 2 3 4 5 6 7 8 > SHOW TABLES > ┌─name─────────────────────┐ > │ .inner.download_daily_mv │ > │ download │ > │ download_daily_mv │ > └──────────────────────────┘
.inner.download_daily_mv就是 internel表或叫私有表
Wrap-up - 总结 我们刚刚审阅的示例使用SummingMergeTree创建一个视图以累加每日用户下载量. 我们从物化视图对SELECT使用了标准SQL语法. 这是SummingMergeTree引擎的特殊功能, 仅适用于总和和计数. 对于其他类型的聚合, 我们需要使用其他方法.
另外, 我们的示例使用POPULATE关键字将现有表数据发布到视图创建的私有目标表(.inner表)中. 如果在填充视图时到达新的INSERT行, ClickHouse将错过它们. 当您是唯一使用数据集的人时, 此限制很容易解决, 但对于不断加载数据的生产系统来说是个问题. 此外, 删除视图后, 专用表也会消失. 这使得很难更改视图以适应源表中的架构更改.
在下一篇文章中, 我们将展示如何创建物化视图来计算其他类型的聚合, 比如平均值或最大值/最小值. 我们还将展示如何显式定义目标表(.inner表), 并使用我们自己的SQL语句手动将数据加载到其中. 我们还将简要介绍模式迁移(schema migration). 同时, 我们希望您喜欢这一简要介绍, 并发现示例有用.
实测及问题 删除基表, 物化视图仍然可以查询 这是符合预期的, 因为物化视图是存储了数据的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 bj2-all-clickhouse-test-02 :) drop table download; DROP TABLE download Ok. 0 rows in set . Elapsed: 0.016 sec. bj2-all-clickhouse-test-02 :) show tables; SHOW TABLES ┌─name─────────────────────┐ │ .inner.download_daily_mv │ │ download_daily_mv │ │ sbtest │ │ sbtest_local │ └──────────────────────────┘ 4 rows in set . Elapsed: 0.001 sec. bj2-all-clickhouse-test-02 :) select * from download_daily_mv; SELECT * FROM download_daily_mv ┌─────────────────day─┬─userid─┬─downloads─┬────────bytes─┐ │ 2020 -08 -18 00 :00 :00 │ 25 │ 1467 │ 75441118166 │ │ 2020 -08 -19 00 :00 :00 │ 25 │ 2880 │ 144811386193 │ │ 2020 -08 -20 00 :00 :00 │ 25 │ 2880 │ 145138479865 │ │ 2020 -08 -21 00 :00 :00 │ 25 │ 2773 │ 138488485955 │ └─────────────────────┴────────┴───────────┴──────────────┘ ┌─────────────────day─┬─userid─┬─downloads─┬───────bytes─┐ │ 2020 -08 -18 00 :00 :00 │ 22 │ 416 │ 21063519801 │ │ 2020 -08 -19 00 :00 :00 │ 22 │ 1440 │ 71523929305 │ │ 2020 -08 -20 00 :00 :00 │ 22 │ 1440 │ 70435459582 │ │ 2020 -08 -21 00 :00 :00 │ 22 │ 1440 │ 70725673036 │ │ 2020 -08 -22 00 :00 :00 │ 22 │ 264 │ 13826466067 │ └─────────────────────┴────────┴───────────┴─────────────┘ 9 rows in set . Elapsed: 0.008 sec.
数据在分区合并时聚合 重新创建download表和物化视图
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 SELECT toStartOfDay(when) AS day, userid, count() AS downloads, sum(bytes) AS bytes FROM download GROUP BY userid, day ORDER BY userid ASC, day ASC ┌─────────────────day─┬─userid─┬─downloads─┬───────bytes─┐ │ 2020 -08 -18 00 :00 :00 │ 25 │ 387 │ 19855551536 │ │ 2020 -08 -19 00 :00 :00 │ 25 │ 1440 │ 73316885071 │ │ 2020 -08 -20 00 :00 :00 │ 25 │ 1440 │ 72322018002 │ │ 2020 -08 -21 00 :00 :00 │ 25 │ 1440 │ 71675677053 │ │ 2020 -08 -22 00 :00 :00 │ 25 │ 293 │ 14125612942 │ └─────────────────────┴────────┴───────────┴─────────────┘ SELECT * FROM download_daily_mv ┌─────────────────day─┬─userid─┬─downloads─┬───────bytes─┐ │ 2020 -08 -18 00 :00 :00 │ 25 │ 387 │ 19855551536 │ │ 2020 -08 -19 00 :00 :00 │ 25 │ 1440 │ 73316885071 │ │ 2020 -08 -20 00 :00 :00 │ 25 │ 1440 │ 72322018002 │ │ 2020 -08 -21 00 :00 :00 │ 25 │ 1440 │ 71675677053 │ │ 2020 -08 -22 00 :00 :00 │ 25 │ 293 │ 14125612942 │ └─────────────────────┴────────┴───────────┴─────────────┘
再次向基表中插入数据, 然后查看物化视图中的数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 INSERT INTO download SELECT now() + (number * 60 ) AS when, 25 , rand() % 100000000 FROM system.numbers LIMIT 5000 SELECT * FROM download_daily_mv ┌─────────────────day─┬─userid─┬─downloads─┬───────bytes─┐ │ 2020 -08 -18 00 :00 :00 │ 25 │ 387 │ 19855551536 │ │ 2020 -08 -19 00 :00 :00 │ 25 │ 1440 │ 73316885071 │ │ 2020 -08 -20 00 :00 :00 │ 25 │ 1440 │ 72322018002 │ │ 2020 -08 -21 00 :00 :00 │ 25 │ 1440 │ 71675677053 │ │ 2020 -08 -22 00 :00 :00 │ 25 │ 293 │ 14125612942 │ └─────────────────────┴────────┴───────────┴─────────────┘ ┌─────────────────day─┬─userid─┬─downloads─┬───────bytes─┐ │ 2020 -08 -18 00 :00 :00 │ 25 │ 385 │ 18771807859 │ │ 2020 -08 -19 00 :00 :00 │ 25 │ 1440 │ 73675739078 │ │ 2020 -08 -20 00 :00 :00 │ 25 │ 1440 │ 70555293899 │ │ 2020 -08 -21 00 :00 :00 │ 25 │ 1440 │ 70773685728 │ │ 2020 -08 -22 00 :00 :00 │ 25 │ 295 │ 14750186600 │ └─────────────────────┴────────┴───────────┴─────────────┘
可以看到物化视图中的数据并没有”全部聚合完整”
查看物化视图private表分区情况
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 bj2-all-clickhouse-test-02 :) select * from system.parts where table='.inner.download_daily_mv'\G SELECT * FROM system.parts WHERE table = '.inner.download_daily_mv' Row 1: ────── partition: 202008 name: 202008_1_1_0 part_type: Wide active: 1 marks: 2 rows: 5 bytes_on_disk: 421 data_compressed_bytes: 200 data_uncompressed_bytes: 120 marks_bytes: 192 modification_time: 2020-08-18 17:33:51 remove_time: 0000-00-00 00:00:00 refcount: 1 min_date: 0000-00-00 max_date: 0000-00-00 min_time: 2020-08-18 00:00:00 max_time: 2020-08-22 00:00:00 partition_id: 202008 min_block_number: 1 max_block_number: 1 level: 0 data_version: 1 primary_key_bytes_in_memory: 16 primary_key_bytes_in_memory_allocated: 8192 is_frozen: 0 database: duyalan table: .inner.download_daily_mv engine: SummingMergeTree disk_name: default path: /data/clickhouse/node2/data/duyalan/%2Einner%2Edownload_daily_mv/202008_1_1_0/ hash_of_all_files: f4b55a88dac393d25ffe1c703cca4f6d hash_of_uncompressed_files: 58a4ab29ef36c22884ee7accd528b590 uncompressed_hash_of_compressed_files: e18b006f608580db132ed90adb46902f Row 2: ────── partition: 202008 name: 202008_2_2_0 part_type: Wide active: 1 marks: 2 rows: 5 bytes_on_disk: 421 data_compressed_bytes: 200 data_uncompressed_bytes: 120 marks_bytes: 192 modification_time: 2020-08-18 17:35:13 remove_time: 0000-00-00 00:00:00 refcount: 1 min_date: 0000-00-00 max_date: 0000-00-00 min_time: 2020-08-18 00:00:00 max_time: 2020-08-22 00:00:00 partition_id: 202008 min_block_number: 2 max_block_number: 2 level: 0 data_version: 2 primary_key_bytes_in_memory: 16 primary_key_bytes_in_memory_allocated: 8192 is_frozen: 0 database: duyalan table: .inner.download_daily_mv engine: SummingMergeTree disk_name: default path: /data/clickhouse/node2/data/duyalan/%2Einner%2Edownload_daily_mv/202008_2_2_0/ hash_of_all_files: 049d090ea65c24be8544ab86846ea9fa hash_of_uncompressed_files: 58a4ab29ef36c22884ee7accd528b590 uncompressed_hash_of_compressed_files: 9ffea93e6b9bc375c7f04374b4a4a6a9 2 rows in set. Elapsed: 0.002 sec.
可以看到, 有两个active分区202008_1_1_0
, 202008_2_2_0
我们手动OPTIMIZE
尝试合并分区
1 2 3 4 5 6 7 bj2-all-clickhouse-test-02 :) optimize table download_daily_mv; OPTIMIZE TABLE download_daily_mvOk. 0 rows in set. Elapsed: 0.004 sec.
再次查询物化视图数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 bj2-all-clickhouse-test-02 :) select * from download_daily_mv; SELECT * FROM download_daily_mv ┌─────────────────day─┬─userid─┬─downloads─┬────────bytes─┐ │ 2020 -08 -18 00 :00 :00 │ 25 │ 772 │ 38627359395 │ │ 2020 -08 -19 00 :00 :00 │ 25 │ 2880 │ 146992624149 │ │ 2020 -08 -20 00 :00 :00 │ 25 │ 2880 │ 142877311901 │ │ 2020 -08 -21 00 :00 :00 │ 25 │ 2880 │ 142449362781 │ │ 2020 -08 -22 00 :00 :00 │ 25 │ 588 │ 28875799542 │ └─────────────────────┴────────┴───────────┴──────────────┘ 5 rows in set . Elapsed: 0.001 sec.
查看private表分区情况
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 bj2-all-clickhouse-test-02 :) select * from system.parts where table='.inner.download_daily_mv'\G SELECT * FROM system.parts WHERE table = '.inner.download_daily_mv' Row 1: ────── partition: 202008 name: 202008_1_1_0 part_type: Wide active: 0 marks: 2 rows: 5 bytes_on_disk: 421 data_compressed_bytes: 200 data_uncompressed_bytes: 120 marks_bytes: 192 modification_time: 2020-08-18 17:33:51 remove_time: 2020-08-18 17:38:24 refcount: 1 min_date: 0000-00-00 max_date: 0000-00-00 min_time: 2020-08-18 00:00:00 max_time: 2020-08-22 00:00:00 partition_id: 202008 min_block_number: 1 max_block_number: 1 level: 0 data_version: 1 primary_key_bytes_in_memory: 16 primary_key_bytes_in_memory_allocated: 8192 is_frozen: 0 database: duyalan table: .inner.download_daily_mv engine: SummingMergeTree disk_name: default path: /data/clickhouse/node2/data/duyalan/%2Einner%2Edownload_daily_mv/202008_1_1_0/ hash_of_all_files: f4b55a88dac393d25ffe1c703cca4f6d hash_of_uncompressed_files: 58a4ab29ef36c22884ee7accd528b590 uncompressed_hash_of_compressed_files: e18b006f608580db132ed90adb46902f Row 2: ────── partition: 202008 name: 202008_1_2_1 part_type: Wide active: 1 marks: 2 rows: 5 bytes_on_disk: 421 data_compressed_bytes: 200 data_uncompressed_bytes: 120 marks_bytes: 192 modification_time: 2020-08-18 17:38:24 remove_time: 0000-00-00 00:00:00 refcount: 1 min_date: 0000-00-00 max_date: 0000-00-00 min_time: 2020-08-18 00:00:00 max_time: 2020-08-22 00:00:00 partition_id: 202008 min_block_number: 1 max_block_number: 2 level: 1 data_version: 1 primary_key_bytes_in_memory: 16 primary_key_bytes_in_memory_allocated: 8192 is_frozen: 0 database: duyalan table: .inner.download_daily_mv engine: SummingMergeTree disk_name: default path: /data/clickhouse/node2/data/duyalan/%2Einner%2Edownload_daily_mv/202008_1_2_1/ hash_of_all_files: fdc534a9b9aa0904cde863ee1deff532 hash_of_uncompressed_files: 58a4ab29ef36c22884ee7accd528b590 uncompressed_hash_of_compressed_files: df972eeaad3304d9a16bfa8cb46861ce Row 3: ────── partition: 202008 name: 202008_2_2_0 part_type: Wide active: 0 marks: 2 rows: 5 bytes_on_disk: 421 data_compressed_bytes: 200 data_uncompressed_bytes: 120 marks_bytes: 192 modification_time: 2020-08-18 17:35:13 remove_time: 2020-08-18 17:38:24 refcount: 1 min_date: 0000-00-00 max_date: 0000-00-00 min_time: 2020-08-18 00:00:00 max_time: 2020-08-22 00:00:00 partition_id: 202008 min_block_number: 2 max_block_number: 2 level: 0 data_version: 2 primary_key_bytes_in_memory: 16 primary_key_bytes_in_memory_allocated: 8192 is_frozen: 0 database: duyalan table: .inner.download_daily_mv engine: SummingMergeTree disk_name: default path: /data/clickhouse/node2/data/duyalan/%2Einner%2Edownload_daily_mv/202008_2_2_0/ hash_of_all_files: 049d090ea65c24be8544ab86846ea9fa hash_of_uncompressed_files: 58a4ab29ef36c22884ee7accd528b590 uncompressed_hash_of_compressed_files: 9ffea93e6b9bc375c7f04374b4a4a6a9 3 rows in set. Elapsed: 0.002 sec.
可以看到只有一个active分区了202008_1_2_1
所以对于本例中的物化视图, 在查询是仍然应该使用聚合函数聚合数据
1 2 3 4 5 6 7 8 9 SELECT day, userid, sum(downloads), sum(bytes) FROM download_no_populate_daily_mvGROUP BY day, userid