clickHouse下篇

clickHouse下篇
    数据标记
        数据标记作为衔接一级索引和数据的桥梁,其像极了做过标记小抄的书签,而且书本中每个一级章节都拥有各自的书签。
            
        数据标记和索引区间是对齐的,均按照index_granularity的粒度间隔。
        为了能够与数据衔接,数据标记文件也与.bin文件一一对应。
每一个列字段[Column].bin文件都有一个与之对应的[Column].mrk数据标记文件,用于记录
数据在.bin文件中的偏移量信息。
        一行标记数据使用一个元组表示,元组内包含两个整型数值的偏移量信息。
它们分别表示在此段数据区间内,在对应的.bin压缩文件中,压缩数据块的起始偏移量;
以及将该数据压缩块解压后,其未压缩数据的起始偏移量。
        每一行标记数据都表示了一个片段的数据(默认8192行)在.bin压缩文件中的读取位置信息。标记
数据与一级索引数据不同,它并不能常驻内存,而是使用LRU(最近最少使用)缓存策略加快其取用速度。
        标记查看命令
od -An -l name.mrk
        工作方式
            MergeTree在读取数据时,必须通过标记数据的位置信息才能够找到所需要的数据。整个查找过程
大致可以分为读取压缩数据块和读取数据两个步骤
                
            数据理解
1B*8192=8192B,64KB=65536B,65536/8192=8
头信息固定由9个字节组成,压缩后大小为8个字节
12016=8+12000+8
            读取压缩数据块:
                在查询某一列数据时,MergeTree无须一次性加载整个.bin文件,而是可以根据需要,只加载
特定的压缩数据块。而这项特性需要借助标记文件中所保存的压缩文件中的偏移量。
            读取数据:
                在读取解压后的数据时,MergeTree并不需要一次性扫描整段解压数据,它可以根据需要,
以index_granularity的粒度加载特定的一小段。为了实现这项特性,需要借助标记文件中保
存的解压数据块中的偏移量。
    数据标记与数据压缩
        由于压缩数据块的划分,与一个间隔(index_granularity)内的数据大小相关,每个压缩数据块的体积都被严格控制在64KB~1MB。而一个间隔(index_granularity)的数据,又只会产生一行数据标记。那么根据一个间隔内数据的实际字节大小,数据标记和压缩数据块之间会产生三种不同的对应关系。
        一条数据默认大小为8192,那么当数据总体大于8192时就需要多个数据标记了。小于的话就是一对几个数据标记
        多对一
            多个数据标记对应一个压缩数据块
            当一个间隔(index_granularity)内的数据未压缩大小size小于64KB时
                
        一对一
            这个一对一就是等于这个大小的样子
            一个数据标记对应一个压缩数据块
            当一个间隔(index_granularity)内的数据未压缩大小size大于等于64KB且小于等于1MB时
                
        一对多
            一个数据标记对应多个压缩数据块
            当一个间隔(index_granularity)内的数据未压缩大小size直接大于1MB时
                
    数据读写流程
        写入数据
            数据写入的第一步是生成分区目录,伴随着每一批数据的写入,都会生成一个新的分区目录。在后续的某一时刻,属于相同分区的目录会依照规则合并到一起;接着,按照index_granularity索引粒
度,会分别生成primary.idx一级索引、每一个列字段的.mrk数据标记和.bin压缩数据文件。
                
            从分区目录201403_1_34_3能够得知,该分区数据共分34批写入,期间发生过3次合并。在数据写入的过程中,依据index_granularity的粒度,依次为每个区间的数据生成索引、标记和压缩数据块。其中,索引和标记区间是对齐的,而标记与压缩块则根据区间数据大小的不同,会生成多对一、一对一和一对多三种关系。
         查询数据
            数据查询的本质,可以看作一个不断减小数据范围的过程。在最理想的情况下,MergeTree首先可以依次借助分区索引、一级索引和二级索引,将数据扫描范围缩至最小。然后再借助数据标记,将
需要解压与计算的数据范围缩至最小。
            图示
                
    数据查询方式
        在日常运转的过程中,数据查询也是ClickHouse的主要工作之一。ClickHouse完全使用SQL作为查
