Skip to main content

Command Palette

Search for a command to run...

一个有趣的项目:chdb

Updated
3 min read

不记得是从哪里知道这个项目,总之是躺在我的 logseq 的 todo 列表里面了,然后几天前(三个朋前)牛刀小试了一下,结果最近瞄到的 1brc 这个项目,正好拿来一下呗

1brc 简介

工程师贡纳尔·莫林在元旦发起一个挑战(1BRC),挑战从 1 月 1 日持续到 1 月 31 日。

如果你决定接受它,你的任务看似简单: 写一个 Java 程序,用于从文本文件中检索温度测量值并计算每个气象站的最小、平均值和最高温度。
只有一点需要注意:文件有 1,000,000,000 行!(1 billion, 10亿行)。

chdb 是什么?

chDB 是一个由 ClickHouse 驱动的嵌入式 SQL OLAP 引擎

对于一个轻量级萌新+爱好者,这东西一出场,便成功吸引了我的注意力,但还没想好用它来做点啥

安装 clickhouse vs chDB

这是一个极易形成对比的地方,如果你想要安装一个完整的clickhouse,

sudo apt-get install -y apt-transport-https ca-certificates dirmngr
sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 8919F6BD2B48D754

echo "deb https://packages.clickhouse.com/deb stable main" | sudo tee \
    /etc/apt/sources.list.d/clickhouse.list
sudo apt-get update

sudo apt-get install -y clickhouse-server clickhouse-client

sudo service clickhouse-server start
clickhouse-client # or "clickhouse-client --password" if you've set up a password.

呃,还是挺复杂的,当然,clickhouse 也有 local 模式:

ClickHouse-local 模式可以让用户能够对本地文件执行快速处理,而无需部署和配置 ClickHouse 服务器。ClickHouse-local 使用与 ClickHouse Server 相同的核心,因此它支持大多数功能以及相同的格式和表引擎。

安装也比较简单:

# curl -O 'https://builds.clickhouse.com/master/macos/clickhouse' && chmod a+x ./clickhouse
# ./clickhouse -q "select version()"
24.3.1.1526

然而,使用chdb,只需如此简单与丝滑:

# pip install chdb
# python -m chdb "select version()"
"23.10.1.1"

应用

虽然知道把 clickhouse 做成 chdb 这种嵌入式形态很厉害,但总需要一个场景去实践,用 1brc 试水再合适不过了

环境:

  • Python 3.12.0

  • OSX 14.5

  • 内存 32 GB 2667 MHz DDR4

  • 处理器 2.6 GHz 六核Intel Core i7

chdb 1.4.1

import time
import chdb

query_sql = """
-- Change to your number of physical CPU threads for the best performance.
SET max_insert_threads = 28;
SET max_threads = 28;
SET format_csv_delimiter = ';';

SELECT
    concat('{', arrayStringConcat(groupArray(formatted_result), ', '), '}') AS final_output
FROM (
    SELECT
        format('{}={}/{}/{}', location, toDecimalString(min(temperature), 1), toDecimalString(avg(temperature), 1), toDecimalString(max(temperature), 1)) AS formatted_result
    FROM file('measurements.txt', 'CSV', 'location String, temperature Float32')
    GROUP BY location
    ORDER BY location
)
"""
start = time.time()
res = chdb.query(query_sql)
elapsed = time.time() - start
# 连续运行三次的耗时
# Query took 59.594 seconds
# Query took 39.029 seconds
# Query took 36.696 seconds
print(f'Query took {elapsed:.3f} seconds')
print(f'{res}')

duckdb 1.0.0

最近 duckdb 发布了 1.0.0 这个版本,来看下表现如何

import duckdb
import time
query_sql = '''
-- Load the data
CREATE OR REPLACE TABLE measurements AS
        SELECT * FROM READ_CSV('measurements.txt', header=false, columns= {'station_name':'VARCHAR','measurement':'double'}, delim=';');

-- Run calculations
WITH src AS (SELECT station_name,
                    MIN(measurement) AS min_measurement,
                    CAST(AVG(measurement) AS DECIMAL(8,1)) AS mean_measurement,
                    MAX(measurement) AS max_measurement
            FROM measurements
            GROUP BY station_name)
    SELECT '{' ||
            ARRAY_TO_STRING(LIST_SORT(LIST(station_name || '=' || CONCAT_WS('/',min_measurement, mean_measurement, max_measurement))),', ') ||
            '}' AS "1BRC"
    FROM src;
'''
start = time.time()
res = duckdb.sql(query_sql)
elapsed = time.time() - start
# 连续运行三次的耗时
# Query took 78.377 seconds
# Query took 72.713 seconds
# Query took 63.916 seconds
print(f'Query took {elapsed:.3f} seconds')
print(f'{res}')

单从时间上看,chdb 平均用时要更少,可以说非常强大了。

go 版本

