ClickHouse原理解析与应用实践

2021-12-01 19:56:29 浏览数 (1)

第1章 ClickHouse的前世今生

  • 在大量数据分析场景的解决方案中,传统关系型数据库很快就被Hadoop生态所取代
  • 传统关系型数据库所构建的数据仓库,被以Hive为代表的大数据技术所取代
  • 数据查询分析的手段也层出不穷,SparkImpalaKylin等百花齐放

1.1 传统BI系统之殇

  • 企业在生产经营的过程中,并不是只关注诸如流程审批、数据录入和填报这类工作。站在监管和决策层面,还需要另一种分析类视角,例如分析报表、分析决策等。而IT系统在早期的建设过程中多呈烟囱式发展,数据散落在各个独立的系统之内,相互割裂、互不相通
  • 为了解决数据孤岛的问题,人们提出了数据仓库的概念。即通过引入一个专门用于分析类场景的数据库,将分散的数据统一汇聚到一处。借助数据仓库的概念,用户第一次拥有了站在企业全局鸟瞰一切数据的视角
  • 相对于联机事务处理系统,我们把这类BI系统称为联机分析(OLAP)系统

1.2 现代BI系统的新思潮

  • 根据一项调查,互联网用户通常都没有耐心。例如47%的消费者希望在2秒或更短的时间内完成网页加载
  • SaaS模式的兴起,为传统企业软件系统的商业模式带来了新的思路,这是一次新的技术普惠
  1. 一方面,SaaS模式将之前只服务于中大型企业的软件系统放到了互联网,扩展了它的受众;
  2. 另一方面,由于互联网用户的基本特征和软件诉求,又倒逼了这些软件系统在方方面面进行革新与升级

2003年起,Google陆续发表的三篇论文开启了大数据的技术普惠,Hadoop生态由此开始一发不可收拾,数据分析开启了新纪元。从某种角度来看,以使用Hadoop生态为代表的这类非传统关系型数据库技术所实现的BI系统,可以称为现代BI系统

  • 在海量数据下要实现多维分析的实时应答,仍旧困难重重。(现代BI系统的典型应用场景是多维分析,某些时候可以直接使用OLAP指代这类场景。)

1.3 OLAP常见架构分类

  • OLAP名为联机分析,又可以称为多维分析,是由关系型数据库之父埃德加·科德(EdgarFrankCodd)于1993年提出的概念。顾名思义,它指的是通过多种不同的维度审视数据,进行深层次分析
  • 数据立方体可以进行如下操作
  1. 下钻:从高层次向低层次明细数据穿透。例如从“省”下钻到“市
  2. 上卷:和下钻相反,从低层次向高层次汇聚。例如从“市”汇聚成“省
  3. 切片:观察立方体的一层,将一个或多个维度设为单个固定值,然后观察剩余的维度,例如将商品维度固定为“足球
  4. 切块:与切片类似,只是将单个固定值变成多个值。例如将商品维度固定成“足球”“篮球
  5. 旋转:旋转立方体的一面,如果要将数据映射到一张二维表,那么就要进行旋转,这就等同于行列置换
OLAP架构大致分成三类
ROLAP(RelationalOLAP,关系型OLAP)
  • 顾名思义,它直接使用关系模型构建,数据模型常使用星型模型或者雪花模型
MOLAP(MultidimensionalOLAP,多维型OLAP)
  • 它的出现是为了缓解ROLAP性能问题。MOLAP使用多维数组的形式保存数据,其核心思想是借助预先聚合结果,使用空间换取时间的形式最终提升查询性能
  1. 维度预处理可能会导致数据的膨胀
  2. 其立方体预聚合后的数据量可能会达到10到20倍的膨胀
  3. 由于使用了预处理的形式,数据立方体会有一定的滞后性,不能实时进行数据分析
HOLAP(HybridOLAP,混合架构的OLAP)
  • 这种思路可以理解成ROLAPMOLAP两者的集成

1.4 OLAP实现技术的演进

  • 演进过程简单划分成两个阶段