询语言,能够以SELECT查询语句的形式从数据库中选取数据,这也是它具备流行潜质的重要原
因。虽然ClickHouse拥有优秀的查询性能,但是我们也不能滥用查询,掌握ClickHouse所支持的各
种查询子句,并选择合理的查询形式是很有必要的。使用不恰当的SQL语句进行查询不仅会带来低
性能,还可能导致不可预知的系统错误。
        ClickHouse对于SQL语句的解析是大小写敏感的,这意味着SELECT a和SELECT A表示的语义是不相同的。
        With子句
            ClickHouse支持CTE(Common Table Expression,公共表表达式),以增强查询语句的表达。
            在改用CTE的形式后,可以极大地提高语句的可读性和可维护性
            With的四种使用方法:
                定义变量
                    可以定义变量,这些变量能够在后续的查询子句中被直接访问。
                    WITH 10 AS start
SELECT number FROM system.numbers
WHERE number > start
LIMIT 5
                调用函数
                    可以访问SELECT子句中的列字段,并调用函数做进一步的加工处理。
                    WITH SUM(data_uncompressed_bytes) AS bytes
SELECT database , formatReadableSize(bytes) AS format FROM
system.columns
GROUP BY database
ORDER BY bytes DESC
                定义子查询
                    可以定义子查询。
                    例如在下面的示例中,借助子查询可以得出各database未压缩数据大小与数据总和大小的比例的排名:
                    WITH (
SELECT SUM(data_uncompressed_bytes) FROM system.columns
) AS total_bytes
SELECT database , (SUM(data_uncompressed_bytes) / total_bytes) * 100
AS database_disk_usage
FROM system.columns
GROUP BY database
ORDER BY database_disk_usage DESC
                    在子查询中重复使用WITH
在子查询中可以嵌套使用WITH子句
例如在下面的示例中,在计算出各database未压缩数据大小与数据总和的比例之后,又
进行了取整函数的调用:
                    WITH (
round(database_disk_usage)
) AS database_disk_usage_v1
SELECT database,database_disk_usage, database_disk_usage_v1
FROM (
--嵌套
WITH (
SELECT SUM(data_uncompressed_bytes) FROM system.columns
) AS total_bytes
SELECT database , (SUM(data_uncompressed_bytes) / total_bytes) * 100
AS database_disk_usage FROM system.colum
GROUP BY database
ORDER BY database_disk_usage DESC
)
        From子句
            FROM子句表示从何处读取数据,目前支持如下3种形式
                从数据表中取数
                    SELECT WatchID FROM hits_v1
                从子查询中取数
                    SELECT MAX_WatchID
FROM (SELECT MAX(WatchID) AS MAX_WatchID FROM hits_v1)
                从表函数中取数
                    SELECT number FROM numbers(5)
            在ClickHouse中,并没有数据库中常见的DUAL虚拟表,取而代之的是system.one。
                SELECT 1
SELECT 1 FROM system.one
            在FROM子句后,可以使用Final修饰符。
                它可以配合CollapsingMergeTree和Versioned-CollapsingMergeTree等表引擎进行查询操
作,以强制在查询过程中合并
                但由于Final修饰符会降低查询性能,所以应该尽可能避免使用它。
        Sample子句
            SAMPLE子句能够实现数据采样的功能,使查询仅返回采样数据而不是全部数据,从而有效减少查询负载。
            SAMPLE子句的采样机制是一种幂等设计,也就是说在数据不发生变化的情况下,使用相同的采样
规则总是能够返回相同的数据,所以这项特性非常适合在那些可以接受近似查询结果的场合使用。
            SAMPLE子句只能用于MergeTree系列引擎的数据表,并且要求在CREATE TABLE时声明SAMPLEBY抽样表达式
            SAMPLE子句目前支持如下3种用法
                SAMPLE factor
                    SAMPLE factor表示按因子系数采样,其中factor表示采样因子,它的取值支持0~1之间的小数。
                    如果factor设置为0或者1,则效果等同于不进行数据采样。
                    SELECT CounterID FROM hits_v1 SAMPLE 0.1
SELECT count() * 10 FROM hits_v1 SAMPLE 0.1
SELECT CounterID, _sample_factor FROM hits_v1 SAMPLE 0.1 LIMIT 2
SELECT count() * any(_sample_factor) FROM hits_v1 SAMPLE 0.1
                SAMPLE rows
                    SAMPLE rows表示按样本数量采样,其中rows表示至少采样多少行数据,它的取值必须是大于1的整数。
                    如果rows的取值大于表内数据的总行数,则效果等于rows=1
                    SELECT count() FROM hits_v1 SAMPLE 10000
SELECT CounterID,_sample_factor FROM hits_v1 SAMPLE 100000 LIMIT 1
                SAMPLE factor OFFSET n
                    SAMPLE factor OFFSET n表示按因子系数和偏移量采样,其中factor表示采样因子,n