第一次看到 1brc 还是今年3月份在 InfoQ 的微信公众号上到到的,看到 Ben Hoyt 大佬孜孜不倦的优化,有点被触动到了。虽然这篇文件拖了这么久,但根据大佬最新的代码和算法,在我本地跑了一下,三次耗时如下所示:

  • 5.659881206s

  • 6.197552364s

  • 4.799696744s

不是最强的,但确实非常优秀就是了。毕竟,最简单的实现耗时是:2m30.835476239s

总结

不考虑 SQL 优化的前提下,个人理解 chdb 与 duckdb 提供的是相对通用的数据分析能力,它们短小而精悍,提供了性能的下限;而使用编程语言,针对特定问题的不断优化,压榨,获得的性能收益是异常惊人的。作为一个算法难民,是不是应该重新捡起算法了

番外插曲

可能是因为太长时间没写 python 了,当我把 chdb 的 1brc 代码示例保存为 chdb.py 时,遇到以下错误:

AttributeError: partially initialized module 'chdb' has no attribute 'query' (most likely due to a circular import)

初,感觉很奇怪,百思不得其解,还排查了好一会,最后才发现是文件命令问题,重新学习一下 python 的包导入

Python解释器在导入模块时,首先会在当前目录查找文件名匹配的模块。如果找到了同名文件,它会试图从这个文件中加载模块,而不是从已安装的包中加载。因此,当你在当前目录下运行 import chdb 时,Python会尝试导入你自己的 chdb.py 文件,而不是你安装的 chdb 包,这就导致了循环导入的问题。

还是要多写代码啊


参考:

151 views

More from this blog

2025: 祛魅 灰度 念头通达

今天是2025年的最后一天,当大家都在准备下班的时候,好巧不巧的,我刚好发现了一个不大不小的问题,大胆猜想,小心求证,向上反馈,暴露风险,作为2025年工作注解,实在是再有趣不过了。 今年的工作,从结果上看,还算平稳,至于过程,有太多不可言说的部分。厂里打镙丝的牛马,有工资可拿,理应知足了,至于其它的,与己无关,也没那么重要了。 祛魅 近距离观察大厂,才发现一些违背常识/直觉的事实:路人以为的高大

Feb 28, 20261 min read21

大厂祛魅:破碎的专注力

毁掉一个人最直接的方法,就是毁掉ta的专注力。 这句话的出处已然模糊,但放在大厂环境中,却显得格外深刻。 围城 大厂宛如一座围城。城外的人满怀憧憬,目之所及皆是光鲜;城内的人却如困笼之鸟,翅膀日渐退化,每日挣扎求生。 高大上 不可否认,大厂的硬件设施确实令人艳羡:宽敞的独立园区内,来往穿梭的人群中,几乎人人手握智能设备。这看似现代化的景象背后,却藏着一个无奈的事实:在工作时段,每台电脑都被严密监控,连听音乐都成奢望。于是,工作之余玩手机,成了许多人难得的解压方式。 大厂的品牌效应确实强大。外界对...

Jul 29, 20251 min read138

Black Swan

黑天鹅理论 是指极不可能发生,实际上却又发生的事件 来到大厂打工已经满一个月了,从一开始的手足无措,到逐渐度过不适期,也算是适应了吧。 不适应 刚入职时,不适应的地方还是挺多的。 第一次只使用台式机工作,这就限制了我一天中的绝大部分时间,都必须呆在自己的工位上,好在工位足够大。只是人与人的沟通少了很多,有问题只能在工位上通过 IM 呼对方,有种魔幻又现实的感觉 第一次只能用 Windows,也不能 WSL,这给我的工作效率带来了很大影响,不能用熟悉的软件,就连写代码用的 VSCode 的...

Jan 24, 20251 min read74

2024年: 逐渐平静

这个世界是一面镜子,会把你的感受反射给你 2024 开端: 相由心生 那时,还带着一着愤懑,因为拿到了低绩效,虽然内心知道这是公司经营困难,想让我离开的一种策略,但仍然感受到自己那可笑的自尊受到了践踏。自那之后,非必要不加班,只做份内事,尽可能地不去涉及份外之事。 2024 年中: 与人为善 组里的项目眼见不行了,我被迫去支援 AI 项目,久违地写起了 python,项目接近完成时,意外收到通知:我拿到大礼包了。在这之前,架构师因故裸辞。在我离开之后不到两周,我的 TL 也裸辞了,直到同事告诉...

Jan 9, 20251 min read92

企业软件之殇

殇 动词 未成年而死。 名词 战死者。 笔者经历了两家打着云原生旗号的企业软件/解决方案公司,都是中途加入,项目都以解(失)散(败)告终。 云原生解决方案 NB 公司:一个传统的 IDC 小厂,想着借云原生的热度,进军企业软件市场。 在加入这个项目之前,笔者考取了 CKAD 认证,彼时对 K8s 相当着迷。先简要介绍一下这个项目背景: 基于 Rancher (换皮肤)的二次开发项目,名字叫:HCaaS ,在笔者加入这个团队之前,项目已经开发近两年了,除了 TL 之外,其它人之前都...

Jul 1, 20241 min read103

just for fun

57 posts

I'm a Software Engineer