传统关系型数据库阶段
  • 在这个阶段中,OLAP主要基于以OracleMySQL为代表的一众关系型数据实现。在这个时期,不论是ROLAP还是MOLAP,在数据体量大、维度数目多的情况下都存在严重的性能问题
大数据技术阶段
  1. 由于大数据处理技术的普及,人们开始使用大数据技术重构ROLAPMOLAP。以ROLAP架构为例,传统关系型数据库就被HiveSparkSQL这类新兴技术所取代
  2. 大数据技术阶段,主流MOLAP架构已经能够在亿万级数据的体量下,实现毫秒级的查询响应时间。尽管如此,MOLAP架构依然存在维度爆炸、数据同步实时性不高的问题

1.5 一匹横空出世的黑马

  • 一款具备现代化SaaS属性的BI分析类产品
  • 必须至少具备如下特征
  1. 一站式:下至数百条数据的个人Excel表格,上至数亿级别的企业数据,都能够在系统内部被直接处理
  2. 自服务,简单易用:面向普通用户而非专业IT人员,通过简单拖拽或搜索维度,就能完成初步的分析查询
  3. 实时应答:无论数据是什么体量级别,查询必须在毫秒至1秒内返回
  4. 专业化、智能化:需要具备专业化程度并具备智能化的提升空间,需要提供专业的数学方法
  • 具有ROLAP、在线实时查询、完整的DBMS、列式存储、不需要任何数据预处理、支持批量更新、拥有非常完善的SQL支持和函数、支持高可用、不依赖Hadoop复杂生态、开箱即用等许多特点
  • 对一张拥有133个字段的数据表分别在1000万、1亿和10亿三种数据体量下执行基准测试,基准测试的范围涵盖43项SQL查询。在1亿数据集体量的情况下,ClickHouse的平均响应速度是Vertica的2.63倍、InfiniDB的17倍、MonetDB的27倍、Hive的126倍、MySQL的429倍以及Greenplum的10倍

详细测试结果:https://clickhouse.yandex/benchmark.html

1.6 ClickHouse的发展历程

  • ClickHouse背后的研发团队是来自俄罗斯的Yandex公司。这是一家俄罗斯本土的互联网企业,于2011年在纳斯达克上市,它的核心产品是搜索引擎。根据最新的数据显示,Yandex占据了本国47%以上的搜索市场,是现今世界上最大的俄语搜索引擎
  • ClickHouse就是在这样的产品背景下诞生的,伴随着Yandex.Metrica业务的发展,其底层架构历经四个阶段
  • Yandex.Metrica研发团队以OLAPServer为基础进一步完善,以实现一个完备的数据库管理系统(DBMS)为目标,最终打造出了ClickHouse,并于2016年开源

ClickHouse的发展历程

1.7 ClickHouse的名称含义

  • 而在采集数据的过程中,一次页面click(点击),会产生一个event(事件)。至此,整个系统的逻辑就十分清晰了,那就是基于页面的点击事件流,面向数据仓库进行OLAP分析。所以ClickHouse的全称是ClickStreamDataWareHouse,简称ClickHouse

1.8 ClickHouse适用的场景

  • 在存储数据超过20万亿行的情况下,ClickHouse做到了90%的查询都能够在1秒内返回的惊人之举
  • ClickHouse非常适用于商业智能领域(也就是我们所说的BI领域),除此之外,它也能够被广泛应用于广告流量、WebApp流量、电信、金融、电子商务、信息安全、网络游戏、物联网等众多其他领域

1.9 ClickHouse不适用的场景

  • 它有以下几点不足
  1. 不支持事务
  2. 不擅长根据主键按行粒度进行查询(虽然支持),故不应该把ClickHouse当作KeyValue数据库使用
  3. 不擅长按行删除数据(虽然支持)

