统一查询分库分表
NineData 表分组查询功能支持您通过 SQL 窗口对多个分库分表进行统一查询,很大程度上简化了分库分表情况下,数据查询的复杂度,提高查询效率。
背景信息
在企业用户规模达到一定程度后,分库分表成为一种常见的数据库架构选择。在这种情况下,查询和维护数据需要高效的解决方案,以避免手动逐一查询、变更和汇总多个分库和分表的繁琐操作。
库分组变更功能的上线在一定程度上解决了分库分表的变更问题,并在很多企业中得到了很好的验证和使用。然而,对于分库分表的查询需求,企业希望能够像操作单表一样便捷,这种操作方式可以满足更多数据处理场景的需求。
前提条件
创建库分组
该步骤用于将多个需要进行查询的数据库分到同一个分组中,以便后续进行统一查询操作。一个查询 SQL 语句将在同个库分组中的所有库中执行。
登录 NineData 控制台。
在左侧导航栏,单击>。
单击页签,单击页面中的>目标数据源。
根据下表配置表单,并单击。
参数 说明 输入库分组的名称,仅支持英文字符、数字和下划线,以英文字符开头。为了方便后续使用和管理,请尽量使用有意义的名称。 (可选) 输入针对该库分组的业务描述。 选择您的业务所属的环境名称,您将根据该环境筛选数据源。 单击,添加数据源。 - :选择需要加入到分组中的数据源,支持多选、全选和反选操作,同时支持输入数据源名称进行搜索。
- :输入库表达式,系统将根据您提供的表达式,自动遍历并提取目标数据源中所有符合表达式的库。表达式的语法请参见本文附录。
库分组创建完毕后,默认使用所属环境中配置的 SQL 开发规范以及审批流程,您可以根据业务需求进行更改,更多信息,请参见修改库分组的 SQL 开发规范和审批流程。
创建表分组
相较于库分组,表分组用于更细粒度的分表配置,一个查询 SQL 语句将在同个表分组中的所有表中统一执行。如需创建表分组,必须已经创建库分组。
登录 NineData 控制台。
在左侧导航栏,单击>。
单击页签,单击目标库分组名称,或单击该库分组右侧列的>。
在页面,单击。
根据下表配置表单,并单击。
参数 说明 输入表分组的名称,仅支持英文字符、数字和下划线,以英文字符开头。为了方便后续使用和管理,请尽量使用有意义的名称。 支持和两种。 选择时需要配置,输入表达式并单击后,系统将根据您提供的表达式,自动遍历并提取目标库中所有符合要求的表。表达式的语法请参见本文附录。 (可选) 选择时可配置,根据您应用中配置的路由算法配置该参数,可以根据路由快速解析需要访问的表,提高查询效率。 选择时需要配置,单击,选择需要加入到分组中的数据源,支持多选、全选和反选操作,同时支持输入数据源名称进行搜索,单击后,还需要选择具体的库和表,根据数据源不同,可能还需要选择具体的 Schema。 提示如需通过快速路由至查询条件所在的表,实现以最快的速度获取查询结果,需要同时满足如下三个条件,如果不满足其中之一,则该查询将遍历所有分库分表进行查询。
- 表分组是通过表达式创建的,并非手动选择。
- 在上述表分组创建流程中正确配置了,且该算法必须和您应用中配置的路由算法一致。
- 查询 SQL 的 WHERE 条件中,该路由字段为等值查询条件。
修改库分组的 SQL 开发规范和审批流程
用户在对目标表分组进行 SQL 查询时,可能会存在使用不规范 SQL 语句的情况,例如慢 SQL 等,这将导致数据库的性能受到严重影响。为解决这个问题,您可以为目标库分组配置 SQL 开发规范,作为系统自动审核用户 SQL 的依据,在检测到用户 SQL 不符合规范时,将会自动进行拦截。
登录 NineData 控制台。
在左侧导航栏,单击>。
在页面,单击 页签,然后单击目标库分组右侧列的。
在窗口中,将规范流程下左侧的勾去掉,然后选择您需要的规范和流程,单击。
提示重新选中即可恢复成默认配置。
执行分库分表查询
实际对库表分组执行查询的操作是通过 SQL 窗口执行的,您可以在 SQL 窗口中直接通过 SQL 查询语句对表分组进行查询。
操作步骤
登录 NineData 控制台。
在左侧导航栏单击 >,随便选一个数据源进入。
提示如果之前登录过数据源且没有关闭,则会自动进入该数据源页面。
在页面左上角,单击当前数据源名称右侧的。在弹出的窗口中,单击下方左侧下拉框,选择,然后单击右侧下拉框,选择目标需要查询的库分组。
您现在可以通过 SQL 窗口对目标库分组进行 SQL 查询。关于 SQL 窗口的使用方法,请参见 SQL 窗口。
附录 1:分组表达式语法说明
NineData 支持通过表达式自动添加名称连续的库表到分组中,表达式的语法说明如下。
<dbname>
、<tablename>
:表示库名和表名。<prefix>
:表示库名或表名的前缀。<suffix>
:表示库名或表名的后缀。
<expression>
:具体的表达式,包含如下规则:<range>
:表示范围,用英文横杠(-)连接,例如1-9
。<steps>
:表示步长,和<range>
配合使用,语法为<range>:<steps>
,即从<range>
的起始位置到结束位置之间每隔多少个元素命中一次。例如0-8:2
,则命中0、2、4、6、8
。<enumeration>
:表示枚举数字,每个数字之间用英文逗号(,)分隔。例如1,3,5
。
<delimiter>
:库名和表名之间的分隔符,用英文点号(.)表示,表示从属关系,例如dbname.tablename
。
语法 | 说明 | 示例 |
---|---|---|
<prefix>[<range>] | <prefix> 为库名或表名前缀,<range> 为库名或表名后缀数字的范围,表示按照自然排序顺序添加对应的库或表。 | user_[0-9] :将名为 user_0、user_1、...、user_9 的 10 张表添加到表分组。 |
<prefix>[<range>:<steps>] | <prefix> 为库名或表名前缀,<range> 为库名或表名后缀数字的范围,<steps> 为步长,即从 <range> 的起始位置到结束位置之间每隔多少个元素拉取一次。 | user_[0-9:3] :将名为 user_0、user_3、user_6、user_9 的 4 张表添加到表分组。 |
<prefix>[<expression>]<suffix> | 通常用于库表名编号位于名称中间的情况。 | user_[0-1]_sample :将名为 user_0_sample、user_1_sample 的 2 张表添加到表分组。 |
<prefix>[<expression>][<expression>] | 用于库名或表名中有多个编号的情况。 | user_[0-2]_[0-2] :将名为 user_0_0、user_0_1、user_0_2、user_1_0、user_1_1、...、user_2_2 的 9 张表添加到表分组。 |
<dbname_prefix>[<expression>].<tablename> | 用于多个库中都有单个相同表名的情况。 | db_[0-2].user :将名为 db_0、db_1、db_2 库下的名为 user 的表都添加到表分组。 |
<dbname_prefix>[<expression>].<tablename_prefix>[<expression>] | 用于多个不同的表分别存储于多个不同库中的情况。 | db_[0-2].user_[0-5] :将分别存储于 db_0 到 db_2 中的 user_0 到 user_5 的 6 张表添加到表分组。 |
<prefix>[<enumeration>] | 用于枚举多个库或表。 | user_[1,3,5] :将名为 user_1、user_3、user_5 的 3 张表添加到表分组。 |
<dbname_prefix>[<expression>].<tablename_prefix>[[<expression>]] | 用于多个库中都有多个相同表名的情况。 |
|
附录 2:路由算法说明
路由算法的主要功能是自动完成数据路由,路由算法配置中,目标分库与分表通过以下表达式定义:
'<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)