ClickHouse物化视图

1. ClickHouse 的物化视图是什么?

ClickHouse 的物化视图(Materialized View)是一种特殊的表,它根据预定义的查询语句自动维护数据。与传统的关系数据库中的视图不同,物化视图在物理上存储了查询结果,而不是在每次查询时重新计算。这意味着物化视图可以显著提高查询性能,特别是对于复杂的聚合查询。

2. ClickHouse 的物化视图解决了什么问题?
  1. 查询性能提升:物化视图通过预先计算并存储查询结果,减少了每次查询时的计算开销,从而显著提高了查询性能。
  2. 减少资源消耗:对于频繁执行的复杂查询,物化视图可以减少 CPU 和内存的使用,降低系统负载。
  3. 实时数据分析:物化视图可以实时更新,确保查询结果的时效性,适用于需要实时数据分析的场景。
  4. 简化查询:用户可以直接查询物化视图,而无需编写复杂的查询语句,简化了数据访问和分析的过程。
3. ClickHouse 的物化视图的应用场景
  1. 实时报表:生成实时报表,如用户行为分析、销售统计等,物化视图可以预先计算并存储聚合结果,提高报表生成的速度。
  2. 日志分析:处理和分析大规模的日志数据,如 Web 服务器日志、应用程序日志等,物化视图可以预先计算常见的聚合指标。
  3. 用户行为分析:分析用户的行为数据,如点击流、购买记录等,物化视图可以预先计算用户的行为特征。
  4. 金融数据分析:处理高频交易数据,进行风险管理、市场分析等,物化视图可以预先计算复杂的金融指标。
  5. 物联网数据分析:处理 IoT 设备产生的大量数据,如传感器数据、设备状态等,物化视图可以预先计算设备的状态和性能指标。
4. ClickHouse 的物化视图的底层原理
  1. 定义和创建

    • 物化视图通过 CREATE MATERIALIZED VIEW 语句定义,并指定一个 TO 子句,指向一个目标表。
    • 物化视图的定义中包含一个 SELECT 查询,该查询的结果会被插入到目标表中。
  2. 数据插入

    • 当数据插入到源表时,ClickHouse 会自动触发物化视图的 SELECT 查询,并将结果插入到目标表中。
    • 这个过程是异步的,确保不会影响源表的插入性能。
  3. 数据更新

    • 物化视图的目标表是普通的 ClickHouse 表,可以进行常规的查询和操作。
    • 如果需要更新物化视图的数据,可以通过删除和重建物化视图来实现。

创建物化视图

scss 复制代码
CREATE MATERIALIZED VIEW [IF NOT EXISTS] [db.]Materialized_name [TO[db.]name] [ON CLUSTER cluster] 
ENGINE = engine_name()
ORDER BY expr 
[POPULATE] 
AS SELECT ...
参数 说明
db 数据库的名称,默认为当前选择的数据库,本文以default为例。
Materialized_name 物化视图名。
TO[db.]name 将物化视图的数据写入到新表中。说明 如果需要将物化视图的数据写入新表,不能使用POPULATE关键字。
[ON CLUSTER cluster] 在每一个节点上都创建一个物化视图,固定为ON CLUSTER default
ENGINE = engine_name() 表引擎类型,具体请参见表引擎
[POPULATE] POPULATE关键字。如果创建物化视图时指定了POPULATE关键字,则在创建时将SELECT子句所指定的源表数据插入到物化视图中。不指定POPULATE关键字时,物化视图只会包含在物化视图创建后新写入源表的数据。说明 一般不推荐使用POPULATE关键字,因为在物化视图创建期间写入源表的数据将不会写入物化视图中。
SELECT ... SELECT子句。当数据写入物化视图中SELECT子句所指定的源表时,插入的数据会通过SELECT子句查询进行转换并将最终结果插入到物化视图中。说明 SELECT查询可以包含DISTINCTGROUP BYORDER BYLIMIT等,但是相应的转换是在每个插入数据块上独立执行的。

创建物化视图的限制:

1.必须指定物化视图的engine 用于数据存储

2.TO [db].[table]语法的时候,不得使用POPULATE。

3.查询语句(select)可以包含下面的子句: DISTINCT, GROUP BY, ORDER BY, LIMIT...

4.雾化视图的alter操作有些限制,操作起来不大方便。

5.若物化视图的定义使用了TO [db.]name 子语句,则可以将目标表的视图 卸载 DETACH 在装载 ATTACH

物化视图的数据更新:

1.物化视图创建好之后,若源表被写入新数据则物化视图也会同步更新

2.POPULATE 关键字决定了物化视图的更新策略: 若有POPULATE 则在创建视图的过程会将源表已经存在的数据一并导入,类似于 create table ... as 若无POPULATE 则物化视图在创建之后没有数据,只会在创建只有同步之后写入源表的数据. clickhouse 官方并不推荐使用populated,因为在创建物化视图的过程中同时写入的数据不能被插入物化视图。

