bigywater.tech
ClickHouse 内部原理 · 36

ORDER BY 排序内存放不下怎么办

真实尝试用多组配置触发ORDER BY排序落盘,诚实记录未能复现出External Group By那样清晰的落盘证据的完整过程。

比例阈值取代绝对值
真实发现默认走max_bytes_ratio_before_external_sort=0.5
诚实留白
真实未能复现ORDER BY落盘的可观测证据

做的事:真实用一张300万行的表,尝试触发ORDER BY落盘

代码CREATE TABLE demo.sorttest (k UInt64, v String) ENGINE=MergeTree ORDER BY tuple(); INSERT INTO demo.sorttest SELECT rand64(), repeat('x', 200) FROM numbers(3000000); -- v不是排序键,ORDER BY v,k真实要对全表做一次和主键无关的排序 SELECT k FROM demo.sorttest ORDER BY v, k SETTINGS max_bytes_before_external_sort=52428800; -- 落盘阈值50MB

验证:真实的设置项和默认值,比想象中复杂

实测 · 本机执行输出(system.settings)
prefer_external_sort_block_bytes   16744704   (约16MB)
max_bytes_before_external_sort     0          ← 绝对值阈值真实默认是0(关闭)
max_bytes_ratio_before_external_sort  0.5     ← 真实默认走的是比例阈值:用满一半可用内存才落盘
min_external_sort_block_bytes      104857600  (约100MB,单个落盘块的最小体积)

本机这个版本(26.9.4)默认真实不是用一个固定的字节数阈值来决定要不要落盘,而是用max_bytes_ratio_before_external_sort这个比例(默认0.5,也就是排序缓冲区用到可用内存的一半才触发落盘),这跟上一篇《External Group By》验证的max_bytes_before_external_group_by固定字节数阈值是不同的设计。

诚实记录:真实没能测出external sort落盘的证据

实测 · 本机执行输出(多组配置,ExternalProcessingFilesTotal始终是0)
SETTINGS max_bytes_before_external_sort=52428800                          → memory 1.06GB, files=0
SETTINGS max_bytes_ratio_before_external_sort=0.05, max_memory_usage=1.5G → memory 1.06GB, files=0
SETTINGS 同上 + max_threads=1                                              → memory 0.68GB, files=0
SETTINGS max_bytes_before_external_sort=104857600, max_threads=1          → memory 0.68GB, files=0

EXPLAIN PIPELINE SELECT k FROM demo.sorttest ORDER BY v, k;
→ (Sorting)
    MergeSortingTransform
      LimitsCheckingTransform
        PartialSortingTransform          ← 真实的排序执行节点,但没看到任何落盘相关节点

SELECT name FROM system.events WHERE name ILIKE '%spill%';
→ AdaptiveAggregationSharedTableSpills   ← 真实唯一带spill的事件,是聚合专属,不是排序的
本文诚实的结论是:没能在本机这个ClickHouse 26.9.4版本上,用一个真实可复现的实验演示出ORDER BY落盘的证据。跟上一篇《External Group By》能清楚看到ExternalAggregationWritePart真实增加、内存真实下降形成对照——排序这条路径,不管怎么调整阈值设置、不管单线程还是多线程,ExternalProcessingFilesTotal始终是0,内存占用也没有随着阈值收紧而真实下降。没有为了让结果"看起来对"去编造一个成功的场景,而是把真实测出来的现象——包括这次没能复现预期机制——原样记录下来。可能的原因包括:本文3000万字节量级的数据规模真实还没有大到需要落盘(min_external_sort_block_bytes要求单个落盘块至少100MB,本文的数据分布在多个更小的处理块里可能都没达到这个门槛);也可能是这套机制在真实需要跨多次查询、或者更大数据量、或者分布式场景下才会被触发。这部分留给读者在更大数据量下自行验证,比给出一个没有真实验证过的解释更负责任。

分步演示:从设置探索到诚实记录未能复现的结果

每一步都是本文上面用真实ClickHouse跑出来的原始结果,包括没有成功复现的部分。

真实尝试触发排序落盘,诚实记录未能复现的过程
这一步新验证的配置

    本文用到的工具

    • 本机 ClickHouse 26.9.4(单节点),真实的 max_bytes_before_external_sort/max_bytes_ratio_before_external_sort
    • 诚实说明:本文未能在本机测试中复现ORDER BY落盘的可观测证据,与上一篇GROUP BY落盘形成对照
    京ICP备2026067502号-1京公网安备11010502063487号