目录
1. ClickHouse简介
1.1 ClickHouse的定义和特点
ClickHouse是一个开源的列式数据库管理系统(DBMS),用于联机分析处理(OLAP),它允许用户使用SQL查询实时生成分析报告。它最初是为Yandex Metrica的网络分析而构建的,通常以其高插入速率、快速分析查询和类似SQL的方言而闻名。
ClickHouse的主要特点包括:
- 真正的列式DBMS:值与值之间没有任何存储。
- 线性可扩展性:可以通过添加服务器来扩展集群。
- 容错性:系统是一个由多个副本组成的分片集群。
- 能够存储和处理PB级别的数据。
- 支持SQL。
- 高性能。
- 数据压缩。
- 硬盘驱动器(HDD)优化 。
1.2 ClickHouse的优势和应用场景
ClickHouse的优势包括:
- 高性能:ClickHouse能够快速处理大量数据,支持实时查询。
- 列式存储:ClickHouse采用列式存储结构,能够有效压缩数据,提高查询效率。
- 可扩展性:ClickHouse支持线性扩展,可以通过添加服务器来扩展集群。
- 容错性:ClickHouse具有容错能力,能够在出现故障时保证数据安全。
- SQL支持:ClickHouse支持SQL语言,方便用户进行数据查询和分析。
ClickHouse的劣势包括:
- 对于事务处理和复杂的联机事务处理(OLTP)场景支持不足。
- 对于小数据量的查询和更新操作性能不如传统的行式数据库。
ClickHouse适用于需要快速处理大量结构化数据的场景,例如数据分析、复杂数据报表、数据科学计算等。一些著名的公司,如Uber、Cloudflare和Disney+等,都在使用ClickHouse来处理他们的大数据需求。
1.3 ClickHouse的发展历程和版本演变
ClickHouse最初是为了支持Yandex.Metrica(世界第二大网络分析平台)而开发的,并且仍然是该系统的核心组件。它拥有超过13万亿条记录的数据库,每天超过200亿个事件,可以直接从非聚合数据中实时生成自定义报告。
ClickHouse在Yandex.Metrica和其他Yandex服务中发挥着多种作用。它的主要任务是使用非聚合数据在线模式下构建报告。它使用374台服务器的集群,在数据库中存储超过20.3万亿行。压缩数据的体积约为2PB,未计算重复和副本。未压缩数据(以TSV格式)的体积约为17PB。ClickHouse还在以下过程中发挥着关键作用:
- 存储Yandex.Metrica的会话重放数据。
- 处理中间数据。
- 使用Analytics构建全局报告。
- 运行查询以调试Yandex.Metrica引擎。
- 分析API和用户界面的日志。
目前,Yandex的其他服务和部门有多十个ClickHouse安装:搜索垂直、电子商务、广告、商业分析、移动开发、个人服务等¹。
ClickHouse不断发展,版本也在不断演变。您可以查看其更新日志和路线图,了解最新功能和未来计划。
2. ClickHouse架构
2.1 ClickHouse的底层存储架构
ClickHouse是一个真正的列式数据库管理系统(DBMS)。数据按列存储,并在执行期间以数组(向量或列块)的形式处理。只要有可能,操作都会在数组上进行分派,而不是在单个值上。这被称为“向量化查询执行”,它有助于降低实际数据处理的成本。
ClickHouse基于共享无关架构。在每个节点中,计算和存储紧密耦合,尽管目前正在开发一种计算和存储的云原生架构。由于没有跨网络数据分发,每个节点都能够快速处理数据¹。
IColumn接口用于表示内存中的列(实际上是列块)。该接口提供了用于实现各种关系运算符的辅助方法。几乎所有操作都是不可变的:它们不会修改原始列,而是创建一个新的修改过的列。例如,IColumn :: filter方法接受一个过滤字节掩码。它用于WHERE和HAVING关系运算符。其他示例:IColumn :: permute方法支持ORDER BY,IColumn :: cut方法支持LIMIT。
各种IColumn实现(ColumnUInt8、ColumnString等)负责列的内存布局。内存布局通常是一个连续数组。对于整数类型的列,它只是一个连续数组,如std :: vector。对于String和Array列,它是两个向量:一个用于所有连续放置的数组元素,另一个用于偏移到每个数组的开头。
2.2 ClickHouse的查询处理流程
当一个查询被发送到ClickHouse时,它会被转换为一个物理查询计划,称为查询管道,它由查询处理阶段组成,这些阶段在从磁盘流入的数据上执行。如前所述,为了执行查询,ClickHouse首先使用主索引选择可能包含与查询的WHERE子句匹配的行的行块。然后,选定的行块并行流入ClickHouse查询引擎进行进一步处理,并将查询结果流式传输给调用者。
下面是一个简单的流程图,说明了ClickHouse如何执行查询:
1. 从涉及的表中加载主索引到主内存。
2. 通常,通过对索引条目进行二分查找,ClickHouse选择可能包含与查询的WHERE子句匹配的行的行块。
3. 选定的行块并行流入ClickHouse查询引擎进行进一步处理,并将查询结果流式传输给调用者。
加速ClickHouse中这种查询执行工作流程的三个主要调节旋钮是:
- ClickHouse需要从磁盘流入主内存的数据越少,查询的执行时间就越快。
- ClickHouse能够更好地利用表的(稀疏)主索引。
- ClickHouse能够更好地利用投影。
2.3 ClickHouse的分布式架构和集群部署
ClickHouse支持分布式架构和集群部署。您可以在集群中的一个或多个服务器上创建分布式表。分布式表本身不存储数据,它只提供对所有本地表的“视图”。当您查询分布式表时,查询将被发送到所有本地表,并在本地执行。然后,结果将被收集并返回给客户端。
ClickHouse的架构是扁平的,没有前端节点或后端节点。可以部署任意大小的集群。您可以通过修改配置文件来设置集群配置。默认情况下,ClickHouse配置文件存储在/etc/clickhouse-server/目录中。config.d和users.d目录下的所有.xml文件都将自动加载到ClickHouse中,建议将所有自定义设置放在此目录中,并使用有意义的文件名(例如cluster、zookeeper、macro等)。
3. 数据类型和表结构
3.1 ClickHouse支持的数据类型
ClickHouse支持多种数据类型,包括:
- 整数类型:有符号和无符号整数(UInt8、UInt16、UInt32、UInt64、UInt128、UInt256、Int8、Int16、Int32、Int64、Int128、Int256)。
- 浮点数:浮点数(Float32和Float64)和Decimal值。
- 布尔值:ClickHouse有一个布尔类型。
- 字符串:String和FixedString。
- 日期:使用Date和Date32表示天,使用DateTime和DateTime64表示时间点。
- JSON:JSON对象将JSON文档存储在单个列中。
- UUID:用于存储UUID值的高性能选项。
- 低基数类型:当您有少量唯一值时,使用Enum;当您有多达10,000个唯一值的列时,使用LowCardinality。
- 数组:任何列都可以定义为值的数组。
- 映射:使用Map存储键/值对。
- 聚合函数类型:使用SimpleAggregateFunction和AggregateFunction存储聚合函数结果的中间状态。
- 嵌套数据结构:嵌套数据结构就像单元格内的表。
- 元组:具有各自类型的元素的元组。
- 可空类型:Nullbale允许您在值“缺失”时将值存储为NULL(而不是该数据类型的列获得其默认值)。
- IP地址:使用IPv4和IPv6有效地存储IP地址。
- 地理类型:用于地理数据,包括Point、Ring、Polygon和MultiPolygon。
- 特殊数据类型:包括Expression、Set、Nothing和Interval¹。
3.2 ClickHouse表结构的创建和管理
在ClickHouse中,您可以使用CREATE TABLE语句创建表。例如,下面是一个简单的示例,它创建了一个名为my_first_table的表,该表位于helloworld数据库中,并具有四个列:user_id、message、timestamp和metric:
CREATE TABLE helloworld.my_first_table (
user_id UInt32,
message String,
timestamp DateTime,
metric Float32
) ENGINE = MergeTree()
PRIMARY KEY (user_id, timestamp)
在上面的示例中,my_first_table是一个MergeTree表,具有四个列:
- user_id:32位无符号整数。
- message:String数据类型,替代了其他数据库系统中的VARCHAR、BLOB、CLOB等类型。
- timestamp:DateTime值,表示时间点。
- metric:32位浮点数。
表引擎决定了数据如何以及在哪里存储。有许多引擎可供选择,但对于单节点ClickHouse服务器上的简单表,MergeTree可能是您的首选。
可以使用ALTER TABLE语句来修改现有表的结构。例如,您可以使用ADD COLUMN子句向表中添加新列,或者使用DROP COLUMN子句从表中删除现有列。
还可以使用DROP TABLE语句删除现有表。请注意,在删除表之前,请确保您已备份所有重要数据。
3.3 ClickHouse表结构的优化和调整
在ClickHouse中,可以通过多种方式优化和调整表结构,以提高查询性能。下面是一些常见的方法:
- 选择合适的表引擎:ClickHouse支持多种表引擎,每种引擎都有其优缺点。选择适当的表引擎可以显著提高查询性能。
- 选择合适的数据类型:选择适当的数据类型可以减少存储空间并提高查询效率。例如,对于整数列,使用最小的整数类型可以节省空间并提高性能。
- 使用索引:ClickHouse支持多种索引类型,包括主索引、辅助索引和位图索引。正确使用索引可以大大加快查询速度。
- 分区数据:ClickHouse支持数据分区。将数据分区到不同的分区中可以减少查询时需要扫描的数据量,从而提高查询性能。
- 调整表设置:ClickHouse允许您调整表的各种设置,以优化查询性能。例如,可以调整索引粒度、合并设置和压缩设置等。
4. 数据导入和导出
4.1 在ClickHouse中导入数据的方法和技巧
在ClickHouse中,可以使用多种方法和技巧导入数据。下面是一些常见的方法:
- 使用INSERT语句:您可以使用INSERT语句将数据插入到ClickHouse表中。例如,您可以使用VALUES子句指定要插入的值,或者使用SELECT子句从另一个表中选择数据。
- 从CSV文件导入:ClickHouse支持从CSV文件导入数据。您可以使用clickhouse-client工具将CSV文件直接导入到ClickHouse表中,或者使用FROM INFILE子句从本地文件中加载数据。
- 从其他数据库导入:您可以使用clickhouse-client或clickhouse-local工具从其他数据库(如MySQL、PostgreSQL或任何ODBC或JDBC兼容的数据库)检索数据并将其导入到ClickHouse中。
- 使用第三方工具:您还可以使用第三方工具(如Kafka、Vector、Airbyte等)将数据导入到ClickHouse中。
4.2 在ClickHouse中导出数据的方法和技巧
在ClickHouse中,您可以使用多种方法和技巧导出数据。下面是一些常见的方法:
- 使用SELECT语句:您可以使用SELECT语句从ClickHouse表中查询数据,并将结果导出到文件或其他应用程序中。
- 导出为CSV文件:ClickHouse支持将数据导出为CSV文件。您可以使用clickhouse-client工具将ClickHouse表中的数据导出到CSV文件中,或者使用INTO OUTFILE子句将数据写入本地文件。
- 导出到其他数据库:您可以使用clickhouse-client或clickhouse-local工具将数据从ClickHouse检索并导入到其他数据库(如MySQL、PostgreSQL或任何ODBC或JDBC兼容的数据库)中。
- 使用第三方工具:您还可以使用第三方工具(如Kafka、Vector、Airbyte等)将数据从ClickHouse导出。
4.3 数据导入和导出过程中的注意事项
在ClickHouse中导入和导出数据时,有一些注意事项需要考虑:
- 数据格式:确保您在导入或导出数据时使用正确的数据格式。ClickHouse支持多种数据格式,包括CSV、TSV、JSON等。
- 数据类型:确保您在导入数据时使用正确的数据类型。如果数据类型不匹配,可能会导致数据丢失或损坏。
- 数据完整性:在导入或导出大量数据时,确保数据完整性。如果可能,使用事务或其他机制来确保数据的一致性。
- 性能:在导入或导出大量数据时,考虑性能问题。您可以使用批量插入、并行处理等技术来提高性能。
- 安全性:确保您在导入或导出数据时遵守安全规范。例如,避免将敏感数据暴露给未经授权的用户。
以上是一些在ClickHouse中导入和导出数据时需要注意的事项。希望对您有所帮助!
5. SQL查询
5.1 在ClickHouse中使用SQL语言进行数据查询
在ClickHouse中,您可以使用SQL语言进行数据查询。ClickHouse支持大多数常用的SQL语法,包括SELECT、INSERT、UPDATE、DELETE等语句。
下面是一个简单的示例,它演示了如何在ClickHouse中使用SELECT语句查询数据:
SELECT user_id, message, timestamp
FROM my_first_table
WHERE timestamp >= '2022-01-01 00:00:00'
AND timestamp < '2022-02-01 00:00:00'
ORDER BY timestamp DESC
LIMIT 10
在上面的示例中,我们从my_first_table表中选择user_id、message和timestamp列。我们使用WHERE子句过滤出2022年1月份的数据,并使用ORDER BY子句按时间戳降序排序。最后,我们使用LIMIT子句限制结果集的大小。
您还可以使用聚合函数(如COUNT、SUM、AVG等)对数据进行汇总和分析。例如,下面是一个简单的示例,它演示了如何在ClickHouse中使用聚合函数:
在上面的示例中,我们从my_first_table表中选择数据,并使用COUNT和AVG函数对user_id和metric列进行汇总和分析。
5.2 ClickHouse支持的SQL语法和函数
ClickHouse支持大多数常用的SQL语法和函数。例如,您可以使用SELECT、INSERT、UPDATE、DELETE等语句来查询和修改数据。您还可以使用聚合函数(如COUNT、SUM、AVG等)对数据进行汇总和分析。
除了标准的SQL语法和函数外,ClickHouse还提供了一些特定于ClickHouse的语法和函数。例如,您可以使用数组函数(如arrayJoin、arrayMap等)对数组数据进行处理,或者使用日期和时间函数(如toStartOfDay、toStartOfMonth等)对日期和时间数据进行处理。
ClickHouse还支持窗口函数,这些函数允许您在查询结果中定义窗口,并在窗口内执行计算。例如,您可以使用RANK、DENSE_RANK或ROW_NUMBER函数对查询结果进行排序。
以上是ClickHouse支持的SQL语法和函数的简要介绍。您可以在ClickHouse文档中查看完整的SQL参考以获取更多信息。
5.3 SQL查询性能优化技巧
好的,我们继续深入学习SQL查询性能优化技巧。这里有一些更详细的技巧和注意事项:
1. **索引**:索引可以帮助数据库快速定位数据,从而提高查询速度。但是,索引也会增加数据插入、更新和删除的开销,因此应谨慎使用。在为列创建索引时,应考虑该列的选择性(即不同值的数量),选择性高的列更适合创建索引。
2. **避免SELECT * **:使用SELECT *会返回表中的所有列,这会增加查询时间和网络传输时间。应尽量只选择需要的列。
3. **使用LIMIT**:如果只需要查询结果的前几行,使用LIMIT可以减少查询时间。但是,应注意LIMIT并不总是能提高查询速度,因为它可能会导致全表扫描。
4. **避免在WHERE子句中使用函数**:在WHERE子句中使用函数会导致索引失效,降低查询速度。例如,下面的查询将无法使用索引:
SELECT * FROM table WHERE YEAR(date) = 2020;
可以改写为下面这种形式,以便使用索引:
SELECT * FROM table WHERE date >= '2020-01-01' AND date < '2021-01-01';