1.10 有谁在使用ClickHouse

  • ClickHouse官网的案例介绍(https://clickhouse.yandex/)

第2章 ClickHouse架构概述

Yandex.Metrica目前已经成为世界第三大Web流量分析平台,每天处理超过200亿个跟踪事件。能够拥有如此惊人的体量,在它背后提供支撑的ClickHouse功不可没。ClickHouse已经为Yandex.Metrica存储了超过20万亿行的数据,90%的自定义查询能够在1秒内返回,其集群规模也超过了400台服务器

  • ClickHouse更像一款“传统”MPP架构的数据库,它没有采用Hadoop生态中常用的主从架构,而是使用了多主对等网络结构,同时它也是基于关系模型的ROLAP方案

2.1 ClickHouse的核心特性

ClickHouse是一款MPP架构的列式存储数据库

完备的DBMS功能
  1. DDL(数据定义语言)
  2. DML(数据操作语言)
  3. 权限控制
  4. 数据备份与恢复
  5. 分布式管理
列大存储与数据压缩
  • 如果你想让查询变得更快,最简单且有效的方法是减少数据扫描范围和数据传输时的大小,而列式存储和数据压缩就可以帮助我们实现上述两点
  • 数据中的重复项越多,则压缩率越高;压缩率越高
  • 数据最可能具备重复的特性呢?答案是属于同一个列字段的数据,因为它们拥有相同的数据类型和现实语义,重复项的可能性自然就更高
向量化执行引擎
  • 这项寄存器硬件层面的特性,为上层应用程序的性能带来了指数级的提升
  • 向量化执行,可以简单地看作一项消除程序中循环的优化
  • 为了制作n杯果汁,非向量化执行的方式是用1台榨汁机重复循环制作n次,而向量化执行的方式是用n台榨汁机只执行1
  • 为了实现向量化执行,需要利用CPUSIMD指令。SIMD的全称是SingleInstructionMultipleData,即用单条指令操作多条数据。现代计算机系统概念中,它是通过数据并行以提高性能的一种实现方式(其他的还有指令级并行和线程级并行),它的原理是在CPU寄存器层面实现数据的并行操作
  • 一个实用的经验告诉我们,存储媒介距离CPU越近,则访问数据的速度越快

图21 距离CPU越远,数据的访问速度越慢

  • 所以利用CPU向量化执行的特性,对于程序的性能提升意义非凡
  • ClickHouse目前利用SSE4.2指令集实现向量化执行
关系模型与SQL查询
  • ClickHouse完全使用SQL作为查询语言(支持GROUPBYORDERBYJOININ等大部分标准SQL),这使得它平易近人,容易理解和学习
  • SQL解析方面,ClickHouse是大小写敏感的,这意味着SELECTaSELECTA所代表的语义是不同的
  • ClickHouse使用了关系模型,所以将构建在传统关系型数据库或数据仓库之上的系统迁移到ClickHouse的成本会变得更低
多样化的表引擎
  • ClickHouse共拥有合并树、内存、文件、接口和其他6大类20多种表引擎。其中每一种表引擎都有着各自的特点,用户可以根据实际业务场景的要求,选择合适的表引擎使用
多线程与分布式
  • 由于SIMD不适合用于带有较多分支判断的场景,ClickHouse也大量使用了多线程技术以实现提速,以此和向量化执行形成互补
  • ClickHouse在数据存取方面,既支持分区(纵向扩展,利用多线程原理),也支持分片(横向扩展,利用分布式原理),可以说是将多线程和分布式的技术应用到了极致
多主架构
  • HDFSSparkHBaseElasticsearch这类分布式系统,都采用了MasterSlave主从架构,由一个管控节点作为Leader统筹全局。而ClickHouse则采用MultiMaster多主架构,集群中的每个节点角色对等,客户端访问任意一个节点都能得到相同的效果。这种多主的架构有许多优势,例如对等的角色使系统架构变得更加简单,不用再区分主控节点、数据节点和计算节点,集群中的所有节点功能相同。所以它天然规避了单点故障的问题,非常适合用于多数据中心、异地多活的场景
在线查询
  • ClickHouse经常会被拿来与其他的分析型数据库作对比,比如VerticaSparkSQLHiveElasticsearch等,它与这些数据库确实存在许多相似之处。例如,它们都可以支撑海量数据的查询场景,都拥有分布式架构,都支持列存、数据分片、计算下推等特性。这其实也侧面说明了ClickHouse在设计上确实吸取了各路奇技淫巧。与其他数据库相比,ClickHouse也拥有明显的优势。
  1. Vertica这类商用软件价格高昂
  2. SparkSQLHive这类系统无法保障90%的查询在1秒内返回,在大数据量下的复杂查询可能会需要分钟级的响应时间;
  3. Elasticsearch这类搜索引擎在处理亿级数据聚合查询时则显得捉襟见肘

ClickHouse的“广告词”所言,其他的开源系统太慢,商用的系统太贵,只有Clickouse在成本与性能之间做到了良好平衡,即又快又开源

数据分片与分布式查询
  • 数据分片是将数据进行横向切分,这是一种在面对海量数据的场景下,解决存储和查询瓶颈的有效手段,是一种分治思想的体现。ClickHouse支持分片,而分片则依赖集群。每个集群由1到多个分片组成,而每个分片则对应了ClickHouse的1个服务节点。分片的数量上限取决于节点数量(1个分片只能对应1个服务节点)
  • ClickHouse提供了本地表(LocalTable)与分布式表(DistributedTable)的概念。一张本地表等同于一份数据的分片。而分布式表本身不存储任何数据,它是本地表的访问代理,其作用类似分库中间件。借助分布式表,能够代理访问多个数据分片,从而实现分布式查询
  • 这种设计类似数据库的分库和分表,十分灵活。例如在业务系统上线的初期,数据体量并不高,此时数据表并不需要多个分片。所以使用单个节点的本地表(单个数据分片)即可满足业务需求,待到业务增长、数据量增大的时候,再通过新增数据分片的方式分流数据,并通过分布式表实现分布式查询。这就好比一辆手动挡赛车,它将所有的选择权都交到了使用者的手中

2.2 ClickHouse的架构设计

Column与Field
  • ColumnFieldClickHouse数据最基础的映射单元
  • ClickHouse按列存储数据,内存中的一列数据由一个Column对象表示
  • 如果需要操作单个具体的数值(也就是单列中的一行数据),则需要使用Field对象,Field对象代表一个单值
  • Field对象内部聚合了NullUInt64、StringArray等13种数据类型及相应的处理逻辑

图22 ClickHouse架构设计中的核心模块

DataType
  • 数据的序列化和反序列化工作由DataType负责。IDataType接口定义了许多正反序列化的方法,它们成对出现,例如serializeBinarydeserializeBinary
  • DataType的实现类中,聚合了相应数据类型的Column对象和Field对象
Block与Block流
  • Block对象的本质是由数据对象、数据类型和列名称组成的三元组,即ColumnDataType及列名称字符串
  • Block流的设计就是水到渠成的事情了。流操作有两组顶层接口:IBlockInputStream负责数据的读取和关系运算,IBlockOutputStream负责将数据输出到下一环节
Table
  • 在数据表的底层设计中并没有所谓的Table对象,它直接使用IStorage接口指代数据表
Functions与Aggregate Functions
  • ClickHouse主要提供两类函数——普通函数和聚合函数。普通函数由IFunction接口定义,拥有数十种函数实现
  • 聚合函数由IAggregateFunction接口定义,相比无状态的普通函数,聚合函数是有状态的
Cluster与Replication
  • ClickHouse的集群由分片(Shard)组成,而每个分片又通过副本(Replica)组成。这种分层的概念,在一些流行的分布式系统中十分普遍。例如,在Elasticsearch的概念中,一个索引由分片和副本组成,副本可以看作一种特殊的分片。如果一个索引由5个分片组成,副本的基数是1,那么这个索引一共会拥有10个分片(每1个分片对应1个副本)
  • ClickHouse的某些设计总是显得独树一帜
  1. ClickHouse的1个节点只能拥有1个分片,也就是说如果要实现1分片、1副本,则至少需要部署2个服务节点
  2. 分片只是一个逻辑概念,其物理承载还是由副本承担的

代码清单21 自定义集群ch_cluster的配置示例

2.3 ClickHouse为何如此之快

  • 在设计软件架构的时候,做设计的原则应该是自顶向下地去设计,还是应该自下而上地去设计呢?在传统观念中,或者说在我的观念中,自然是自顶向下的设计,通常我们都被教导要做好顶层设计。而ClickHouse的设计则采用了自下而上的方式。ClickHouse的原型系统早在2008年就诞生了,在诞生之初它并没有宏伟的规划。相反它的目的很单纯,就是希望能以最快的速度进行GROUPBY查询和过滤
着眼硬件,先想后做
  • 从硬件功能层面着手设计,在设计伊始就至少需要想清楚如下几个问题
  1. 我们将要使用的硬件水平是怎样的?包括CPU、内存、硬盘、网络等
  2. 在这样的硬件上,我们需要达到怎样的性能?包括延迟、吞吐量等
  3. 我们准备使用怎样的数据结构?
  • 基于将硬件功效最大化的目的,ClickHouse会在内存中进行GROUPBY,并且使用HashTable装载数据。与此同时,他们非常在意CPUL3级别的缓存,因为一次L3的缓存失效会带来70~100ns的延迟。这意味着在单核CPU上,它会浪费4000万次/秒的运算;而在一个32线程的CPU上,则可能会浪费5亿次/秒的运算。所以别小看这些细节,一点一滴地将它们累加起来,数据是非常可观的。正因为注意了这些细节,所以ClickHouse在基准查询中能做到1.75亿次/秒的数据扫描性能
算法在前,抽象在后
  • 在字符串搜索方面,针对不同的场景,ClickHouse最终选择了这些算法:对于常量,使用Volnitsky算法;对于非常量,使用CPU的向量化执行SIMD,暴力优化;正则匹配使用re2hyperscan算法。性能是算法选择的首要考量指标
勇于尝鲜,不行就换
  • ClickHouse会使用最合适、最快的算法。如果世面上出现了号称性能强大的新算法,ClickHouse团队会立即将其纳入并进行验证
特定场景,特殊优化
  • 大家熟知的大杀器——向量化执行了。SIMD被广泛地应用于文本转换、数据过滤、数据解压和JSON转换等场景。相较于单纯地使用CPU,利用寄存器暴力优化也算是一种降维打击了

第3章 安装与部署

  • ClickHouse的安装显得尤为简单,它自成一体,在单节点的情况下不需要额外的系统依赖

3.2 客户端的访问接口

  • ClickHouse的底层访问接口支持TCPHTTP两种协议,其中,TCP协议拥有更好的性能,其默认端口为9000
  • 通常而言,并不建议用户直接使用底层接口访问ClickHouse,更为推荐的方式是通过CLIJDBC这些封装接口,因为它们更加简单易用
CLI
  • CLICommandLineInterface)即命令行接口,其底层是基于TCP接口进行通信的,是通过clickhouseclient脚本运行的。它拥有两种执行模式
  • 交互式执行可以广泛用于调试、运维、开发和测试等场景,它的使用方法是直接运行clickhouseclient进行登录
  • 通过交互式执行的SQL语句,相关查询结果会统一被记录到~/.clickhouseclienthistory文件
  • 非交互式模式主要用于批处理场景,诸如对数据的导入和导出等操作。在执行脚本命令时,需要追加query参数指定执行的SQL语句
  • 可以追加multiquery参数,它可以支持一次运行多条SQL查询,多条查询语句之间使用分号间隔

