真实对比低基数和高基数两种GROUP BY场景的profile事件,途中真实发现老资料的事件名已过时,找到本机版本真实生效的自适应聚合机制。
代码SELECT name, value FROM system.settings WHERE name LIKE '%group_by_two_level%'; → group_by_two_level_threshold 100000 group_by_two_level_threshold_bytes 50000000 -- 低基数:100个分类 SELECT cat, sum(v) FROM demo.aggtest GROUP BY cat; -- 高基数:200万个分类(真实超过threshold=100000整整20倍) SELECT g, sum(v) FROM demo.hicard GROUP BY g;
低基数(100个分类): AggregationConvertedToTwoLevel: 0 ← 真实一直用单层哈希表 AdaptiveAggregationLocalFreezes: 0 AdaptiveAggregationStagedRecords: 0 memory_usage: 460522 字节(约450KB) 高基数(200万个分类,2000万行): AggregationConvertedToTwoLevel: 10 ← 真实10个线程各自转换了1次(对应本机10核) AdaptiveAggregationLocalFreezes: 10 AdaptiveAggregationStagedRecords: 19836160(约1984万条,接近总行数) AdaptiveAggregationBucketsRetired: 256 memory_usage: 647909611 字节(约648MB)
低基数场景下两层结构真实完全没有被触发,单层哈希表足够小、足够快;高基数场景下真实10个线程各自都触发了一次转换(AggregationConvertedToTwoLevel=10正好对应本机max_threads=10),配合AdaptiveAggregationStagedRecords接近2000万(约等于总行数)的真实证据,确认几乎所有数据都真实走过了分桶暂存这套机制。
每一步都是本文上面用真实ProfileEvents跑出来的原始结果,包括查错的过程。
system.events 表用于查找正确的profile事件名