ClickHouse--11--物化视图

news2024/12/27 15:52:40

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

文章目录

  • 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

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

WorkPlus一站式IM即时通讯解决方案,提升企业沟通效率与协作能力

在企业内部沟通与协作中&#xff0c;高效的即时通讯是实现团队协作与工作效率的重要保障。而WorkPlus以其稳定可靠的性能和全面的功能&#xff0c;为企业提供一站式的IM即时通讯解决方案&#xff0c;助力企业提升沟通效率与协作能力。IM即时通讯在企业中的重要性不言而喻。作为…

【索引失效】MySQL索引失效场景

1、对索引使用左或者左右模糊匹配 当我们使用左或者左右模糊匹配的时候&#xff0c;也就是 like %xx 或者 like %xx% 这两种方式都会造成索引失效。 比如下面的 like 语句&#xff0c;查询 name 后缀为「林」的用户&#xff0c;执行计划中的 typeALL 就代表了全表扫描&#xff…

解决Animate.css动画效果无法在浏览器运行问题

背景 在开发官方网站的时候&#xff0c;临时更换了电脑&#xff0c;发现原本正常的动画效果突然不动了。 经过 chrome、Microsoft Edge都无法运行。 Animate.css | A cross-browser library of CSS animations. 问题排查 通过审查元素后发现类名是注入并且生效的。 验证 然…

【Linux】vim配置及安装方法

注 安装方法在文章最后 配置文件的位置 在目录 /etc/ 下面&#xff0c;有个名为vimrc的文件&#xff0c;这是系统中公共的vim配置文件&#xff0c;对所有用户都有效。而在每个用户的主目录下&#xff0c;都可以自己建立私有的配置文件&#xff0c;命名为“.vimrc”。例如&…

小目标检测篇 | YOLOv8改进之增加小目标检测层(四头检测机制)

前言:Hello大家好,我是小哥谈。小目标检测是计算机视觉领域中的一个研究方向,旨在从图像或视频中准确地检测和定位尺寸较小的目标物体。相比于常规目标检测任务,小目标检测更具挑战性,因为小目标通常具有低分辨率、低对比度和模糊等特点,容易被背景干扰或遮挡。为了解决小…

Windows复现SiamCAR代码遇到的报错与解决方法

一、环境基础 Windows10以上 已装Anaconda 支持GPU 已经gitclone:https://github.com/HonglinChu/SiamTrackers 二、遇到的报错 1. No module named pycocotools._mask 方案一&#xff1a;加载非常慢 conda install -c conda-forge pycocotools 方…

Yocto学习笔记1-下载与首次编译

Yocto学习笔记1-下载与首次编译 1、基础环境介绍2、注意点3、安装依赖3.1 yocto常规系统构建所需依赖库&#xff08;较全&#xff09;3.2 龙芯适配时的最小依赖库&#xff08;最小&#xff09; 4、下载4.1 通过git克隆4.2 查看所有远程分支4.3 签出一个长期支持的稳定版本4.4 查…

2024年noc指导教师认证测评参考试题题目1-2合集

[noc指导教师认证] 测评参考试题 说明:NOC教师指导认证考试题目是从题库里抽题,因此每位老师每次考试题目都不一样以下题目为测试考试时收集到的一些题目,作为辅助提供给各位老师,老师们可以记住题目及答案的具体内容 (选项顺序会变),以免考试时遇到。2024年的做的题目有的…

【前端寻宝之路】学习和使用表单标签和表单控件

&#x1f308;个人主页: Aileen_0v0 &#x1f525;热门专栏: 华为鸿蒙系统学习|计算机网络|数据结构与算法|MySQL| ​&#x1f4ab;个人格言:“没有罗马,那就自己创造罗马~” #mermaid-svg-cR8zvB8CkpxTk485 {font-family:"trebuchet ms",verdana,arial,sans-serif;f…

DataEase大屏iframe嵌入自建网站(React)

