You need to enable JavaScript to run this app.
导航
唯一键表冷存去重
最近更新时间:2025.06.13 09:58:43首次发布时间:2025.06.13 09:58:43
我的收藏
有用
有用
无用
无用

唯一键表支持冷存去重,支持删除冷存数据中的重复数据,提升存储空间利用率。本文介绍了如何启用唯一键表冷存去重功能以及如何配置相关内存参数,减少内存占用。

背景信息

在 ByteHouse 中,冷存数据存储在 S3 的同时,本地磁盘也会缓存远端的 unique_key.idx 索引文件,存储至 /remote_unique_key_index_cache/ 目录中(所有唯一键表共享),可避免去重时频繁读取 S3 索引文件带来额外的性能开销。本地磁盘空间充足的前提下,/remote_unique_key_index_cache/ 目录默认大小是 min(50 GiB,初始化容量大小为可用空间 * 0.25),如果存储目录达到存储上限,系统将触发 LRU(最近最少使用)淘汰机制。当远端 part(数据分片)转为非活跃状态并被清理后,该 part 在本地磁盘缓存的唯一键索引(unique key index)会通过唯一键表的后台清理线程异步删除。
为了实现更好的写冷存性能,唯一键表新生成的 part 都会生成在本地磁盘:主节点支持 write、merge、mutate 操作,备节点支持 fetch part 操作。满足 TTL 规则(按行设置过期时间)的 part 将通过后台 move 线程移动到 S3/HDFS 冷存储。
开启唯一键表冷存去重功能后,内存会短暂上升,这是因为系统在写入冷数据时需要对 S3 上的 parts 执行去重,由于 S3 上的 parts 可能未设置磁盘唯一索引(disk unique index),需先将 parts 数据读取至内存并构造内存唯一索引(memory unique index)。ByteHouse 支持通过内存唯一索引缓存机制(memory unique index cache)管理内存占用,通过后台线程及时淘汰、释放掉超过内存阈值的内存索引,提升全局内存限制的能力。如需限制内存唯一索引的内存占用,您可参考memory_unique_index_max_bytes设置参数阈值,启用后需要等待一段时间(分钟级)才会生效,可能短暂超过设定的内存阈值。

说明

Part 的内存索引采用 lazy 加载模式,在去重时被用到才会加载,新写入的 part 的内存索引并不会及时放在内存中,因此可能查出来内存索引总占用量为 0。

启用唯一键表冷存去重

语法

执行以下命令,开启唯一键表和冷存上 part 去重功能。启用后,仅支持对增量 part(即新写入的 part)去重。

alter table {db}.{table} on cluster {xxx} modify setting enable_unique_dedup_with_remote_disk = true;

参数说明

参数

默认值

含义

enable_unique_dedup_with_remote_disk

false

表级粒度,设置为 true 后,允许新的写入和远端的 parts 去重,保证唯一性。

注意

如果希望对所有表都生效,请参考修改配置参数,将参数添加到 config.xml 下的 <merge_tree></merge_tee> 中。调整参数后,需重启服务器生效。

使用示例

以下操作以 S3 上的某张唯一键表为例。

  1. 开启冷存去重功能。请使用实际的库、表、集群名称替换以下命令中的变量。

    alter table {db}.{table} on cluster {xxx} modify setting enable_unique_dedup_with_remote_disk = true;
    
  2. 开启冷存 merge 开关,否则当 S3 parts 过多时,将影响写入去重性能。

    ALTER TABLE {db}.{table} on cluster {xxx} modify setting skip_merge_for_unique_data_in_remote_disk = false; 
    
  3. 查看节点所有唯一键表的内存使用量。更多内存查询命令请参见memory_unique_index_max_bytes
    您可根据命令输出结果查看内存使用情况,如果内存使用量上升,您可按照步骤 4 的操作降低内存占用。

    select formatReadableSize(sum(unique_index_bytes_in_memory))
    from system.parts
    where engine = 'HaUniqueMergeTree'; 
    
  4. (可选)若您的内存使用上升较多并期望降低内存,您可通过以下两种方法降低内存占用:

    方法

    操作说明

    调整 memory_unique_index_max_bytes 参数

    memory_unique_index_max_bytes 参数定义了所有唯一键表的内存唯一索引的最大可用内存,默认值为最大可用内存 * 0.3**,**单位:字节。
    您可参考修改配置参数,在 config.xml 中配置 memory_unique_index_max_bytes 参数。下图示例将 memory_unique_index_max_bytes 配置为 30MiB(30 * 1024 * 1024 = 31457280)。调整参数后,需重启服务器生效。
    Image
    更多关于该参数的说明,请参考 memory_unique_index_max_bytes 章节。

    物化索引

    执行物化索引命令,将某个分区的唯一键表的 memory unique index 转化为 disk unique index。该 mutation 操作比较重,建议按分区级别进行物化 index,避免一次性对过多 parts 重写,占满本地磁盘。

    ALTER TABLE {} on cluster {} MATERIALIZE UNIQUE INDEX IN PARTITION '{}';
    

    更多关于物化索引的说明,请参考 materialize unique index 章节。

