比较 ClickHouse Cloud 和 BigQuery
资源组织
ClickHouse Cloud 中的资源组织方式类似于 BigQuery 的资源层次结构。我们将在下面的图表中描述具体的差异,该图表显示了 ClickHouse Cloud 的资源层次结构
组织机构
与 BigQuery 类似,组织机构是 ClickHouse 云资源层次结构中的根节点。您在 ClickHouse Cloud 帐户中设置的第一个用户将自动分配到一个由该用户拥有的组织机构。用户可以邀请其他用户加入该组织机构。
BigQuery 项目与 ClickHouse Cloud 服务
在组织机构中,您可以创建与 BigQuery 项目大致等效的服务,因为 ClickHouse Cloud 中存储的数据与服务相关联。ClickHouse Cloud 中有 几种可用的服务类型。每个 ClickHouse Cloud 服务都部署在一个特定的区域中,并包括
- 一组计算节点(目前,开发版服务的节点数为 2 个,生产版服务的节点数为 3 个)。对于这些节点,ClickHouse Cloud 支持垂直和水平扩展,手动和自动均可。
- 一个对象存储文件夹,服务将所有数据存储在该文件夹中。
- 一个端点(或通过 ClickHouse Cloud UI 控制台创建的多个端点) - 用于连接到服务的服务 URL(例如,
https://dv2fzne24g.us-east-1.aws.clickhouse.cloud:8443)
BigQuery 数据集与 ClickHouse Cloud 数据库
ClickHouse 将表逻辑分组到数据库中。与 BigQuery 数据集类似,ClickHouse 数据库是逻辑容器,用于组织和控制对表数据的访问。
BigQuery 文件夹
ClickHouse Cloud 目前没有与 BigQuery 文件夹等效的概念。
BigQuery 插槽预留和配额
与 BigQuery 插槽预留类似,您可以在 ClickHouse Cloud 中 配置垂直和水平自动扩展。对于垂直扩展,您可以设置服务中计算节点的内存和 CPU 核心的最小值和最大值。然后,该服务将在这些范围内根据需要进行扩展。这些设置也在初始服务创建流程期间可用。服务中的每个计算节点的大小相同。您可以使用 水平扩展更改服务中的计算节点数量。
此外,与 BigQuery 配额类似,ClickHouse Cloud 提供并发控制、内存使用限制和 I/O 调度,使您可以将查询隔离到工作负载类中。通过为特定的工作负载类设置共享资源(CPU 核心、DRAM、磁盘和网络 I/O)的限制,可以确保这些查询不会影响其他关键业务查询。并发控制可以防止在高并发查询场景中出现线程过度订阅的情况。
ClickHouse 跟踪服务器、用户和查询级别内存分配的字节大小,从而实现灵活的内存使用限制。内存过度提交使查询可以使用超出保证内存的额外空闲内存,同时保证其他查询的内存限制。此外,聚合、排序和连接子句的内存使用量可以限制,并在超过内存限制时回退到外部算法。
最后,I/O 调度允许您根据最大带宽、飞行中请求和策略来限制工作负载类的本地和远程磁盘访问。
ClickHouse 通过 云控制台和 数据库这两个地方控制用户访问。控制台访问通过 clickhouse.cloud 用户界面进行管理。数据库访问通过数据库用户帐户和角色进行管理。此外,可以向数据库授予控制台用户角色,使控制台用户能够通过我们的 SQL 控制台与数据库交互。
数据类型
ClickHouse 在数值方面提供更精细的精度。例如,BigQuery 提供数值类型 INT64、NUMERIC、BIGNUMERIC 和 FLOAT64。与 ClickHouse 形成对比,后者为小数、浮点数和整数提供多种精度类型。使用这些数据类型,您可以优化存储和内存开销,从而提高查询速度并降低资源消耗。下面我们将为每种 BigQuery 类型映射等效的 ClickHouse 类型
| BigQuery | ClickHouse |
|---|
| ARRAY | Array(t) |
| NUMERIC | Decimal(P, S), Decimal32(S), Decimal64(S), Decimal128(S) |
| BIG NUMERIC | Decimal256(S) |
| BOOL | Bool |
| BYTES | FixedString |
| DATE | Date32(范围较窄) |
| DATETIME | DateTime, DateTime64(范围较窄,精度更高) |
| FLOAT64 | Float64 |
| GEOGRAPHY | 地理数据类型 |
| INT64 | UInt8, UInt16, UInt32, UInt64, UInt128, UInt256, Int8, Int16, Int32, Int64, Int128, Int256 |
| INTERVAL | NA - 作为表达式或 通过函数支持 |
| JSON | JSON |
| STRING | 字符串(字节) |
| STRUCT | Tuple, Nested |
| TIME | DateTime64 |
| TIMESTAMP | DateTime64 |
当 ClickHouse 类型有多个选项时,请考虑数据的实际范围并选择所需的最低范围。此外,请考虑使用 适当的编解码器进行进一步压缩。
查询加速技术
主键和外键以及主索引
在 BigQuery 中,表可以具有 主键和外键约束。通常,主键和外键用于关系数据库以确保数据完整性。主键值通常对于每一行都是唯一的,并且不为 NULL。表中的每一行中的外键值必须存在于主键表的主键列中,或者为 NULL。在 BigQuery 中,这些约束不会被强制执行,但查询优化器可以使用此信息来更好地优化查询。
在 ClickHouse 中,表也可以具有主键。与 BigQuery 类似,ClickHouse 不会强制执行表主键列值的唯一性。与 BigQuery 不同,表的数据按主键列排序存储在磁盘上。查询优化器利用此排序顺序来防止重新排序,以最大限度地减少连接的内存使用量,并为 limit 子句启用短路。与 BigQuery 不同,ClickHouse 会根据主键列值自动创建 (稀疏)主索引。此索引用于加速包含主键列过滤器的所有查询。ClickHouse 目前不支持外键约束。
辅助索引(仅在 ClickHouse 中可用)
除了从表的的主键列创建的主索引外,ClickHouse 允许您在主键中其他列上创建辅助索引。ClickHouse 提供几种类型的辅助索引,每种索引都适用于不同类型的查询
- 布隆过滤器索引:
- 用于加速具有相等条件(例如,=、IN)的查询。
- 使用概率数据结构来确定值是否存在于数据块中。
- Token 布隆过滤器索引:
- 类似于布隆过滤器索引,但用于标记字符串,适用于全文搜索查询。
- 最小值-最大值索引:
- 维护每个数据部分中列的最小值和最大值。
- 有助于跳过不落入指定范围内的的数据部分。
搜索索引
类似于 BigQuery 中的搜索索引,全文索引可以为 ClickHouse 具有字符串值的表创建。
向量索引
BigQuery 最近引入了 向量索引作为 Pre-GA 功能。同样,ClickHouse 也对 索引提供实验性支持,以加速向量搜索用例。
与 BigQuery 类似,ClickHouse 使用表分区来提高大型表的性能和可管理性,方法是将表划分为更小、更易于管理的部分,称为分区。我们详细描述了 ClickHouse 分区 此处。
通过聚类,BigQuery 会自动根据几个指定列的值对表数据进行排序,并将它们放置在大小合适的块中。聚类可以提高查询性能,使 BigQuery 能够更好地估算运行查询的成本。使用聚类列,查询还会消除不必要的数据扫描。
在 ClickHouse 中,数据会自动 根据表的的主键列在磁盘上进行聚类,并以逻辑方式组织成块,这些块可以通过使用主索引数据结构来快速定位或修剪查询。
物化视图
BigQuery 和 ClickHouse 都支持物化视图——基于基础表转换查询结果的预计算结果,以提高性能和效率。
查询物化视图
BigQuery 物化视图可以直接查询,也可以由优化器用于处理对基础表的查询。如果基础表的更改可能会使物化视图失效,则直接从基础表读取数据。如果基础表的更改不会使物化视图失效,则从物化视图读取剩余数据,并仅从基础表读取更改。
在 ClickHouse 中,物化视图只能直接查询。但是,与 BigQuery(物化视图在基础表更改后的 5 分钟内自动刷新,但刷新频率不超过 30 分钟)相比,物化视图始终与基础表同步。
更新物化视图
BigQuery 会定期通过对基础表运行视图的转换查询来完全刷新物化视图。在刷新之间,BigQuery 将物化视图的数据与新的基础表数据结合起来,以提供一致的查询结果,同时仍然使用物化视图。
在 ClickHouse 中,物化视图是增量更新的。这种增量更新机制提供高可扩展性和低计算成本:增量更新的物化视图专门为基础表包含数十亿或数万亿行的情况而设计。ClickHouse 不会重复查询不断增长的基础表来刷新物化视图,而是仅从新插入的基础表行的值中计算部分结果。此部分结果会在后台与先前计算的部分结果进行增量合并。与从整个基础表重复刷新物化视图相比,这大大降低了计算成本。
与 ClickHouse 相比,BigQuery 支持单个查询内的多语句事务,或在使用会话时跨多个查询进行多语句事务。多语句事务允许您执行修改操作,例如在一个或多个表上插入或删除行,并以原子方式提交或回滚更改。多语句事务在 ClickHouse 的 2024 年路线图上。
聚合函数
与 BigQuery 相比,ClickHouse 具有更多的内置聚合函数
与 BigQuery 相比,ClickHouse 支持更多的文件格式和数据源
- ClickHouse 原生支持从几乎任何数据源加载 90 多种文件格式的数据
- BigQuery 支持 5 种文件格式和 19 个数据源
SQL 语言特性
ClickHouse 提供了带有许多扩展和改进的标准 SQL,使其更适合分析任务。例如,ClickHouse SQL 支持 lambda 函数和高阶函数,因此您无需在应用转换时展开/explode 数组。这比 BigQuery 等其他系统具有很大的优势。
与 BigQuery 的 8 个数组函数相比,ClickHouse 拥有超过 80 个 内置数组函数,用于优雅而简单地建模和解决各种问题。
在 ClickHouse 中,一种典型的设计模式是使用 groupArray 聚合函数将表的特定行值(临时)转换为数组。然后可以通过数组函数方便地处理它,并通过 arrayJoin 聚合函数将结果转换回单个表行。
由于 ClickHouse SQL 支持 高阶 lambda 函数,许多高级数组操作可以通过简单地调用高阶内置数组函数来实现,而无需像 BigQuery 中经常 需要的那样将数组临时转换回表,例如用于 过滤或 压缩数组。在 ClickHouse 中,这些操作只是对高阶函数 arrayFilter 和 arrayZip 的简单函数调用。
在下文中,我们提供了 BigQuery 到 ClickHouse 的数组操作映射
为子查询中的每一行创建一个数组
BigQuery
ARRAY 函数
SELECT ARRAY
(SELECT 1 UNION ALL
SELECT 2 UNION ALL
SELECT 3) AS new_array;
/*-----------*
| new_array |
+-----------+
| [1, 2, 3] |
*-----------*/
ClickHouse
groupArray 聚合函数
SELECT groupArray(*) AS new_array
FROM
(
SELECT 1
UNION ALL
SELECT 2
UNION ALL
SELECT 3
)
┌─new_array─┐
1. │ [1,2,3] │
└───────────┘
将数组转换为一组行
BigQuery
UNNEST 运算符
SELECT *
FROM UNNEST(['foo', 'bar', 'baz', 'qux', 'corge', 'garply', 'waldo', 'fred'])
AS element
WITH OFFSET AS offset
ORDER BY offset;
/*----------+--------*
| element | offset |
+----------+--------+
| foo | 0 |
| bar | 1 |
| baz | 2 |
| qux | 3 |
| corge | 4 |
| garply | 5 |
| waldo | 6 |
| fred | 7 |
*----------+--------*/
ClickHouse
ARRAY JOIN 子句
WITH ['foo', 'bar', 'baz', 'qux', 'corge', 'garply', 'waldo', 'fred'] AS values
SELECT element, num-1 AS offset
FROM (SELECT values AS element) AS subquery
ARRAY JOIN element, arrayEnumerate(element) AS num;
/*----------+--------*
| element | offset |
+----------+--------+
| foo | 0 |
| bar | 1 |
| baz | 2 |
| qux | 3 |
| corge | 4 |
| garply | 5 |
| waldo | 6 |
| fred | 7 |
*----------+--------*/
返回一个日期数组
BigQuery
GENERATE_DATE_ARRAY 函数
SELECT GENERATE_DATE_ARRAY('2016-10-05', '2016-10-08') AS example;
/*--------------------------------------------------*
| example |
+--------------------------------------------------+
| [2016-10-05, 2016-10-06, 2016-10-07, 2016-10-08] |
*--------------------------------------------------*/
range + arrayMap 函数
ClickHouse
SELECT arrayMap(x -> (toDate('2016-10-05') + x), range(toUInt32((toDate('2016-10-08') - toDate('2016-10-05')) + 1))) AS example
┌─example───────────────────────────────────────────────┐
1. │ ['2016-10-05','2016-10-06','2016-10-07','2016-10-08'] │
└───────────────────────────────────────────────────────┘
返回一个时间戳数组
BigQuery
GENERATE_TIMESTAMP_ARRAY 函数
SELECT GENERATE_TIMESTAMP_ARRAY('2016-10-05 00:00:00', '2016-10-07 00:00:00',
INTERVAL 1 DAY) AS timestamp_array;
/*--------------------------------------------------------------------------*
| timestamp_array |
+--------------------------------------------------------------------------+
| [2016-10-05 00:00:00+00, 2016-10-06 00:00:00+00, 2016-10-07 00:00:00+00] |
*--------------------------------------------------------------------------*/
ClickHouse
range + arrayMap 函数
SELECT arrayMap(x -> (toDateTime('2016-10-05 00:00:00') + toIntervalDay(x)), range(dateDiff('day', toDateTime('2016-10-05 00:00:00'), toDateTime('2016-10-07 00:00:00')) + 1)) AS timestamp_array
Query id: b324c11f-655b-479f-9337-f4d34fd02190
┌─timestamp_array─────────────────────────────────────────────────────┐
1. │ ['2016-10-05 00:00:00','2016-10-06 00:00:00','2016-10-07 00:00:00'] │
└─────────────────────────────────────────────────────────────────────┘
过滤数组
BigQuery
需要通过 UNNEST 运算符将数组临时转换回表
WITH Sequences AS
(SELECT [0, 1, 1, 2, 3, 5] AS some_numbers
UNION ALL SELECT [2, 4, 8, 16, 32] AS some_numbers
UNION ALL SELECT [5, 10] AS some_numbers)
SELECT
ARRAY(SELECT x * 2
FROM UNNEST(some_numbers) AS x
WHERE x < 5) AS doubled_less_than_five
FROM Sequences;
/*------------------------*
| doubled_less_than_five |
+------------------------+
| [0, 2, 2, 4, 6] |
| [4, 8] |
| [] |
*------------------------*/
ClickHouse
arrayFilter 函数
WITH Sequences AS
(
SELECT [0, 1, 1, 2, 3, 5] AS some_numbers
UNION ALL
SELECT [2, 4, 8, 16, 32] AS some_numbers
UNION ALL
SELECT [5, 10] AS some_numbers
)
SELECT arrayMap(x -> (x * 2), arrayFilter(x -> (x < 5), some_numbers)) AS doubled_less_than_five
FROM Sequences;
┌─doubled_less_than_five─┐
1. │ [0,2,2,4,6] │
└────────────────────────┘
┌─doubled_less_than_five─┐
2. │ [] │
└────────────────────────┘
┌─doubled_less_than_five─┐
3. │ [4,8] │
└────────────────────────┘
压缩数组
BigQuery
需要通过 UNNEST 运算符将数组临时转换回表
WITH
Combinations AS (
SELECT
['a', 'b'] AS letters,
[1, 2, 3] AS numbers
)
SELECT
ARRAY(
SELECT AS STRUCT
letters[SAFE_OFFSET(index)] AS letter,
numbers[SAFE_OFFSET(index)] AS number
FROM Combinations
CROSS JOIN
UNNEST(
GENERATE_ARRAY(
0,
LEAST(ARRAY_LENGTH(letters), ARRAY_LENGTH(numbers)) - 1)) AS index
ORDER BY index
);
/*------------------------------*
| pairs |
+------------------------------+
| [{ letter: "a", number: 1 }, |
| { letter: "b", number: 2 }] |
*------------------------------*/
ClickHouse
arrayZip 函数
WITH Combinations AS
(
SELECT
['a', 'b'] AS letters,
[1, 2, 3] AS numbers
)
SELECT arrayZip(letters, arrayResize(numbers, length(letters))) AS pairs
FROM Combinations;
┌─pairs─────────────┐
1. │ [('a',1),('b',2)] │
└───────────────────┘
聚合数组
BigQuery
需要通过 UNNEST 运算符将数组转换回表
WITH Sequences AS
(SELECT [0, 1, 1, 2, 3, 5] AS some_numbers
UNION ALL SELECT [2, 4, 8, 16, 32] AS some_numbers
UNION ALL SELECT [5, 10] AS some_numbers)
SELECT some_numbers,
(SELECT SUM(x)
FROM UNNEST(s.some_numbers) AS x) AS sums
FROM Sequences AS s;
/*--------------------+------*
| some_numbers | sums |
+--------------------+------+
| [0, 1, 1, 2, 3, 5] | 12 |
| [2, 4, 8, 16, 32] | 62 |
| [5, 10] | 15 |
*--------------------+------*/
ClickHouse
arraySum、arrayAvg、... 函数,或将任何现有的 90 多个聚合函数名称作为 arrayReduce 函数的参数
WITH Sequences AS
(
SELECT [0, 1, 1, 2, 3, 5] AS some_numbers
UNION ALL
SELECT [2, 4, 8, 16, 32] AS some_numbers
UNION ALL
SELECT [5, 10] AS some_numbers
)
SELECT
some_numbers,
arraySum(some_numbers) AS sums
FROM Sequences;
┌─some_numbers──┬─sums─┐
1. │ [0,1,1,2,3,5] │ 12 │
└───────────────┴──────┘
┌─some_numbers──┬─sums─┐
2. │ [2,4,8,16,32] │ 62 │
└───────────────┴──────┘
┌─some_numbers─┬─sums─┐
3. │ [5,10] │ 15 │
└──────────────┴──────┘