1、修改dataease 所在的服务器nginx配置 server {listen 80;server_name dataease.ibaiqiu.cn;return 307 https://$host$request_uri; } server {listen 443 ssl;server_name dataease.ibaiqiu.cn;client_max_body_size 30M;ssl_certificate /usr/local/nginx/co…

明日周刊-第3期

第3期&#xff0c;分享自己最近的感悟和实用工具。 文章目录 1. 一周热点2. 资源分享3. 言论4. 歌曲推荐 1. 一周热点 国内生产总值持续增长&#xff1a;统计局最新数据显示&#xff0c;2023年全年国内生产总值&#xff08;GDP&#xff09;超过126万亿元&#xff0c;比上年增长…

Android Preference简单介绍

Android Preference简单介绍 文章目录 Android Preference简单介绍一、前言二、Preference 简单介绍二、PreferenceScreen和SwitchPreference 简单示例2、相关demo代码示例&#xff08;1&#xff09;SettingsActivity.Java&#xff08;2&#xff09;layout\settings_activity.x…

Docker Command

小试牛刀 # 查看docker版本 docker -v docker --version # 查看帮助 docker --help # 永远的Hello World docker run hello-world镜像操作 查看本地已有的镜像 docker images -a :列出本地所有的镜像&#xff08;含中间映像层&#xff09; -q :只显示镜像ID --digests :显示…

39 openlayers 对接地图图层 绘制点线面圆

前言 这里主要是展示一下 openlayers 的一个基础的使用 主要是设计 接入地图服务器的 卫星地图, 普通的二维地图, 增加地区标记 增加 省市区县 的边界标记 基础绘制 点线面园 等等 测试用例 <template><div style"width: 1920px; height:1080px;" &g…

【嵌入式】Docker镜像构建指南:引领应用部署的革新之路

&#x1f9d1; 作者简介&#xff1a;阿里巴巴嵌入式技术专家&#xff0c;深耕嵌入式人工智能领域&#xff0c;具备多年的嵌入式硬件产品研发管理经验。 &#x1f4d2; 博客介绍&#xff1a;分享嵌入式开发领域的相关知识、经验、思考和感悟。提供嵌入式方向的学习指导、简历面…

深度学习pytorch——GPU加速(持续更新)

使用 .to(device)&#xff0c;以前使用 .cuda() &#xff0c;但是现在基本不使用了。 代码示例&#xff1a; 查看电脑GPU运行情况&#xff1a; 使用Ctrl Shift ESC快捷键&#xff1a;

Unreal中的四元数FQuat

四元数&#xff1a;Quaternion&#xff0c;四维数域内的数&#xff0c;可用于描述点在三维空间内的旋转&#xff08;因为三维的旋转可以理解为绕某个轴旋转一个角度&#xff0c;所以需要4个维度的信息&#xff09; 注意这里的旋转的轴&#xff0c;指的是从原点到 ( x , y , z )…

vue3+threejs新手从零开发卡牌游戏(九):添加抽卡逻辑和动效

首先优化下之前的代码&#xff0c;把game/deck/p1.vue中修改卡组方法和渲染卡组文字方法提到公共方法中&#xff0c;此时utils/common.ts完整代码如下&#xff1a; import { nextTick } from vue; import * as THREE from three; import * as TWEEN from tweenjs/tween.js impo…

数据库基础篇-------语法结构

友友们&#xff0c;大家好&#xff0c;今天我们来回顾我们的数据库啦&#xff0c;数据库技术是在我们大一就进行了解的&#xff0c;但是在大二的时候有的学校会进行数据库开发技术的教学&#xff0c;这两本书是不一样的&#xff0c;数据库基础更加偏向于对应的基础语法结构&…

计算方法实验2:列主元消元法和Gauss-Seidel迭代法解线性方程组

Task 即已知 y 0 0 , y 100 1 y_00,y_{100}1 y0​0,y100​1&#xff0c;解线性方程组 A y b \mathbf{A}\mathbf{y} \mathbf{b} Ayb&#xff0c;其中 A 99 99 [ − ( 2 ϵ h ) ϵ h 0 ⋯ 0 ϵ − ( 2 ϵ h ) ϵ h ⋯ 0 0 ϵ − ( 2 ϵ h ) ⋯ 0 ⋮ ⋮ ⋱ ⋱ ⋮ 0 0 ⋯…