PostgreSQL码农集散地

网友称DuckDB是玩具 | 你同意吗?

网友称DuckDB是玩具

昨天发的一篇文章《DuckDB进军DB4AI|“语义(向量)搜索、全文检索、BM25、模糊检索”一网打尽》网友留言非常激烈!

一位朋友留言称使用过DuckDB后发现了几个问题:

  • 1、列存中的PK,高频插入时一天无故报错几回;
  • 2、内存管理,特别是读写外部数据源时,内存狂泄不止;
  • 3、SQL算子一致进,非一致出,计算结果不一致是常态。

随后这位朋友另一段留言更是给DuckDB判了死刑:

  • DuckDB用一句话总结的话, 就是 “写不进、存不下、算不准.”

Image
pic

Image
pic

非常感谢这位盆友的留言,我相信这位盆友肯定用过DuckDB, 不然不可能说出这些个问题. 但是我又不太认同这种“消极”的处理方法, 更无法理解的是“DuckDB是国外信创产品”这个说法是怎么得出的?当然了这是他的自由, 别人无法干涉.

假如开源项目的issue长久都没有开发人员回应或解决, 那我会非常理解为什么不去发issue. 而DuckDB开源项目现在极其活跃, 显然不存在这种没人理会issue问题. 

个人非常感谢盆友的留言,但并不认同他的做法: 把产品说得几乎一无是处, 然后也不去社区反馈问题, 例如什么版本, 什么环境, 如何复现问题等等. 

产品好对用户才会好, 除非你未来不用它(或者已经有更好的选择), 否则应该本着开源共建的协作精神, 把问题复现方法通过issue反馈给社区让更多人来一起解决. 这样的话开源产品才会越来越好. 有利于用户同时也有利于开源项目背后的公司或社区.

换位思考一下, 如果开源项目用户遇到问题都不反馈,只是消极抵抗, 那开源还怎么良性发展?

这位盆友也许不适合使用开源产品,或许商业产品更适合。

关于问题,我不是DuckDB内核研发,盆友反馈的信息也比较有限,但是第一时间想到了deepwiki, 可以用AI来分析一下.

先说结论. 经过deepwiki对问题和代码的分析, 给出了3条建议:

  • 问题1 未直接给出解决方案但是介绍了duckdb提升插入吞吐背后的原理, 所以理论上不使用并发、采用批量写入即可解决. 但是个人更推荐把duckdb当成计算节点来使用更靠谱, 数据嘛就不要存duckdb里面, 存成parquet更靠谱.
  • 问题2 建议检查enable_external_file_cache设置,必要时可以禁用此功能来避免内存泄漏。
  • 问题3 可以通过设置ieee_floating_point_ops为true来启用IEEE-754兼容模式,但这可能影响性能并引入其他兼容性问题。

以下是详细分析内容

https://deepwiki.com/duckdb/duckdb

https://deepwiki.com/search/duckdb-1pk23sql_c06bb1c5-8487-4ef5-a47c-f5ecaf57921c

基于对DuckDB代码的分析,我来为您解答这三个问题:

1. 列存中的PK高频插入报错问题

这个问题可能与DuckDB的主键约束实现机制有关。DuckDB中主键约束是通过唯一约束实现的,使用ART(Adaptive Radix Tree)索引来检测冲突。

在高频插入场景下,可能出现的问题包括:

  • 约束状态管理的并发冲突
  • 事务级存储与全局存储的约束验证不同步

2. 外部数据源内存泄漏问题

这个问题很可能与DuckDB新增的外部文件缓存系统有关。代码显示DuckDB最近引入了一个外部文件缓存机制,专门用于缓存外部文件数据。

该系统有专门的内存标签进行跟踪,但在某些情况下可能出现内存未正确释放的问题。系统包含校验和验证机制:

建议检查enable_external_file_cache设置,必要时可以禁用此功能来避免内存泄漏。

3. SQL算子计算结果不一致问题

这个问题主要与DuckDB对浮点数处理的策略有关。DuckDB默认不遵循IEEE-754标准,特别是在处理NaN值时采用了不同的策略。

DuckDB默认将NaN值视为相等且为最大值,这与标准的IEEE-754行为不同。这种设计是为了确保总排序,但可能导致:

  • 相同输入在不同执行路径下产生不同结果
  • 浮点数比较的不一致性
  • 连接操作和过滤操作的结果差异

可以通过设置ieee_floating_point_ops为true来启用IEEE-754兼容模式,但这可能影响性能并引入其他兼容性问题。

Notes

这些问题反映了DuckDB作为OLAP数据库在追求性能优化时做出的一些权衡:

  1. 主键约束:列存储格式下的约束检查比行存储更复杂,特别是在高并发场景下
  2. 内存管理:外部文件缓存是新功能,可能还有一些边界情况未完全处理
  3. 浮点数处理:为了保证确定性查询结果,DuckDB选择了偏离IEEE-754标准的实现

