两双筷子 - ClickHouse
type: channel
link: https://www.dbkuaizi.com/category/clickhouse/
items: GORM Map 动态写入 ClickHouse 字段
items: ClickHouse 数据类型
items: ClickHouse 的安装与连接
items: ClickHouse架构概述
items: ClickHouse 的前世今生

GORM Map 动态写入 ClickHouse 字段
type: item
date: 2023-06-24T11:41:00+00:00
description: 在工作中遇到了一个 Map 写入 ClickHouse 时类型转换的问题，解决后记录如下。GORM 动态写入 ClickHouse 字段需求场景业务上游会生成多个下面这种 JSON 字符串，以及这样的表结构。{ "name": "张三", "age": 18, "phone": 15300000000, "sex": 1, "ip": "127.0.0.1", "time": 1687007258 }表结构是：CREATE TABLE gorm.test ( `name` String, `age` UInt8 ) ENGINE = MergeTree ORDER BY name SETTINGS index_granularity = 8192;在实现写入逻辑时，我们需要考虑这几个业务前提：上游提供的 JSON 字段可能会增加研发或运维或许会动态的调整数据库的字段所以我们需要根据 JSON 中有的字段以及数据表中的字段进行动态的匹配写入，这就要求我们编码时不能使用 Struct 结构体来定义 GORM Model，需要将 JSON 变成 Map 然后使用 GORM 写入数据库。暴露问题db, _ := gorm.Open(clickhouse.Open("clickhouse://default:@192.168.0.10:19000/gorm"), &gorm.Config{}) var ( str = "{\"name\":\"dbkuaizi\",\"age\":18,\"phone\":15300000000,\"sex\":1,\"ip\":\"127.0.0.1\",\"time\":1687007258}" Data map[string]any ) json.Unmarshal([]byte(str), &Data) if err := db.Table("test").Select("name", "age").Create(Data).Error; err != nil { fmt.Println(err) }运行程序输出了一个错误：2023/06/24 18:33:27 E:/code/ginweb/main.go:18 clickhouse [AppendRow]: age clickhouse [AppendRow]: converting float64 to UInt8 is unsupported [1.334ms] [rows:0] INSERT INTO `test` (`age`,`name`) VALUES (18.000000,'dbkuaizi') clickhouse [AppendRow]: age clickhouse [AppendRow]: converting float64 to UInt8 is unsupported 出错的原因是 ClickHouse 数据库中 age 字段类型是 Uint8，而 Json 反序列化时映射成了 Float64 类型， 接着 GORM 在入库前会对数据的类型进行校验，如果与字段类型不一致，且不能无损转换，就会报错。(Gorm ClickHouse 驱动实现依赖 ClickHouse官方提供的 go 驱动包，同样也会继承官方 Go 驱动的类型校验逻辑，具体可以参考 https://github.com/ClickHouse/clickhouse-go/blob/main/TYPES.md ) 解决方案这个出错的原因从官方的角度看是非常合理的，但我们数据是从 JSON 反序列化过来的，即使我们明知入库存储不存在范围的问题，也会因为数据类型的原因无法入库。所以我们如果想实现使用 map[string]any 插入数据到 clickhouse ，就需要根据数据表中实际的字段类型对 map[string]any 进行一次转换。获取字段类型实现类型转换的第一步，我们需要首先知道目标表有哪些字段需要写入，以及这些字段的类型。可以通过读取 clickhouse 的系统表获取字段信息：SELECT `name`,`type` FROM `system`.columns WHERE `database` = 'gorm' AND `table` = 'test' -- 结果 name|type | ----+------+ name|String| age |UInt8 |然后我们使用 Gorm 来读取： // 先定义一个结构体用来获取数据 type FieldType struct { FieldName string `gorm:"column:name"` FieldType string `gorm:"column:type"` } func …

ClickHouse 数据类型
type: item
date: 2023-05-08T14:50:00+00:00
description: 对于一款支持海量数据分析系统而言，能支持 DML 查询实属难得可贵。在海量的数据场景下，很多看似简单的操作也会变得举步维艰，所以一些系统会选择做减法来规避一些难题。而 ClickHouse 支持完备的 DML 命令，包括 INSERT、SELECT、UPDATE 和 DELETE。虽UPDATE 和 DELETE 可能会存在一些性能问题，但这些能力的提供确实丰富了架构师的筹码，在架构设计师可以多几个选择。作为一款完备的 DBMS，ClickHouse 提供了 DDL 和 DML 功能，并支持大部分标准的SQL。这也是 ClickHouse 相对容易上手的原因。但作为一款异军突起的 OLAP 数据库黑马，ClickHouse 有着属于自己的设计目标，高性能才是它的根本。比如 ClickHouse 在基础数据方面相比于其他常规数据库会少一些，但它又同时提供了实用的复合数据类型，而这些复合类型是常规数据库所不具备的。再比如，ClickHouse 所提供的 DDL 和 DML 查询，在部分细节上和其他数据库也是不同的（例如 UPDATE、DELETE 是借助 ALTER 的变种实现的）。所以掌握 ClickHouse 中的数据定义方法是很重要的，这能帮助我们深刻理解和使用 ClickHouse。ClickHouse 数据类型作为一款分析型数据库，ClickHouse 具备了很多数据类型，他们可以划分为：基础类型、复合类型和特殊类型。其中基础类型使 ClickHouse 具备了描述数据的基础能力，另外两个类型则使得 ClickHouse 数据的表达能力更加丰富立体。基础类型基础的数据类型只有数值、字符串、时间三种类型，没有 Boolean 类型，但是可以用 0 和 1 替代。数值类型整型名称大小(字节)范围普遍概念Int81-128 到 127TinyintInt162-32768 到 32767SmallintInt324-2147483648 到 2147483647IntInt648-9223372036854775808 到 9223372036854775807BigintUInt810 到 255Tinyint UnsignedUInt1620 到 65535Smallint UnsignedUInt3240 到 4294967295Int UnsignedUInt6480 到 18446744073709551615Bigint Unsigned在传统观念中，常用 Tinyint、Smallint、Int 和 Bigint 指代整数的不同取值范围。而 ClickHouse 则直接用Int8、Int16、Int32、Int64 来指代四种大小的 Int 类型，其末尾的数字用来表明占用字节的大小（8位 = 1 字节）。无符号则使用前缀 U 来表示（Unsigned）。浮点型名称大小(字节)有效精度（位数）普遍概念Float3247FloatFloat64816Double在使用浮点数的时候，要意识到他的精度是有限的。例如，Float32 的有效长度为小数点后 7 位，实际存储可以存储 8 位，但第八位的精度不准，Float64 则为是从第十七位开始，精度不准。dbkuaizi-clickhouse :) SELECT toFloat32('0.123456789') as f32, toTypeName(f32); SELECT toFloat32('0.123456789') AS f32, toTypeName(f32) Query id: 502f6090-cc47-41d7-819e-37cf6b90b0aa ┌────────f32─┬─toTypeName(toFloat32('0.123456789'))─┐ │ 0.12345679 │ Float32 │ └────────────┴──────────────────────────────────────┘ 1 row in set. Elapsed: 0.001 sec. ClickHouse 的浮点型支持正无穷、负无穷、以及 非数字三种表达方式：dbkuaizi-clickhouse :) SELECT 0.8/0,-0.8/0,0/0; SELECT 0.8 / 0, -0.8 / 0, 0 / 0 Query id: 789b7cc8-df3d-49eb-ad18-de1aec7867b4 ┌─divide(0.8, 0)─┬─divide(-0.8, 0)─┬─divide(0, 0)─┐ │ inf │ -inf │ nan │ └────────────────┴─────────────────┴──────────────┘ 1 row …

