建议优先使用 ByteHouse 企业版的 SQL 诊断功能定位到 CPU 占用高的 SQL,SQL 诊断功能详情请参见SQL 诊断。然后根据以下建议尝试优化。
该思路同样适用于内存、IO 水位高的场景。当业务流量上涨时可优先通过垂直扩容缓解资源压力,垂直扩容操作详情请参见垂直变配。
WHERE 中包含分区键的过滤条件。WHERE 子句的列上使用非单调函数,这可能导致索引和分区裁剪失效。推荐:在值上进行计算
WHERE event_time >= '2025-08-01 00:00:00' AND event_time < '2025-09-01 00:00:00';
反模式:在列上使用函数
WHERE toYYYYMM(event_time) > 202508;
使用值过滤条件,在分区过滤基础上引擎可以进一步通过 Part 分区键上的 minmax 信息,裁剪掉不必要的 Part。
JOIN 子句的左侧,小表放在右侧,通常引擎会自动 reorder。JOIN 的表进行过滤和聚合,减少 JOIN 的数据量。合理选择分区键(Partition Key)
分区键是 ByteHouse 中最重要、最有效的剪枝工具。通过在 WHERE 子句中指定分区键的过滤条件,ByteHouse 可以仅扫描相关的分区,跳过大量无关数据。
选择原则:
dt, event_date)。-- 创建一个按天分区的事件表 CREATE TABLE events ( event_id String, user_id UInt64, event_time DateTime, -- ... 其他列 ) ENGINE = CNCHMergeTree PARTITION BY toYYYYMMDD(event_time) -- 使用日期作为分区键 ORDER BY (user_id, event_time);
排序键(Order Key)与数据分布
排序键决定了在每个分区内部,数据是如何物理排序存储的。这种有序性带来了两大好处:
WHERE 条件的列放在排序键的最前面。country,gender)放在基数较高的列(如 user_id)前面,可以提升压缩效果。数据类型选择
选择最紧凑、最合适的数据类型,不仅可以节省存储空间,还能提升计算效率。
UInt 系列代替 Int(如果无负数),并选择能容纳数据范围的最小类型,如用 UInt8 或 UInt16 代替 UInt64。LowCardinality(String) 或 Enum 类型,可以将其转换为字典编码存储,极大减少存储并加速过滤和聚合。****NULL:尽量为列定义 NOT NULL 属性,Nullable 列会带来额外的存储和计算开销。跳数索引是 ByteHouse 支持的一种查询加速功能。在处理大量数据时,查询性能可能会因为需要进行全列扫描来应用 WHERE 子句而下降。跳数索引通过让查询跳过那些确认不包含匹配值的数据块来解决这个问题。
创建索引时涉及四个主要参数:
语法示例
/* 索引名称: key_i_idx 索引表达式: key_i 类型: minmax 粒度: 1 */ INDEX key_i_idx key_i TYPE minmax GRANULARITY 1
max_size,用于设置每个块的值集大小。当 max_size 为 0 时,值集大小不受限制。它适用于每组颗粒中值聚集在一起的列。max_size 而为空,则索引不会被应用。tokenbf_v1:专为增强的布隆过滤器功能定制,适用于 String 和 FixedString 类型。它将输入表达式按非字母数字字符分割成字符序列。此索引可用于 LIKE、EQUALS、in 等操作,适合在非结构化日志中搜索少量特定值。其参数包括:
ngrambf_v1:功能与 tokenbf_v1 类似,但增加了一个额外参数,即要索引的 ngram 的大小。它对于没有单词间断的语言(如中文)的文本搜索很有用。bloom_filter([false_positive]):通用布隆过滤器,可通过 false_positive 参数(范围 0-1,默认 0.025)指定假阳性概率。支持多种数据类型,包括 Int*, UInt*, Float*, String, Array 等。建议开启高级诊断功能后,联系 ByteHouse 团队处理,高级诊断操作详情请参见高级诊断。
当集群开启冷存后,强烈建议不设置本地存储上限,并为每张表设置冷存移动的 TTL,避免因设置不当导致新写入的数据直接进入冷存储,进而影响整表的查询的性能。为表设置冷存移动 TTL 操作请参见通过 SQL 语句建表。
执行以下命令,定位占用空间多的表,并根据查询结果判断是调整 TTL 或扩容磁盘。TTL 用法详情请参见TTL,扩容磁盘操作详情请参见垂直变配。
SELECT database, table, formatReadableSize(sum(bytes_on_disk)) AS disk_bytes FROM system.parts WHERE active and disk_name='default' GROUP BY database, table ORDER BY sum(bytes_on_disk);
特殊情况:
若集群存储空间小(小于 500G)且表数量多(高于 2000 张),则可能存在表元信息占据过多磁盘空间的场景。此时,需要通过 XML 修改集群参数,找到 merge_tree 相关的部分,添加以下参数并重启集群,以释放多余的磁盘空间。修改集群参数操作详情请参见配置集群参数。
<merge_tree> <manifest_store_keep_log_file_num>1</manifest_store_keep_log_file_num> <merge_tree>