表示偏移多少数据后才开始采样,它们两个的取值都是0~1之间的小数。
                    SELECT CounterID FROM hits_v1 SAMPLE 0.4 OFFSET 0.5
SELECT CounterID,_sample_factor FROM hits_v1 SAMPLE 1/10 OFFSET 1/2
                    最终的查询会从数据的二分之一处开始,按0.4的系数采样数据
                        
                    如果在计算OFFSET偏移量后,按照SAMPLE比例采样出现了溢出,则数据会被自动截断
                        
         Array Join子句
            ARRAY JOIN子句允许在数据表的内部,与数组或嵌套类型的字段进行JOIN操作,从而将一行数组
展开为多行。接下来让我们看看它的基础用法。
                CREATE TABLE query_v1
(
title String,
value Array(Int8)
) ENGINE = Log
INSERT INTO query_v1 VALUES ('food', [1,2,3]), ('fruit', [3,4]),
('meat', [])
SELECT title,value FROM query_v1
            在一条SELECT语句中,只能存在一个ARRAY JOIN(使用子查询除外)。目前支持INNER和LEFT两种
                INNER ARRAY JOIN
                    ARRAY JOIN在默认情况下使用的是INNER JOIN策略
                    SELECT title,value FROM query_v1 ARRAY JOIN value
SELECT title,value,v FROM query_v1 ARRAY JOIN value AS v
                    从查询结果可以发现,最终的数据基于value数组被展开成了多行,并且排除掉了空数组。
                    在使用ARRAY JOIN时,如果为原有的数组字段添加一个别名,则能够访问展开前的数组字段
                LEFT ARRAY JOIN
                    ARRAY JOIN子句支持LEFT连接策略
                    SELECT title,value,v FROM query_v1 LEFT ARRAY JOIN value AS v;
SELECT title,value,v ,arrayMap(x -> x * 2,value) as mapv,v_1 FROM
query_v1 LEFT ARRAY JOIN value AS v , mapv as v_1;
                    在改为LEFT连接查询后,可以发现,在INNER JOIN中被排除掉的空数组出现在了返回的结果集中。
                    当同时对多个数组字段进行ARRAY JOIN操作时,查询的计算逻辑是按行合并而不是产生笛卡儿积。
         Join 子句
            JOIN子句可以对左右两张表的数据进行连接
            JOIN的语法包含连接精度和连接类型两部分
            JOIN查询还可以根据其执行策略被划分为本地查询和远程查询。
                
            连接精度
                连接精度决定了JOIN查询在连接数据时所使用的策略,目前支持ALL、ANY和ASOF三种类型。如果不主动声明,则默认是ALL。
                    对数据是否连接匹配的判断是通过JOIN KEY进行的,目前只支持等式(EQUAL JOIN)。
                    交叉连接(CROSS JOIN)不需要使用JOINKEY,因为它会产生笛卡儿积
                all
                    如果左表内的一行数据,在右表中有多行数据与之连接匹配,则返回右表中全部连接的数据。
                    而判断连接匹配的依据是左表与右表内的数据,基于连接键(JOIN KEY)的取值完全相等
(equal),等同于left.key=right.key。
                    select EMPNO,ENAME,DEPTNO,DNAME from emp all INNER JOIN dept d on
emp.DEPTNO = d.DEPTNO;
                any
                    如果左表内的一行数据,在右表中有多行数据与之连接匹配,则仅返回右表中第一行连接的数据
                    select distinct DEPTNO,DNAME from emp all INNER JOIN dept d on
emp.DEPTNO = d.DEPTNO;
select DEPTNO,DNAME from emp any INNER JOIN dept d on emp.DEPTNO =
d.DEPTNO;
                asof
                    ASOF是一种模糊连接,它允许在连接键之后追加定义一个模糊连接的匹配条件asof_column。
                    最终返回的查询结果符合连接条件a.id=b.id AND a.time>=b.time,且仅返回了右表中第一行
连接匹配的数据。
                    ASOF支持使用USING的简写形式,USING后声明的最后一个字段会被自动转换成asof_colum模糊连接条件
                    asof_colum必须是整型、浮点型和日期型这类有序序列的数据类型;
                    asof_colum不能是数据表内的唯一字段
                    select emp.*,dept.* from emp asof INNER JOIN dept using (DEPTNO,SAL);
--相当于
select * from emp all INNER JOIN dept d on emp.DEPTNO = d.DEPTNO where
emp.SAL>=d.SAL;
            连接类型
                Inner
                    INNER JOIN表示内连接,在查询时会以左表为基础逐行遍历数据,然后从右表中找出与左边
