查询超出内存限制
聚合
max_bytes_before_external_group_by
和 max_bytes_before_external_sort。
前者已在这里进行了详细讨论。
简而言之,这可以确保当超过内存
阈值时,聚合操作可以“落盘”到磁盘。这必然会影响查询性能,但也
有助于避免查询发生 OOM。后者这个排序设置则有助于解决类似的
内存密集型排序问题。这在
Distributed 环境中特别重要,因为协调节点会接收来自各个分片的已排序响应。
在这种情况下,协调服务器可能需要对一个
大于其可用内存的数据集进行排序。借助 max_bytes_before_external_sort,
可以允许排序结果落盘到磁盘。对于用户在 GROUP BY 后使用带有 LIMIT 的 ORDER BY 的情况,
这一设置同样很有帮助,尤其是在 Distributed 查询中。
连接
JOIN 算法,这有助于
降低所需内存。默认情况下,连接使用 hash join,它在功能支持方面最完整,
而且通常也有最佳性能。该算法会将 JOIN 的右侧表加载到内存中的哈希
表中,然后用它来匹配左侧表。因此,为了尽量减少内存占用,
用户应将较小的表放在右侧。不过,这种方法在受内存限制的场景下
仍然存在局限。在这类情况下,可以通过 join_algorithm
设置启用 partial_merge
连接。作为 sort-merge algorithm 的一种变体,
它会先将右侧表按块排序,并为这些块创建 min-max index。
随后,它会按连接键对左侧表的部分数据进行排序,再与
右侧表执行连接。min-max index 用于跳过不需要的右侧表块。
这种方式会占用更少内存,但代价是性能有所下降。在这一思路基础上更进一步,
full_sorting_merge 算法允许在右侧数据非常大、
无法装入内存且无法执行 lookup 时进行 JOIN,例如右侧是一个复杂子查询。
在这种情况下,如果右侧和左侧数据都放不进内存,就会在磁盘上对两侧进行排序,
从而支持大表连接。
自 20.3 起,ClickHouse 已支持将 join_algorithm 设置为 auto。
这表示 ClickHouse 会采用自适应连接策略:优先使用 hash join
算法,直到超过内存限制,此时再尝试
partial_merge 算法。最后,关于连接,我们建议
读者了解 Distributed joins 的行为方式,以及如何尽量减少
其内存消耗。更多信息可参见此处。