ClickHouse--11--物化视图

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录

  • 1.物化视图
      • 什么是物化视图?
    • 1.1 普通视图
    • ==1.2 物化视图==
    • 1.3 优缺点
    • 1.4 基本语法
    • 1.5 在生产环境中创建物化视图
    • 1.6 AggregatingMergeTree 表引擎
      • 3.1 概念
      • 3.2 AggregatingMergeTree 建表语句
      • 3.3 搭配使用 案例
  • 物化视图--- 案例1
    • 1.原始数据表
    • 物化视图---方式1:
    • 物化视图---方式2:
      • 为什么查询物化视图 还要GROUP BY +sum ?
        • ==在使用 MV 的聚合引擎时,也需要按照聚合查询 配合 GROUP BY 来写sql,因为聚合时机不可控==
    • 物化视图---方式3:
  • 物化视图--- 案例2
    • 1.原始数据表----以Wikistat的10亿行数据集为例:
    • 2.创建物化视图
    • 3.填充数据
    • 4.测试查询 物化视图
      • 为什么查询物化视图 还要GROUP BY +sum ?
        • ==在使用 MV 的聚合引擎时,也需要按照聚合查询 配合 GROUP BY 来写sql,因为聚合时机不可控==
    • 5.更新物化视图中的数据
        • ==在使用 MV 的聚合引擎时,也需要按照聚合查询 配合 GROUP BY 来写sql,因为聚合时机不可控==
    • 6.使用物化视图加速聚合(AggregatingMergeTree引擎)
        • ==在使用 MV 的聚合引擎时,也需要按照聚合查询 配合 GROUP BY 来写sql,因为聚合时机不可控==
    • 7.验证和过滤数据
    • 8.数据路由到表格
    • 9.数据转换
    • 10.物化视图和JOIN操作
        • ClickHouse博客; [https://blog.csdn.net/ClickHouseDB?type=blog](https://blog.csdn.net/ClickHouseDB?type=blog)


1.物化视图

ClickHouse 中视图分为普通视图和物化视图,两者区别如图所示

在这里插入图片描述
在这里插入图片描述

什么是物化视图?

  • 物化视图是一种特殊的触发器,当数据被插入时,它将数据上执行 SELECT 查询的结果存储为到一个目标表中:

在这里插入图片描述

1.1 普通视图

  • 普通视图不存储数据,它只是一层 select 查询映射,类似于表的别名或者同义词,能简化查询,对原有表的查询性能没有增强的作用,具体性能依赖视图定义的语句,
  • 当从视图中查询时,视图只是替换了映射的查询语句。普通视图当基表删除后不可用。
    在这里插入图片描述

1.2 物化视图

  • 物化视图是查询结果集的一份持久化存储,所以它与普通视图完全不同,而非常趋近于表。”查询结果集”的范围很宽泛,可以是基础表中部分数据的一份简单拷贝,也可以是多 表 join 之后产生的结果或其子集,或者原始数据的聚合指标等等。
  • 物化视图创建好之后,若源表被写入新数据则物化视图也会同步更新,POPULATE 关键字决定了物化视图的更新策略,若有 POPULATE 则在创建视图的过程会将源表已经存在的 数据一并导入,类似于 create table … as,若无 POPULATE则物化视图在创建之后 没有数据,只会在创建只有同步之后写入源表的数据,clickhouse 官方并不推荐使用 populated,因为在创建物化视图的过程中同时写入的数据不能被插入物化视图。
  • 物化视图是种特殊的数据表,创建时需要指定引擎,可以用 show tables 查看。另外,物化视图不支持 alter 操作。
  • 产生物化视图的过程就叫做“物化”(materialization),广义地讲,物化视图是 数据库中的预计算逻辑+显式缓存,典型的空间换时间思路,所以用得好的话,它可以避免 对基础表的频繁查询并复用结果,从而显著提升查询的性能。
    在这里插入图片描述

1.3 优缺点

优点:查询速度快

缺点:写入过程中消耗较多机器资源,比如带宽占满,存储增加等。本质是一个流式数据的使用场景,是累加式的技术,所以要用历史数据做去重、去核的分析操作不太好用。

1.4 基本语法

创建一个隐藏的目标表来保存视图数据,表名默认是.inner.物化视图名。如果加了TO表名,将保存到显式的表。

create [materialized] view [if not exists] [db.]table_name [to [db.]name] 
[engine = engine] [populate]
as select ...

限制条件:

  1. 必须指定物化视图的engine用于数据存储(要么是物化视图,要么是指定的显式表)
  2. to [db.]table的时候,不得使用populate
  3. 查询语句可以包含子句:distinct, group by, order by, limit …

1.5 在生产环境中创建物化视图

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

1.6 AggregatingMergeTree 表引擎

在这里插入图片描述

3.1 概念

  • 该表引擎继承自 MergeTree,可以使用 AggregatingMergeTree表来做增量数据统计聚合。如果要按一组规则来合并减少行数,则使AggregatingMergeTree 是合适的。AggregatingMergeTree 是通过预先定义的聚合函数计算数据并通过二进制的格式存入表内。
  • 与 SummingMergeTree 的区别在于:SummingMergeTree 对非主键列进行 sum 聚 合,而 AggregatingMergeTree 则可以指定各种聚合函数。对某些字段需要进行聚合时, 需要在创建表字段时指定成 AggregateFunction 类型

3.2 AggregatingMergeTree 建表语句

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

3.3 搭配使用 案例

  • 以上方式使用 AggregatingMergeTree 表引擎比较不方便,更多情况下,我们将AggregatingMergeTree 作为物化视图的表引擎与 MergeeTree 搭配使用

示例:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

物化视图— 案例1

1.原始数据表

-- 建表
CREATE TABLE test.tb_mtview_counter (
      create_time DateTime DEFAULT now(),
      device UInt32,
      value Float32
) 
ENGINE=MergeTree
PARTITION BY toYYYYMM(create_time)
ORDER BY (device, create_time);

  • 插入数据
-- 插入数据
INSERT INTO test.tb_mtview_counter
SELECT
      toDateTime('2015-01-01 00:00:00') + toInt64(number/10) AS create_time,
      (number % 10) + 1 AS device,
      (device * 3) +  (number/10000) + (rand() % 53) * 0.1 AS value
FROM system.numbers LIMIT 100000;

-- 查询源表
SELECT
    toStartOfMonth(create_time) as day,
    device,
    count(*) as count,
    sum(value) as sum,
    max(value) as max,
    min(value) as min,
    avg(value) as avg
from test.tb_mtview_counter 
GROUP BY device, day
ORDER BY day, device;

  • 数据表查询结果如下:
┌────────day─┬─device─┬─count─┬────────────────sum─┬─────max─┬─────min─┬────────────────avg─┐
│ 2015-01-01110000106363.5000033378618.0963.02110.636350000333787 │
│ 2015-01-01210000136010.9000520706221.10116.170113.601090005207062 │
│ 2015-01-01310000166312.000029563924.19429.002216.63120000295639 │
│ 2015-01-01410000195977.0000085830727.178312.000319.597700000858307 │
│ 2015-01-01510000226182.1999397277830.182415.028422.61821999397278 │
│ 2015-01-01610000256159.1999626159733.079518.029525.615919996261596 │
│ 2015-01-01710000286113.200002670336.197621.101628.61132000026703 │
│ 2015-01-01810000315845.900049209639.088724.123731.58459000492096 │
│ 2015-01-01910000345891.3000373840342.042827.004834.589130003738404 │
│ 2015-01-011010000376212.099996566845.078930.000937.62120999965668 │
└────────────┴────────┴───────┴────────────────────┴─────────┴─────────┴────────────────────┘

物化视图—方式1:

-- 创建物化视图 -- 没有to table时必须有engine
CREATE MATERIALIZED VIEW test.tb_mtview_counter_daily_mv
ENGINE = SummingMergeTree()
PARTITION BY toYYYYMM(day) ORDER BY (device, day)
AS SELECT
    toStartOfMonth(create_time) as day,
    device,
    count(*) as count,
    sum(value) as sum,
    max(value) as max,
    min(value) as min,
    avg(value) as avg
FROM test.tb_mtview_counter
WHERE create_time >= toDate('2016-01-01 00:00:00')
GROUP BY device, day
ORDER BY device, day;

  • 查询物化视图
-- 查询物化视图
SELECT
  device, day, count, sum, max, min, avg
FROM test.tb_mtview_counter_daily_mv;

查询结果,物化视图中此时没有数据,为何?这是因为未使用 populate 关键字,该关键字并不推荐使用。

思考:为什么建表要加条件 WHERE create_time >= toDate(‘2016-01-01 00:00:00’) ?

在后续的测试中发现其实不加也没有问题,猜测加过滤条件是为了确保建表时数据无法被导入,从而确保数据不会出错。

  • 向源表插入数据
-- 源表插入数据
INSERT INTO test.tb_mtview_counter
SELECT
      toDateTime('2017-01-01 00:00:00') + toInt64(number/10) AS create_time,
      (number % 10) + 1 AS device,
      (device * 3) +  (number/10000) + (rand() % 53) * 0.1 AS value
FROM system.numbers LIMIT 100000;

-- 查询物化视图
SELECT
  device, day, count, sum, max, min, avg
FROM test.tb_mtview_counter_daily_mv;

  • 结果如下:
┌─device─┬────────day─┬─count─┬────────────────sum─┬─────max─┬─────min─┬────────────────avg─┐
│      12017-01-0110000106250.9000189304418.1533.12210.625090001893044 │
│      22017-01-0110000135986.0999360084521.18516.105113.598609993600846 │
│      32017-01-0110000165927.1999521255524.18629.203216.592719995212555 │
│      42017-01-0110000195965.700024604827.174312.019319.59657000246048 │
│      52017-01-0110000226203.9000482559230.122415.005422.62039000482559 │
│      62017-01-0110000256157.800012588533.191518.002525.61578000125885 │
│      72017-01-0110000285870.000099182136.157621.003628.587000009918214 │
│      82017-01-0110000315986.5999450683639.147724.026731.598659994506836 │
│      92017-01-0110000346104.499822616642.197827.002834.610449982261656 │
│     102017-01-0110000376108.500066757245.180930.005937.61085000667572 │
└────────┴────────────┴───────┴────────────────────┴─────────┴─────────┴────────────────────┘

  • 向物化视图插入数据
-- 向物化视图插入数据
insert into test.tb_mtview_counter_daily_mv
SELECT
    toStartOfMonth(create_time) as day,
    device,
    count(*) as count,
    sum(value) as sum,
    max(value) as max,
    min(value) as min,
    avg(value) as avg
from test.tb_mtview_counter where create_time < toDate('2016-01-01 00:00:00')
GROUP BY device, day
ORDER BY device, day;

-- 查询物化视图
SELECT
  device, day, count, sum, max, min, avg
FROM test.tb_mtview_counter_daily_mv;

  • 结果如下:
┌─device─┬────────day─┬─count─┬────────────────sum─┬─────max─┬─────min─┬────────────────avg─┐
│      12017-01-0110000106250.9000189304418.1533.12210.625090001893044 │
│      22017-01-0110000135986.0999360084521.18516.105113.598609993600846 │
│      32017-01-0110000165927.1999521255524.18629.203216.592719995212555 │
│      42017-01-0110000195965.700024604827.174312.019319.59657000246048 │
│      52017-01-0110000226203.9000482559230.122415.005422.62039000482559 │
│      62017-01-0110000256157.800012588533.191518.002525.61578000125885 │
│      72017-01-0110000285870.000099182136.157621.003628.587000009918214 │
│      82017-01-0110000315986.5999450683639.147724.026731.598659994506836 │
│      92017-01-0110000346104.499822616642.197827.002834.610449982261656 │
│     102017-01-0110000376108.500066757245.180930.005937.61085000667572 │
└────────┴────────────┴───────┴────────────────────┴─────────┴─────────┴────────────────────┘
┌─device─┬────────day─┬─count─┬────────────────sum─┬─────max─┬─────min─┬────────────────avg─┐
│      12015-01-0110000105885.8000040054318.1663.02110.588580000400544 │
│      22015-01-0110000136100.1999921798721.03616.039113.610019999217988 │
│      32015-01-0110000166083.2999429702824.09429.043216.608329994297026 │
│      42015-01-0110000196134.9000501632727.178312.036319.613490005016327 │
│      52015-01-0110000225946.5999670028730.199415.158422.594659996700287 │
│      62015-01-0110000256283.3999137878433.190518.013525.628339991378784 │
│      72015-01-0110000286232.7000560760535.991621.006628.623270005607605 │
│      82015-01-0110000315966.500055313139.153724.057731.596650005531313 │
│      92015-01-0110000345799.699810028142.138827.053834.579969981002805 │
│     102015-01-0110000375820.099843978945.150930.077937.582009984397885 │
└────────┴────────────┴───────┴────────────────────┴─────────┴─────────┴────────────────────┘

  • 向源表插入同分区数据
  • 插入一个同分区(对物化视图而言),但日期不同的数据。对比查询源表结果,与物化视图的结果有什么区别
-- 源表插入数据
INSERT INTO test.tb_mtview_counter
SELECT
      toDateTime('2017-01-02 00:00:00') + toInt64(number/10) AS create_time,
      (number % 10) + 1 AS device,
      (device * 3) +  (number/10000) + (rand() % 53) * 0.1 AS value
FROM system.numbers LIMIT 100000;

-- 查询物化视图
SELECT
  device, day, count, sum, max, min, avg
FROM test.tb_mtview_counter_daily_mv;

  • 结果如下:
    在这里插入图片描述
┌─device─┬────────day─┬─count─┬────────────────sum─┬─────max─┬─────min─┬────────────────avg─┐
│      12015-01-0110000105885.8000040054318.1663.02110.588580000400544 │
│      22015-01-0110000136100.1999921798721.03616.039113.610019999217988 │
│      32015-01-0110000166083.2999429702824.09429.043216.608329994297026 │
│      42015-01-0110000196134.9000501632727.178312.036319.613490005016327 │
│      52015-01-0110000225946.5999670028730.199415.158422.594659996700287 │
│      62015-01-0110000256283.3999137878433.190518.013525.628339991378784 │
│      72015-01-0110000286232.7000560760535.991621.006628.623270005607605 │
│      82015-01-0110000315966.500055313139.153724.057731.596650005531313 │
│      92015-01-0110000345799.699810028142.138827.053834.579969981002805 │
│     102015-01-0110000375820.099843978945.150930.077937.582009984397885 │
└────────┴────────────┴───────┴────────────────────┴─────────┴─────────┴────────────────────┘
┌─device─┬────────day─┬─count─┬────────────────sum─┬─────max─┬─────min─┬────────────────avg─┐
│      12017-01-0110000106250.9000189304418.1533.12210.625090001893044 │
│      22017-01-0110000135986.0999360084521.18516.105113.598609993600846 │
│      32017-01-0110000165927.1999521255524.18629.203216.592719995212555 │
│      42017-01-0110000195965.700024604827.174312.019319.59657000246048 │
│      52017-01-0110000226203.9000482559230.122415.005422.62039000482559 │
│      62017-01-0110000256157.800012588533.191518.002525.61578000125885 │
│      72017-01-0110000285870.000099182136.157621.003628.587000009918214 │
│      82017-01-0110000315986.5999450683639.147724.026731.598659994506836 │
│      92017-01-0110000346104.499822616642.197827.002834.610449982261656 │
│     102017-01-0110000376108.500066757245.180930.005937.61085000667572 │
└────────┴────────────┴───────┴────────────────────┴─────────┴─────────┴────────────────────┘
┌─device─┬────────day─┬─count─┬────────────────sum─┬─────max─┬─────min─┬────────────────avg─┐
│      12017-01-0110000106321.7000019550318.1963.00710.632170000195503 │
│      22017-01-0110000135868.999980926521.15016.004113.586899998092651 │
│      32017-01-0110000165784.1999101638824.15729.055216.57841999101639 │
│      42017-01-0110000196065.5000419616727.188312.076319.606550004196166 │
│      52017-01-0110000225919.3999738693230.137415.028422.591939997386934 │
│      62017-01-0110000256105.4000186920233.186518.085525.6105400018692 │
│      72017-01-0110000286283.8001251220736.198621.099628.628380012512206 │
│      82017-01-0110000316006.700065612839.121724.016731.60067000656128 │
│      92017-01-0110000345796.39997482342.177827.026834.5796399974823 │
│     102017-01-0110000376074.899896621745.162930.064937.60748998966217 │
└────────┴────────────┴───────┴────────────────────┴─────────┴─────────┴────────────────────┘


数据暂时未合并,可以执行 optimize 来手动进行合并(就算不手动执行,未来某个时刻也会自动合并)

optimize table test.tb_mtview_counter_daily_mv final;
  • 合并后查询结果:
┌─device─┬────────day─┬─count─┬────────────────sum─┬─────max─┬─────min─┬────────────────avg─┐
│      12015-01-0110000105885.8000040054318.1663.02110.588580000400544 │
│      22015-01-0110000136100.1999921798721.03616.039113.610019999217988 │
│      32015-01-0110000166083.2999429702824.09429.043216.608329994297026 │
│      42015-01-0110000196134.9000501632727.178312.036319.613490005016327 │
│      52015-01-0110000225946.5999670028730.199415.158422.594659996700287 │
│      62015-01-0110000256283.3999137878433.190518.013525.628339991378784 │
│      72015-01-0110000286232.7000560760535.991621.006628.623270005607605 │
│      82015-01-0110000315966.500055313139.153724.057731.596650005531313 │
│      92015-01-0110000345799.699810028142.138827.053834.579969981002805 │
│     102015-01-0110000375820.099843978945.150930.077937.582009984397885 │
└────────┴────────────┴───────┴────────────────────┴─────────┴─────────┴────────────────────┘
┌─device─┬────────day─┬─count─┬────────────────sum─┬───────max─┬───────min─┬────────────────avg─┐
│      12017-01-0120000212572.6000208854736.3496.128999721.257260002088547 │
│      22017-01-0120000271855.0999169349742.335212.109227.185509991693497 │
│      32017-01-0120000331711.399862289448.343418.258433.171139986228944 │
│      42017-01-0120000392031.2000665664754.362624.095639.20312000665665 │
│      52017-01-0120000452123.3000221252460.259830.033845.212330002212525 │
│      62017-01-0120000512263.200031280566.37800636.08851.22632000312805 │
│      72017-01-0120000572153.800224304272.356242.103257.21538002243042 │
│      82017-01-0120000631993.300010681278.269448.043463.19933000106812 │
│      92017-01-0120000691900.899797439684.37559554.02960269.19008997974396 │
│     102017-01-0120000752183.399963378990.34379660.070875.21833999633789 │
└────────┴────────────┴───────┴────────────────────┴───────────┴───────────┴────────────────────┘

从结果可以看到,分区数据执行了合并,而且合并是依据order by字段进行的,除了device和day以外的字段全部自动求和了,这个就是SummingMergeTree的特性。

物化视图—方式2:

在前一种物化视图中,我们看到,SummingMergeTree()对常规的除了求和以外的聚合函数支持并不好,在本例中,我们采用 聚合函数名称加-State后缀 的函数形式来获取聚合值,通过例子来了解具体是怎么一回事。

官网介绍:以-State后缀的函数总是返回AggregateFunction类型的数据的中间状态。对于SELECT而言AggregateFunction类型总是以特定的二进制形式展现在所有的输出格式中。
参考:https://clickhouse.com/docs/zh/sql-reference/data-types/aggregatefunction

-- 没有to table时必须有engine
CREATE MATERIALIZED VIEW test.tb_mtview_counter_daily_mv2
ENGINE = SummingMergeTree()
PARTITION BY toYYYYMM(day) ORDER BY (device, day)
AS SELECT
    toStartOfMonth(create_time) as day,
    device,
    count(*) as count,
    sum(value) as sum,
    maxState(value) AS max_value_state,
    minState(value) AS min_value_state,
    avgState(value) AS avg_value_state
FROM test.tb_mtview_counter
WHERE create_time >= toDate('2016-01-01 00:00:00')
GROUP BY device, day
ORDER BY device, day;

  • 源表新增数据
INSERT INTO test.tb_mtview_counter
SELECT
      toDateTime('2016-01-01 00:00:00') + toInt64(number/10) AS create_time,
      (number % 10) + 1 AS device,
      (device * 3) +  (number/10000) + (rand() % 53) * 0.1 AS value
FROM system.numbers LIMIT 100000;

-- 查询源表
SELECT
    toStartOfMonth(create_time) as day,
    device,
    count(*) as count,
    sum(value) as sum,
    max(value) as max,
    min(value) as min,
    avg(value) as avg
from test.tb_mtview_counter 
GROUP BY device, day
ORDER BY day, device;

-- 查询物化视图
SELECT
  day, device, 
  sum(count) AS count,
  sum(sum) as sum, 
  maxMerge(max_value_state) AS max,
  minMerge(min_value_state) AS min,
  avgMerge(avg_value_state) AS avg
FROM test.tb_mtview_counter_daily_mv2
GROUP BY device, day
ORDER BY day, device;

-- 显示当前数据库所有表
show tables from test;

  • 二者结果均为:
┌────────day─┬─device─┬─count─┬────────────────sum─┬─────max─┬─────min─┬────────────────avg─┐
│ 2016-01-01110000105755.7999913692518.113.00410.575579999136925 │
│ 2016-01-01210000136052.3999481201221.19716.041113.605239994812012 │
│ 2016-01-01310000165888.8000183105524.19529.001216.588880001831054 │
│ 2016-01-01410000196001.4000816345227.156312.022319.600140008163454 │
│ 2016-01-01510000225971.7999095916730.092415.007422.597179990959166 │
│ 2016-01-01610000256052.8000469207833.168518.075525.605280004692077 │
│ 2016-01-01710000286267.60006904636.166621.009628.6267600069046 │
│ 2016-01-01810000315901.299957275439.111724.054731.59012999572754 │
│ 2016-01-01910000345774.4999389648442.167827.134834.57744999389649 │
│ 2016-01-011010000375901.9999046325745.145930.000937.590199990463255 │
└────────────┴────────┴───────┴────────────────────┴─────────┴─────────┴────────────────────┘

为什么查询物化视图 还要GROUP BY +sum ?

  • 由于SummingMergeTree引擎是异步的(这节省了资源并减少了对查询处理的影响),所以某些值可能尚未被计算,我们仍然需要在此使用 GROUP BY 。
在使用 MV 的聚合引擎时,也需要按照聚合查询 配合 GROUP BY 来写sql,因为聚合时机不可控

物化视图—方式3:

  1. 一般需要先建一张表
  2. 再采用使用to db.table方法,将物化视图的实体表指定为特定名称的表。
-- 先建一张表
CREATE TABLE test.tb_mtview_counter_daily (
	day Date,
	device UInt32,
	count UInt64,
    sum Float64,
    max_value_state AggregateFunction(max, Float32),
    min_value_state AggregateFunction(min, Float32),
    avg_value_state AggregateFunction(avg, Float32)
)
ENGINE = SummingMergeTree()
PARTITION BY toYYYYMM(day)
ORDER BY (device, day);

-- 将物化视图的实体表指定为特定名称的表
CREATE MATERIALIZED VIEW test.tb_mtview_counter_daily_mv3
TO test.tb_mtview_counter_daily
AS SELECT
    toStartOfMonth(create_time) as day,
    device,
    count(*) as count,
    sum(value) as sum,
    maxState(value) AS max_value_state,
    minState(value) AS min_value_state,
    avgState(value) AS avg_value_state
FROM test.tb_mtview_counter
WHERE create_time >= toDate('2019-01-01 00:00:00')
GROUP BY device, day
ORDER BY device, day;

  • 向源表导入数据
INSERT INTO test.tb_mtview_counter
SELECT
      toDateTime('2020-01-01 00:00:00') + toInt64(number/10) AS create_time,
      (number % 10) + 1 AS device,
      (device * 3) +  (number/10000) + (rand() % 53) * 0.1 AS value
FROM system.numbers LIMIT 10000;

-- 查询物化视图实体表
SELECT
    device, day, 
    sum(count) AS count,
    sum(sum) as sum, 
    maxMerge(max_value_state) AS max,
    minMerge(min_value_state) AS min,
    avgMerge(avg_value_state) AS avg
FROM test.tb_mtview_counter_daily
GROUP BY device, day
ORDER BY day, device;

-- 查询物化视图
SELECT
    device, day, 
    sum(count) AS count,
    sum(sum) as sum, 
    maxMerge(max_value_state) AS max,
    minMerge(min_value_state) AS min,
    avgMerge(avg_value_state) AS avg
FROM test.tb_mtview_counter_daily_mv3
GROUP BY device, day
ORDER BY day, device;

结果二者查询的结果一致:

┌─device─┬────────day─┬─count─┬────────────────sum─┬─────max─┬─────min─┬────────────────avg─┐
│      12020-01-0110006121.6999993324289.1653.1116.121699999332428 │
│      22020-01-0110009138.19999694824212.17416.00419.138199996948241 │
│      32020-01-01100012132.70000171661415.18629.014212.132700001716614 │
│      42020-01-01100015055.10000228881818.176312.016315.055100002288818 │
│      52020-01-01100018032.10001277923621.145415.052418.032100012779235 │
│      62020-01-01100021153.60003852844224.172518.126521.15360003852844 │
│      72020-01-01100024141.30000495910627.123621.119624.141300004959106 │
│      82020-01-01100027071.19997596740730.115724.098727.071199975967406 │
│      92020-01-01100030123.69999313354533.141827.052830.123699993133545 │
│     102020-01-01100033096.89997863769536.094930.050933.096899978637694 │
└────────┴────────────┴───────┴────────────────────┴─────────┴─────────┴────────────────────┘

物化视图— 案例2

1.原始数据表----以Wikistat的10亿行数据集为例:

CREATE TABLE wikistat
(
    `time` DateTime CODEC(Delta(4), ZSTD(1)),
    `project` LowCardinality(String),
    `subproject` LowCardinality(String),
    `path` String,
    `hits` UInt64
)
ENGINE = MergeTree
ORDER BY (path, time);
 
Ok.
 
INSERT INTO wikistat SELECT *
FROM s3('https://ClickHouse-public-datasets.s3.amazonaws.com/wikistat/partitioned/wikistat*.native.zst') LIMIT 1e9
  • 假设我们经常查询某个日期最受欢迎的项目:
SELECT
    project,
    sum(hits) AS h
FROM wikistat
WHERE date(time) = '2015-05-01'
GROUP BY project
ORDER BY h DESC
LIMIT 10
  • 这个查询在测试实例上需要15秒来完成:
┌─project─┬────────h─┐
│ en      │ 34521803 │
│ es      │  4491590 │
│ de      │  4490097 │
│ fr      │  3390573 │
│ it      │  2015989 │
│ ja      │  1379148 │
│ pt      │  1259443 │
│ tr      │  1254182 │
│ zh      │   988780 │
│ pl      │   985607 │
└─────────┴──────────┘
 
10 rows in set. Elapsed: 14.869 sec. Processed 972.80 million rows, 10.53 GB (65.43 million rows/s., 708.05 MB/s.)

2.创建物化视图

CREATE TABLE wikistat_top_projects
(
    `date` Date,
    `project` LowCardinality(String),
    `hits` UInt32
)
ENGINE = SummingMergeTree
ORDER BY (date, project);
 
Ok.
 
CREATE MATERIALIZED VIEW wikistat_top_projects_mv TO wikistat_top_projects AS
SELECT
    date(time) AS date,
    project,
    sum(hits) AS hits
FROM wikistat
GROUP BY
    date,
    project;

在这两个查询中:

  • wikistat_top_projects 是我们要用来保存物化视图的表的名称,
  • wikistat_top_projects_mv 是物化视图本身(触发器)的名称,
  • 我们使用了SummingMergeTree表引擎,因为我们希望为每个date/project汇总hits值,
  • AS 后面的内容是构建物化视图的查询。

我们可以创建任意数量的物化视图,但每一个新的物化视图都是额外的存储负担,因此保持总数合理,即每个表下的物化视图数目控制在10个以内。

3.填充数据

现在,我们使用与 wikistat 表相同的查询来填充物化视图的目标表:

INSERT INTO wikistat_top_projects SELECT
    date(time) AS date,
    project,
    sum(hits) AS hits
FROM wikistat
GROUP BY
    date,
    project

请注意,这只花费了ClickHouse 3ms来产生相同的结果,而原始查询则花费了15秒

4.测试查询 物化视图

由于 wikistat_top_projects 是一个表,我们可以利用ClickHouse的SQL功能进行查询:

SELECT
    project,
    sum(hits) hits
FROM wikistat_top_projects
WHERE date = '2015-05-01'
GROUP BY project
ORDER BY hits DESC
LIMIT 10
 
┌─project─┬─────hits─┐
│ en      │ 34521803 │
│ es      │  4491590 │
│ de      │  4490097 │
│ fr      │  3390573 │
│ it      │  2015989 │
│ ja      │  1379148 │
│ pt      │  1259443 │
│ tr      │  1254182 │
│ zh      │   988780 │
│ pl      │   985607 │
└─────────┴──────────┘
 
10 rows in set. Elapsed: 0.003 sec. Processed 8.19 thousand rows, 101.81 KB (2.83 million rows/s., 35.20 MB/s.)

请注意,这只花费了ClickHouse 3ms来产生相同的结果,而原始查询则花费了15秒

为什么查询物化视图 还要GROUP BY +sum ?

  • 由于SummingMergeTree引擎是异步的(这节省了资源并减少了对查询处理的影响),所以某些值可能尚未被计算,我们仍然需要在此使用 GROUP BY 。
在使用 MV 的聚合引擎时,也需要按照聚合查询 配合 GROUP BY 来写sql,因为聚合时机不可控

5.更新物化视图中的数据

  • 物化视图的最强大的特点是当向源表插入数据时,目标表中的数据会使用 SELECT 语句自动更新:
    在这里插入图片描述
  • 因此,我们不需要额外地刷新物化视图中的数据 - ClickHouse会自动完成一切操作。假设我们向 wikistat 表插入新数据:
INSERT INTO wikistat
VALUES(now(), 'test', '', '', 10),
      (now(), 'test', '', '', 10),
      (now(), 'test', '', '', 20),
      (now(), 'test', '', '', 30);

现在,让我们查询物化视图的目标表,以验证 hits 列是否已正确汇总。我们使用FINAL修饰符以确保SummingMergeTree引擎返回汇总的hits,而不是单个、未合并的行:

SELECT hits
FROM wikistat_top_projects
FINAL
WHERE (project = 'test') AND (date = date(now()))
 
┌─hits─┐
│   70 │
└──────┘
 
1 row in set. Elapsed: 0.005 sec. Processed 7.15 thousand rows, 89.37 KB (1.37 million rows/s., 17.13 MB/s.)
  • 在生产环境中,避免在大表上使用 FINAL ,并始终优先使用 sum(hits)。还请检查optimize_on_insert参数设置,该选项控制如何合并插入的数据。
在使用 MV 的聚合引擎时,也需要按照聚合查询 配合 GROUP BY 来写sql,因为聚合时机不可控

6.使用物化视图加速聚合(AggregatingMergeTree引擎)

  • 如前一节所示,物化视图是一种提高查询性能的方法。对于分析查询,常见的聚合操作不仅仅是前面示例中展示的 sum() 。SummingMergeTree非常适用于计算汇总数据,但还有更高级的聚合可以使用AggregatingMergeTree引擎进行计算。

假设我们经常执行以下类型的查询:

SELECT
    toDate(time) AS date,
    min(hits) AS min_hits_per_hour,
    max(hits) AS max_hits_per_hour,
    avg(hits) AS avg_hits_per_hour
FROM wikistat
WHERE project = 'en'
GROUP BY date
  • 这为我们提供了给定项目的每日点击量的月最小值、最大值和平均值:
┌───────date─┬─min_hits_per_hour─┬─max_hits_per_hour─┬──avg_hits_per_hour─┐
│ 2015-05-011368024.586310181621408 │
│ 2015-05-021233314.241388590780171 │
│ 2015-05-031246784.317835245126423...
└────────────┴───────────────────┴───────────────────┴────────────────────┘
 
38 rows in set. Elapsed: 8.970 sec. Processed 994.11 million rows

在这里插入图片描述

  • 在我们的示例中,我们将使用 min 、 max 和 avg 状态。在新物化视图的目标表中,我们将使用AggregateFunction 类型存储聚合状态而不是值
CREATE TABLE wikistat_daily_summary
(
    `project` String,
    `date` Date,
    `min_hits_per_hour` AggregateFunction(min, UInt64),
    `max_hits_per_hour` AggregateFunction(max, UInt64),
    `avg_hits_per_hour` AggregateFunction(avg, UInt64)
)
ENGINE = AggregatingMergeTree
ORDER BY (project, date);
 
Ok.
 
CREATE MATERIALIZED VIEW wikistat_daily_summary_mv
TO wikistat_daily_summary AS
SELECT
    project,
    toDate(time) AS date,
    minState(hits) AS min_hits_per_hour,
    maxState(hits) AS max_hits_per_hour,
    avgState(hits) AS avg_hits_per_hour
FROM wikistat
GROUP BY project, date
  • 现在,让我们为它填充数据:
INSERT INTO wikistat_daily_summary SELECT
    project,
    toDate(time) AS date,
    minState(hits) AS min_hits_per_hour,
    maxState(hits) AS max_hits_per_hour,
    avgState(hits) AS avg_hits_per_hour
FROM wikistat
GROUP BY project, date
 
0 rows in set. Elapsed: 33.685 sec. Processed 994.11 million rows
  • 在查询时,我们使用相应的 Merge 组合器来检索值:
在使用 MV 的聚合引擎时,也需要按照聚合查询 配合 GROUP BY 来写sql,因为聚合时机不可控
SELECT
    date,
    minMerge(min_hits_per_hour) min_hits_per_hour,
    maxMerge(max_hits_per_hour) max_hits_per_hour,
    avgMerge(avg_hits_per_hour) avg_hits_per_hour
FROM wikistat_daily_summary
WHERE project = 'en'
GROUP BY date

请注意,我们得到的结果完全相同,但速度快了数千倍:

┌───────date─┬─min_hits_per_hour─┬─max_hits_per_hour─┬──avg_hits_per_hour─┐
│ 2015-05-011368024.586310181621408 │
│ 2015-05-021233314.241388590780171 │
│ 2015-05-031246784.317835245126423...
└────────────┴───────────────────┴───────────────────┴────────────────────┘
 
32 rows in set. Elapsed: 0.005 sec. Processed 9.54 thousand rows, 1.14 MB (1.76 million rows/s., 209.01 MB/s.)

任何聚合函数都可以作为一个聚合物化视图的一部分与State/Merge组合器一起使用。

7.验证和过滤数据

使用物化视图的另一个流行的示例是在插入后立即处理数据。数据验证就是一个很好的例子。
在这里插入图片描述
假设我们想要滤掉所有包含不需要的符号的path,再保存到结果表中。我们的表中有大约1%这样的值:

SELECT count(*)
FROM wikistat
WHERE NOT match(path, '[a-z0-9\\-]')
LIMIT 5
 
┌──count()─┐
│ 12168918 │
└──────────┘
 
1 row in set. Elapsed: 46.324 sec. Processed 994.11 million rows, 28.01 GB (21.46 million rows/s., 604.62 MB/s.)

为了实现验证过滤,我们需要两个表 - 一个带有所有数据的表和一个只带有干净数据的表。

  1. 物化视图的目标表将扮演一个只带有干净数据的最终表的角色,
  2. 源表将是暂时的。我们可以根据TTL从源表中删除数据,就像我们在上一节中所做的那样,或者将此表的引擎更改为Null,该引擎不存储任何数据(数据只会存储在物化视图中):
CREATE TABLE wikistat_src
(
    `time` DateTime,
    `project` LowCardinality(String),
    `subproject` LowCardinality(String),
    `path` String,
    `hits` UInt64
)
ENGINE = Null

现在,让我们使用数据验证查询创建一个物化视图:

CREATE TABLE wikistat_clean AS wikistat;
 
Ok.
 
CREATE MATERIALIZED VIEW wikistat_clean_mv TO wikistat_clean
AS SELECT *
FROM wikistat_src
WHERE match(path, '[a-z0-9\\-]')

当我们插入数据时, wikistat_src 将保持为空:

INSERT INTO wikistat_src SELECT * FROM s3('https://ClickHouse-public-datasets.s3.amazonaws.com/wikistat/partitioned/wikistat*.native.zst') LIMIT 1000

在这里插入图片描述

8.数据路由到表格

物化视图可以用于的另一个示例是基于某些条件将数据路由到不同的表:
在这里插入图片描述
例如,我们可能希望将无效数据路由到另一个表,而不是删除它。在这种情况下,我们创建另一个物化视图,但使用不同的查询:

CREATE TABLE wikistat_invalid AS wikistat;
 
Ok.
 
CREATE MATERIALIZED VIEW wikistat_invalid_mv TO wikistat_invalid
AS SELECT *
FROM wikistat_src
WHERE NOT match(path, '[a-z0-9\\-]')

当我们有单个物化视图用于同一源表时,它们将按字母顺序进行处理。请记住,不要为源表创建超过几十个物化视图,因为插入性能可能会下降。

如果我们再次插入相同的数据,我们会在 wikistat_invalid 物化视图中找到942个无效的行:

SELECT count(*)
FROM wikistat_invalid
 
┌─count()─┐
│     942 │
└─────────┘

9.数据转换

由于物化视图基于查询的结果,所以我们可以在SQL中使用所有ClickHouse函数的功能来转换源值,以丰富和提升数据的清晰度。作为一个快速的例子,让我们将project、subproject和path列合并到一个单一的page列,并将时间分割为date和hour列:

CREATE TABLE wikistat_human
(
    `date` Date,
    `hour` UInt8,
    `page` String
)
ENGINE = MergeTree
ORDER BY (page, date);
 
Ok.
 
CREATE MATERIALIZED VIEW wikistat_human_mv TO wikistat_human
AS SELECT
    date(time) AS date,
    toHour(time) AS hour,
    concat(project, if(subproject != '', '/', ''), subproject, '/', path) AS page,
    hits
FROM wikistat

现在, wikistat_human 将填充转换后的数据:

┌───────date─┬─hour─┬─page──────────────────────────┬─hits─┐
│ 2015-11-088 │ en/m/Angel_Muñoz_(politician)1 │
│ 2015-11-093 │ en/m/Angel_Muñoz_(politician)1 │
└────────────┴──────┴───────────────────────────────┴──────┘

10.物化视图和JOIN操作

由于物化视图是基于SQL查询的结果工作的,我们可以使用JOIN操作以及任何其他SQL功能。但是应该小心使用JOIN操作。

假设我们有一个带有页面标题的表:

CREATE TABLE wikistat_titles
(
    `path` String,
    `title` String
)
ENGINE = MergeTree
ORDER BY path

这个表中的title与path关联:

SELECT *
FROM wikistat_titles
 
┌─path─────────┬─title────────────────┐
│ Ana_Sayfa    │ Ana Sayfa - artist   │
│ Bruce_Jenner │ William Bruce Jenner │
└──────────────┴──────────────────────┘

现在我们可以创建一个物化视图,从 wikistat_titles 表中通过joinpath值连接title:

CREATE TABLE wikistat_with_titles
(
    `time` DateTime,
    `path` String,
    `title` String,
    `hits` UInt64
)
ENGINE = MergeTree
ORDER BY (path, time);
 
Ok.
 
CREATE MATERIALIZED VIEW wikistat_with_titles_mv TO wikistat_with_titles
AS SELECT time, path, title, hits
FROM wikistat AS w
INNER JOIN wikistat_titles AS wt ON w.path = wt.path

注意,我们使用了 INNER JOIN ,所以在填充后,我们只会得到在 wikistat_titles 表中有对应值的记录:

SELECT * FROM wikistat_with_titles LIMIT 5
 
┌────────────────time─┬─path──────┬─title──────────────┬─hits─┐
│ 2015-05-01 01:00:00 │ Ana_Sayfa │ Ana Sayfa - artist │    5 │
│ 2015-05-01 01:00:00 │ Ana_Sayfa │ Ana Sayfa - artist │    7 │
│ 2015-05-01 01:00:00 │ Ana_Sayfa │ Ana Sayfa - artist │    1 │
│ 2015-05-01 01:00:00 │ Ana_Sayfa │ Ana Sayfa - artist │    3 │
│ 2015-05-01 01:00:00 │ Ana_Sayfa │ Ana Sayfa - artist │  653 │
└─────────────────────┴───────────┴────────────────────┴──────┘

我们在 wikistat 表中插入一个新记录,看看我们的新物化视图是如何工作的:

INSERT INTO wikistat VALUES(now(), 'en', '', 'Ana_Sayfa', 123);
 
1 row in set. Elapsed: 1.538 sec.

注意这里的插入时间 - 1.538秒。我们可以在 wikistat_with_titles 中看到我们的新行:

SELECT *
FROM wikistat_with_titles
ORDER BY time DESC
LIMIT 3
 
┌────────────────time─┬─path─────────┬─title────────────────┬─hits─┐
│ 2023-01-03 08:43:14 │ Ana_Sayfa    │ Ana Sayfa - artist   │  123 │
│ 2015-06-30 23:00:00 │ Bruce_Jenner │ William Bruce Jenner │  115 │
│ 2015-06-30 23:00:00 │ Bruce_Jenner │ William Bruce Jenner │   55 │
└─────────────────────┴──────────────┴──────────────────────┴──────┘

但是,如果我们向 wikistat_titles 表添加数据会发生什么呢?:

INSERT INTO wikistat_titles
VALUES('Academy_Awards', 'Oscar academy awards');

尽管我们在 wikistat 表中有相应的值,但物化视图中不会出现任何内容:

SELECT *
FROM wikistat_with_titles
WHERE path = 'Academy_Awards'
 
0 rows in set. Elapsed: 0.003 sec.

这是因为物化视图只在其源表接收插入时触发。它只是源表上的一个触发器,对连接表一无所知。注意,这不仅仅适用于join查询,并且在物化视图的SELECT语句中引入任何外部表时都很相关,例如使用 IN SELECT 。

在我们的情况下, wikistat 是物化视图的源表,而 wikistat_titles 是我们要连接的表:
在这里插入图片描述
在这里插入图片描述
要小心,因为JOIN操作可能会在连接大表时显著降低插入性能,如上所示。考虑使用字典作为更有效的替代方法。

ClickHouse博客; https://blog.csdn.net/ClickHouseDB?type=blog

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/485312.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Linux】Linux工具学习之git

&#x1f525;博客主页&#xff1a; 小羊失眠啦. &#x1f3a5;系列专栏&#xff1a;《C语言》 《数据结构》 《C》 《Linux》 《Cpolar》 ❤️感谢大家点赞&#x1f44d;收藏⭐评论✍️ 文章目录 前言一、账号注册1.1 GitHub与Gitee 二、构建仓库三、安装git 四、配置git五、克…

树状数组原理和代码

树状数组 求下标的对应 求i管着的下标的范围 方法&#xff1a;拆掉最右侧的1然后1 到你自己 query sum 1-i的和 拆掉最右侧的1 再把下一个数值吸收到sum 重复这个过程直到全变0为止 add 方法&#xff1a;加上最右侧的1 到上限为止 lowbit方法 单点增加范围查询模板 #inc…

Redis持久化【RDB,bgsave的写时复制机制】【AOF,aof重写机制】【Redis混合持久化,以及对应改变aof重写规则】【Redis数据备份策略】

Redis持久化 RDB快照&#xff08;snapshot&#xff09;bgsave的写时复制(COW)机制 AOF&#xff08;append-only file&#xff09;AOF重写 Redis 4.0 混合持久化开启持久化后&#xff0c;AOF重写规则发生了变化 Redis数据备份策略&#xff1a; 转自 图灵课堂 RDB快照&#xff0…

第390场 LeetCode 周赛题解

A 每个字符最多出现两次的最长子字符串 滑动窗口&#xff1a;枚举窗口的左边界&#xff0c;尽可能右移窗口的右边界。 (当然也可以暴力枚举) class Solution { public:int maximumLengthSubstring(string s) {vector<int> cnt(26);int res 0;for (int l 0, r -1, n s…

python第三方库的安装,卸载和更新,以及在cmd下pip install安装的包在pycharm不可用问题的解决

目录 第三方库pip安装&#xff0c;卸载更新 1.安装&#xff1a; 2.卸载 3.更新 一、第三方库pip安装&#xff0c;卸载更新 1.安装 pip install 模块名 加镜像下载&#xff1a;pip install -i 镜像网址模块名 常用的是加清华镜像&#xff0c;如 pip install -i https://pyp…

jmeter链路压测

比如登录后返回token&#xff0c;业务打印上传的操作需要用到token 线程组中添加登录请求&#xff0c;并执行 1、添加登录并执行&#xff0c;查看结果 2、结果树中下拉选择正则表达式&#xff0c;将token参数和值复制粘贴到下方&#xff0c;将token值改为(.*?)&#xff0…

Pinctrl子系统_05_Pincontroller构造过程情景分析

上一节我们了解了Pinctrl子系统主要的数据结构&#xff0c;要想更好的掌握Pinctrl子系统&#xff0c;还需要知道他的构造过程。 本节我们就来分析一下Pinctrl子系统的构造过程。 以内核面向对象的思想&#xff0c;设备树可以分为两部分&#xff0c;左边是Pinctrl子系统节点&a…

毕业论文降重(gpt+完美降重指令),sci论文降重gpt指令——超级好用,重复率低于4%

1. 降重方法&#xff1a;gpt降重指令 2. gpt网站 https://yiyan.baidu.com/ https://chat.openai.com/ 3. 降重指令——非常好用&#xff01;&#xff01;sci论文&#xff0c;本硕大论文都可使用&#xff01; 请帮我把下面句子重新组织&#xff0c;通过调整句子逻辑&#xff0…

牛客NC218 检测循环依赖【中等 图 Java,Go,PHP】

题目 题目链接&#xff1a; https://www.nowcoder.com/practice/8dc02ad98553432a90affc3a0484910b 思路 图的基本知识要理解&#xff0c;一般用Map来表示 图解决拓扑排序&#xff0c;依赖之类的问题 感觉课程数在这道题里面可以不用&#xff0c;因为没有规定所有课程都得有先…

解决方案Please use Oracle(R) Java(TM) 11, OpenJDK(TM) 11 to run Neo4j.

文章目录 一、现象二、解决方案 一、现象 当安装好JDK跟neo4j&#xff0c;用neo4j.bat console来启动neo4却报错&#xff1a; 部分报错信息&#xff1a; Starting Neo4j. WARNING! You are using an unsupported Java runtime. Please use Oracle Java™ 11, OpenJDK™ 11 t…

Jenkins中使用Generic Webhook Trigger插件实现持续集成

项目环境 宝塔Linux面板DockerJenkinsgitee 目的 实现每次push推送dev分支到gitee上&#xff0c;Jenkins自动构建项目&#xff1b;push其它分支时&#xff0c;不运行。 实现方法 1.在Jenkins上安装Generic Webhook Trigger插件 在“系统设置–插件管理–可选插件”界面搜…

jmeter中参数加密

加密接口常用的方式有&#xff1a; MD5&#xff0c;SHA&#xff0c;HmacSHA RSA AES&#xff0c;DES&#xff0c;Base64 压测中有些参数需要进行加密&#xff0c;加密方式已接口文档为主。 MD5加密 比如MD5加密的接口文档&#xff1a; 请求URL&#xff1a;http://101.34.221…

STM32 | Systick定时器(第四天源码解析)

STM32 | Systick定时器(第四天)STM32 | STM32F407ZE中断、按键、灯(续第三天)1、参考delay_us代码,完成delay_ms的程序 定时器频率换算单位:1GHZ=1000MHZ=1000 000KHZ = 1000 000 000HZ 定时器定时时间:计数个数/f(频率) 或者 (1/f(频率))*计数的个数 500/1MHZ = 500/1…

Spring相关框架八股

单例bean是线程安全的吗&#xff1f; AOP 事务失效 Bean生命周期 Bean循环依赖解决 MVC执行流程 自动装配原理 Spring常见注解 SpringMVC注解 SpringBoot注解 MyBatis执行流程 MyBatis延迟加载 MyBatis缓存 SpringCloud五大组件 注册中心Nacos、Eureka 负载均衡Ribbon 服务雪崩…

Godot.NET C# 工程化开发(1):通用Nuget 导入+ 模板文件导出,包含随机数生成,日志管理,数据库连接等功能

文章目录 前言Github项目地址&#xff0c;包含模板文件后期思考补充项目设置编写失误环境visual studio 配置详细的配置看我这篇文章 Nuget 推荐NewtonSoft 成功Bogus 成功Github文档地址随机生成构造器生成构造器接口(推荐) 文件夹设置Nlog 成功&#xff01;Nlog.configNlogHe…

2025汤家凤考研数学视频,基础网课百度网盘课程+PDF讲义资料

2025汤家凤大神及数学全程 docs.qq.com/doc/DTmtOa0Fzc0V3WElI 复制粘贴到浏览器&#xff0c;可以见所有的Ke 第一轮 夯实基础 1.阅读大纲考查要求&#xff0c;明确每章的学习目标&#xff1b; 2.按节学习数学理论基础知识&#xff0c;吃透书中例题&#xff1b; 3.学习每章…

红外遥控器的使用和详细解释

infrared.c #include "infrared.h"/* 红外 --- PA8*/void Infrared_Init(void) {GPIO_InitTypeDef GPIO_InitStruct; EXTI_InitTypeDef EXTI_InitStruct;NVIC_InitTypeDef NVIC_InitStruct;//使能SYSCFG时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, E…

【数据结构】五分钟自测主干知识(十)

上一节&#xff0c;我们讲述了二叉树的概念&#xff0c;二叉树又有什么基本操作呢&#xff1f;今天我们来讲述二叉树的应用~ 话不多说&#xff0c;书继上回 5.3二叉树的遍历及应用 二叉树由三个基本部分组成&#xff1a;根结点&#xff08;D&#xff09;&#xff0c;左子树&a…

ForkJoinPool在生产环境中使用遇到的一个问题

1、背景 在我们的项目中有这么一个场景&#xff0c;需要消费kafka中的消息&#xff0c;并生成对应的工单数据。早些时候程序运行的好好的&#xff0c;但是有一天&#xff0c;我们升级了容器的配置&#xff0c;结果导致部分消息无法消费。而消费者的代码是使用CompletableFutur…

综合知识篇21-项目管理考点(2024年软考高级系统架构设计师冲刺知识点总结系列文章)

专栏系列文章: 2024高级系统架构设计师备考资料(高频考点&真题&经验)https://blog.csdn.net/seeker1994/category_12593400.html案例分析篇00-【历年案例分析真题考点汇总】与【专栏文章案例分析高频考点目录】(2024年软考高级系统架构设计师冲刺知识点总结-案例…