连接的行,它只会返回左表与右表两个数据集合中交集的部分,其余部分都会被排除
                        
                OUTER
                    OUTER JOIN表示外连接,它可以进一步细分为左外连接(LEFT)、右外连接(RIGHT)和全
外连接(FULL)三种形式。根据连接形式的不同,其返回数据集合的逻辑也不尽相同。
                Cross
                    CROSS JOIN表示交叉连接,它会返回左表与右表两个数据集合的笛卡儿积。
                        
            查询优化
                为了能够优化JOIN查询性能,首先应该遵循左大右小的原则 ,无论使用的是哪种连接方式,右表
都会被全部加载到内存中与左表进行比较。
                JOIN查询目前没有缓存的支持
                如果是在大量维度属性补全的查询场景中,则建议使用字典代替JOIN查询
                连接查询的空值是由默认值填充的,这与其他数据库所采取的策略不同(由Null填充)。
                    连接查询的空值策略是通过join_use_nulls参数指定的,
默认为0。当参数值为0时,空值由数据类型的默认值填充;
当参数值为1时,空值由Null填充。
        WHERE与PREWHERE子句
            WHERE子句基于条件表达式来实现数据过滤。如果过滤条件恰好是主键字段,则能够进一步借助
索引加速查询,
WHERE子句是一条查询语句能否启用索引的判断依据
            PREWHERE目前只能用于MergeTree系列的表引擎,它可以看作对WHERE的一种优化,其作用与
WHERE相同,均是用来过滤数据。
使用PREWHERE时,首先只读取PREWHERE指定的列字段数据,用于数据过滤的条件判断。
待数据过滤之后再读取SELECT声明的列字段以补全其余属性。
            ClickHouse实现了自动优化的功能,会在条件合适的情况下将WHERE替换为PREWHERE。
如果想开启这项特性,需要将optimize_move_to_prewhere设置为1
        GROUP BY子句
            GROUP BY又称聚合查询
            聚合查询目前还能配合WITH ROLLUP、WITHCUBE和WITH TOTALS三种修饰符获取额外的汇总信息。
            WITH ROLLUP
                ROLLUP能够按照聚合键从右向左上卷数据,基于聚合函数依次生成分组小计和总计。
如果设聚合键的个数为n,则最终会生成小计的个数为n+1
                SELECT table, name, SUM(bytes_on_disk) FROM system.parts
GROUP BY table,name
WITH ROLLUP
ORDER BY table
             WITH CUBE
                CUBE会像立方体模型一样,基于聚合键之间所有的组合生成小计信息。如果设聚合键的个数为n,则最终小计组合的个数为2的n次方。
            WITH TOTALS
                使用TOTALS修饰符后,会基于聚合函数对所有数据进行总计
                SELECT database, SUM(bytes_on_disk),COUNT(table) FROM system.parts
GROUP BY database WITH TOTALS
        Having子句
            HAVING子句需要与GROUP BY同时出现,不能单独使用。它能够在聚合计算之后实现二次过滤数据
        ORDER BY子句
            ORDER BY子句通过声明排序键来指定查询数据返回时的顺序。
                在MergeTree中指定ORDER BY后,数据在各个分区内会按照其定义的规则排序,这是一种分
区内的局部排序。如果在查询时数据跨越了多个分区,则它们的返回顺序是无法预知的,每一
次查询返回的顺序都可能不同。
                如果需要数据总是能够按照期望的顺序返回,就需要借助ORDER BY子句来指定全局顺序。
            ORDER BY在使用时可以定义多个排序键,每个排序键后需紧跟ASC(升序)或DESC(降序)来确
定排列顺序。如若不写,则默认为ASC(升序)。
                
            空值处理
                NULLS LAST
数据的排列顺序为其他值(value)→NaN→NULL。
                NULLS FIRST
数据的排列顺序为NULL→NaN→其他值(value)
ORDER BY v1 DESC NULLS FIRST
        LIMIT BY子句
            LIMIT BY子句和大家常见的LIMIT所有不同,它运行于ORDER BY之后和LIMIT之前,能够按照指定
分组,最多返回前n行数据(如果数据少于n行,则按实际数量返回)
            常用于TOP N的查询场景。LIMIT BY的常规语法如下:
LIMIT n BY express
            基于数据库和数据表分组的情况下,查询返回数据占磁盘空间最大的前3张表:
            SELECT database,table,MAX(bytes_on_disk) AS bytes FROM system.parts
