ClickHouse的原理及使用,

news2024/11/24 8:42:10

1、前言

一款MPP查询分析型数据库——ClickHouse。它是一个开源的,面向列的分析数据库,由Yandex为OLAP和大数据用例创建。ClickHouse对实时查询处理的支持使其适用于需要亚秒级分析结果的应用程序。ClickHouse的查询语言是SQL的一种方言,它支持强大的声明性查询功能,同时为最终用户提供熟悉度和较小的学习曲线。

它可以替代Elasticserach做深度聚合需求,性能表现不错,在数据量千万级亿级表现很好,且资源消耗相比之前降低不少,同样的服务器资源可以承担更多的业务需求。

2、ClickHouse 概述

1.1 什么是ClickHouse

ClickHouse 是俄罗斯的 Yandex 于2016年开源的列式存储数据库(DBMS),主要用于在线分析处理查询(OLAP),能够使用SQL 查询实时生成分析数据报告。

1.2 什么是列式存储

以下面的表为例:

IdNameAge
1张三18
2李四22
3王五34

采用行式存储时,数据在磁盘上的组织结构为:

好处是想查某个人所有的属性时,可以通过一次磁盘查找加顺序读取就可以。但是当想查所有人的年龄时,需要不停的查找,或者全表扫描才行,遍历的很多数据都是不需要的。

而采用列式存储时,数据在磁盘上的组织结构为:

这时想查所有人的年龄只需把年龄那一列拿出来就可以了。

1.3 安装前的准备

1.3.1 CentOS 取消打开文件数限制

在/etc/security/limits.conf、 /etc/security/limits.d/90-nproc.conf 这2个文件的末尾加入一下内容:

vi /etc/security/limits.conf
在文件末尾添加:
* soft nofile 65536
* hard nofile 65536
* soft nproc 131072
* hard nproc 131072

vi /etc/security/limits.d/90-nproc.conf
在文件末尾添加:
* soft nofile 65536
* hard nofile 65536
* soft nproc 131072
* hard nproc 131072

重启服务器之后生效,用ulimit -n 或者 ulimit -a 查看设置结果

ulimit -n

1.3.2 CentOS 取消SELINUX

SELINUX 是 CentOS 类似于windows 下的安全360,修改 /etc/selinux/config 中的 SELINUX=disabled 后重启

vi /etc/selinux/config
SELINUX=disabled

1.3.3 关闭防火墙

service iptables stop
service ip6tables stop

1.3.4 安装依赖

yum install -y libtool
yum install -y *unixODBC*
yum search libicu
yum install libicu.x86_64

2、安装

2.1 网址

官网:https://clickhouse.yandex/

下载地址:http://repo.red-soft.biz/repos/clickhouse/stable/el7/

2.2 单机模式

上传5个文件到 mkdir /usr/local/clickhouse

clickhouse-client-1.1.54236-4.el7.x86_64.rpm    09-Jun-2017 11:02   3.0K     
clickhouse-compressor-1.1.54236-4.el7.x86_64.rpm    09-Jun-2017 11:02   880K     
clickhouse-debuginfo-1.1.54236-4.el7.x86_64.rpm 09-Jun-2017 11:02   8.6M     
clickhouse-server-1.1.54236-4.el7.x86_64.rpm    09-Jun-2017 11:02   32M  
clickhouse-server-common-1.1.54236-4.el7.x86_64.rpm 09-Jun-2017 11:02   8.0K

2.2.2 分别安装这5个rpm 文件

