DuckDB还是ClickHouse:单机快,不等于多人并发也该嵌入

|作者: QUASA 编辑团队|2 分钟阅读| 2
DuckDB还是ClickHouse:单机快,不等于多人并发也该嵌入

本地查询 Parquet、在应用内运行分析,通常先考虑 DuckDB 的进程内引擎;持续接收事件并服务多人仪表盘,更适合评估 ClickHouse。前一种负载可以让查询随 Notebook 或应用进程运行,后一种负载则需要考虑多个请求如何共享服务资源。

决定选型的不是单条 SQL 在一台机器上跑得多快,而是数据何时到达、谁同时查询,以及结果需要多新。同一份事件数据,交给一个分析人员探索、交给定时作业汇总,或交给不断刷新的多人仪表盘,会产生不同的读取、写入和运维成本。

本地 Parquet:直接查询何时更省事

DuckDB 查询事件 Parquet 时,筛选条件使读取集中在相关列与行组

设想一份已存为 Parquet 的事件数据,分析人员在 Notebook 中按时间和事件类型筛选,再统计各类事件的数量。这是示意负载,不代表某次实测。数据已经以文件形式存在,分析人员只需在自己的进程里运行查询;为一次探索先部署常驻服务并导入数据,会增加准备工作。

DuckDB 的 Parquet 查询文档说明,它可以直接读取文件,并将过滤条件下推到扫描阶段,只读取查询涉及的列。因此,筛选少数事件类型、只取少数列的查询,不必先把整份文件转换为原生表。文件本身仍需从存储中读取,实际耗时会随文件组织、筛选条件和缓存状态变化。

直接查文件与导入后查询应按完整任务比较。如果只需要回答一次临时问题,导入、建表和维护存储的时间可能比后续查询收益更大;如果同一批数据会被反复查询,预先组织存储也可能值得。比较时应分别记录文件扫描、数据导入和重复查询,避免只截取两条路径各自最快的 SELECT。

定时批处理:成本落在作业周期内

把同一份事件数据交给定时作业,任务可以读取新文件、生成汇总,再退出。DuckDB 随作业进程启动,查询完成后也无需留下一项等待客户端连接的数据库服务。对按批到达、允许按批发布结果的数据,这种生命周期使部署和资源占用较容易对应到具体作业。

这里仍有真实的工程成本:输入文件要有明确版本,失败后重跑不能悄悄混用新旧批次,汇总结果也要在约定时间交付。如果每次作业都重扫全部历史数据,扫描成本会随着积累增加;若作业只处理新增文件,历史结果如何合并则成为设计重点。这些问题属于批处理链路,不能由一次查询的低延迟替代回答。

刷新要求会改变判断。按批发布汇总时,使用者看到的是最近一次作业完成后的状态;若仪表盘要求新事件持续进入并很快可查,缩短作业间隔还会增加调度、重复读取和结果切换的压力。此时要比较的不只是数据库引擎,还包括把批处理结果发布给使用者的整条路径。

多人仪表盘:先分清进程内并发与跨进程访问

多人仪表盘的负载同时包含查询数量和查询形态。一次页面加载可能触发多项筛选与聚合;不同使用者还可能选择不同时间窗口,使请求难以完全复用。单人 Notebook 的响应时间无法说明这些请求一起到来时的排队时间、内存占用或尾部延迟。

DuckDB 的并发文档区分了几种情形:单个读写进程内可以有多个写入线程;多个进程可在只读模式下读取同一原生数据库文件;跨进程写入也可通过 Quack 远程协议实现,届时部署形态转为客户端与服务端。因而,“DuckDB 不能并发”过于笼统,真正需要确认的是应用有几个进程、谁负责写入,以及它们访问的是文件还是远程服务。

把 DuckDB 嵌入一个对外提供 API 的应用,也能服务多个使用者,只是请求入口属于该应用。应用需要安排并发请求、限制昂贵查询、处理写入与结果发布;当查询量增加,还要决定如何扩展这个入口。若这些能力已经由现有服务承担,嵌入式方案可能仍然简洁;若它们都要新建,数据库进程少并不等于整个系统更省运维。

ClickHouse 的常驻服务为多个客户端提供共同的查询入口,更贴近持续使用的仪表盘。但“有服务器”本身也不保证容量:筛选、聚合、排序和导出的资源需求不同,新增事件又会与读取争用资源。选型应以高峰时实际执行的查询组合和可接受的延迟为依据,而不是把在线用户数直接当成同时执行的 SQL 数量。

持续写入:写入方式会影响读取延迟

同一份事件 Parquet 的精确匹配查询,在特定 chDB 读取路径中漏掉部分应匹配记录

当事件不断到达,ClickHouse 也需要合适的写入批次。ClickHouse 的并发与容量指南指出,频繁的小批量同步写入可能让数据片段产生得比后台合并更快,从而拖慢读取;客户端批量写入或异步写入可以减轻这类压力。异步写入只是把批量处理移到服务端,刷新、生成片段和合并仍会消耗资源。

这使“能接收持续写入”与“写入期间仍能稳定回答仪表盘”成为两个需要分别观察的问题。事件进入系统时,应同时关注查询的高位延迟、失败与排队情况,以及后台合并是否持续积压。若只在停止写入后测读取,得到的是另一种负载,无法估计使用者实际看到的响应。

运维成本也因此落在不同位置。运行 ClickHouse 服务意味着规划计算与存储资源、写入批次、查询限制、监控和故障处理;使用托管服务则将部分工作转为服务费用。嵌入 DuckDB 省去独立数据库服务,却仍要为面向多人的应用安排请求控制、数据更新与发布。比较总成本时,应把这些由应用承担的工作一同计算。

单机跑分:答案和测试条件先于耗时

一项使用合成 OCSF 形态事件数据的 可复现基准显示,单机查询的快慢随查询而变;在扩展到一亿条事件时,chDB 4.1.8 直接读取 Parquet 的特定精确字符串匹配路径,比 DuckDB 少返回 49 条应匹配记录,且没有报错。测试对象是嵌入式 chDB 的这条读取路径,不能将漏数归为 ClickHouse 常驻服务器的结果。

这类差异会让单纯的耗时表失去意义:筛选结果少了,后续聚合要处理的数据也可能变少。上述基准先核对两边答案,再记录延迟,因而发现了问题。对同一份事件数据做选型比较时,行数、筛选结果和聚合值应与耗时放在一起;只公布最快一次响应,无法说明两边回答的是否是同一个问题。

缓存和数据准备也必须使用一致口径。首次读 Parquet、重复查询已读文件,以及导入原生存储后再查询,涉及不同的准备成本;多人仪表盘还要加入同时到来的请求和正在进行的写入。本地探索与独立批处理可从 DuckDB 的直接读取和进程内运行受益;持续更新的共享查询更适合用 ClickHouse 服务的完整负载来评估。

相关阅读:

分享:

订阅我们的新闻通讯

将最新 Web3、AI 和加密货币新闻直接发送到您的邮箱。

0