3.物化视图不支持同步删除,若源表的数据不存在(删除了)则物化视图的数据仍然保留

4.物化视图是野种特殊的数据表,可以用show tables 查看

  1. ClickHouse中的物化视图的实现更像是插入触发器。 如果视图查询中存在某种汇总,则仅适用于这批新插入的数据。
  2. 对源表的现有数据进行的任何更改(例如更新,删除,删除分区等)都不会更改物化视图。
js 复制代码
CREATE TABLE order (
    order_id UInt64,
    user_id UInt64,
    order_date Date,
    amount Float64
) ENGINE = MergeTree()
ORDER BY (order_date, user_id);


drop view daily_sale_mv 

-- 创建目标表(显式定义)
CREATE TABLE daily_sale_target (
    order_date Date,
    total_sales Float64
) ENGINE = SummingMergeTree()
ORDER BY (order_date);


-- 创建指向目标表的物化视图
CREATE MATERIALIZED VIEW daily_sale_mv
TO daily_sale_target
AS
SELECT
    order_date,
    SUM(amount) AS total_sales
FROM order
GROUP BY order_date;




INSERT INTO order (order_id, user_id, order_date, amount) VALUES
(1, 101, '2023-10-01', 100.0),
(2, 102, '2023-10-01', 200.0),
(3, 103, '2023-10-02', 150.0),
(4, 104, '2023-10-02', 250.0);


INSERT INTO order (order_id, user_id, order_date, amount) VALUES
(5, 101, '2023-10-01', 100.0),
(6, 102, '2023-10-01', 200.0),
(7, 103, '2023-10-02', 150.0),
(8, 104, '2023-10-02', 250.0);

select  * from  daily_sale_target 

--两次 INSERT 操作的影响:
每次 INSERT 都会生成新的数据部分(part)
物化视图会为每个新部分单独计算聚合
这些部分尚未被合并,所以您看到的是两个部分的独立聚合结果

---   `SummingMergeTree` 不会立即合并数据,而是在后台异步合并
--手动触发合并
OPTIMIZE TABLE daily_sale_target;

ClickHouse 物化视图指定表与不指定表的区别

特性 指定目标表 (TO) 不指定目标表 目标表控制权 完全控制 有限控制 目标表引擎 可自由选择 必须声明 表结构修改 可独立修改目标表 需要重建物化视图 数据插入 可直接向目标表插入 只能通过源表触发 维护复杂度 需要维护两个对象 单一对象

SummingMergeTree 的 columns 参数使用说明

SummingMergeTree([columns]) 中的可选 columns 参数用于:

  1. 明确指定哪些列需要被求和聚合
  2. 其他未指定的列会保留第一次插入的值(或任意值,因为合并时非聚合列的值是不确定的)

例子为什么没指定

js 复制代码
CREATE TABLE daily_sale_target (
    order_date Date,
    total_sales Float64
) ENGINE = SummingMergeTree()
ORDER BY (order_date);
没有指定 `columns` 参数是因为:

1.  表结构非常简单,只有两个列
1.  `order_date` 是排序键,自然成为聚合键
1.  `total_sales` 是唯一的数值列,会自动被识别为需要求和的列

改进后:

js 复制代码
CREATE TABLE daily_sale_target (
    order_date Date,
    total_sales Float64
) ENGINE = SummingMergeTree(['total_sales'])
ORDER BY (order_date);

应该指定 columns 参数的场景

当表中有多个数值列,但只想对其中部分列求和时,就需要明确指定:

js 复制代码
CREATE TABLE example (
    date Date,
    user_id UInt32,
    clicks UInt32,
    views UInt32,
    revenue Float64
) ENGINE = SummingMergeTree(['clicks', 'views', 'revenue'])
ORDER BY (date, user_id);
相关推荐
小句26 分钟前
MySQL索引
数据库·mysql
TDengine (老段)1 小时前
TDengine IDMP 基本功能(3.数据三化处理)
大数据·数据库·物联网·ai·语言模型·时序数据库·tdengine
GreatSQL2 小时前
GreatSQL备份报错"PROCESS权限不足"分析与解决
数据库
专注VB编程开发20年3 小时前
C#教程之NPOI读写excel文件XLS,XLSX格式
数据库·microsoft·c#·excel·xlsx·xls
winfield8213 小时前
间隙锁(Gap Lock)
数据库·mysql
TDengine (老段)13 小时前
TDengine IDMP 快速体验(方式二 通过 docker)
大数据·数据库·docker·ai·时序数据库·tdengine·涛思数据
CANI_PLUS14 小时前
ESP32将DHT11温湿度传感器采集的数据上传到XAMPP的MySQL数据库
android·数据库·mysql
国王不在家17 小时前
3.5-非关系型数据库-反规范化-sql语言
数据库·nosql
Code季风19 小时前
如果缓存和数据库更新失败,如何实现最终一致性?
数据库·分布式·缓存·微服务·性能优化