批量数据库变更
NineData 批量数据库变更支持对数据库结构或数据进行统一的修改和更新操作,可同时覆盖多个数据源、库、表,确保在分布式环境下的数据源能够在同一时间内完成相同变更。
背景信息
在业务不断发展的过程中,企业面临着多套环境和多地区的部署情况,在单个业务数据量庞大的场景下,企业可能采用分库分表的方式来满足查询和存储需求。随着业务的迭代,需要对同一套分库分表进行结构或数据的修改。传统的部署方式是按照数据库数量逐个进行任务,但这容易导致变更遗漏、变更不一致、研发和审批者反复工作等问题。
在这种背景下,企业迫切需要一种高效的批量数据变更方式,能够通过一次提交覆盖多套环境、多个地域、一个分表的所有分片,并确保变更的一致性。这对于企业在规模扩大后的管理问题以及运维人员的挑战是比较大的。解决这个问题需要一种创新的变更管理方案,以提高效率、降低风险,并更好地适应不断变化的业务环境。
前提条件
创建库分组
该步骤用于将多个需要进行批量变更的数据库分到同一个分组中,以便后续进行批量变更操作。一个变更 SQL 语句将在同个库分组中的所有库中挨个执行。
登录 NineData 控制台。
在左侧导航栏,单击>。
单击页签,单击页面中的>目标数据源。
根据下表配置表单,并单击。
参数 说明 输入库分组的名称,仅支持英文字符、数字和下划线,以英文字符开头。为了方便后续使用和管理,请尽量使用有意义的名称。 (可选) 输入针对该库分组的业务描述。 选择您的业务所属的环境名称,您将根据该环境筛选数据源。 单击,选择需要加入到分组中的数据源,支持多选、全选和反选操作,同时支持输入数据源名称进行搜索,单击后,还需要选择具体的库,根据数据源不同,可能还需要选择具体的 Schema。
库分组创建完毕后,默认使用所属环境中配置的 SQL 开发规范以及审批流程,您可以根据业务需求进行更改,更多信息,请参见修改库分组的 SQL 开发规范和审批流程。
创建表分组
相较于库分组,表分组用于更细粒度的批量数据变更,一个变更 SQL 语句将在同个表分组中的所有表中挨个执行。如需创建表分组,必须已经创建库分组。
登录 NineData 控制台。
在左侧导航栏,单击>。
单击页签,单击目标库分组名称,或单击该库分组右侧列的>。
在页面,单击。
根据下表配置表单,并单击。
参数 说明 输入表分组的名称,仅支持英文字符、数字和下划线,以英文字符开头。为了方便后续使用和管理,请尽量使用有意义的名称。 支持和两种。 选择时需要配置,输入表达式并单击后,系统将根据您提供的表达式,自动遍历并提取目标库中所有符合要求的表。 (可选) 选择时可配置,根据您应用中配置的路由算法配置该参数,可以根据路由快速解析需要访问的表,提高查询效率。 选择时需要配置,单击,选择需要加入到分组中的数据源,支持多选、全选和反选操作,同时支持输入数据源名称进行搜索,单击后,还需要选择具体的库和表,根据数据源不同,可能还需要选择具体的 Schema。
修改库分组的 SQL 开发规范和审批流程
用户在目标库分组中执行 SQL 进行批量变更时,该库分组的 SQL 开发规范将作为自动审核的依据对该 SQL 进行审核,同时,审批流程用于管理变更请求的生命周期,涉及到是否要求人工进行审批,以及配置多层审批等,以增强变更的安全性。
登录 NineData 控制台。
在左侧导航栏,单击>。
在页面,单击 页签,然后单击目标库分组右侧列的。
在窗口中,将规范流程下左侧的勾去掉,然后选择您需要的规范和流程,单击。
提示重新选中即可恢复成默认配置。
执行批量变更
实际对库分组执行批量变更的操作是通过 SQL 任务执行的,SQL 任务是将数据变更操作流程化、自动化的机制,还支持 SQL 的定时执行。基于配置的 SQL 开发规范,SQL 任务会自动审核目标变更语句,并自动拦截不符合规范的 SQL 语句,以确保变更的安全可控。
登录NineData 控制台。
在左侧导航栏,单击 >。
在 页面,单击页面中的,然后根据下表配置表单。
参数 说明 输入 SQL 任务的名称,该名称通常包含了 SQL 语句的执行目的,为减少沟通成本,请尽量使用有意义的名称。最多支持 64 个字符。 单击左侧下拉框,选择,然后单击右侧下拉框,选择目标需要变更的库分组。 当前 SQL 任务审批通过后的 SQL 语句执行人。
说明:列表中的可选项取决于如下两种情况:输入此次变更预计会影响多少行数据。在 SQL 任务的阶段,系统会校验 SQL 实际的影响行数和输入的预估行数是否有出入,如果不一样则会进行提示。 (可选) 针对当前 SQL 任务未尽事项的说明,例如执行任务的原因,期望执行时间等。 输入需要执行的 SQL 语句或上传包含 SQL 语句的文件。 - :直接在文本框中输入需要执行的 SQL 语句。
- :单击,选择并上传包含需执行 SQL 语句的文件。
说明:上传完成后,把鼠标移动到文件名处,可在文件名右侧选择(预览文件)或(删除文件)。
(可选) 针对需要对变更提供回滚预案的企业,此处输入的回滚 SQL 会记录在当前 SQL 任务中,但在当前 SQL 任务的全生命周期中不会产生任何影响,仅用于合规操作。 单击,系统会提前对 SQL 语句进行检查,排除语法错误等无法执行的情况。如果 SQL 语句有问题,会在下方出现提示,您可以在中展开任务查看具体的错误信息,方便您进行定位和修改。
单击,进入页面。系统将基于当前库分组关联的 SQL 开发规范对 SQL 语句进行预审,会有如下几个结果:
- 预审通过:根据审批流程的配置情况,任务状态会更改为或,如果是前者,请继续下一步,如果是后者,单击页面右上角的即可,本流程结束。
- 预审不通过:任务状态会更改为,您可以单击页面右上角的再次预审,也可以撤回 SQL 任务重新编辑并提交。
提示预审出来的问题,包含了、、、四个类别:
- :命中了 SQL 开发规范中规范问题。
- :命中了 SQL 开发规范中规范问题。
- :请重点关注,由系统自动检测出来的语法问题,虽然不阻断 SQL 任务流程,但是该 SQL 可能会执行失败,请检查库、表存在性及语法正确性。
- :命中了管理员在 SQL 开发规范中配置的如下两个规则,SQL 任务流程被阻断。
- :用于允许或禁用结构变更类型的 SQL 语法。
- :用于允许或禁用数据变更类型的 SQL 语法。
在页面右上角单击,在弹出的窗口中选择流程审批人员,单击。
提示根据审批流程配置的不同,此处需要选择的审批人员数量不同,请根据实际情况选择。
任务状态变更为,在审批通过之前,您可以进行如下操作。
- :撤回 SQL 任务。更多信息,请参见撤回 SQL 任务。
- :更改该 SQL 任务的审批人。
审批通过后,任务状态会更改为,单击页面右上角的,执行批量数据库变更。
附录:路由算法说明
路由算法的主要功能是自动完成数据路由,路由算法配置中,目标分库与分表通过以下表达式定义:
'<dbname_expression>''.<tablename_expression>'
<dbname_expression>
:分库名表达式,格式:'<dbname_prefix>'
+(<expression>)
+'<dbname_suffix>'
。'<dbname_prefix>'
:分库名前缀,例如'logical_db_0'
。(<expression>)
:分库名组合的动态数字部分,例如#user_id#%4
。假设user_id
列的值为1
,除以4
取余的结果就是1
,则结合分库名前缀即为logical_db_01
。NineData 规定在路由算法中的字段名前后使用#
进行标识,方便解析。'<dbname_suffix>'
:分库名后缀,根据实际情况配置,可为空。例如'_bak'
。则组合后的分库名为logical_db_01_bak
。
示例:假设通过
#user_id#%4
计算的结果为 0,则路由到对应分库的<dbname_expression>
写法如下。需路由的分库名称 <dbname_expression>
写法logical_db_01 'logical_db_0'+(#user_id#%4+1) logical_db_01_bak 'logical_db_0'+(#user_id#%4+1)+'_bak' logical_db_00 'logical_db_0'+(#user_id#%4) logical_db_1 'logicaldb'+(#user_id#%4+1) .<tablename_expression>
:分表名表达式,格式:'.<tablename_prefix>'
+(<expression>)
+'<tablename_suffix>'
。'.<tablename_prefix>'
:分表名前缀,例如'.test_time_0'
。点(.)代表该表名隶属于前面的库。(<expression>)
:分表名组合的动态数字部分,例如#user_id#%4
。假设user_id
列的值为1
,除以4
取余的结果就是1
,则结合分表名前缀即为test_time_01
。NineData 规定在路由算法中的字段名前后使用#
进行标识,方便解析。'<tablename_suffix>'
:分库名后缀,根据实际情况配置,可为空。例如'_bak'
。则组合后的分表名为.test_time_01_bak
。
示例:假设通过
#user_id#%4
计算的结果为 0,则路由到对应分表的.<tablename_expression>
写法如下。需路由的分表名称 <dbname_expression>
写法test_time_01 '.test_time_0'+(#user_id#%4+1) test_time_01_bak '.test_time_0'+(#user_id#%4+1)+'_bak' test_time_00 '.test_time_0'+(#user_id#%4) test_time_1 '.testtime'+(#user_id#%4+1)
结合上述的例子,如果 user_id 列的值为 0,那下述路由算法将路由至 logical_db_01 分库下的 test_time_01 分表。
'logical_db_0'+(#user_id#%4+1)'.test_time_0'+(#user_id#%4+1)