DuckDB还是SQLite:百万行聚合快百倍,也不能取代事务库

|作者: QUASA 编辑团队|2 分钟阅读| 1
DuckDB还是SQLite:百万行聚合快百倍,也不能取代事务库

如果项目主要按键查记录、持续更新业务状态,通常应先保留SQLite;如果主要工作是扫描大量数据并生成汇总报表,DuckDB更合适。两类请求同时存在时,可以让SQLite继续承担事务写入,再接入DuckDB做分析,不必只凭聚合跑分迁走主库。

一项百万行模拟订单测试的配置表列出AMD EPYC 4个虚拟CPU、8 GB内存、NVMe SSD、Ubuntu 22.04、DuckDB 1.5.2和SQLite 3.45.1:按商品类别计算订单数、收入与均价的查询分别耗时0.020秒和2.275秒,DuckDB约快114倍;不过文末另将复核环境写为16 GB内存。这两处内存配置不能视为同一次测量的完整说明,也没有证据表明同样差距会出现在点查询或事务写入中。

百万行聚合测到了什么

测试数据是生成的订单记录,所测SQL按类别分组,读取大量行后输出少量汇总值。这正是分析查询的典型形状,却与按订单ID取回一条记录、修改订单状态或提交关联记录不同。公开结果没有提供对应的主键点查、单笔写入及多写者事务耗时,因此不能由聚合成绩推算这些操作的响应时间。

计时的边界也需要看清。测试方法的文字称DuckDB直接读取CSV,而给出的SQL示例却先从CSV创建表;SQLite示例先将CSV导入表。两边列出的都是查询耗时,没有把准备数据、迁移现有文件或持续同步新记录的成本纳入比较。记录还只说查询运行了多次并给出代表性时间,没有逐次结果或波动范围;这使它适合说明特定负载的性能差异,不适合充当生产环境的延迟承诺。

对已有项目而言,数据形状会改变收益。类别字段的取值分布、过滤条件、索引、内存是否足以容纳工作集,以及报表与业务请求是否同时运行,都会影响实际耗时。尤其不能把这组各自查询本地表的成绩,直接套到DuckDB读取现有SQLite文件的工作流上:数据仍从SQLite表中取得,访问路径已经不同。

点查询与事务写入为何优先考虑SQLite

业务请求通常需要迅速定位少量记录,并保证一组修改一起提交或回滚。已有SQLite项目如果围绕这些请求建立了表、索引和事务边界,报表变慢本身不足以证明主库必须迁移。更直接的判断是:这些在线请求是否已经达到延迟要求,写入等待是否可接受,以及慢查询究竟发生在点查还是大范围扫描。

SQLite的适用场景说明指出,同一数据库文件允许多个读者,但同一时刻只能有一个写者;短写事务可以排队,必须同时推进的大量写入则更适合客户端/服务器数据库。这一限制要按事务持续时间理解:写者很快释放锁时,排队未必构成问题;长事务持续占用写入机会,其他请求的等待就会累积。

“适合点查询”也不是对任意SQL的速度保证。按键查询仍取决于是否有可用索引、返回多少数据,以及缓存和存储设备的状态。若应用还承担大量远程客户端的同时写入,需要评估客户端/服务器架构;把SQLite换成另一款嵌入式分析数据库,并不会自动解决多写者协调问题。

全表分析为何偏向DuckDB

聚合报表的工作量来自读过的行数和参与计算的列,而不只是最终返回多少行。按类别求收入、按时间段汇总订单,往往需要连续处理成批数据。DuckDB的设计说明将扫描大部分数据的聚合与连接列为目标负载,并说明其采用列式、向量化查询执行,同时支持事务保证。这解释了它在所测分组任务中的优势方向,但不能把某次跑分解释成所有查询都按同一倍数加速。

DuckDB具备事务能力,关键区别是系统围绕什么操作优化。批量导入、转换和分析可以让查询引擎连续处理大量值;频繁修改少量业务行则更在意每次请求的提交、冲突处理和并发访问。若项目只有偶发报表,增加分析引擎的维护成本可能高于节省的查询时间;若反复扫描历史数据,专门的分析层才更有比较价值。

还应区分查询时间与报表交付时间。把数据复制进DuckDB原生表,可能改变后续分析的读取方式,但也增加首次装载、增量更新和副本存储的成本。选择直接查询原有文件还是维护分析副本,取决于数据更新频率与报表运行频率,不能只比较单条SQL执行完成的时间。

并发写入要分清文件、线程和进程

DuckDB支持事务,不等于原生数据库文件可以像事务服务那样由多个独立进程直接写入。DuckDB的并发说明写明:在嵌入式读写模式下,一个进程持有读写权,进程内多个线程可在不冲突时并行写入,更新同一行可能触发冲突;Quack远程协议另提供跨进程写入,但属于客户端/服务器模式,文档仍将其列为测试阶段。

因此,“能并发写”必须说明并发的是同一进程内的线程,还是各自打开数据库的进程。前者可以利用DuckDB的并发控制,遇到相同行的修改仍须处理失败和重试;后者涉及不同的访问模式与部署条件。把分析任务、应用服务和后台写入者混在一项单进程跑分里,无法回答实际系统的写入协调问题。

SQLite文件的单写者规则与DuckDB原生文件的进程限制也不能互换着理解。若项目已经由SQLite可靠地处理业务写入,增加DuckDB分析查询不会改变原文件的写锁规则。报表运行时还可能与在线请求争用存储和计算资源,所以混合方案同样需要关注报表时段与业务延迟。

已有SQLite数据怎样增加分析层

迁移成本最低的路径,是让原应用继续写SQLite文件,由DuckDB读取其中的表。DuckDB的SQLite扩展文档说明,可用ATTACH接入SQLite文件并直接查询或写入底层表;同时访问时由SQLite负责锁,同一时刻仍只有一个写者,而列类型不符合DuckDB读取规则时还可能报错。直接接入省去了先导出整库的步骤,却不意味着原有查询会自动得到原生DuckDB表的聚合耗时。

这种组合适合先解决“能否分析现有数据”的问题。DuckDB查询所附加的SQLite表时,数据在查询时从原文件读取;如果分析反复扫描大量记录,读取成本仍会出现。将常用分析数据定期复制到DuckDB表,可以改变后续查询的执行条件,但项目也要承担副本更新、报表新鲜度和额外存储的取舍。

类型差异是接入现存数据时容易遇到的实际障碍。SQLite列中可能存在与声明类型不一致的历史值;DuckDB为列确定类型后,读到不匹配的内容会报错。遇到这类数据,需决定是清理原值、在分析查询中明确转换,还是按文本读取后处理。文件能被接入,只说明数据有了读取路径,并不保证旧数据无需整理就能参与计算。

保留、替换还是组合

决策应以决定用户体验的请求为准,再计入接入和维护数据的成本。下面三种情况对应不同的主路径:

  • 保留SQLite:主要是按键读取、短事务和可排队的写入,现有延迟满足要求,聚合报表又不频繁。优先区分慢报表与在线请求,避免为少量分析工作迁移整个主库。
  • 改用DuckDB:数据主要用于本地探索、批量转换或反复运行的扫描聚合,在线事务写入不构成核心负载。比较时应把装载数据和更新分析结果的时间算入总成本。
  • 组合使用:SQLite已稳定承担业务写入,但大范围汇总成为明确瓶颈。先通过扩展直接读取原库;只有当频繁分析的收益足以覆盖同步与存储成本时,再维护DuckDB分析副本。

相关阅读:

分享:

订阅我们的新闻通讯

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

0