开发规范
说明
本文档规范仅供参考。
1. 总则
1.1 目标
为了项目组规范使用 OceanBase 分布式数据库产品,拟定关于 OceanBase 产品的开发指引及规范。
1.2 适用范围
本规范适用于参与各类应用实现中需使用到数据库基础数据管理功能的业务人员和技术人员,以及负责应用投产后的运维人员。
1.3 术语定义
租户(tenant)
OceanBase 数据库是一个多租户的数据库。在一个 OceanBase 数据库集群之中,可以提供多个数据库服务的实例。每个数据库服务的实例不感知其他实例的存在。这些不同的实例,每一个实例叫做一个租户。租户拥有一组计算和存储资源,提供一套完整独立的数据库服务。
NDV(Number of Distinct Values)
数据列所包含的不同值的数量,或称为区分度。数值越大,平均每个值过滤出来的行数越少,索引过滤效果越好。
复合索引(Composite Index)
包含一个以上列的索引,也称为联合索引。
执行计划(Execution Plan)
数据库 SQL 执行使用的一种可行策略,以改善性能并让 SQL 更快、更准确地处理。通过在 SQL 语句之前增加 explain 关键字,显示具体的执行计划。不同的数据库其执行计划的显示内容有所不同。
表连接(Table Join)
多张表关联查询时进行的合并操作。数据库优化器根据表的大小和查询条件等信息,选择一个最低成本的表连接方式来进行表连接操作。常见的表连接方式有嵌套循环连接(Nested Loop Join),散列连接(Hash Join),排序合并连接(Sort Merger Join)。
驱动表(Drive Table)
又称外层表(Outer Table),表连接中的基础表,并以此表的数据为依据,逐步获得其它表(被驱动表)的数据,直至最终查询到所有满足条件的数据的第一个表。左连接中,左表是驱动表,右表是被驱动表;右连接中,右表是驱动表,左表是被驱动表;内连接中,表数据量较小的表会由数据库自动选择作为驱动表去驱动大表。
死锁(Dead Lock)
两个或多个事务各自占有对方的期望获得的资源,形成的循环等待,彼此无法继续正常执行的一种状态。
自增列(Auto Increment Column)
如果创建表时需要某个数值列的值不重复并且保持递增,这就是自增列。列的类型需定义为 AUTO_INCREMEN。
序列(Sequence)
在数据库中按照一定规则自增的一种数字序列。
2. 数据库设计
OceanBase 数据库对于使用者来讲,自上而下结构为:集群(cluster) -> 租户(tenant) -> 数据库(database)-> 表(table);OceanBase 数据库支持 MySQL 和 Oracle 两种模式,模式为租户级别,在创建租户的时候指定。
2.1 租户命名设计
-
【推荐】普通租户名:小写 32 字符,t + 应用标识(4 位)+ 租户编号(XX,从 00 开始)。
-
【推荐】单元化租户名:2 字符,t + 应用标识(4 位)+ Zone 类型(G/C/R)+ 租户编号(XX,从 00 开始)。
2.2 数据库命名设计
- 【建议】数据库名:应用标识(4 位)+ 子应用名(最多 4 位,可选)+ db,例如:gcdsdb 或 gcdsamndb(Oracle 租户请忽略)。
2.3 表命名设计
-
【强制】MySQL 租户表名称必须控制在 64 个字节以内。
-
【强制】创建表名和列名时统一使用小写,禁止大小写混用。
-
【强制】表名和列名只能使用字母、数字和下划线,并且必须以字母开头,不得使用系统保留字和特殊字符。表名禁止两个下划线中间只出现数字。
-
【推荐】联机业务表和批量业务表分开存放,防止跑批时影响联机业务。
2.4 字段设计
-
【强制】每张表上都必须设定主键。
-
【强制】MySQL 模式小数类型使用 decimal 类型存储,禁止使用 double,float。
-
【强制】对于字符类型,MySQL 模式建议采用 varchar,不建议使用 tinytext、text、mediumtext、longtext。
-
【强制】禁止使用枚举列类型:enum(‘x’,’y’,’z’),需使用字符串类型替代。
-
【强制】对于日期类型,有时间精度要求的业务,可以使用 DATATIME;对精度没要求的,设置为 DATE 即可;不要使用字符作为时间字段的数据类型;建议不要使用 TIMESTAMP,范围有限而且要避免 TIMESTAMP+TIME_ZONE=‘SYSTEM’ 的问题。
-
【推荐】非定长字段建议使用 varchar。
-
【推荐】建议表上默认添加 gmt_create 和 gmt_modified 两字段,记录创建和变更时间;gmt_create 加上 default current_timestamp 属性,gmt_modified 加上 default current_timestamp on update current_timestamp 属性。
-
【强制】建议表中所有字段都配置为 NOT NULL 属性,并根据业务需要定义 DEFAULT 值。
-
【强制】每个字段应加注释。
-
【强制】禁止使用外键自引用且级联删除更新的表字段约束定义,否则可能导致重复删除的问题。
2.5 自增列设计
-
【强制】创建序列必须指定 cache 大小,cache 值可设置为租户 tps100606024。
-
【强制】序列禁止添加 order 属性。
-
【强制】自增列字段使用 bigint,禁止使用 int 类型,防止存储溢出。
-
【强制】禁止使用自增列作为分区键。因为当使用自增列作为分区键时, 不保证自增列的值分区内自增,并且性能损耗较大。
2.6 分区表设计
OceanBase 数据库在 MySQL 模式下支持 range/range columns 分区、hash/key 分区和 list/list columns 分区,支持二级分区。
-
【注意】分区表的分区规则在表创建的时候需要指定,OceanBase 数据库 4.0 以后版本才支持将非分区表在线改造成分区表的 offline DDL 操作。
-
【推荐】分区表索引建议:按照本地索引 -> 全局分区索引 -> 全局索引的顺序进行选择,只有在有必要的时候才使用全局索引,原因是全局索引会降低 DML 的性能,可能会因此产生分布式事务。
-
【强制】分区表的查询或修改必须带上分区键。
-
【强制】对于 range 分区,需要业务自行做分区管理,定时增加分区,避免分区越界问题。
-
【推荐】range 分区不建议指定 MAXVALUE ,否则后续无法新增分区。
-
【推荐】在业务查询条件明确的情况下根据业务场景进行分区规划,分区目的是要利用分区裁剪的能力提高查询效率,禁止在场景不明确的情况下随意规划分区规则。如果查询条件部分场景下仅能覆盖一级分区,建议按照一级分区规划,不需要强行规划为二级分区。
-
【推荐】OceanBase 数据库 4.0 以前版本,需要控制一个事务中的分区数参与数量,建议 XA 事务的分区参与数在 600 以内,普通事务的分区参与数在 1000 以内。需要注意 insert select 存在未按结果集裁剪,导致事务提交按照所有分区作为参与者的情况。
-
【推荐】使用分区表时 要选择合适的拆分键(列)以及拆分策略。
-
【推荐】为保证 HASH 分区模式下分区间数据均衡,MySQL 模式下分数个数建议采用奇数个分区,即 3、7、15、31 这样。
-
【强制】禁止使用生成列作为分区键。
-
【强制】有历史数据清理的表,需要根据业务使用场景和清理周期进行分区表设计。如交易流水表,可按日分区并按日删除旧分区。
-
【注意】关于分区键在多维业务查询场景下的选择,如账号和卡号同时存在情况下,需根据业务使用频率和业务重要性等维度来考虑分区键的选择。
2.7 索引设计
在 OceanBase 数据库中,索引可以分为两种类型:本地索引和全局索引,默认创建的是全局索引。两者之间的区别在于:本地索引与分区数据共用分区,全局索引为单独分区;创建本地的索引需要指定 local 关键字,未指定或者指定 global 关键字为全局索引。
-
【推荐】分区表建议优先创建 LOCAL 索引。
-
【强制】不允许创建全文索引。
-
【强制】单个索引字段值的总长度不能超过 64KB。
-
【强制】单个表上的索引个数建议不超过 5 个左右。
-
【强制】索引名称必须控制在 64 个字符以内,主键索引命名为 pk_表名_字段名,唯一索引名为 uk_表名_字段名;普通索引名则为 idx_表名_字段名。
-
【推荐】在建索引时,建议将表中可能会被查询投影、ORDER BY、GROUP BY 等操作频繁使用的列添加到索引后面,形成覆盖索引避免回表查询或排序。