3.3 内置的实用工具

clickhouse-local
  • clickhouselocal可以独立运行大部分SQL查询,不需要依赖任何ClickHouse的服务端程序,它可以理解成是ClickHouse服务的单机版微内核,是一个轻量级的应用程序。clickhouselocal只能够使用File表引擎
  • 也可以借助操作系统的命令,实现对系统用户内存用量的查询
  • clickhousebenchmark是基准测试的小工具,它可以自动运行SQL查询,并生成相应的运行指标报告,例如执行下面的语句启动测试
  • 可以指定多条SQL进行测试,此时需要将SQL语句定义在文件中
  • clickhousebenchmark支持对比测试,此时需要通过此参数声明两个服务端的地址

第4章 数据定义

  • 对于一款可以处理海量数据的分析系统而言,支持DML查询实属难能可贵
  • ClickHouse支持较完备的DML语句,包括INSERTSELECTUPDATEDELETE。虽然UPDATEDELETE可能存在性能问题,但这些能力的提供确实丰富了各位架构师手中的筹码,在架构设计时也能多几个选择
  • 作为一款完备的DBMS(数据库管理系统),ClickHouse提供了DDLDML的功能,并支持大部分标准的SQL。也正因如此,ClickHouse十分容易入门
  • 作为一款异军突起的OLAP数据库黑马,ClickHouse有着属于自己的设计目标,高性能才是它的根本,所以也不能完全以对传统数据库的理解度之。比如,ClickHouse在基础数据类型方面,虽然相比常规数据库更为精练,但同时它又提供了实用的复合数据类型,而这些是常规数据库所不具备的