GROUP BY database,table ORDER BY database ,bytes DESC
LIMIT 3 BY database
            SELECT database,table,MAX(bytes_on_disk) AS bytes FROM system.parts
GROUP BY database,table ORDER BY bytes DESC
LIMIT 3 OFFSET 1 BY database
        LIMIT子句
            LIMIT子句用于返回指定的前n行数据,常用于分页场景
            它的三种语法形式如下所示:
                LIMIT n
SELECT number FROM system.numbers LIMIT 10
LIMIT n OFFSET m
SELECT number FROM system.numbers LIMIT 10 OFFSET 5
LIMIT m,n
SELECT number FROM system.numbers LIMIT 5 ,10
            查询返回数据占磁盘空间最大的前3张表,而返回的总数据行等于10。
            SELECT database,table,MAX(bytes_on_disk) AS bytes FROM system.parts
GROUP BY database,table ORDER BY bytes DESC
LIMIT 3 BY database
LIMIT 10
            使用LIMIT子句时有一点需要注意,如果数据跨越了多个分区,在没有使用ORDER BY指定全局顺序
的情况下,每次LIMIT查询所返回的数据有可能不同。如果对数据的返回顺序敏感,则应搭配ORDER BY一同使用。
    副本与分片
        自己看
            
    常见类型表引擎
        外部存储
            外部存储表引擎直接从其他的存储系统读取数据
            例如直接读取HDFS的文件或者MySQL数据库的表。
            这些表引擎只负责元数据管理和数据查询,而它们自身通常并不负责数据的写入,数据文件直接由外部系统提供。
            HDFS
                --在HDFS上创建用于存放文件的目录
hadoop fs -mkdir /clickhouse
--在HDFS上给ClickHouse用户授权
hadoop fs -chown -R clickhouse:clickhouse /clickhouse
--hdfs_uri表示HDFS的文件存储路径,format表示文件格式
ENGINE = HDFS(hdfs_uri,format)
CREATE TABLE hdfs_table1(
id UInt32,
code String,
name String
INSERT INTO hdfs_table1 SELECT
number,concat('code',toString(number)),concat('n',toString(number)) FROM
numbers(5)
--其他方式,只能读取
ENGINE =
3}.csv','CSV')
ENGINE =
v','CSV')
            Mysql
                MySQL表引擎可以与MySQL数据库中的数据表建立映射,并通过SQL向其发起远程查询,包括SELECT和INSERT
                host:port表示MySQL的地址和端口。
database表示数据库的名称。
table表示需要映射的表名称。
user表示MySQL的用户名。
password表示MySQL的密码。
replace_query默认为0,对应MySQL的REPLACE INTO语法。如果将它设置为1,则会用
REPLACEINTO代替INSERT INTO。
on_duplicate_clause默认为0,对应MySQL的ON DUPLICATE KEY语法。如果需要使用该设
置,则必须将replace_query设置成0。
                ENGINE = MySQL('host:port', 'database', 'table', 'user', 'password'[,replace_query, 'on_duplicate_clause'])
            JDBC
                JDBC表引擎不仅可以对接MySQL数据库,还能够与PostgreSQL、SQLite和H2数据库对接。
                JDBC表引擎无法单独完成所有的工作,它需要依赖名为clickhouse-jdbc-bridge的查询代理服务
                clickhouse-jdbc-bridge是一款基于Java语言实现的SQL代理服务,它的项目地址为 GitHub - ClickHouse/clickhouse-jdbc-bridge: A JDBC proxy from ClickHouse to external databases
                clickhouse-jdbc-bridge可以为ClickHouse代理访问其他的数据库,并自动转换数据类型。
            kafka
                目前ClickHouse还不支持恰好一次(Exactly once)的语义,因为这需要应用端与Kafka深度配合才能实现。
                必填参数:
                    kafka_broker_list:表示Broker服务的地址列表,多个地址之间使用逗号分隔。
kafka_topic_list:表示订阅消息主题的名称列表,多个主题之间使用逗号分隔。
kafka_group_name:表示消费组的名称,表引擎会依据此名称创建Kafka的消费组。
kafka_format:表示用于解析消息的数据格式,在消息的发送端,必须按照此格式发送
消息。数据格式必须是ClickHouse提供的格式之一
                选填参数:
                    kafka_row_delimiter:表示判定一行数据的结束符,默认值为'\0'。
