通过并行 Truncate Table 提升大批量清空表的性能
在 OceanBase 历史上,把 DDL 操作作为用户低频且需要严格管控的行为来对待,但是随着数据库应用场景的不断增加,其中对 DDL 的性能挑战越来越多,尤其是以业务遇到的大量 Truncate Table 的场景最为明显。
OceanBase Truncate Table 性能瓶颈主要来自两个方面:
Schema 架构的事务串行导致的,其原因是要保证租户级 schema 版本和事务偏序一致。
Truncate Table 是通过 DDL 事务内原子的 DROP 和 CREATE TABLE 来实现,这一过程需要重建所有涉及的 schema 对象,包括 index、foreign key、audit、trigger 等,Table 对象越复杂,所需要重建的代价越大。
针对单路 Truncate Table,在 OceanBase 数据库 V4.1 及之后版本采用只修改分区的方式,由于不涉及 table id 的变化,可以尽可能复用 Schema 对象。
另外针对 Schema 架构串行执行的限制,基于更深入的性能分析,提出了使用 DDL 事务并行 + 串行提交的方式,在不打破 Schema 整体架构的基础上提供并行执行的能力。
1.新建 create_table.sh 文件,写入批量创建表的 shell 脚本
vim create_table.sh
#!/bin/sh
# 定义数据库连接参数
DB_HOST="127.0.0.1"
DB_USER="test@sys"
DB_NAME="testdb"
DB_POST="2881"
for t in $(seq 0 99)
do
{
for i in $(seq 1 10000)
do
index=$(($i%100))
if [ $index -eq $t ]
then
TABLE="table_$i"
obclient -h $DB_HOST -P$DB_POST -u $DB_USER -D$DB_NAME -e "CREATE TABLE $TABLE (c1 int, c2 int);"
if(($i%100 == 0))
then
echo $i "tables processed"
fi
fi
done
} &
done
wait
完成后,按 ESC 键,输入 :wq,按下回车键,保存退出.
2.新建 truncate_table.sh 文件用于存放批量执行 Truncate Table 的 shell 脚本
vim truncate_table.sh
#!/bin/bash
# 定义数据库连接参数
DB_HOST="127.0.0.1"
DB_USER="test@sys"
DB_NAME="testdb"
DB_POST="2881"
for t in $(seq 0 99)
do
{
for i in $(seq 1 10000)
do
index=$(($i%100))
if [ $index -eq $t ]
then
TABLE="table_$i"
obclient -h $DB_HOST -P$DB_POST -u $DB_USER -D$DB_NAME -e "TRUNCATE TABLE $TABLE"
if(($i%100 == 0))
then
echo $i "tables processed"
fi
fi
done
} &
done
wait
3.授权执行 shell 脚本
chmod u+x *.sh
4.执行创建表的 shell 脚本
time ./create_table.sh
5.执行批量 truncate table 的 shell 脚本。
time ./truncate_table.sh
根据上述案例,可以发现使用了 4 分钟左右(具体时间以实际为准),就完成了 10000 张表的 Truncate Table,大大提高了批量 Truncate Table 的效率
3.x 版本每次 truncate table 操作都要在 drop table 时对这些元信息执行删除操作,在 create table 时再对这些元信息执行写入操作,当 table 上的附属对象较多时,大量附属对象元信息的删除和写入会让truncate table 耗费大量的时间。
而 OceanBase 4.x 中 truncate table 的实现不再修改表的元数据信息,所以oceanbase._all_column、oceanbase._all_constraint 等系统表的数据都不会发生改变。数据的清除通过更换 tablet 来实现。oceanbase._all_table 表内会增加一列 tablet_id 表示一张表对应的 tablet,truncate table 时创建一个新的空 tablet,将新 tablet_id 写入 oceanbase._all_table 表替换之前的旧值,这样就完成了 truncate 表的操作,之后旧的 tablet 即可删除。
对于分区表,会在 oceanbase._all_part 表中记录每个分区对应的 tablet_id,truncate table 时将每个分区对应的 tablet 替换成新的空 tablet 即可。
熟悉 Oracle 的同学可以把 table_id 对应成 Oracle 的 object_id,把 tablet_id 对应成 Oracle 的data obiect_id,上述 OceanBase 4.x 版本 truncate table 的实现方式就和 Oracle 的实现逻辑是类似的了。