相关参数说明

查询磁盘唯一索引缓存

您可使用以下命令查询磁盘索引缓存的大小和容量。该缓存用于存储 unique_key.idx 索引文件(按 part 粒度管理),支持 LRU 淘汰机制和全局内存限制。

SELECT
    metric,
    formatReadableSize(value)
FROM system.asynchronous_metrics
WHERE metric LIKE 'UniqueKeyIndex%Bytes'

Query id: 20528fa9-5d92-4961-90ae-1c221e8d8cb7

┌─metric────────────────┬─formatReadableSize(value)─┐
│ UniqueKeyIndexMetaCacheBytes     │ 0.00 B                      │
│ UniqueKeyIndexBlockCapacityBytes │ 20.00 GiB                   │
│ UniqueKeyIndexMetaCapacityBytes  │ 10.00 GiB                   │
│ UniqueKeyIndexBlockCacheBytes    │ 0.00 B                      │
└────────────────────┴──────────────────┘

memory_unique_index_max_bytes

内存唯一索引是内存表,用于存储 unique index 的数据。memory_unique_index_max_bytes 参数可用于限制内存唯一索引的最大可用内存,避免内存溢出(OOM)。

  • 查看内存唯一索引最大容量:

    -- 查询 Memory unique index 最大容量:
    SELECT
        metric,
        formatReadableSize(value)
    FROM system.asynchronous_metrics
    WHERE metric LIKE 'MemoryUniqueKeyIndex%'
    
  • 查看内存唯一索引占用内存情况:

    -- 获取节点所有 unique 表的 memory index 内存使用量
    select formatReadableSize(sum(unique_index_bytes_in_memory))
    from system.parts
    where engine = 'HaUniqueMergeTree';
    
    -- 获取节点 memory index 内存使用量 Top 10 的 unique 表
    select database || '.' || table as db_tbl, 
    formatReadableSize(sum(unique_index_bytes_in_memory)) 
    from system.parts where engine = 'HaUniqueMergeTree' and active 
    group by db_tbl order by sum(unique_index_bytes_in_memory) desc limit 10;
    
    -- 查询某张表 memory unique index 总计内存
    SELECT formatReadableSize(sum(unique_index_bytes_in_memory))
    FROM system.parts
    WHERE engine = 'HaUniqueMergeTree' and table = '';
    

materialize unique index

使用内存唯一索引将指定 parts 通过变更(mutation)转化为使用本地磁盘唯一索引的 parts,以降低内存。该命令也称物化索引,这里物化的含义是指将内存态的 index 转化为磁盘态的 index。您可在主、备节点上执行该命令,备节点接收到命令后会转发给主节点。示例如下:

ALTER TABLE materialize_unique_index_{table.table_name} [on cluster {}] MATERIALIZE UNIQUE INDEX;

示例 1:全表级设置

ALTER TABLE materialize_unique_index_tests.test_table1 [on cluster {}] MATERIALIZE UNIQUE INDEX;

示例 2:分区级设置

ALTER TABLE materialize_unique_index_tests.test_table1 on cluster {} MATERIALIZE UNIQUE INDEX IN PARTITION '2024-10-02';