kafka_schema:对应Kafka的schema参数。
kafka_num_consumers:表示消费者的数量,默认值为1。
kafka_skip_broken_messages:当表引擎按照预定格式解析数据出现错误时,允许跳过
失败的数据行数,默认值为0,即不允许任何格式错误的情形发生。
kafka_commit_every_batch:表示执行Kafka commit的频率
默认值为0,即当一整个Block数据块完全写入数据表后才执行Kafka commit。
如果将其设置为1,则每写完一个Batch批次的数据就会执行一次Kafka commit
                再次执行SELECT查询会发现kafka_table数据表空空如也,这是因为Kafka表引擎在执行查询之
后就会移动offset,导致数据无法重复读取。
                首先是Kafka数据表A,它充当的角色是一条数据管道,负责拉取Kafka中的数据。
接着是另外一张任意引擎的数据表B,它充当的角色是面向终端用户的查询表,在生产环境中
通常是MergeTree系列。
最后,是一张物化视图C,它负责将表A的数据实时同步到表B。
                    
            File
                File表引擎能够直接读取本地文件的数据,通常被作为一种扩充手段来使用。
                File表引擎的定义参数中,并没有包含文件路径这一项。所以,File表引擎的数据文件只能保存在config.xml配置中由path指定的路径下。
                每张File数据表均由目录和文件组成,其中目录以表的名称命名,而数据文件则固定以data.format命名
        内存类型
            将数据全量放在内存中,对于表引擎来说是一把双刃剑:
                一方面,这意味着拥有较好的查询性能;
                另一方面,如果表内装载的数据量过大,可能会带来极大的内存消耗和负担。
            Memory
                Memory表引擎直接将数据保存在内存中,数据既不会被压缩也不会被格式转换,数据在内存中保存的形态与查询时看到的如出一辙。
                当ClickHouse服务重启的时候,Memory表内的数据会全部丢失。
                当数据被写入之后,磁盘上不会创建任何数据文件。
            Set
                Set表引擎是拥有物理存储的,数据首先会被写至内存,然后被同步到磁盘文件中。
                所以当服务重启时,它的数据不会丢失,当数据表被重新装载时,文件数据会再次被全量加载至内存。
                Set表引擎具有去重的能力,在数据写入的过程中,重复的数据会被自动忽略。
                Set表引擎的存储结构由两部分组成,它们分别是:
                    [num].bin数据文件:保存了所有列字段的数据。其中,num是一个自增id,从1开始。伴随
着每一批数据的写入(每一次INSERT),都会生成一个新的.bin文件,num也会随之加1。
                    tmp临时目录:数据文件首先会被写到这个目录,当一批数据写入完毕之后,数据文件会被移出此目录。
            Join
                Join表引擎可以说是为JOIN查询而生的,它等同于将JOIN查询进行了一层简单封装。在Join表引擎的底层实现中,它与Set表引擎共用了大部分的处理逻辑,所以Join和Set表引擎拥有许多相似之
处。
                ENGINE = Join(join_strictness, join_type, key1[, key2, ...])
                join_strictness:连接精度,它决定了JOIN查询在连接数据时所使用的策略,目前支持ALL、ANY和ASOF三种类型。
                join_type:连接类型,它决定了JOIN查询组合左右两个数据集合的策略,它们所形成的结果
是交集、并集、笛卡儿积或其他形式,目前支持INNER、OUTER和CROSS三种类型。当
join_type被设置为ANY时,在数据写入时,join_key重复的数据会被自动忽略。
                join_key:连接键,它决定了使用哪个列字段进行关联。
        日志类型
            TinyLog
                TinyLog是日志家族系列中性能最低的表引擎,它的存储结构由数据文件和元数据两部分组成
                    数据文件是按列独立存储的,也就是说每一个列字段都拥有一个与之对应的.bin文件。
TinyLog既不支持分区,也没有.mrk标记文件
由于没有标记文件,它自然无法支持.bin文件的并行读取操作,所以它只适合在非常简单的场景下使用
            StripeLog
                StripeLog表引擎的存储结构由固定的3个文件组成,它们分别是:
data.bin:数据文件,所有的列字段使用同一个文件保存,它们的数据都会被写入data.bin。
index.mrk:数据标记,保存了数据在data.bin文件中的位置信息。利用数据标记能够使用多
个线程,以并行的方式读取data.bin内的压缩数据块,从而提升数据查询的性能。
sizes.json:元数据文件,记录了data.bin和index.mrk大小的信息。
            Log
                Log表引擎结合了TinyLog表引擎和StripeLog表引擎的长处,是日志家族系列中性能最高的表引擎。
                Log表引擎的存储结构由3个部分组成:
