Redshift UNLOAD异常:SELECT DISTINCT生成的GZIP文件为SELECT *的三倍
我之前帮同事排查过几乎一模一样的问题,其实这个现象的核心原因和数据重复度对GZIP压缩效率的影响直接相关,再结合Redshift UNLOAD的并行机制,就会出现你看到的“去重后压缩文件反而更大”的情况,具体拆解一下:
GZIP压缩的核心逻辑:重复度越高,压缩率越好
GZIP基于DEFLATE算法工作,它的压缩效率高度依赖数据中的重复字节序列。当你用SELECT *卸载时,原始数据里有大量完全重复的行,GZIP会把这些重复内容用更短的标记替代,压缩后的体积会非常小。但SELECT DISTINCT之后,所有重复行都被剔除了,每行的内容都是唯一的,GZIP能找到的重复模式大幅减少,自然压缩率暴跌,最终文件体积反而更大——这是最关键的原因。并行UNLOAD的数据分布放大了这个差异
你开启了PARALLEL TRUE,Redshift会启动多个并行进程处理UNLOAD任务。执行DISTINCT时,Redshift需要先对全表数据做排序去重,这个过程会改变数据在节点间的分布:原本同一节点上可能堆积着大量重复数据,排序后数据会被重新打散到不同节点,每个并行进程处理的数据重复度更低,进一步降低了压缩效率。而SELECT *时,数据基本按原始分布处理,每个进程内的重复数据多,压缩效果自然更好。多字段组合的去重让数据“独特性”更强
你要卸载的是29个字段的组合,去重后每行的字段组合都是唯一的,这意味着每行的字节序列差异会非常大,GZIP很难找到可批量压缩的重复块。相反,未去重的行很多是完全一致的,压缩时只需要存储一次完整行内容,剩下的重复行只用引用标记即可,体积自然小很多。
几个验证建议
- 先统计
SELECT COUNT(*)和SELECT COUNT(DISTINCT <29 fields>)的结果,如果重复率很高(比如去重后行数只有原来的1/10甚至更少),那这个体积差异就完全合理; - 试试把
PARALLEL改成FALSE,生成单个压缩文件,看看体积变化——这样能排除并行数据分布的影响,更直观验证重复度对压缩的作用; - 可以尝试换用SNAPPY压缩(Redshift UNLOAD支持),它的压缩逻辑更侧重速度而非极致压缩率,去重后的体积差异可能会比GZIP小一些,但核心还是数据重复度的问题。
内容的提问来源于stack exchange,提问作者EricBlair1984