ClickHouse 的安装与连接
type: item
date: 2023-03-29T14:53:00+00:00
description: ClickHouse 支持 X84-64、ARM(aarch64) 或 PowerPC 三种 CPU 架构的 Linux、FreeBSD 或 macOS 系统上运行。安装使用 RPM 离线安装rpm 发行包地址：https://packages.clickhouse.com/rpm/stable/我们以 x86_64 架构，下载 23.2.4.12 版本为例，需要下载如下三个文件：clickhouse-client-23.2.4.12.x86_64.rpmclickhouse-common-static-23.2.4.12.x86_64.rpmclickhouse-server-23.2.4.12.x86_64.rpm官方提供了对每个版本分别提供了五个安装文件，他们的含义如下：clickhouse-common-static 安装 ClickHouse 编译的二进制文件clickhouse-server 创建符号链接和默认服务器配置clickhouse-client 为其他客户端创建符号链接，并安装客户端配置文件。clickhouse-common-static-dbg 安装带有调试信息的 ClickHouse 编译的二进制文件clickhouse-keeper 在专用的 Clickhouse Keeper 节点上安装 ClickHouse Keeper。如果您在与ClickHouse服务器相同的服务器上运行ClickHouse Keeper，则无需安装此软件包。安装 ClickHouse Keeper 和默认的 ClickHouse Keeper 配置文件。执行命令安装：[root@MiWiFi-RA69-srv rpms]# ll 总用量 256628 -rw-r--r-- 1 root root 34978 3月 11 01:51 clickhouse-client-23.2.4.12.x86_64.rpm -rw-r--r-- 1 root root 262688105 3月 27 21:41 clickhouse-common-static-23.2.4.12.x86_64.rpm -rw-r--r-- 1 root root 61353 3月 27 21:20 clickhouse-server-23.2.4.12.x86_64.rpm [root@MiWiFi-RA69-srv rpms]# rpm -ivh clickhouse-*在线安装使用 yumsudo yum install yum-utils sudo rpm --import https://repo.clickhouse.com/CLICKHOUSE-KEY.GPG sudo yum-config-manager --add-repo https://repo.clickhouse.com/rpm/clickhouse.repo sudo yum install clickhouse-server clickhouse-client sudo /etc/init.d/clickhouse-server start使用 apt 安装sudo apt-get install clickhouse-server clickhouse-client clickhouse-common-static -- 也可以指定版本 sudo apt-get install clickhouse-server=21.8.5.7 clickhouse-client=21.8.5.7 clickhouse-common-static=21.8.5.7其他系统安装如果是 Ubuntu 或 Debian 官方提供了 deb 安装包，如果是其他发行版 官方也提供了 tgz 包的安装方式：https://clickhouse.com/docs/en/install访问接口ClickHouse 自身提供了很多种访问协议（接口），比较有代表性的是 TCP 协议（原生接口）和 HTTP 协议，默认端口 9000 主要用于 CLI 客户端连接或其他语言通过 TCP 连接使用，TCP 协议的性能最高；HTTP 协议则拥有更好的兼容性，可以在任何编程语言的任何平台上使用 ClickHouse，HTTP 接口下相比原生 TCP 接口收到了更多的限制，但也拥有更好的兼容性。除了 TCP 协议 和 HTTP 协议之外，ClickHouse 还支持了 MySQL 通讯协议（9004）和 PostgreSQL 通讯协议（9005）。例如可以直接使用 MySQL 命令行工具进行连接。PS C:\Users\Administrator> mysql -h 192.168.0.100 -u default …

