实时分析数据仓储Cloud
前置条件
- A running ClickHouse Cloud service. If you don’t have one yet, complete the ClickHouse Cloud quick start first.
uk_price_paid 表展开。
你将构建的内容
town 或 county 查询 uk_price_paid 时需要全表扫描,因为该表按 (postcode, addr1, addr2) 排序。
在本快速入门中,你将通过创建一个按 (town, date) 排序、存储相同数据的 materialized view 来解决这个问题,从而在不更改原始表的情况下实现按 town 的快速查找。
完成后,你将了解 materialized view 如何作为插入触发器工作、如何回填现有数据,以及将数据存储两次带来的磁盘空间权衡。
理解为什么需要 materialized view
你的
uk_price_paid 表按 (postcode, addr1, addr2) 排序。这意味着,当你按 postcode、addr1 或 addr2 过滤时,ClickHouse 可以跳过大量数据块;但按 town 过滤的查询则必须扫描每一行——整整 3000 万行。你可以再创建一张使用不同 ORDER BY 的表,但这样一来,每次有新数据到达时,你都得记得同时向两张表插入数据。materialized view 可以将这个过程自动化:它会监视源表中的插入操作,对这些行进行转换,并自动将结果写入目标表。可以把 materialized view 看作一种插入触发器——每当有行被插入源表时,MV 的 SELECT 查询都会针对新插入的数据块运行,并将结果插入目标表。创建目标表
materialized view 需要一个地方来存储其输出。这只是一个普通的 MergeTree 表——你可以完全控制它的 schema、这个表并没有什么特别之处——它就是一个标准的 MergeTree 表。你接下来要创建的 materialized view 只是将数据写入其中。确认该表已创建:
ORDER BY 和 PARTITION BY。创建一个按 (town, date) 排序、只包含按 town 查询所需列的表:创建 materialized view
现在创建一个 materialized view,将源表 (
uk_price_paid) 连接到目标表 (uk_price_paid_by_town) :TO uk_price_paid_by_town 子句会告诉 ClickHouse 将 SELECT 的输出写入目标表。从现在起,每当有行插入到 uk_price_paid 时,这个 MV 都会触发,并将转换后的行插入到 uk_price_paid_by_town。这里有一个重要的注意事项:materialized views 只会在 inserts 时触发。如果你删除或更新源表中的行,目标表并不会感知到——MV 不会与删除或更新保持同步。如果你需要这种同步机制,请考虑改用 projections。回填现有数据
materialized view 只会处理后续的插入操作。这会直接插入目标表中 - 此步骤不会经过 MV。完成后,验证行数是否一致:两个表的行数应当相同。
uk_price_paid 中现有的 3000 万行是在 MV 创建之前插入的,因此目标表目前还是空的。请手动回填:查询 materialized view 的目标表
现在,在目标表上运行一个按 查看查询统计信息——由于 再次查看查询统计信息——读取的行数明显更少,因为目标表按 你会同时看到
town 过滤的查询,并将其与直接查询源表的结果进行比较。首先,查询源表:town 不在源表的 ORDER BY 中,因此会读取全部 3000 万行。现在在 materialized view 的目标表上运行相同的查询:(town, date) 排序,ClickHouse 可以跳过所有与 LONDON 不匹配的数据。运行 SHOW TABLES,查看已创建的内容:uk_price_paid_by_town (目标表) 和 uk_price_paid_by_town_mv (视图) 。由于你使用了 CREATE MATERIALIZED VIEW ... TO,因此可以自行控制目标表的名称。如果省略 TO 子句,ClickHouse 会创建一个使用隐式名称的目标表 (.inner.xxx) ,这会让直接操作变得更困难。
因此,建议在创建 materialized view 时使用 TO 子句。