HashJoin内存不足时触发溢出机制,将大表按哈希值分片写入磁盘,逐片加载哈希表与小表匹配;分区数由哈希桶数或数据量预估决定,确保单分区可载入内存,哈希函数需保持一致性。

HashJoin 在内存不足时会触发溢出机制,核心是将大表分片写入磁盘,再逐片加载哈希表与小表匹配,避免 OOM。
溢出触发条件与分区逻辑
数据库(如 PostgreSQL、Spark SQL)通常在构建哈希表阶段检测内存使用。当哈希表大小超过 work_mem(PostgreSQL)或 spark.sql.autoBroadcastJoinThreshold 等阈值时,引擎自动启用溢出(spill-to-disk)。此时大表(通常是右表)被按哈希值分成多个分区(partition),每个分区独立写入临时文件。
- 分区数一般由哈希桶数量或预估数据量决定,目标是让单个分区能完整装入内存
- 哈希函数需具备一致性,确保相同连接键始终落入同一分区
- 分区文件通常以 spill_001.tmp、spill_002.tmp 命名,存于 temp_directory 指定路径
两阶段执行:Build + Probe with Spill
溢出后 HashJoin 不再单次完成,而是拆为多轮 Build-Probe 循环:
使用模板与程序分离的方式构建,依靠专门设计的数据库操作类实现数据库存取,具有专有错误处理模块,通过 Email 实时报告数据库错误,除具有满足购物需要的全部功能外,成新商城购物系统还对购物系统体系做了丰富的扩展,全新设计的搜索功能,自定义成新商城购物系统代码功能代码已经全面优化,杜绝SQL注入漏洞前台测试用户名:admin密码:admin888后台管理员名:admin密码:admin888
- 第一轮:读取大表第一个分区,构建内存哈希表;扫描整个小表,匹配该分区的键
- 后续轮次:依次加载其余大表分区,重复构建哈希表 + 扫描小表(注意:小表可能被缓存或重复读取)
- 部分优化器支持“小表分片”(如 Adaptive Query Processing),对小表也分区,减少重复扫描
常见问题与调优建议
溢出虽保稳定,但显著拖慢性能。定位和缓解需关注三点:
- 查执行计划:PostgreSQL 中看 Hash Cond 下是否出现 Buckets: xxx (originally yyy), Batches: zzz (originally www) —— Batch 数 > 1 即已溢出
- 增大内存参数:临时提高 work_mem(会话级)或 hash_mem_multiplier(某些引擎),但需权衡并发数
- 优化数据分布:连接键存在倾斜时,大量数据挤进少数分区,加剧溢出。可加随机前缀打散(salting),或改用 Sort-Merge Join