[column].bin:数据文件,数据文件按列独立存储,每一个列字段都拥有一个与之对应的.bin
文件。
marks.mrk:数据标记,统一保存了数据在各个[column].bin文件中的位置信息。利用数据标
记能够使用多个线程,以并行的方式读取.bin内的压缩数据块,从而提升数据查询的性能。
sizes.json:元数据文件,记录了[column].bin和__marks.mrk大小的信息。
        接口类型
            在数据仓库的设计中,数据按年分表存储,例如test_table_2018、test_table_2019和
test_table_2020。假如现在需要跨年度查询这些数据 ?
            Merge表引擎就如同一层使用了门面模式的代理,它本身不存储任何数据,也不支持数据写入。
它的作用就如其名,即负责合并多个查询的结果集。
Merge表引擎可以代理查询任意数量的数据表,这些查询会异步且并行执行,并最终合成一个结果集返回
            被代理查询的数据表被要求处于同一个数据库内,且拥有相同的表结构,但是它们可以使用不同的表引擎以及不同的分区定义
            ENGINE = Merge(database, table_name)
            database表示数据库名称;
table_name表示数据表的名称,它支持使用正则表达式
    MergeTree Family
        MergeTree
            数据TTL
                TTL即Time To Live,顾名思义,它表示数据的存活时间。在MergeTree中,可以为某个列字段或整张表设置TTL。
                    当时间到达时,如果是列字段级别的TTL,则会删除这一列的数据;
如果是表级别的TTL,则会删除整张表的数据;
如果同时设置了列级别和表级别的TTL,则会以先到期的那个为主
                设置TTL
                    INTERVAL完整的操作包括SECOND、MINUTE、HOUR、DAY、WEEK、MONTH、QUARTER和YEAR。
                    ClickHouse没有提供取消列级别TTL的方法。
                    ClickHouse没有表级别TTL目前也没有取消的方法。
                TTL的运行机制
                    如果一张MergeTree表被设置了TTL表达式,那么在写入数据时,会以数据分区为单位,在每个分区目录内生成一个名为ttl.txt的文件。
                    tl.txt文件中通过一串JSON配置保存了TTL的相关信息
{"columns":[{"name":"code","min":1557478860,"max":1557651660}],"table":
{"min":1557565200,"max":1557738000}}
columns用于保存列级别TTL信息;
table用于保存表级别TTL信息;
min和max则保存了当前数据分区内,TTL指定日期字段的最小值、最大值分别与
INTERVAL表达式计算后的时间戳。
            多路径存储策略
                19.15版本之前,MergeTree只支持单路径存储,所有的数据都会被写入config.xml配置中path指定的路径下,即使服务器挂载了多块磁盘,也无法有效利用这些存储空间。
                19.15版本开始,MergeTree实现了自定义存储策略的功能,支持以数据分区为最小移动单元,将分区目录写入多块磁盘目录。
                存储策略
                    默认策略:
MergeTree原本的存储策略,无须任何配置,所有分区会自动保存到config.xml配置中path指定的路径下
                    JBOD策略:
这种策略适合服务器挂载了多块磁盘,但没有做RAID的场景。
JBOD的全称是Just a Bunch of Disks,它是一种轮询策略,每执行一次INSERT或者MERGE,所产生的新分区会轮询写入各个磁盘。
                    HOT/COLD策略:
这种策略适合服务器挂载了不同类型磁盘的场景。
将存储磁盘分为HOT与COLD两类区域。
HOT区域使用SSD这类高性能存储媒介,注重存取性能;
COLD区域则使用HDD这类高容量存储媒介,注重存取经济性。
数据在写入MergeTree之初,首先会在HOT区域创建分区目录用于保存数据,当分区数
据大小累积到阈值时,数据会自行移动到COLD区域。
                配置方式
                    存储配置需要预先定义在config.xml配置文件中,由storage_configuration标签表示。
                    在storage_configuration之下又分为disks和policies两组标签,分别表示磁盘与存储策略。
                    <storage_configuration>
  <disks>
    <disk_name_a> <!--自定义磁盘名称 -->
      <path>/chbase/data</path><!—磁盘路径 -->
      <keep_free_space_bytes>1073741824</keep_free_space_bytes>
    </disk_name_a>
    <disk_name_b>
   <path>… </path>
      <keep_free_space_bytes>...</keep_free_space_bytes>
    </disk_name_b>
  </disks>
  <policies>
    <default_jbod> <!--自定义策略名称 -->
      <volumes>
        <jbod> <!—自定义名称 磁盘组 -->
          <disk>disk_name_a</disk>
          <disk>disk_name_b</disk>
        </jbod>
      </volumes>
    </default_jbod>
  </policies>