ClickHouse架构概述
type: item
date: 2023-03-13T14:46:00+00:00
description: 随着业务的增长，ClickHouse 已经为 Yandex.Metrica 存储了超过二十万亿行数据，90% 的自定义查询都能在 1 秒内响应结果，集群规模也超过了 400 台服务器。ClickHouse 的核心特性ClickHouse 是一款 MPP 架构的列式数据库，但 MPP 和列式存储并不是什么新鲜玩意，为什么只有 ClickHouse 的性能如此出众？通过前面的介绍，我们知道ClickHouse 发展至今的演进过程。一共经历了四个阶段，每一个阶段的迭代都是取其精华去其糟粕。可以说 ClickHouse 吸收了个各种技术的精髓，下面了解一下 ClickHouse 数据库的一些和新特性，正是这些特性使得 ClickHouse 如此有优秀。完整的 DBMS 功能ClickHouse 具备完整的管理功能，所以称得上 DBMS (Datbase Management System，数据库管理系统)，不仅仅是一个数据库，作为一个 DBMS，还具备以下功能（仅为代表性功能，并非全部功能）：DDL (数据库定义语言)：动态的创建、修改或删除数据库、表或视图。DML (数据操作语言)：查询、插入、修改、删除记录。权限控制：按照用户粒度设置数据库或者表的操作权限，保障数据安全。数据备份与恢复：提供数据库备份与导入导出恢复机制，满足生产环境需求。分部署管理：提供集群模式，能够自动管理多个数据库节点。列式存储和数据压缩列式存储和数据压缩，对于一款高性能数据库来说一个必不可少的特性。如果你想让查询变得更快，最简单有效的方法是减少数据扫描范围和数据传输时的大小，而列式存储可以帮助我们实现上述两点。列式存储和数据压缩通常是相伴而生的，一般来说列式存储是数据压缩的前提。列式存储相比行式存储，可以减少查询时所需扫描的数据量。例如一个用户表有 50 个字段，查询前 5 个字段，因为是行式存储，所以逐行扫描时实际会获取所有的字段，然后返回前五个。这样就意味着需要扫描磁盘更多空间，然后不返回这些数据。如果是按列获取数据，就不会存在这样的问题，直接扫描并返回前五列数据即可，避免了多余的数据扫描。按照列式存储相比按行式存储另一个优势就是对数据压缩的友好性。ClickHouse 的数据按列进行组织，属于同一列的数据会被保存在一起，而压缩的本质就是如此，同一列的数据类型和语义相同，数据具有更高比例的重复性，对应的压缩比也会也大。数据默认采用LZ4 压缩算法，在 Yandex.Metrica 的生产环境中，数据总体的压缩比可以达到 8:1 (由 17PB 压缩至 2PB)。列式存储除了降低 IO 和存储的压力之外，还为向量化执行做好了铺垫。HBase，BigTable 这些系统也能实现列式存储，但无法有效处理分析查询需求。在这些系统中，每秒可以实现数十万的数据吞吐量，但不会达到数亿行的级别。向量化执行引擎向量化执行是 CPU 寄存器硬件层面的特性，为上层应用带来指数级的提升。向量化执行可以看作是一项消除程序中循环结果的优化。为了实现向量化执行，需要利用 CPU 的 SIMD 指令（全称是 ingle Instruction Multiple Data 即 单条指令操作多条数据）。它是通过数据并行以提高性能的一种实现方式，原理是在 CPU 寄存器层面实现并行操作。具体实现原理参考：Clickhouse SIMD 使用初探 - 简书关系模型和 SQL 查询相比 Redis 和 HBase 这类 NoSQL 数据库，ClickHouse 使用关系模型描述数据并提供了传统数据库的概念（数据库、表、视图和函数等）。与此同时，ClickHouse 完全支持使用 SQL 作为查询语言，兼容大多数标准 SQL 。也正因为 ClickHouse 提供标准协议的 SQL 查询接口，是的现有的第三方系统可以轻松与它对接。在 SQL 解析方面，ClickHouse 是大小写敏感的。关系模型相比文档或键值对等其他模型，拥有更好的描述能力，也能够更加清晰的表述实体之间的关系。更重要的是，在 OLAP 领域，已有的大量数据建模工作都是基于关系模型展开的（星型模型、雪花模型或宽表模型）。ClickHouse 使用了关系模型，所以构建在传统关系型数据库或数据仓库之上的系统迁移到 ClickHouse 的成本会变得更低。多样化的表引擎因为 Yandex.Metrica 的最初架构是基于 MySQL 实现的，所以在 ClickHouse 的设计中，能够看到 MySQL 的影子，表引擎的设计就是其中之一。与 MySQL 类似， ClickHouse 也将存储部分进行了抽象，把存储引擎作为一层独立的接口。ClickHouse 拥有合并树、内存、文件、接口和其他 6 大类 20 多种表引擎，每个引擎都有各自的…