4.1 ClickHouse的数据类型

  • ClickHouse提供了许多数据类型,它们可以划分为基础类型、复合类型和特殊类型
  • 基础类型
  1. 数值
  2. 字符串
  3. 时间
  • 数值类型
  1. 整数
  2. 浮点数
  3. 定点数
  • Int 类型
  1. Int8
  2. Int16
  3. Int32
  4. Int64

其末尾的数字正好表明了占用字节的大小(8位=1字节)

  • ClickHouse的浮点数
  1. 正无穷
  2. 负无穷
  3. 非数字
  • 在使用定点数时还有一点值得注意:由于现代计算器系统只支持32位和64位CPU,所以Decimal128是在软件层面模拟实现的,它的速度会明显慢于Decimal32与Decimal64
  • 字符串类型
  1. String
  2. FixedString
  3. UUID
  • 时间类型分为DateTimeDateTime64和Date三类。ClickHouse目前没有时间戳类型。时间类型最高的精度是秒,也就是说,如果需要处理毫秒、微秒等大于秒分辨率的时间,则只能借助UInt类型实现
  • DateTime64可以记录亚秒,它在DateTime之上增加了精度的设置
  • 四类复合类型
  1. 数组:在同一个数组内可以包含多种数据类型,例如数组[1,2.0]是可行的。但各类型之间必须兼容,例如数组[1,'2']则会报错
  2. 元组:元组类型由1~n个元素组成,每个元素之间允许设置不同的数据类型,且彼此之间不要求兼容
  3. 枚举
  4. 嵌套:嵌套类型,顾名思义是一种嵌套表结构。一张数据表,可以定义任意多个嵌套类型字段,但每个字段的嵌套层级只支持一级。每个数组的元素个数必须相等。在访问嵌套类型的数据时需要使用点符号
  • 准确来说,Nullable并不能算是一种独立的数据类型,它更像是一种辅助的修饰符,需要与基础数据类型一起搭配使用
  • 在使用Nullable类型的时候还有两点值得注意
  1. 首先,它只能和基础类型搭配使用,不能用于数组和元组这些复合类型,也不能作为索引字段;
  2. 应该慎用Nullable类型,包括Nullable的数据表,不然会使查询和写入性能变慢。因为在正常情况下,每个列字段的数据会被存储在对应的[Column].bin文件中。如果一个列字段被Nullable类型修饰后,会额外生成一个[Column].null.bin文件专门保存它的Null值。这意味着在读取和写入数据时,需要一倍的额外文件操作
  • 域名类型
  1. IPv4
  2. IPv6
  • 本质上它们是对整型和字符串的进一步封装。IPv4类型是基于UInt32封装的