建议在生产环境中根据具体业务需求调整相关设置,并关注DuckDB的版本更新来获得这些问题的修复。


 第一个列存中的PK高频插入报错问题的问题如何规避?  

主键实现

DuckDB中的主键是通过由ART(自适应基数树)索引支持的特殊唯一约束来实现的。  系统将主键视为设置了is_primary_key标志为true的唯一约束,并自动为主键列添加NOT NULL约束。

列存储与事务隔离

DuckDB使用列存储模型结合多版本并发控制(MVCC)来处理并发访问。事务管理器为每个事务分配唯一的开始时间戳和事务ID来提供隔离性。  这种基于时间戳的方法确保事务可以并发操作而不会干扰彼此对数据的视图。

高频插入的本地存储模式

为了高效处理高频插入,DuckDB采用使用事务本地存储的两阶段方法。插入操作首先进入LocalTableStorage结构,该结构维护自己的行组和索引,与主表存储分离。  这个本地存储包括追加索引和删除索引,用于跟踪事务范围内的修改。

主键约束验证

主键约束强制执行通过VerifyUniqueIndexes方法进行,该方法在数据插入期间检查违规情况。  验证过程扫描所有唯一ART索引(包括主键索引)以检测重复值。当没有提供冲突管理器时,如果检测到违规,系统会立即抛出异常。

冲突检测和解决

对于需要优雅处理冲突的操作(如带有ON CONFLICT子句的INSERT),DuckDB使用ConflictManager,它有两种操作模式:SCAN模式用于收集冲突而不抛出异常,THROW模式用于处理冲突目标未处理的冲突。  冲突管理器跟踪哪些索引匹配冲突目标并管理解决过程。

并发控制机制

为了防止高频插入期间的同步问题,DuckDB实现了几种机制:

  1. 乐观并发控制:系统使用乐观并发控制,在提交时而不是插入期间检测冲突,减少锁争用。

  2. 事务本地修改:事务内的所有修改都保存在本地存储中直到提交,防止其他事务看到不完整的更改。

  3. 追加锁:系统使用追加锁来防止高频插入期间对表结构的并发修改。

  4. 索引级验证:全局和本地存储都维护自己的索引,在提交过程中在两个级别都进行验证。

两阶段提交过程

在提交期间,事务本地的更改通过适当的约束检查合并到主存储中。验证过程处理本地存储索引和全局表索引以确保一致性。

Notes

DuckDB在高频插入期间的主键约束强制执行方法旨在最小化争用同时保持数据完整性。系统通过事务隔离、本地存储缓冲区和延迟约束检查直到提交时间来实现这一点。ART索引的使用提供了高效的重复检测,而冲突管理器允许在需要时对约束违规进行复杂处理。这种架构在保持ACID属性和约束强制执行的同时,支持高吞吐量插入场景。


 补充: 问题2, 泄与cache是有区别的. 问题3, 说的是算子, 而不是数据类型. 

感谢您的补充说明。让我重新分析这两个问题:

问题2:内存泄漏(非缓存问题)

您提到的是真正的内存泄漏问题,而不是缓存占用。从代码分析来看,DuckDB在处理外部数据源时确实存在潜在的内存管理问题:

外部文件缓存系统使用EXTERNAL_FILE_CACHE内存标签分配内存,但在某些异常情况下可能未正确释放。特别是在读取外部数据源时:

当block_handle->IsUnloaded()返回false但后续操作失败时,可能导致内存泄漏。

规避方法:

  1. 设置enable_external_file_cache=false禁用外部文件缓存
  2. 调整内存限制设置强制回收:

问题3:SQL算子执行不一致

您指的是查询执行过程中算子(operators)的行为不一致,而非数据类型问题。这涉及DuckDB的查询执行引擎:

DuckDB使用管道化执行模型,不同的物理算子可能在并行执行时产生不确定的结果顺序。特别是在以下情况:

  1. 并行执行算子:多个线程同时执行相同算子时,由于调度差异可能产生不同结果
  2. 内存压力下的算子行为:当内存不足时,某些算子可能切换到不同的执行策略
  3. 浮点运算算子:虽然您说不是数据类型问题,但算子内部的浮点计算仍可能影响结果一致性

规避方法:

  1. 使用ORDER BY子句确保结果顺序的确定性
  2. 设置maximum_threads=1强制单线程执行
  3. 增加内存限制避免算子执行策略切换

Notes

这两个问题都反映了DuckDB作为高性能分析数据库在优化执行时的权衡。内存泄漏问题主要出现在外部数据源访问的边界情况,而算子不一致问题则与并行执行和资源管理策略相关。

DuckDB真的一无是处?而且还是国外信创产品?你怎么看, 欢迎留言讨论!