ClickHouse 的前世今生
type: item
date: 2023-01-29T14:49:00+00:00
description: 如果要说明白为什么需要在业务中引入 ClickHouse ，我们就需要从BI系统的发展开始说起。传统 BI 系统随着互联网技术的不断发展，越来越多的企业通过 ERP、CRM 等系统将自己的业务进行数字化管理，我们通常将这类系统称为“联机事务处理 (OLTP) 系统”。在企业的生产经营过程中，并不是只关注流程审批、数据录入这些工作。站在监管和决策层面，还需要另一种分析类的视角，例如分析报表、分析决策等。而 IT 系统的早期建设过程一般都缺少与其他系统互相配合的规划，数据散落在各个独立的系统中，互不相通。为了解决数据孤岛的问题，人们提出了数据仓库的概念，通过引入一个专门用于分析类场景的数据库，将分散的数据汇总在一起。随着数据库仓库的发展，专注于提供数据分析、决策类功能的系统于解决方案应运而生。最终在二十世纪九十年代，第一次有人提出了 BI （商业智能）系统的概念。自此之后，人们通常用 BI 一次指代这类分析系统。相对于“联机事务处理系统”，我们把这类 BI 系统称为 “联机分析 (OLAP) 系统”传统 BI 系统的设计初衷虽好，但实际应用效果却不令人满意，主要原因有如下几点：传统 BI 系统对企业的信息化水平要求较高。按照传统的 BI 设计思路，只有中大型企业才有能力实施。因为它的定位是站在企业视角通盘分析并辅助决策，所以如果企业的信息化水平不高，基础设施不完善，想要实施 BI 根本无从谈起。狭小的受众制约了传统 BI 系统发展的生命力。传统 BI 系统的主要受众是企业中的管理层或决策层。这类用户通常有着较高的话语权和决策权，但用户基数太小，同时他们对系统的参与度和使用度不高，久而久之这类所谓的 BI 系统就沦为了领导视察时用于演示的特供系统。研发过程滞后了需求的响应时效，传统 BI 不够灵活，有任何需求都想要大量的开发人员参与，一个分析需求的产生到最终实现，可能想要数周或者几个月的时间。现代 BI 系统SaaS 模式的兴起，为传统企业软件系统的商业模式带来了新思路，是一次新的技术普惠。一方面 SaaS 模式将之前只服务于大型企业的软件系统放到了互联网，扩展了它的受众；另一方面，由于互联网用户的基本特征和软件诉求，加上同类系统的互相竞争，又倒逼了这些软件系统在方方面面进行革新于升级。而这次的技术普惠，同样也影响了 BI 系统在设计思路上的变革。随着时代的发展，BI 系统的受众变的更加多元化，几乎所有人都可以成为数据分析师。现代的 BI 系统不在需要研发人员深度参与，用户直接通过自助的形式，通过简单拖拽、搜索就能得到自己想要的分析结果。经过互联网的系列，即使现代 BI 系统仍私有化部署在企业内部，只服务于企业用户，但它也必须具有快速应答，简单易用的使用体验，从某种角度来看，互联网浪潮帮助企业系统在易用性和用户体验上进行了革命性的提升。如果说 SaaS 化为现代 BI 系统提供了新的思路与契机，那么背后的技术创新则保障了其思想的落地。在传统 BI 系统的架构体系中，数据存储使用的是传统的关系型数据库（OLTP 数据库）。为了能够解决在海量数据下分析查询的性能问题，在数据库仓库的基础上衍生了众多新的概念：数据分层：通过对对数据进行分层，通过层层递进形成数据集市，从而减少最终查询到数据体量。数据立方体：通过对数据进行预先处理，以空间换时间，提高查询性能。然而，无论如何努力，数据库设计的局限性始终是无法突破的瓶颈，OLTP 技术诞生的那一刻起，就注定不是为了数据分析而生的，于是很多人将目光投向了新的研究方向。随着 Google 陆续发表的三篇论文开启了大数据时代的技术普惠，Hadoop 生态由此刻开始一发不可收拾，数据分析开启了新纪元。从某种角度来看，使用 Hadoop 生态为代表的这类非传统关系型数据库技术所实现的 BI 系统，可以被称之为现代 BI 系统。换装了大马力发动机的现代 BI 系统在面对海量数据分析时的场景时，显得更加游刃有余。然而 Hadoop 技术也不是银弹，在现代 BI 系统的构建中仍面临诸多挑战，在海量数据下要实现多维度分析的实时应答，仍困难重重。::: alert-info现代 BI 系统的典型应用场景是多维分析，某些时候可以直接使用 OLAP 指代这类场景:::OLAP 常见架构分类OLAP 技术发展至今，分析型数据库百花齐放。然而，看似手上拥有很多筹码的架构师们，有时却面临无牌可打的窘境，为什么会这样？要理解这个问题，我们需要重温一下什么是 OLAP，以及实现 OLAP 的几种思路。之前说过，OLAP 为联机分析，又称多维分析，是由数据库关系之父 埃德加 ·科德 于 1993 年提出的概念。顾名思义，它是通过多种不同的维度审视数据，进行深层次的分析。维度可以看作是观察数据的一种视角，例如人类能看到的世界是三维的…