4.2 如何定义数据表

  • 数据库目前一共支持5种引擎
  1. Ordinary:默认引擎,在绝大多数情况下我们都会使用默认引擎,使用时无须刻意声明。在此数据库下可以使用任意类型的表引擎
  2. Dictionary:字典引擎
  3. Memory:内存引擎,用于存放临时数据
  4. Lazy:日志引擎,此类数据库下只能使用Log系列的表引擎
  5. MySQLMySQL引擎,此类数据库下会自动拉取远端MySQL中的数据,并为它们创建MySQL表引擎的数据表
  • 默认数据库的实质是物理磁盘上的一个文件目录,所以在语句执行之后,ClickHouse便会在安装路径下创建DB_TEST数据库的文件目录
  • metadata路径下也会一同创建用于恢复数据库的DB_TEST.sql文件
  • ClickHouse目前提供了三种最基本的建表方法
  1. 使用[db_name.]参数可以为数据表指定数据库,如果不指定此参数,则默认会使用default数据库
  2. 第二种定义方法是复制其他表的结构
  3. 第三种定义方法是通过SELECT子句的形式创建
  • 在这种方式下,不仅会根据SELECT子句建立相应的表结构,同时还会将SELECT子句查询的数据顺带写入
  • 表字段支持三种默认值表达式的定义方法,分别是DEFAULTMATERIALIZEDALIAS
  • 表字段一旦被定义了默认值,它便不再强制要求定义数据类型,因为ClickHouse会根据默认值进行类型推断
  • 默认值表达式的三种定义方法之间也存在着不同之处
  1. 数据写入:在数据写入时,只有DEFAULT类型的字段可以出现在INSERT语句中。而MATERIALIZEDALIAS都不能被显式赋值,它们只能依靠计算取值
  2. 数据查询:在数据查询时,只有DEFAULT类型的字段可以通过SELECT返回。而MATERIALIZEDALIAS类型的字段不会出现在SELECT查询的返回结果集中
  3. 数据存储:在数据存储时,只有DEFAULTMATERIALIZED类型的字段才支持持久化。如果使用的表引擎支持物理存储(例如TinyLog表引擎),那么这些列字段将会拥有物理存储。而ALIAS类型的字段不支持持久化,它的取值总是需要依靠计算产生,数据不会落到磁盘
  • 修改动作并不会影响数据表内先前已经存在的数据。但是默认值的修改有诸多限制,例如在合并树表引擎中,它的主键字段是无法被修改
  • ClickHouse也有临时表的概念,创建临时表的方法是在普通表的基础之上添加TEMPORARY关键字
  • 临时表特殊之处
  1. 它的生命周期是会话绑定的,所以它只支持Memory表引擎,如果会话结束,数据表就会被销毁;
  2. 临时表不属于任何数据库,所以在它的建表语句中,既没有数据库参数也没有表引擎参数。