</storage_configuration>
        ReplacingMergeTree
            MergeTree拥有主键,但是它的主键却没有唯一键的约束。这意味着即便多行数据的主键相同,它们还是能够被正常写入。
            ReplacingMergeTree就是在这种背景下为了数据去重而设计的,它能够在合并分区时删除重复的数据。
            ReplacingMergeTree是以分区为单位删除重复数据的。
只有在相同的数据分区内重复的数据才可以被删除,而不同数据分区之间的重复数据依然不能被剔除。
如果要求主键完全不重复,那么这张表就不能分区
            操作方式
ENGINE = ReplacingMergeTree(ver)
ver是选填参数,会指定一个UInt*、Date或者DateTime类型的字段作为版本号。这个参数决定了数据去重时所使用的算法。
        SummingMergeTree
            终端用户只需要查询数据的汇总结果,不关心明细数据,并且数据的汇总条件是预先明确的(GROUP BY条件明确,且不会随意改变
            原始方案:通过GROUP BY聚合查询,并利用SUM聚合函数汇总结果
                存在额外的存储开销:终端用户不会查询任何明细数据,只关心汇总结果,所以不应该一直保存所有的明细数据。
                存在额外的查询开销:终端用户只关心汇总结果,虽然MergeTree性能强大,但是每次查询都进行实时聚合计算也是一种性能消耗。
            SummingMergeTree就是为了应对这类查询场景而生的
                它能够在合并分区的时候按照预先定义的条件聚合汇总数据,将同一分组下的多行数据汇总合并成一行
                这样既减少了数据行,又降低了后续汇总查询的开销。
         AggregatingMergeTree
            数据立方体
                它通过以空间换时间的方法提升查询性能,将需要聚合的数据,预先计算出来,并将结果保存起来。
                在后续进行聚合查询的时候,直接使用结果数据。
            AggregatingMergeTree更为常见的应用方式是结合物化视图使用,将它作为物化视图的表引擎。
        CollapsingMergeTree
            CollapsingMergeTree就是一种通过以增代删的思路,支持行级数据修改和删除的表引擎。它通过定义一个sign标记位字段,记录数据行的状态。
            如果sign标记为1,则表示这是一行有效的数据;如果sign标记为-1,则表示这行数据需要被删除。
            当CollapsingMergeTree分区合并时,同一数据分区内,sign标记为1和-1的一组数据会被抵消删除。
            这种1和-1相互抵消的操作,犹如将一张瓦楞纸折叠了一般。
            折叠规则
                如果sign=1比sign=-1的数据多一行,则保留最后一行sign=1的数据。
如果sign=-1比sign=1的数据多一行,则保留第一行sign=-1的数据。
如果sign=1和sign=-1的数据行一样多,并且最后一行是sign=1,则保留第一行sign=-1和最后
一行sign=1的数据。
如果sign=1和sign=-1的数据行一样多,并且最后一行是sign=-1,则什么也不保留。
其余情况,ClickHouse会打印警告日志,但不会报错,在这种情形下,查询结果不可预知
            特点:
                折叠数据并不是实时触发的,和所有其他的MergeTree变种表引擎一样,这项特性也只有在分区合并的时候才会体现。
                所以在分区合并之前,用户还是会看到旧的数据。解决这个问题的方式有两种。
                    在查询数据之前,使用optimize TABLE table_name FINAL命令强制分区合并,但是这种方法效率极低,在实际生产环境中慎用。
                    需要改变我们的查询方式
                        SELECT id,SUM(code),COUNT(code),AVG(code),uniq(code)
FROM collpase_table
GROUP BY id
SELECT id,SUM(code * sign),COUNT(code * sign),AVG(code *
sign),uniq(code * sign)
FROM collpase_table
GROUP BY id
HAVING SUM(sign) > 0
                只有相同分区内的数据才有可能被折叠。
                CollapsingMergeTree对于写入数据的顺序有着严格要求。
先写入sign=1,再写入sign=-1,则能够正常折叠
先写入sign=-1,再写入sign=1,则不能够折叠
        VersionedCollapsingMergeTree
            VersionedCollapsingMergeTree表引擎的作用与CollapsingMergeTree完全相同
            它们的不同之处在于,VersionedCollapsingMergeTree对数据的写入顺序没有要求,在同一个分区内,任意顺序的数据都能够完成折叠操作。
         MergeTree关系梳理
            MergeTree表引擎向下派生出6个变种表引擎
                
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值