数据库关系型数据库【免费下载链接】serverMariaDB server is a community developed fork of MySQL server. Started by core members of the original MySQL team, MariaDB actively works with outside developers to deliver the most featureful, stable, and sanely licensed open SQL server in the industry.项目地址https://gitcode.com/gh_mirrors/server1/server点击查看免费下载导读本文围绕 MariaDB Server 内嵌 DuckDB 存储引擎storage/duckdb/在数据导入大规模COPY、INSERT ... SELECT、run_in_duckdb()过程中的内存控制问题展开。你将掌握 DuckDB 内存限制的本质——只有memory_limit别名max_memory这一实例级硬上限且它只有在配置了temp_directoryspill 空间时才能被强制执行——并学会通过write_buffer_row_group_count、preserve_insertion_order、partitioned_write_flush_threshold等设置降低导入峰值内存同时理解单一共享实例 GLOBAL 设置带来的运维约束。1. 核心结论DuckDB 没有导入专用内存预算首先必须澄清一个常见误解DuckDB 不存在任何按操作ingestion-specific划分的内存预算。对于内存密集型算子DuckDB 能做的只有两件事遵守实例级硬上限memory_limit别名max_memory前提是它能将数据 spill 到临时目录temp_directory。如果实例没有配置临时目录也没有 swap 空间DuckDB 的临时内存管理器会明确放弃限制内存将持续增长到物理资源耗尽。这一逻辑在 DuckDB 源码中写得非常直白见third_parties/duckdb/src/storage/temporary_memory_manager.cpp} else if (!has_temporary_directory) { // We cannot offload, so we cannot limit memory usage. Set reservation equal to the remaining size SetReservation(temporary_memory_state, temporary_memory_state.GetRemainingSize()); }一句话总结memory_limit只是上限的承诺temp_directory才是兑现承诺的手段。没有后者前者在导入大表时形同虚设。由此推导出两个直接后果如果共享实例没有temp_directory或系统没有 swap重负载导入期间内存上限无法被强制执行进程可能被 OOM killer 杀死memory_limit被设为-1/none/null时表示无限对应DBConfig::ParseMemoryLimit的解析逻辑config.cpp:633-637此时即便有 spill 空间也不会主动 spill。2. 影响导入内存的真实设置项全部为树内原生设置下面这些设置都是 DuckDB 源码中真实注册的配置项在src/main/config.cpp中注册在src/include/duckdb/main/settings.hpp中定义在 MariaDB 的 DuckDB 引擎中通过全局代理系统变量暴露见common/duckdb_config.h与runtime/duckdb_config.cc。2.1write_buffer_row_group_count—— 最接近导入专用内存控制的参数作用域GLOBAL默认值5官方描述The amount of row groups to buffer in bulk ingestion prior to flushing them together. Reducing this setting can reduce memory consumption.批量导入时一次性合并 flush 前缓冲的 row group 数量调小它可以降低内存消耗。定义位置settings.hpp:1609-1618这是本文所涉及参数中与批量导入内存最直接相关的一个。批量写入Appender / 批量COPY会先在一组 row group 中缓冲数据再一起 flush缓冲的 row group 越多峰值内存越高。在内存受限的环境中调小该值可以让 flush 更早发生、更频繁从而压低峰值。2.2memory_limit/max_memory—— 实例级内存天花板作用域GLOBAL别名max_memory定义位置MaxMemorySettingcustom_settings.cpp:1295-1309这是整个 DuckDB 实例唯一的硬性内存上限。注意它的强制力依赖第 1 节的条件没有 spill 空间就无法强制执行。在 MariaDB 侧duckdb_memory_limit系统变量的 ON_UPDATE 回调会把值翻译成 DuckDB 的SET GLOBAL memory_limit语句下发见runtime/duckdb_config.cc的update_memory_limit_cb当值为 0 时执行RESET GLOBAL memory_limit否则执行SET GLOBAL memory_limit 人类可读大小。2.3temp_directorymax_temp_directory_size—— spill 空间的配置与配额作用域GLOBAL定义位置custom_settings.cpp:1314-1358temp_directory、custom_settings.cpp:1606-1633max_temp_directory_size要让memory_limit真正生效必须给 DuckDB 一个可以卸载中间数据的临时目录SET GLOBAL temp_directory /var/lib/mariadb/duckdb-tmp; SET GLOBAL max_temp_directory_size 10GB; SET GLOBAL memory_limit 8GB;max_temp_directory_size控制 spill 文件可占用的最大磁盘空间避免 spill 反过来把磁盘写满。MariaDB 侧对应duckdb_temp_directory与duckdb_max_temp_directory_size代理变量runtime/duckdb_config.cc的update_max_temp_directory_size_cb同样通过SET GLOBAL max_temp_directory_size ...下发。2.4preserve_insertion_order—— 关闭顺序保证换取流式并行插入作用域GLOBAL默认值true影响机制当该值为false时查询规划器会启用并行/流式插入parallel_streaming_insert允许结果不保持插入顺序从而减少缓冲、降低内存占用。该逻辑在PlanInsert中通过parallel_streaming_insert !PreserveInsertionOrder(...)门控plan_insert.cpp:102。适用场景对插入顺序没有硬性要求的批处理导入例如先落地再在应用层排序可以接受行顺序被打乱以换取更低的内存与更高的并行度。2.5 分区写入专用partitioned_write_flush_threshold与partitioned_write_max_open_files针对COPY ... TO ... (PARTITION_BY ...)这种写出分区文件的场景还有两个细分控制设置项默认值作用源码位置partitioned_write_flush_threshold524288行提前 flush 某个线程的分区缓冲区行数达到阈值即落盘减少内存中积压的行数settings.hpp:1257-1266使用于physical_copy_to_file.cpp:287,317partitioned_write_max_open_files100同时打开的文件数越少缓冲越少调小可降低内存占用settings.hpp:1268-1277-- 示例控制分区写出时的内存占用 SET GLOBAL partitioned_write_flush_threshold 100000; SET GLOBAL partitioned_write_max_open_files 50;2.6 容易混淆streaming_buffer_size与导入无关需要特别澄清streaming_buffer_size只控制结果集流式返回给客户端时的缓冲与导入过程的内存无关见client_config.hpp:82-83。排查导入内存问题时不要在这个参数上浪费时间。3. 关键前提单一共享实例上的 GLOBAL 设置以上设置全部是GLOBAL作用域且作用于唯一的共享 DuckDB 实例——也就是run_in_duckdb()所使用的那个实例详见 security-model.md。这意味着通过run_in_duckdb()执行SET GLOBAL ...会影响每一个会话不存在按调用per-call或按租户per-tenant的内存隔离任何有权限的调用者都可以调高memory_limit甚至直接设为无限从而绕过内存限制。从仓库架构文档 shared-resources.md 可以看到所有 MariaDB 客户端线程共享由DuckdbManager单例管理的同一个duckdb::DuckDB实例单一duckdb.db文件、共享 buffer pool / 内存分配器、共享 temp/swap 目录、单一 WAL。各线程THD只是各自持有独立的duckdb::Connection与事务上下文。因此buffer pool 压力是共享的一个连接执行大扫描会驱逐另一个连接需要的页面内存与 spill 空间是全实例共享的一个导入任务的内存暴涨会直接挤压其他查询。4. 在 MariaDB 中配置的落地方式4.1 通过系统变量推荐MariaDB 侧提供了duckdb_前缀的系统变量作为 DuckDB 设置的代理定义与回调见common/duckdb_config.h、runtime/duckdb_config.cc-- 实例级 SET GLOBAL duckdb_memory_limit 8G; SET GLOBAL duckdb_temp_directory /var/lib/mariadb/duckdb-tmp; SET GLOBAL duckdb_max_temp_directory_size 10G; -- 降低导入峰值内存 SET GLOBAL duckdb_appender_allocator_flush_threshold 128M; -- 批量写入 flush 阈值对于仓库自带的 duckdb.cnf 示例默认已启用引擎插件并开启run_in_duckdb且预留了#loose-duckdb-memory-limit10G的注释示例[mysqld] plugin-maturitygamma plugin-load-addha_duckdb.so duckdb-allow-run-in-duckdbON #loose-duckdb-memory-limit10G去掉#并按需调整loose-duckdb-memory-limit即可在启动时固化内存上限。4.2 通过run_in_duckdb()直接下发 DuckDB 设置SELECT run_in_duckdb(SET GLOBAL memory_limit 8GB); SELECT run_in_duckdb(SET GLOBAL temp_directory /var/lib/mariadb/duckdb-tmp); SELECT run_in_duckdb(SET GLOBAL write_buffer_row_group_count 2); SELECT run_in_duckdb(SET GLOBAL preserve_insertion_order false);注意这些设置是 GLOBAL 且跨会话生效见第 3 节并且run_in_duckdb()本身需要duckdb_allow_run_in_duckdbON且调用者持有SUPER权限security-model.md明确说明该函数默认关闭、受SUPER门控。5. 实操建议一份低内存导入检查清单结合以上原理当导入大表时发现内存不受控增长按优先级依次检查确认 spill 空间存在temp_directory是否已设置磁盘是否有足够空间max_temp_directory_size是否合理——这是最常被忽略、也最可能导致看似无上限增长的根因对应第 1 节。确认memory_limit不是无限检查是否被设成了-1/none/null。调低write_buffer_row_group_count批量导入场景优先尝试如2或3观察峰值内存变化。如可接受乱序关闭preserve_insertion_order换取并行流式插入减少缓冲。分区写出时调低partitioned_write_flush_threshold与partitioned_write_max_open_files。注意共享性以上均为 GLOBAL 设置修改会影响所有会话在多租户或多人共享实例上调整前先评估对其他查询的影响。6. 参考与延伸阅读本文涉及的源码与文档位置均为仓库内相对路径本文主文档storage/duckdb/docs/ingestion-memory-limits.md共享实例架构storage/duckdb/docs/shared-resources.mdrun_in_duckdb()安全模型与权限门控storage/duckdb/docs/security-model.mdMariaDB 侧全局代理变量定义与 ON_UPDATE 回调common/duckdb_config.h、runtime/duckdb_config.cc引擎总览与使用场景storage/duckdb/README.md配置示例storage/duckdb/duckdb.cnfDuckDB 侧源码随仓库 vendored 在storage/duckdb/third_parties/duckdb/下src/storage/temporary_memory_manager.cpp无 temp 目录则无法限内存、src/main/config.cpp与src/main/settings/custom_settings.cpp设置定义、src/include/duckdb/main/settings.hpp默认值与描述、src/execution/physical_plan/plan_insert.cpp插入顺序与并行流式插入、src/execution/operator/persistent/physical_copy_to_file.cpp分区写出缓冲、src/include/duckdb/main/client_config.hppstreaming_buffer_size提醒所有涉及导入性能与内存的结论均以当前仓库所 vendored 的 DuckDB 版本为准不同 DuckDB 版本的默认值与行为可能存在差异升级前请以对应版本的settings.hpp定义为准。赞分享数据库关系型数据库【免费下载链接】serverMariaDB server is a community developed fork of MySQL server. Started by core members of the original MySQL team, MariaDB actively works with outside developers to deliver the most featureful, stable, and sanely licensed open SQL server in the industry.项目地址https://gitcode.com/gh_mirrors/server1/server点击查看免费下载相关推荐MariaDB DuckDB 存储引擎安全模型解析run_in_duckdb() 函数与嵌入式 DuckDB 实例的权限边界MariaDB DuckDB 存储引擎安全模型解析 run_in_duckdb 函数与嵌入式 DuckDB 实例的权限边界 本文围绕 MariaDB 服务器中数据库关系型数据库MariaDB存储引擎开发完全指南从零打造自定义数据存储方案MariaDB存储引擎开发完全指南从零打造自定义数据存储方案 还在为特定业务场景找不到合适的存储引擎而烦恼MariaDB强大的可扩展性让你可以自定义存储引擎数据库关系型数据库Presto Memory Connector 完整指南纯内存存储引擎的配置、SQL 支持与限制详解Presto Memory Connector 完整指南纯内存存储引擎的配置、SQL 支持与限制详解 导读 Memory Connector 是 Presto大数据数据库后端上一篇搞定shadcn-vue复杂组件TypeScript类型体操实战指南下一篇终极免费文件清理工具Czkawka三步定位重复文件一次释放几十G空间创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