临时表的优先级是大于普通表的。当两张数据表名称相同的时候,会优先读取临时表的数据

  • 数据分区(partition)和数据分片(shard)是完全不同的两个概念。
  • 数据分区是针对本地数据而言的,是数据的一种纵向切分。而数据分片是数据的一种横向切分(第10章会详细介绍)。数据分区对于一款OLAP数据库而言意义非凡:借助数据分区,在后续的查询过程中能够跳过不必要的数据目录,从而提升查询的性能。合理地利用分区特性,还可以变相实现数据的更新操作,因为数据分区支持删除、替换和重置操作
  • 目前只有合并树(MergeTree)家族系列的表引擎才支持数据分区
  • 通过一个简单的例子演示分区表的使用方法。首先由PARTITIONBY指定分区键,例如下面的数据表partition_v1使用了日期字段作为分区键,并将其格式化为年月的形式:
  • 接着写入不同月份的测试数据:
  • 最后通过system.parts系统表,查询数据表的分区状态:
  • partition_v1按年月划分后,目前拥有两个数据分区,且每个分区都对应一个独立的文件目录,用于保存各自部分的数据
两种视图
普通视图
  • 只是一层简单的查询代理
  • 普通视图不会存储任何数据,它只是一层单纯的SELECT查询映射,起着简化查询、明晰语义的作用,对查询性能不会有任何增强