rpm -ivh /usr/local/clickhouse/*.rpm

2.2.3 启动 ClickServer

前台启动:

clickhouse-server --config-file=/etc/clickhouse-server/config.xml

查看启动后的进程:ps -aux | grep click

后台启动:

nohup clickhouse-server --config-file=/etc/clickhouse-server/config.xml >null 2>&1 &

2.2.4 使用 client 连接server

clickhouse-client

2.3 分布式集群安装

2.3.1 在node-02、node-03 上面执行之前的所有步骤

2.3.2 三台机器修改配置文件 vi /etc/clickhouse-server/config.xml

<listen_host>0.0.0.0</listen_host>
    <!-- <listen_host>::1</listen_host> -->
    <!-- <listen_host>127.0.0.1</listen_host> -->

将刚刚修改好的配置分发到三台机器上去: ync.sh /etc/clickhouse-server/config.xml

2.3.3 在三台机器的etc 目录下新建 metrika.xml 文件

vi /etc/metrika.xml
添加如下内容:

<yandex>
<clickhouse_remote_servers>
<perftest_3shards_1replicas>
<shard>
<internal_replication>true</internal_replication>
<replica>
<host>node-01</host>
<port>9000</port>
</replica>
</shard>
<shard>
<replica>
<internal_replication>true</internal_replication>
<host>node-02</host>
<port>9000</port>
</replica>
</shard>
<shard>
<internal_replication>true</internal_replication>
<replica>
<host>node-03</host>
<port>9000</port>
</replica>
</shard>
</perftest_3shards_1replicas>
</clickhouse_remote_servers>

<!--zookeeper相关配置-->
<zookeeper-servers>
<node index="1">
<host>node-01</host>
<port>2181</port>
</node>
<node index="2">
<host>node-02</host>
<port>2181</port>
</node>
<node index="3">
<host>node-03</host>
<port>2181</port>
</node>
</zookeeper-servers>

<macros>
<replica>node-01</replica>
</macros>

<networks>
<ip>::/0</ip>
</networks>

<clickhouse_compression>
<case>
<min_part_size>10000000000</min_part_size>
<min_part_size_ratio>0.01</min_part_size_ratio>
<method>lz4</method>
</case>
</clickhouse_compression>

</yandex>

注意:下面标红的地方需要根据机器不同去修改,node-02就是修改成node-02, node-03就是修改成node-03

node-01

3.3.4 三台机器启 ClickServer

首先在三台机器开启Zookeeper

前台启动:

clickhouse-server --config-file=/etc/clickhouse-server/config.xml

查看启动后的进程:ps -aux | grep click

后台启动:

nohup clickhouse-server --config-file=/etc/clickhouse-server/config.xml >null 2>&1 &

集群搭建成功,进入clickhouse-client 客户端:

这里补充ClickHouse与Elasticsearch一样,都采用列式存储结构,都支持副本分片,不同的是ClickHouse底层有一些独特的实现,如下:

  • MergeTree 合并树表引擎,提供了数据分区、一级索引、二级索引。
  • Vector Engine 向量引擎,数据不仅仅按列存储,同时还按向量(列的一部分)进行处理,这样可以更加高效地使用CPU。

3、数据类型

3.1 整型

固定长度的整型,包括有符号整型或无符号整型。Clickhouse 对大小写敏感。整型范围(-2^(n-1) ~ 2^(n-1) - 1):

Int8 −128:127
Int16 −32768:32767
Int32 −2147483648:2147483647
Int64 −9223372036854775808:9223372036854775807

无符号整型范围(0 ~ 2^n -1)

UInt8 0:255
UInt16 0:65535
UInt32 0:4294967295
UInt64 0:18446744073709551615

3.2 浮点型

Float32 - float
Float64 - double

建议尽可能以整型形式存储数据。例如,将固定精度的数字转换为整数值,如果间用毫秒为单位表示,因为浮点型进行计算时可能引起四舍五入的误差,比如1-0.9。

与标准SQL 相比,ClickHouse 支持以下类别的浮点数:Inf - 正无穷  1/0-Inf - 负无穷 NaN - 非数字:

3.3 布尔型

没有单独的类型来存储布尔值。可以使用 UInt8 类型,取值限制为 0 或 1 。

3.4 字符串

1)String

字符串可以任意长度的。它可以包含任意的字节集,包含空字节。

2) FixedString(N)

固定长度N 的字符串,N 必须是严格的正自然数。当服务端读取长度小于N的字符串时候,通过在字符串末尾添加空字节来达到N 字节长度。当服务端读取长度大于 N 的字符串时候,将返回错误消息。与String 相比,极少会使用FixedString,因为使用起来不是很方便。

3.5 枚举类型

ClickHouse 支持枚举类型,这是一种在定义常量时经常会使用的数据类型。ClickHouse 提供了Enum8 和Enum16 两种枚举类型,它们除了取值范围不同之外,别无二致。枚举固定使用(String:Int)Key/Value 键值对的形式定义数据,所以Enum8 和Enum16分别会对应(String:Int8)和(String:Int16)

用法演示:

create table enum(enum Enum8('hello'=0, 'enum'=1))engine=TinyLog
-- 枚举数据类型
CREATE TABLE test_enum(id Int8, color Enum8('red'=1, 'green'=2, 'blue'=3)) engine=Memory;
insert into test_enum values(1,'red'),(2,'red'),(3,'green');
-- 也可以使用这种方式进行插入数据:
insert into test_enum values(4,3);
insert into test_enum values(5,'pink'); -- 没有声明的值是不能插入

select id, toInt32(color) from test_enum;
-- 节省存储空间,提升处理效率;底层存储Int类型,占用空间最小

3.6 数组

Array(T):由T 类型元素组成的数组。T 可以是任意类型,包含数组类型。但不推荐使用多维数组,ClickHouse 对多维数组的支持有限。例如,不能在MergeTree 表中存储多维数组。可以使用 array 函数来创建数组:array(T)也可以使用方括号:[]   -- 数组数据类型array(T) 数组是强数据类型e1,e2,d3...   toTypeName() -- 查看变量的数据类型

CREATE TABLE test_array
(
    name String, 
    hobby Array(String)
) ENGINE = Log

insert into test_array values
('张三',['读书','爬山','散步']),
('李四',['read','hiking','dance']),
('王五',array('吃','睡','喝','玩'));

select * from test_array;

insert into test_array values ('张三2',['读书','爬山','散步']);
insert into test_array values ('李四2',['read','hiking','dance']);
insert into test_array values ('王五2',array('吃','睡','喝','玩'));

-- clickhouse 会利用多核处理器将数据分块存储、计算
select * from test_array;

-- 查询数组中的数据
select *, hobby[1] from test_array;

-- 遍历数组中每个元素,给每个元素加上'abc'
select arrayMap(e -> concat(e, 'abc'), hobby) from test_array;

3.7 Tupe 元组

是一个特殊的数据类型,集合
可以存储任意的数据类型,在定义的时候声明数据类型和数据元素个数
元组类型由1~n 个元素组成,每个元素之间允许设置不同的数据类型,且彼此之间不要求兼容。无组同样支持类型推断,
其推断依据仍然以最小存储代码为原则。与数组类似,元组也可以使用两种方式定义

常规方式tuple(T):元组中可以存储多种数据类型,但是要注意数据类型的顺序
Tuple(String, UInt8, Date)

select tuple(1, 'abc', 12.33) as x, toTypeName(x);

┌─x───────────────┬─toTypeName(tuple(1, \'abc\', 12.33))─┐
│ (1,'abc',12.33) │ Tuple(UInt8, String, Float64)        │
└─────────────────┴──────────────────────────────────────┘

select (1, 2, 'hello') as x, toTypeName(x);
┌─x─────────────┬─toTypeName(tuple(1, 2, \'hello\'))─┐
│ (1,2,'hello') │ Tuple(UInt8, UInt8, String)        │
└───────────────┴────────────────────────────────────┘

创建tuple表及查询示例:

-- 注意:建表的时候使用元组的需要制定元组的数据类型
create table test_tuple(
    name String,
    info Tuple(String, String, UInt8)
) engine=Memory;

insert into test_tuple values
    ('zss', ('M', 'coder', 23)),
    ('lss', tuple('F', 'coder', 23));

select * from test_tuple;

┌─name─┬─info─────────────┐
│ zss  │ ('M','coder',23) │
│ lss  │ ('F','coder',23) │
└──────┴──────────────────┘

-- 通过下标查询tupe数据
select name, info.1, info.2, info.3 from test_tuple;

┌─name─┬─tupleElement(info, 1)─┬─tupleElement(info, 2)─┬─tupleElement(info, 3)─┐
│ zss  │ M                     │ coder                 │                    23 │
│ lss  │ F                     │ coder                 │                    23 │
└──────┴───────────────────────┴───────────────────────┴───────────────────────┘

3.8 Nested 嵌套表结构

Nested 是一种嵌套表结构。一张数据表,可以定义任意多个嵌套类型字段,但每个字段的嵌套层级只支持一级,
即嵌套表内不能继续使用嵌套类型。对于简单场景的层级关系或关联关系,使用嵌套类型也是一种不错的选择。

create table test_nested (
    id Int8,
    name String,
    hobby Nested(
        hid Int8,
        h1 String,
        h2 String
    )
)engine=Memory;

查看表结构:
┌─name──────┬─type──────────┬─default_type─┬─default_expression─┐
│ id        │ Int8          │              │                    │
│ name      │ String        │              │                    │
│ hobby.hid │ Array(Int8)   │              │                    │
│ hobby.h1  │ Array(String) │              │                    │
│ hobby.h2  │ Array(String) │              │                    │
└───────────┴───────────────┴──────────────┴────────────────────┘

嵌套类型本质是一种多维数组的结构。嵌套表中每个字段都是一个数组,并且行与行之间数组的长度无须对齐。
需要注意的是,在同一行数据内每个数组字段的长度必须相等。

-- 插入数据
insert into test_nested values (1, 'zss', [1,2,3],['吃','喝','睡'],['eat','drink','sleep']);
insert into test_nested values (2, 'lss', [1,2,3],['吃','喝','睡'],['eat','drink','sleep']);

-- 查询数据    
select * from test_nested;

┌─id─┬─name─┬─hobby.hid─┬─hobby.h1──────┬─hobby.h2────────────────┐
│  1 │ zss  │ [1,2,3]   │ ['吃','喝','睡'] │ ['eat','drink','sleep'] │
└────┴──────┴───────────┴───────────────┴─────────────────────────┘
┌─id─┬─name─┬─hobby.hid─┬─hobby.h1──────┬─hobby.h2────────────────┐
│  2 │ lss  │ [1,2,3]   │ ['吃','喝','睡'] │ ['eat','drink','sleep'] │
└────┴──────┴───────────┴───────────────┴─────────────────────────┘

-- 复杂查询数据
select id, name, hobby.hid, hobby.h1, hobby.h1[1] from test_nested;

┌─id─┬─name─┬─hobby.hid─┬─hobby.h1──────┬─arrayElement(hobby.h1, 1)─┐
│  1 │ zss  │ [1,2,3]   │ ['吃','喝','睡'] │ 吃                         │
└────┴──────┴───────────┴───────────────┴───────────────────────────┘
┌─id─┬─name─┬─hobby.hid─┬─hobby.h1──────┬─arrayElement(hobby.h1, 1)─┐
│  2 │ lss  │ [1,2,3]   │ ['吃','喝','睡'] │ 吃                         │
└────┴──────┴───────────┴───────────────┴───────────────────────────┘

3.9 复杂数据类型

3.9.1 domain

-- Domain pojo beans:https://clickhouse.tech/docs/zh/sql-reference/data-types/domains/ipv4/
域名类型分为IPv4和IPv6两类,本质上它们是对整型和字符串的进一步封装。IPv4类型是基于UInt32封装的

(1)出于便携性的考量,例如IPv4类型支持格式检查,格式错误的IP数据是无法被写入的,例如:INSERT INTO IPv4_test values('www.nauu.com', '192.0.0.1')

(2)出于性能的考量,同样以IPv4为例,IPv4使用UInt32存储,相比String 更加紧凑,占用的空间更小,查询性能更快。IPv6类型是基于FixedString(16) 封装的,它的使用方法与IPv4别无二致,在使用Domain类型的时候还有一点需要注意,虽然它从表象上看起来与String 一样,但Domain 类型并不是字符串,所以它不支持隐式的自动类型转换。如果需要返回IP的字符串形式,则需要显式调用IPv4NumToString 或 IPv6NumToString 函数进行转换。

create table test_domain1(
    id Int8,
    ip IPv4
)engine=Memory;

insert into test_domain1 values(1, '192.168.133.1');
insert into test_domain1 values(1, '192.168.133');

create table test_domain2(
    id Int8,
    ip String
)engine=Memory;

insert into test_domain2 values(1, '192.168.133.1');
insert into test_domain2 values(1, '192.168.133');

四、数据库

数据库起到了命名空间的作用,可以有效规避命名冲突的问题,也为后续的数据隔离提供了支撑。任何一张数据表,都必须归属在某个数据库之下。

在CK中数据库也有自己的引擎,数据库目前支持的数据库引擎有5种:

1)Ordinary:默认引擎,在绝大多数情况下我们都会使用默认引擎,使用时无须刻意声明。在此数据库下可以使用任意类型的表引擎

2) Dictionary:字典引擎,此类数据库会自动为所有数据字典创建它们的数据表

3) Memory:内存引擎,用于存放临时数据。此类数据库下的数据表只会停留在内存中,不会涉及任何磁盘操作,当服务重启后数据会被清除

4) Lazy:日志引擎,此类数据库下只能使用Log系列的表引擎

5) MySQL:MySQL引擎,此类数据库下会自动拉取远端MySQL中的数据,并为它们创建MySQL表引擎的数据表

6)  MaterializeMySQL:MySQL数据同步;将MySQL数据全量或增量方式同步到clickhouse中,解决mysql服务并发访问压力过大的问题

4.1 MySQL 数据库引擎

MySQL数据库引擎

先在mysql中先创建好数据库db_mysql_test

  • 确认远程访问权限
  • 确认域名是否配置
create database school_score engine=MySQL('node-01:3306','school_score','root','aa_bb_CC1234');

这样就可以在clickhouse下查询mysql中的数据了

use school_score;
show tables;

在clickhouse 不能创建mysql引擎表。但可以在clickhouse插入数据到mysql;因为 clickhouse不支持delete删除数据、update更新操作;原因是clickhouse定位于olap分析,不支持事务

4.2 Log 家族【Log系列引擎】

Log家族,比较简单,数据少,测试使用,本地表,本地存储表数据。默认数据存储在:/var/lib/clickhouse/data/...

Log家族具有最小功能的轻量级引擎。当您需要快速写入许多小表(最多约100万行)并在以后整体读取它们时,该类型的引擎是最有效的

4.2.1 TinyLog引擎(数据不分块)

TinyLog引擎数据不分块,而Log会进行分块。所以效率上来说:TinyLog不如Log快,因为它是单线程的。

最简单的表引擎,用于将数据存储在磁盘上。每列都存储在单独的压缩文件中,写入时,数据将附加到文件末尾。

该引擎没有并发控制。

  1. 只支持并发读
  2. 如果同时从表中读取和写入数据,则读取操作将抛出异常;
  3. 如果同时写入多个查询中的表,则数据将被破坏。
-- 建表
create table tb_tinylog(id Int8, name String, age Int8, birthDay Date) engine=TinyLog;

-- 插入数据
insert into tb_tinylog values(1,'马云',56, '1990-01-01'),(2,'马化腾',55, '1990-01-01'),(3,'马克思',123, '1990-01-01');

-- 查询数据
select * from tb_tinylog;

ll /var/lib/clickhouse/data/default/test_db

-rw-r--r-- 1 root root  29 Jan 10 15:17 age.bin
-rw-r--r-- 1 root root  32 Jan 10 15:17 birthDay.bin
-rw-r--r-- 1 root root  29 Jan 10 15:17 id.bin
-rw-r--r-- 1 root root  54 Jan 10 15:17 name.bin
-rw-r--r-- 1 root root 121 Jan 10 15:17 sizes.json

数据存储在机器的磁盘上,每列一个文件,插入数据向列文件的后面追加

再插入一条数据后,存储列数据的文件的大小增加了

age.bin 和 id.bin, name.bin 是压缩过的对应的列的数据,sizes.json 中记录了每个 *.bin 文件的大小:

cat sizes.json

[root@node-01 tb_tinylog]# cat sizes.json 
{"yandex":{"age%2Ebin":{"size":"29"},"birthDay%2Ebin":{"size":"32"},"id%2Ebin":{"size":"29"},"name%2Ebin":{"size":"54"}}}[root@node-01 tb_tinylog]#

补充说明,如果表损坏,需要将表删除、表对应的元数据删除,然后重启clickhouse-server服务

[root@node-01 test_db]# rm -rf /var/lib/clickhouse/data/test_db/tb_tinylog
[root@node-01 test_db]# rm -rf /var/lib/clickhouse/metadata/test_db/tb_tinylog.sql

这种表引擎的典型用法是 write-once:

  1. 首先只写入一次数据,然后根据需要多次读取。此引擎适用于相对较小的表(建议最多1,000,000行)。
  2. 如果有许多小表,则使用此表引擎是适合的,因为它比需要打开的文件更少。当拥有大量小表时,可能会导致性能低下。不支持索引。

4.2.2 StripLog (数据分块列在一起)

在你需要写入许多小数据量(小于一百万行)的表的场景下使用这个引擎。

-- 建表
create table stripe_log_table (
    timestamp DateTime,
    message_type String,
    message String
) engine=StripeLog;

5、数据表

ClickHouse 数据表的定义语法,是在标准SQL的基础上建立的,所以熟悉数据库的读者们在看到接下来的语法时,应该会感到熟悉。ClickHouse 目前提供了三种最基本的建表方法!但是注意的是在CK中建表一定要指定表的引擎,那么表的引擎的详细文档在后面。

5.1 创建表

create table [if not exists] [db_name.]table_name (
name1 [type][DEFAULT|MATERLIALIZED|ALIAS expr],
name2 [type][DEFAULT|MATERLIALIZED|ALIAS expr],
省略...
) ENGINE=engine

第一种建表方式:

create table test_db.test1(
    id Int16 DEFAULT 0 comment '用户的标识',
    name String comment '用户姓名',
    age UInt8 comment '用户年龄'
) ENGINE=Log;

上述语句将会在default 默认的数据库下创建一张内存表。注意末尾的ENGINE 参数,它被用于指定数据表的引擎。表引擎决定了数据表的特性,也决定了数据将会被如何存储及加载。例如示例中使用的Memory表引擎,是ClickHouse最简单的表引擎,数据只会被保存在内存中,在服务重启时数据会丢失。

第二种方式建表:

这种方式其实就是复制已经存在的一张的表结构,可用于数据的备份,可用于多个数据库之间复制表结构

CREATE TABLE [IF NOT EXISTS] [db_name.]table_name AS [db_name2.]table_name2[ENGINE=engine];

示例:

create database newdb;
use newdb;

-- 将复制test_db 数据库中的test1 表的表结构
create table tb_test1 as test_db.test1;
desc tb_test1;

第三种方式建表:

通过SELECT 查询的方式创建表,同时也会导入查询的结果数据

-- 语法
CREATE TABLE [IF NOT EXISTS] [db_name.]table_name ENGINE=engine AS SELECT ...

示例

create table tb_log engine=Memory as select * from test_db.tb_tinylog;

5.2 删除表

DROP TABLE [IF EXISTS] [db_name.]table_name;

5.3 临时表

ClickHouse 也有临时表的概念,创建临时表的方法是在普通表的基础之上添加TEMPORARY 关键字,相比普通表而言,临时表也如下两点特殊之处:

  • 它的生命周期是会话绑定的,所以它只支持Memeory 表引擎,如果会话结束,数据表就会被销毁;
  • 临时表不属于任何数据库所以在它的建表语句中,既没有数据库参数也没有表引擎参数

临时表的有优先级大于系统中的表,一般用于集群之间的数据传播的载体

临时表的创建语法如下:

CREATE TEMPORARY TABLE [IF NOT EXISTS] table_name (
  name1 [type] [DEFAULT|MATERIALIZED|ALIAS expr],
  name2 [type] [DEFAULT|MATERIALIZED|ALIAS expr],
  ...
)

-- 直接创建临时表,临时表不属于任何一个数据库,也不会持久保存,不用指定引擎
create temporary table tb_tmp(id Int8, name String); -- 临时表不需要指定表的引擎

-- 创建临时表并加载数据
create temporary table log as select * from test_log;

-- 将临时表的数据导入到当前数据库表中,实现不同数据库的数据迁移
create table tb_log engine=Log as select * from log;

我们可以理解成临时表会将当前数据库中已经存在的同名表覆盖隐藏,当出现操作的时候,如果有临时表,那么会操作临时表!

临时表:

  1. 不属于任何数据库
  2. 会话断开以后表删除,不会持久化
  3. 如果本地表和临时表冲突,临时表优先
  4. 数据库之间的数据迁移
create table tb_name engine=Log as select * from db.tb;

create temporary table log as select * from test_db.test_log;
create table tb_log engine=Log as select * from log;

5.4 视图

5.4.1 普通视图

ClickHouse拥有普通和物化两种视图,其中物化视图拥有独立的存储,而普通视图只是一层简单的查询代理

CREATE VIEW [IF NOT EXISTS] [db_name.]view_name AS SELECT ...

普通视图不会存储任何数据,它只是一层单酏的SELECT 查询映射,起着简化查询、明晰语义的作用,对查询性能不会有任何增强。假设有一张普通视图 view_tb_v1,它是基于数据表 tb_v1创建的,那么下面的两格SELECT 查询是完全等价的。

SELECT * FROM tb_v1
-- tb_v1 的视图
SELECT * FROM view_tb_v1;

示例:

create table tb_teacher (
    tid Int8,
    name String,
    age UInt8,
    gender String,
    sal Float64
)engine=Log;

insert into tb_teacher values
    (1, 'wbb', 27, 'm', 20000),
    (2, 'lbb', 25, 'f', 30000),
    (3, 'mbb', 26, 'm', 40000),
    (4, 'sbb', 37, 'f', 50000),
    (5, 'lbb', 17, 'm', 60000);


create view teacher_view as select name, sal from tb_teacher;
-- 普通视图不存储数据,只是一个指向
select * from teacher_view;

5.4.2 物化视图

物化视图支持表引擎,相当于特殊的表,数据保存形式由它的表引擎决定,创建物化视图的完整语法如下所示:

create materialized view mv_log engine=Log populate as select * from log;
在磁盘上有表目录,目录中的文件和映射表的结构一样

-- 物化视图 特殊的表 结构 引擎 持久化
create materialized view m_teacher_view as engine=Log populate as select * from tb_teacher;

select * from m_teacher_view;

-- 向普通表tb_teacher插入数据
insert into tb_teacher values(6, 'xingge', 48, 'm', 1500);

-- 查询物化视图中的数据,同步数据
select * from m_teacher_view;

5.5 分区表

数据分区(partition)和数据分片(shard)是完全不同的两个概念。数据分区是针对本地数据而言的,是数据的一种纵向切分。而数据分片是数据的一种横向切分。数据分区对于一款OLAP数据库而言意义非凡:借助数据分共,在后续的查询过程中能够跳过不必要的数据目录,从而提升查询的性能。合理地利用分区特性,还可以变相实现数据的更新操作,因为数据分区支持删除、替换和重置操作。假设数据表按照月份分区,那么数据就可以按月份的粒度被替换更新。分区虽好,但不是所有的表引擎都可以使用这项特性,目前只有合并树(MergeTree)家族系列的表引擎才支持数据分区。接下来通过一个简单的例子演示分区表的使用方法。首先由PARTITION BY 指定分区键,并将其格式化为年月的形式:

create table tb_partition(
    cid String,
    ctime DateTime,
    money Float64
)engine=MergeTree() -- MergeTree家族最简单的引擎
partition by toYYYYMM(ctime) -- 按照年月来分区
order by cid -- 指定排序字段; 当排序字段与主键字段是同一个字段时,就会将主键字段不指定
primary key cid;

-- 插入数据
insert into tb_partition values
(1, '2020-12-01 11:00:21', 100),
(2, '2020-12-02 11:12:21', 300),
(3, '2020-11-01 11:00:21', 200);

-- 查询tb_partition表的分区信息
select table, partition, engine, path from system .parts where table='tb_partition';

-- 再次插入数据,进入到/var/lib/clickhouse/data/test_db/tb_partition/ 会发现11、12月份的数据都各有2个块
insert into tb_partition values
(4, '2020-12-01 11:00:21', 100),
(5, '2020-12-02 11:12:21', 300),
(6, '2020-11-01 11:00:21', 200);

-- 合并数据
optimize table tb_partition; -- 一次合并两个分区

-- 进入到/var/lib/clickhouse/data/test_db/tb_partition/ 会发现11、12月份的数据都各有1个块
-- 之前老的分区,默认8分钟会被删除

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

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

相关文章

Python 情感分析与词向量

Python 情感分析与词向量 在现代数据驱动的世界中&#xff0c;情感分析成为了一种重要的文本分析技术&#xff0c;它帮助我们理解和挖掘用户对产品、服务或事件的情感倾向。Python 作为一种强大的编程语言&#xff0c;提供了丰富的工具和库来支持情感分析的实现&#xff0c;其…

【Kubernets】配置类型资源 Etcd, Secret, ConfigMap

文章目录 所有资源概览Etcd详细说明一、基本概念二、主要功能三、架构与组件四、数据模型与操作五、安全与认证六、集群部署与管理 Secret详细说明一、Secret 的类型二、Secret 的创建三、Secret 的使用四、Secret 的更新与删除五、Secret 的安全性 ConfigMap详细说明一、Confi…

Web服务器小项目(Linux / C / epoll)

注意&#xff1a;前置知识: HTTP: https://xingzhu.top/archives/web-fu-wu-qi Linux 多线程: https://xingzhu.top/archives/duo-xian-cheng 源码放github上了&#xff0c;欢迎star: https://github.com/xingzhuz/webServer 思路 实现代码 server.h #pragma once #include &…

毕设成品 基于深度学习二维码检测识别系统

文章目录 0 简介1 二维码基础概念1.1 二维码介绍1.2 QRCode1.3 QRCode 特点 2 机器视觉二维码识别技术2.1 二维码的识别流程2.2 二维码定位2.3 常用的扫描方法 4 深度学习二维码识别4.1 部分关键代码 最后 0 简介 今天学长向大家分享一个毕业设计项目 **毕业设计 基于深度学习…

【最新华为OD机试E卷-支持在线评测】第K个排列(100分)多语言题解-(Python/C/JavaScript/Java/Cpp)

🍭 大家好这里是春秋招笔试突围 ,一枚热爱算法的程序员 💻 ACM金牌🏅️团队 | 大厂实习经历 | 多年算法竞赛经历 ✨ 本系列打算持续跟新华为OD-E/D卷的多语言AC题解 🧩 大部分包含 Python / C / Javascript / Java / Cpp 多语言代码 👏 感谢大家的订阅➕ 和 喜欢�…

【MySQL 保姆级教学】在Linux(CentoS 7)中安装MySQL(1)

目录 1. 卸载linux&#xff08;Centos7&#xff09; 中不要的环境2. 获取MySQL官方yum源2.1 获取yum源前先查看自己 linux&#xff08;Centos&#xff09;的版本2.2 获取官方yum源 3. 安装xftp和连接4. 开放连接端口5. 上传文件到Centos76. 安装MySQL6.1 顺利安装6.2 查询是否安…

Terminus ssh key 登陆

生成key 一、添加 KEY 配置 电脑: Terminus > Preferences&#xff0c;或 ⌘,。选择左侧 Keychain 标签。 手机: Terminus > Keychain 电脑: 点击右侧上方的 NEW KEY 按钮, 手机: 点加号 电脑: 在最右侧弹出的页面中填写 Label 和 Private key&#xff0c;Private ke…

电脑怎么录屏?探索屏幕捕捉的奥秘,新手也能成为录屏高手!

在数字时代&#xff0c;无论是制作教学视频、分享游戏精彩瞬间还是展示软件操作流程&#xff0c;屏幕录制都成了一项必不可少的技能。然而&#xff0c;对于许多初次接触录屏的新手来说&#xff0c;如何开始这一过程似乎充满了挑战。本文将为你揭开录屏的神秘面纱&#xff0c;带…

golang-基础知识(流程控制)

1 条件判断if和switch 所有的编程语言都有这个if&#xff0c;表示如果满足条件就做某事&#xff0c;不满足就做另一件事&#xff0c;go中的if判断和其它语言的区别主要有以下两点 1. go里面if条件判断不需要括号 2. go的条件判断语句中允许声明一个变量&#xff0c;这个变量…

MySQL8.0环境部署+Navicat17激活教程

安装MySQL 下载MySQL MySQL官网下载当前最新版本&#xff0c;当前是8.0.39。 选择No thanks, just start my download等待下载即可。 安装MySQL 下载完成后&#xff0c;双击安装进入安装引导页面。选择Custom自定义安装。 选择MySQL Server 8.0.39 - X64安装。 点击Execute执…

基于BeautyEye开发Java程序用户界面

文章目录 I idea引入jar包添加本地jar包maven方式引入本地包方式1:将第三方JAR包安装到本地仓库maven方式引入本地包方式2:引用本地路径将本地jar包打进war包Maven内置变量说明II BeautyEye Swing外观实现方案案例III 知识扩展Swing常用的顶级容器BeautyEye SwingI idea引入j…

在python中如何判断回文串(二)?

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;开发者-曼亿点 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 曼亿点 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a…

一次性解决vue3引入@jiaminghi/data-view需要手动修改node_modules下文件

修改文件1&#xff1a;node_modules\jiaminghi\data-view\lib\components\decoration6\src\main.vue 修改文件2&#xff1a; node_modules\jiaminghi\data-view\lib\components\decoration3\src\main.vue 修改前&#xff1a; 修改后&#xff1a; 通过打补丁的方式对引用库进行…

SpringBoot购物推荐网站:从零到一的构建过程

1系统概述 1.1 研究背景 如今互联网高速发展&#xff0c;网络遍布全球&#xff0c;通过互联网发布的消息能快而方便的传播到世界每个角落&#xff0c;并且互联网上能传播的信息也很广&#xff0c;比如文字、图片、声音、视频等。从而&#xff0c;这种种好处使得互联网成了信息传…

如何使用ipopt进行非线性约束求目标函数最小值(NLP非线性规划)内点法(Interior point method)

非线性规划,一般用matlab调用cplex和gurobi了,但这两个一般用于线性规划和二次规划 线性规划LP,二次规划(quadratic programming),如果要求更一般的非线性规划IPOT是个很好的选择,求解器很多,根据情况自己选择 非线性 具体的,这篇文章介绍的很清楚了https://blog.csd…

Javascript笔试题目(一)

1.JS查找文章中出现频率最高的单词? 要在JavaScript中查找文章中出现频率最高的单词&#xff0c;你可以按照以下步骤进行操作&#xff1a; 将文章转换为小写&#xff1a;这可以确保单词的比较是大小写不敏感的。移除标点符号&#xff1a;标点符号会干扰单词的计数。将文章拆…

SpringBoot环境下的电商推荐网站开发全攻略

1系统概述 1.1 研究背景 如今互联网高速发展&#xff0c;网络遍布全球&#xff0c;通过互联网发布的消息能快而方便的传播到世界每个角落&#xff0c;并且互联网上能传播的信息也很广&#xff0c;比如文字、图片、声音、视频等。从而&#xff0c;这种种好处使得互联网成了信息传…

题目:1297. 子串的最大出现次数

> Problem: 1297. 子串的最大出现次数 题目&#xff1a;1297. 子串的最大出现次数 题目描述 给定一个字符串 s&#xff0c;要求找到满足以下条件的任意子串的出现次数&#xff0c;并返回该子串的最大出现次数&#xff1a; 子串中不同字母的数目必须小于等于 maxLetters。…

使用3080ti配置安装blip2

使用3080ti运行blip2的案例 本机环境&#xff08;大家主要看GPU&#xff0c;ubuntu版本和cuda版本即可&#xff09;&#xff1a;安装流程我最后安装的所有包的信息&#xff08;python 3.9 &#xff09;以供参考&#xff08;environment.yml&#xff09;&#xff1a; 本机环境&a…

Git:LF will be replaced by CRLF、pytest PermissionError以及Git应用中的一些问题解决及一些使用技巧

一、Git:LF will be replaced by CRLF和pytest: --cov NTERNALERROR PermissionError 1. git warning: LF will be replaced by CRLF in ***file 偶然git add在进行代码提交的时候碰到警告warning: LF will be replaced by CRLF in ***file&#xff0c;原因是编辑的代码内容中…