真实开启external_group_by落盘阈值,验证同一条GROUP BY的内存占用真实降低多少,以及内存预算给得不够时会在哪个阶段真实失败。
代码-- 同一张3000万行、k列全部唯一的表(上一篇验证过默认要用约1.02GB内存) SELECT k, count() FROM demo.bigcard GROUP BY k SETTINGS max_bytes_before_external_group_by=52428800; -- 落盘阈值50MB,不额外限制max_memory_usage
开启external_group_by(阈值50MB): memory_usage: 290058897 字节(约290MB,比上一篇不开时的1.02GB少了约72%) query_duration_ms: 879 ExternalAggregationWritePart: 60 ← 真实写出60个临时落盘的part ExternalAggregationCompressedBytes: 143254990 ← 真实压缩后向磁盘写了约143MB
开启max_bytes_before_external_group_by之后,GROUP BY真实的执行方式变成了:内存里的哈希表一旦超过这个阈值(本文设的50MB),就先把当前已经聚合出来的部分结果真实压缩后写成一个临时文件(本文真实产生了60个这样的临时part),清空内存继续处理后续数据;等所有数据都处理完,再把这60个临时文件真实读回来做一次最终的归并聚合,得到正确的完整结果。整个过程用峰值内存从约1.02GB压到了约290MB。
SETTINGS max_bytes_before_external_group_by=52428800, max_memory_usage=150000000 → Query memory limit exceeded: would use 145.15 MiB (attempt to allocate chunk of 4.11 MiB), maximum: 143.05 MiB: While executing AggregatingTransform. (MEMORY_LIMIT_EXCEEDED) SETTINGS max_bytes_before_external_group_by=52428800, max_memory_usage=200000000 → Query memory limit exceeded: would use 191.92 MiB (attempt to allocate chunk of 4.00 MiB), maximum: 190.73 MiB: While executing SourceFromNativeStream. (MEMORY_LIMIT_EXCEEDED) ← 注意:这次是在"读回临时文件"阶段失败的
每一步都是本文上面用真实external_group_by跑出来的原始结果,包括没配置好导致的失败。
max_bytes_before_external_group_byExternalAggregationWritePart/ExternalAggregationCompressedBytes ProfileEvents