物化视图
  • 物化视图拥有独立的存储
  • 物化视图支持表引擎,数据保存形式由它的表引擎决定
  • 物化视图创建好之后,如果源表被写入新数据,那么物化视图也会同步更新。POPULATE修饰符决定了物化视图的初始化策略:如果使用了POPULATE修饰符,那么在创建视图的过程中,会连带将源表中已存在的数据一并导入,如同执行了SELECTINTO一般;反之,如果不使用POPULATE修饰符,那么物化视图在创建之后是没有数据的,它只会同步在此之后被写入源表的数据。物化视图目前并不支持同步删除,如果在源表中删除了数据,物化视图的数据仍会保留
  • 物化视图本质是一张特殊的数据表,例如使用SHOWTABLE查看数据表的列表:
  • 删除视图的方法是直接使用DROPTABLE查询

4.3 数据表的基本操作

  • 目前只有MergeTreeMergeDistributed这三类表引擎支持ALTER查询

4.4 数据分区的基本操作

  • ClickHouse内置了许多system系统表,用于查询自身的状态信息。其中parts系统表专门用于查询数据表的分区信息
  • 如果数据表某一列的数据有误,需要将其重置为初始值,此时可以使用下面的语句实现:
  • 表分区可以通过DETACH语句卸载,分区被卸载后,它的物理数据并没有删除,而是被转移到了当前数据表目录的detached子目录下。而装载分区则是反向操作,它能够将detached子目录下的某个分区重新装载回去。卸载与装载这一对伴生的操作,常用于分区数据的迁移和备份场景
  • 一旦分区被移动到了detached子目录,就代表它已经脱离了ClickHouse的管理,ClickHouse并不会主动清理这些文件。这些分区文件会一直存在,除非我们主动删除或者使用ATTACH语句重新装载它们

4.5 分布式DDL执行

  • ClickHouse支持集群模式,一个集群拥有1到多个节点。CREATEALTERDROPRENMAETRUNCATE这些DDL语句,都支持分布式执行
  • 将一条普通的DDL语句转换成分布式执行十分简单,只需加上ONCLUSTERcluster_name声明即可

4.6 数据的写入

  • INSERT语句支持三种语法范式,三种范式各有不同,可以根据写入的需求灵活运用
  1. 第一种是使用VALUES格式的常规语法:
  1. 第二种是使用指定格式的语法:
  1. 第三种是使用SELECT子句形式的语法:
  • 在通过SELECT子句写入数据的时候,同样也支持加入表达式或函数,例如:
  • VALUESSELECT子句的形式都支持声明表达式或函数,但是表达式和函数会带来额外的性能开销,从而导致写入性能的下降。所以如果追求极致的写入性能,就应该尽可能避免使用它们
  • ClickHouse内部所有的数据操作都是面向Block数据块的,所以INSERT查询最终会将数据转换为Block数据块。也正因如此,INSERT语句在单个数据块的写入过程中是具有原子性的
  • max_insert_block_size参数在使用CLI命令行或者INSERTSELECT子句写入时是不生效的

4.7 数据的删除与修改

  • ClickHouse提供了DELETEUPDATE的能力,这类操作被称为Mutation查询,它可以看作ALTER语句的变种。虽然Mutation能最终实现修改和删除,但不能完全以通常意义上的UPDATEDELETE来理解,我们必须清醒地认识到它的不同:
  1. 首先,Mutation语句是一种“很重”的操作,更适用于批量数据的修改和删除;
  2. 其次,它不支持事务,一旦语句被提交执行,就会立刻对现有数据产生影响,无法回滚;
  3. 最后,Mutation语句的执行是一个异步的后台过程,语句被提交之后就会立即返回。

所以这并不代表具体逻辑已经执行完毕,它的具体执行进度需要通过system.mutations系统表查询


第5章 数据字典

  • 字典中的数据会主动或者被动(数据是在ClickHouse启动时主动加载还是在首次查询时惰性加载由参数设置决定)加载到内存,并支持动态更新。由于字典数据常驻内存的特性,所以它非常适合保存常量或经常使用的维度表数据,以避免不必要的JOIN查询。

0 人点赞