在 OceanBase 数据库 V3.x 版本,对大表创建索引会使用较多的系统资源,可能对磁盘空间、CPU 使用造成很大影响,也可能会碰到 OceanBase 数据库 的某些限制或者已知问题,需要提前考虑避免。本文基于实践经验,对大表创建索引的注意事项进行说明。
适用版本
OceanBase 数据库 V3.x 版本。
超时时间设置
对大表创建全局索引是一个非常耗时的过程,需要调整超时时间,避免因为超时而失败。
alter system set global_index_build_single_replica_timeout = '168h';
如果使用 ODC 连接数据库创建索引,也需要调大 ODC 的任务超时时间为 168h。
磁盘空间
由于 V3.x 版本全局索引是整张表数据全部构建,而局部索引是按照一批分区构建。所以全局索引占用的临时空间量跟整张表的数据量有关,而局部索引跟当时同时构建的分区的数据量总和有关。
全局索引表
对于全局索引表,临时空间的估算有两种方式。
如果方便查询索引表每一列的平均长度,可以加所有索引列的平均长度加起来作为平均行长,再乘以主表的行数 * 5 。查询索引列的平均列长
select sum(length(c1)) / count(1) from t1;。如果不方便查询索引表每一列的平均长度,则建议用索引表所有字段的长度/主表的字段总长度进行大致的估算,最终再乘以主表的压缩后的数据量 * 数据压缩比,得到临时空间大小,其中数据压缩比在3.X上查不到,一般采用经验值4。主表数据量的查询方式
select sum(data_size) from __all_virtual_meta_table where table_id =xxx and role = 1;。
局部索引表
局部索引表跟正在构建的分区数的数据量总和有关,通常单分区能占满所有建索引线程,一般只需要考虑最大的分区的磁盘空间使用量,对于单个分区,也可以采用类似于全局索引估算空间的方式。
注意:
- 在计算好临时空间后,还需要考虑每台 OBServer 会默认预留 10% 的空间给其他任务。
- 在公有云上,可能有磁盘自动扩容能力,目前的步长 50G。由于建索引的写入速度很快,可能扩容的速度跟不上写入的速度,有可能还会碰到磁盘空间不足,建议先预估好空间一次性扩好。
关闭合并
为了避免因保留快照点带来的主表空间放大问题,建议关掉合并。
minor_freeze_times参数调大足够大,比如 500。major_freeze_duty_time配置成 disable。
CPU
建索引的线程数 = 系统租户的 parallel_servers_target * 2,为了避免对业务的影响,有两种方式。
建索引的机器预留足够多的CPU资源给业务,例如:(
parallel_servers_target可以配置成物理 CPU 的个数 - 业务用到的峰值CPU数) / 4,也就是在剩余的CPU资源中,一半给建索引。建索引的任务开启后,将主切到其他的副本。具体的可以观察
__all_virtual_sys_task_status表中task_type= 'create index' 类型任务所在的机器,将业务流量从这些机器上切走。select svr_ip,count(1) from __all_virtual_sys_task_status where comment like 'build index task%' group by svr_ip;表
__all_virtual_sys_task_status中建索引任务执行到“job=3”阶段,即为排序阶段。
注意:在 OceanBase 数据库 V3.x 版本,全局索引的构建任务最大的并行度是 100。
内存
索引创建过程中会有数据的排序操作,需要调整好 ob_sql_work_area_percentage 参数,可以按以下公式来保守估计排序所需的内存资源。
ob_sql_work_area_percentage * 租户内存大小 = 主表分区数 * 索引表分区数 * 16M
同时,创建索引任务的内存使用与其并行线程数有关,其内存计算根据索引类型的不同而不同。
全局索引表
分区表上的全局索引构建任务,其内存使用与分区数量有关,可以按以下公式来计算任务内存使用。
任务的内存量 = 主表分区数 * 索引表分区数 * 8M
局部索引表
局部索引的构建任务,其内存估算公式为:
任务的内存量 = 线程数 * 128M
局部索引构建的内存来源为 500 租户,不需要调整参数。
IO 资源
V3.x 版本会根据用户 RT 的变化自动的限制建索引的 IO,这块可以不用做特殊配置。