赞
踩
数据库的体系结构是从某一个角度来分析和考察数据库的组成、工作过程与原理,以及数据在数据库中的组织与管理机制。
Oracle11g作为传统关系数据库的代表、Oceanbase作为分布式关系数据库的代表,体系结构上的设计差别很大。
一般Oracle数据库(Oracle Database)可以分为两部分。
(1)实例(Instance)
实例是一个非固定的、基于内存的基本进程与内存结构。当服务器关闭后,实例也就不存在了。
(2)数据库(Database)
数据库指的是固定的、基于磁盘的数据文件、控制文件、日志文件、参数文件和归档日志文件等。
一个实例只能对应一个数据库。但是一个数据库有可能对应多个实例。除非使用并行Oracle服务器选项,在并行的数据库系统中,一个数据库会对应多个实例,同一时间用户只与一个实例相联系,当某一个实例出现故障时,其他实例自动服务,保证数据库正常运行。
在Oracle数据库系统中,用于存放数据库表、索引、回滚段等对象的磁盘逻辑空间叫表空间(tablespace)。数据库是通过表空间来存储物理表的,一个数据库实例可以有N个表空间,一个表空间下可以包含一个或者多个数据文件。数据文件(Datafile)是用于保存用户应用数据和Oracle系统内部数据的文件。
表空间是逻辑概念
一般在完成Oracle系统的安装并创建Oracle实例后,Oracle系统自动建立多个表空间。
Oracle 11g版本默认创建的主要表空间:
(1)SYSTEM表空间
SYSTEM表空间用于存放Oracle系统内部表和数据字典的数据,如表名、列名、用户名等。
不建议将用户创建的表、索引等存放在SYSTEM表空间中。
(2)撤销表空间
撤销表空间(Undo Tablesapce)用于存储撤销信息的表空间。当我们对数据库表进行修改(包括INSERT,UPDATE,DELETE操作)时,Oracle系统自动使用撤销表空间来临时存放修改前的数据(Before Image)。当所做的修改操作完成并提交(Commit)后,Oracle系统可根据需要保留修改前数据时间长短来释放撤销表空间的部分空间。
(3)USERS表空间
USER是Oracle建议用户使用的表空间,可以在这个表空间上创建各种对象,如创建表、索引等。
当我们创建表空间时至少需要创建一个以上的数据文件,Oracle创建数据文件时,实际上是将磁盘的操作系统块重新格式化成Oracle数据块,并且每个Oracle数据块都有唯一的标识。
对于传统数据库而言一般采用分库分表进行水平拓展。通过分库分表,可以快速实现数据库的水平扩展。采用这种方式,技术成本相对低,不需要改造核心数据库引擎,或者只需要做很少的改造。但是或多或少会存在一些问题:
Oracle通过对自身的改进,引入了RAC在一定程度上规避了些上述的问题,但是和Oceanbase这种原生支持分布式的数据库比,存在差距。
Oracle RAC,全称是Oracle Real Application Cluster,翻译过来为Oracle真正的应用集群,它是Oracle提供的一个并行集群系统。
Oracle RAC的实质是位于不同操作系统的Oracle实例节点同时访问同一个Oracle数据库 ,每个节点间通过私有网络进行通信,互相监控节点的运行状态,Oracle数据库所有的数据文件、联机日志文件、控制文件等均放在集群的共享存储设备(可以是RAW、ASM、OCFS2等)上,所有集群节点可以同时读写共享存储。
共享存储设备有全部的数据文件,可以看出来oracle体系结构并不是天然支持分布式的。(横向扩展困难)
RAC数据库如何实现节点数据的一致性?
每个RAC实例的SGA内有一个buffer cache(缓冲区),通过Cache Fusion(缓存融合)技术,RAC在各个节点之间同步SGA中的缓存信息,从而保证节点数据的一致性,同时也提高集群的访问速度。(性能不如单机)
OceanBase 数据库的一个集群由若干个节点组成。这些节点分属于若干个可用区(Zone), 每个节点属于一个可用区。可用区是一个逻辑概念,表示集群内具有相似硬件可用性的一组节 点,它在不同的部署模式下代表不同的含义。例如,当整个集群部署在同一个数据中心(IDC)内的时候,一个可用区的节点可以属于同一个机架,同一个交换机等。当集群分布在
多个数据中心的时候,每个可用区可以对应于一个数据中心。
正是由于Oceanbase可用区的概念设计,分区对于Oceanbase而言是极为重要的概念。
为了使 OceanBase 数据库对应用程序屏蔽内部分区和副本分布等细节,使应用访问分布式数 据库像访问单机数据库一样简单,这里使用了 obproxy 代理服务。OBProxy是OceanBase数据库高性能反向代理服务器,它接收客户端的应用请求,并转发给OBServer。obproxy 是无状态的服务,多个 obproxy 节点通过网络负载均衡(SLB)对 应用提供统一的网络地址。
在集群的每个节点上会运行一个叫做 observer 的服务进程,它内部包含多个操作系统线程。 节点的功能都是对等的。每个服务负责自己所在节点上分区数据的存取,也负责路由到本机 的 SQL 语句的解析和执行。这些服务进程之间通过 TCP/IP 协议进行通信。同时,每个服务会 监听来自外部应用的连接请求,建立连接和数据库会话,并提供数据库服务。
为了简化大规模部署多个业务数据库的管理并降低资源成本,OceanBase 数据库提供了独特 的多租户特性。在一个 OceanBase 集群内,可以创建很多个互相之间隔离的数据库"实例", 叫做一个租户。从应用程序的视角来看,每个租户等同于一个独立的数据库实例。租户是一个逻辑概念。在 OceanBase 数据库中,租户是资源分配的单位,是数据库对象管理 和资源管理的基础。
为了隔离租户的资源,每个 observer 进程内可以有多个属于不同租户的虚拟容器,叫做资源 单元(UNIT)。每个租户在多个节点上的资源单元组成一个资源池。资源单元包括 CPU 和内 存资源。OB的多租户资源隔离通过cgroup实现租户资源隔离,还无法实现磁盘空间的分配和IO隔离 (考虑资源竞争的情况)。
在 OceanBase 数据库中,一个表的数据可以按照某种划分规则水平拆分为多个分片,每个分 片叫做一个表分区,简称分区(Partition)。某行数据属于且只属于一个分区,一个表的若干个分区可以分布在一个可用区内的多个节点上。分区的规则由 用户在建表的时候指定,包括hash、range、list等类型的分区,还支持二级分区。分区就是表的子集。
OceanBase非分区表只有一个分区,非分区表不能添加分区,非分区表只会被创建在一个OBSever中无法在集群内多节点横向扩展。一个分区表可以有多个分区,单个分区只能在一个节点上,不同分区可以在不同节点上。
每个分区都有多个副本,自动建立paxos组,在分区级采用多副本保障数据可靠性和服务高可用。
在OB数据库中创建一张表的时候需要考虑采用哪种模式,是创建为分区表还是普通的表,如果创建表的时候不指定是分区表,那么这张表,无法在集群内多节点横向扩展。另外如果有多张表要进行JOIN,如果要JOIN的数据分别属于不同的OBSERVER管理,那么这种JOIN是跨网络的,其性能也会受到一定的影响。
如果表分区设计不合理,或者无较好的分区列,容易出现分区倾斜,数据热点等问题,需要熟悉对应的业务场景 。
为了能够保护数据,并在节点发生故障的时候不中断服务,每个分区有多个副本。一般来说, 一个分区的多个副本分散在多个不同的可用区里。多个副本中有且只有一个副本接受修改操 作,叫做主副本(Leader),其他副本叫做从副本(Follower)。主从副本之间通过分布式共识协议实现了副本之间数据的一致性。
对于分布式数据库, 多个表中的数据可能会分布在不同的机器上, 这样在执行 Join 查询或跨表 事务等复杂操作时就需要涉及跨机器的通信,而表组功能可以避免这种跨机器操作,从而提高 数据库性能。
将分区方式相同的表聚集到一起就形成了表组(以 Hash 分区为例,分区方式相同等价于分区个数相同,当然计算分区的 Hash 算法也是一样的),表组内每个表的同号分区称为一个分区组。
对于访问数据库的应用而言,逻辑上访问的只有一个表或一个索引,但是实际上这个表可能由 数十个物理分区对象组成,每个分区都是一个独立的对象,可以独自处理访问,也可以作为表 的一部分处理访问。分区对应用来说是完全透明的,不影响应用的业务逻辑。
OceanBase是鼓励使用分区的。
使用分区的好处如下:
1.提高了可用性
分区不可用并不意味着对象不可用。查询优化器自动从查询计划中删除未引用的分区。因此,当分区不可用时,查询不受影响。
2.更轻松地管理对象
分区对象具有可以集体或单独管理的片段。DDL语句可以操作分区而不是整个表或索引。因 此,可以对重建索引或表等资源密集型任务进行分解。例如,可以一次只移动一个分区。如 果出现问题,只需要重做分区移动,而不是表移动。此外,对分区进行 TRUNCATE 操作可 以避免大量数据被 DELETE 。
3.减少 OLTP 系统中共享资源的争用
在 TP 场景中,分区可以减少共享资源的争用。例如,DML 分布在许多分区而不是一个表 上。
4.增强数据仓库中的查询性能
在 AP 场景中,分区可以加快即席查询的处理速度。分区键有天然的过滤功能。例如,查询 一个季度的销售数据,当销售数据按照销售时间进行分区时,仅仅需要查询一个分区或者几个分区,而不是整个表。
5.提供更好的负载均衡效果
OceanBase 数据库的存储单位和负载均衡单位都是分区。不同的分区可以存储在不同的节 点。因此,一个分区表可以将不同的分区分布在不同的节点,这样可以将一个表的数据比较 均匀的分布在整个集群。
OceanBase和传统数据库的对比
维度 | 传统集中式数据库 | 以OceanBase为代表的分布式数据库 |
---|---|---|
产品架构 | 经典的“单点集中式”架构,采用“全共享(Share-Everything)” 架构。构建于高端的硬件基础之上,比如IBM高端服务器和EMC 高端存储设备等 | 原生的“分布式”数据库,采用业界最严格的Paxos分布式一致性协议。基于普通PC硬件的设计,不需要高端硬件。 |
数据可靠性和服务高可用性 | 利用高端硬件设备保证数据可靠性。采用“主从复制”,主节点故障的情况下,会有数据损失 (RPO>0);不能自动恢复服务,服务恢复时间(RTO)通常以小时为单位计算 | 以普通PC硬件为基础,利用Paxos分布式一致性协议保证数据可靠性。主节点故障的情况下,Paxos可以保证数据无损(即RPO=0),并 且自动选举并恢复服务,服务恢复时间(RTO)在30秒以内。 |
扩展性 | 数据存储只能在单点内实现纵向扩展,最终必然触达单点架构下 的容量上限。计算节点通常无法扩展。少数模式下(如RAC, pureScale)可做计算节点扩展,但多个计算节点之间仍需访问单 点共享存储,并且可扩展的计算节点数量有限。 | 数据节点和计算节点均可以在MPP架构下实现水平扩展。 数据节点和计算节点均没有数量限制,在网络带宽足够的前提下, 可以扩充至任意数目。 |
应用场景 | 集中在企业客户(金融、电信、政企等)的核心系统。 无法应付互联网业务场景,应用案例很少。 | 支付宝核心、网商银行核心、阿里巴巴的众多业务,以及多家外 部商业银行。逐渐迈向传统业务。 |
使用成本 | 比较昂贵。需要支付高端基础硬件的费用、高昂的软件授权费用以及产品服 务费用。 | 相对较低。基于普通X86服务器保证高可用性,无需使用高端小型机和存储。 软件授权费用和服务费用也 有优势。 |
从数据库体系结构可以看到,OceanBase不兼容Oracle,原因源于结构性差异,通过适配只能解决一部分的问题。具体使用时要考虑两者的差异性。
四种隔离级别比较如下所示:
OceanBase 数据库(Oracle 模式)目前支持了以下几种隔离级别:
读已提交(Read Committed)
可重复读(Repeatable Read)
可串行化(Serializable)
Oracle上述隔离级别均支持。
OceanBase 和Oracle数据库默认的隔离级别为读已提交(Read Committed)。存在不可重复读和幻读的可能性。
不过对于读未提交的隔离级别只有理论上的意义,没有实践上的价值。
二叉树
任何节点的左子节点的键值都小于当前节点的键值,右子节点的键值都大于当前节点的键值
由于二叉树的根节点是确定不变的,所以当调整数据的插入或删除顺序,会造成二叉树朝着单项链表的方向发展,大大降低了数据的查询效率。
平衡二叉树/AVL树
当二叉树非常极端,变成一个链表后,它就没有了二叉树的相关优秀性质了。所以我们在insert节点的时候,需要不断的旋转,来使二叉树平衡,最终使得其查询效率最高。调整一共分为四种情况:LL,RR,LR,RL
B-树
因为数据库中大部分数据都存在于磁盘,但是IO一次磁盘的代价相对来说比较大,我们需要尽可能的减少AVL树的深度,即增加每个节点的数据量。这便是B-树的由来。
每一个节点称为页,也就是一个磁盘块。 B-树相对于平衡二叉树,每个节点存储了更多的键值(key)和数据(data),并且每个节点拥有更多的子节点
B-树的查询流程:
如上图我要从找到E字母,查找流程如下:
1)获取根节点的关键字进行比较,当前根节点关键字为M,E<M(26个字母顺序),所以往找到指向左边的子节点(二分法规则,左小右大,左边放小于当前节点值的子节点、右边放大于当前节点值的子节点)。
2)拿到关键字D和G,D<E<G 所以直接找到D和G中间的节点。
3)拿到E和F,因为E=E 所以直接返回关键字和指针信息(如果树结构里面没有包含所要查找的节点则返回null)。
4)通过指针信息取出这条记录的所有信息。
因为 B 树索引在数据更新和删除时的维护成本相对较低,Oracle的数据结构组织形式采用B树。
B+树
是B-树的变形,相对于B-树来说,B+树最主要的不同之处就是其非叶子节点上是不存储数据的,数据全在叶子节点存储。这就意味着B+树比B-树更胖。因为B+树索引的所有数据均存储在叶子节点,而且数据是按照顺序排列的。那么B+树使得范围查找,排序查找,分组查找以及去重查找变得异常简单。而B树因为数据分散在各个节点,要实现这一点是很不容易的。
B+树和B-树的区别是:
1)B-树的节点(根节点/父节点/中间节点/叶子节点)中没有重复元素,B+树有。
2)B-树的中间节点会存储数据指针信息,而B+树只有叶子节点才存储。
3)B+树的每个叶子节点有一个指针指向下一个节点,把所有的叶子节点串在了一起。
从下图我们可以直观的看到B-树和B+树的区别:紫红色的箭头是指向被索引的数据的指针,大红色的箭头即指向下一个叶子节点的指针。
B+树是B-树的改良版,但是索引在数据更新和删除时效率会更低。
Mysql的数据组织形式采用B+树。
LSM树
LSM树,即日志结构合并树(Log-Structured Merge-Tree)。 其实它并不属于一个具体的数据结构,它更多是一种数据结构的结合。 大多NoSQL数据库核心思想都是基于LSM来做的, 只是具体的实现不同。LSM树由两个或以上的存储结构组成,存在多种实现方式。
它的核心思路其实非常简单,就是假定内存足够大,因此不需要每次有数据更新就必须将数据写入到磁盘中, 而可以先将最新的数据驻留在内存中,等到积累到最后多之后,再使用归并排序的方式将内存内的数据合并追加到磁盘队尾 (因为所有待排序的树都是有序的,可以通过合并排序的方式快速合并到一起)。
LSM具有批量特性,存储延迟。当写读比例很大的时候(写比读多),LSM树相比于B树有更好的性能。因为随着insert操作,为了维护B树结构,节点分裂。 读磁盘的随机读写概率会变大,性能会逐渐减弱。 多次单页随机写,变成一次多页随机写,复用了磁盘寻道时间,极大提升效率。
核心思想的核心就是放弃部分读能力,换取写入的最大化能力。
OceanBase 数据库的存储引擎基于 LSM-Tree 架构,将数据分为 静态基线数据 (放在 SSTable 中)和 动态增量数据 (放在 MemTable 中)两部分,其中 SSTable 是只读的,一旦生成就不再被修改,存储于磁盘;MemTable 支持读写,存储于内存。数据库 DML 操作插入、更新、删除等首先写入 MemTable,等到 MemTable 达到一定大小时转储到磁盘成为 SSTable。在进行查询时,需要分别对 SSTable 和 MemTable 进行查询,并将查询结果进行归并,返回给 SQL 层归并后的查询结果。同时在内存实现了 Block Cache 和 Row cache,来避免对基线数据的随机读。
OceanBase 数据库的内存存储引擎 MemTable 由 BTree 和 Hashtable 组成,在插入/更新/删除数据时,数据被写入内存块,在 HashTable 和 BTree 中存储的均为指向对应数据的指针。
当 MemTable 的大小达到某个阈值后,OceanBase 数据库会将 MemTable 中的数据转存于磁盘上,转储后的结构称之为 SSTable。
OceanBase采用LSM进行数据结构的组织。这就导致OceanBase对内存要求极高。基于LSM树结构的缺点,内存和磁盘数据合并时需要同时保存前后两个版本的数据,至少需要2倍的磁盘空间。
OceanBase3.2.3 Oracle模式是兼容Oracle11g语法的,支持90%的Oracle数据类型和内置函数; 支持分布式执行的存储过程(PL/SQL);
在OB中,非分区表作为一个独立的分区表对待 。如果数据量比较大,建议建设分区。如果不指定分区表,默认为非分区表,非分区表后续不能添加分区。
OB建表设计主键或者唯一键(对提高性能和后期维护有益)
如果没有合适的字段作为主键,可以使用一个序列号(sequence)填充的数值列作为主键。
ALTER TABLE 语法不支持创建表以后添加主键,所以在建表的时候需要决定主键列
注:如果建表时没有指定主键列,OB会自动使用一个隐含列作为主键,此列对用户不可见。
Oracle 租户不支持create table like …语法,Oracle 租户支持 CREATE TABLE AS SELECT 复制表的基本数据类型和数据,但不包含约束、索引和非空等属性。
表组是OB特有的概念。
表组是表的属性,影响多个表分区在 OBServer 上的分布特征。
为降低分布式访问的影响,OceanBase建议对业务上关系密切的表,设置相同的表组。 OceanBase 对于同一个表组中表的同号分区会放置在一个分区组内。同一个分区组中的分 区,OceanBase 会将其尽可能的分配到同一个节点内部,尽量规避跨节点的请求。
创建表组时,首先要规划好表组的用途。如果是用于普通表(单分区),表组不用分区; 如果是用于分区表的属性,表组就要指定分区策略,并且要跟分区表的分区策略保持一致。
创建表组的语法在OceanBase不同版本是有差异的。
表创建后加入到表组有两种方式:
• 修改表的表组属性
• 使用 ALTER TABLEGROUP ADD 语法,对一个表组增加多张表。
ALTER TABLEGROUP tablegroup_name ADD [TABLE] table_name [, table_name...];
查看表组信息:
分区是OB最重要的设计之一。相比Oracle,除了分区物理模型上的不同,OB在逻辑模型上多了二级分区的设计。
OB 现在支持的一级分区类型有:HASH, KEY, LIST,RANGE,RANGE COLOMNS,生成列分区。
HASH 分区
HASH分区需要指定分区键和分区个数。通过HASH的分区表达式计算得到一个int类型的结果,这个结果再跟分区个 数取模得到具体这行数据属于那个分区。通常用于给定分区键的点查询,例如按照用户id来分区。 HASH分区通常 能消除热点查询。
create table t1 (c1 int, c2 int) partition by hash(c1 + 1) partitions 5
其中partition by hash(c1+1)指定了分区键c1和分区表达式c1 + 1;
partitions 5指定了分区数
KEY 分区
KEY分区与HASH分区类似,不同在于:
create table t1 (c1 varchar(16), c2 int) partition by key(c1) partitions 5
create table t1 (c1 int primary key, c2 int) partition by key() partitions 5
KEY分区分区键不写任何column,表示key分区的列是主键
LIST 分区
LIST分区是根据枚举类型的值来划分分区的,主要用于枚举类型
LIST分区的限制和要求
create table t1 (c1 int, c2 int) partition by list(c1)
(partition p0 values in (1,2,3),
partition p1 values in (5, 6),
partition p2 values in (default));
List columns 和 list 的区别是:
●list columns分区不要求是int类型,可以是任意类型
●list columns分区不能写表达式
●list columns分区支持向量
RANGE 分区
RANGE分区是按用户指定的表达式范围将每一条记录划分到不同分区 常用场景: 按时间字段进行分区
目前提供对range分区的分区操作功能,能add/drop分区
add分区现在只能加在最后,可以存在maxvalue的分区,但是不建议。
CREATE TABLE `info_t`(id INT, gmt_create TIMESTAMP, info VARCHAR(20), PRIMARY KEY (gmt_create)) PARTITION BY RANGE(UNIX_TIMESTAMP(gmt_create))
(PARTITION p0 VALUES LESS THAN (UNIX_TIMESTAMP('2015-01-01 00:00:00')), PARTITION p1 VALUES LESS THAN (UNIX_TIMESTAMP('2016-01-01 00:00:00')), PARTITION p2 VALUES LESS THAN (UNIX_TIMESTAMP('2017-01-01 00:00:00')));
RANGE COLUMNS 分区
RANGE COLUMNS分区与RANGE分区类似,但不同点在于RANGE COLUMNS分区可以按一个或多个分区键向量 进行分区,并且每个分区键的类型除了INT类型还可以支持其他类型,比如VARCHAR、DATETIME等
RANGE COLUMNS和RANGE的区别是
CREATE TABLE `info_t`(id INT, gmt_create DATETIME, info VARCHAR(20), PRIMARY KEY (gmt_create)) PARTITION BY RANGE COLUMNS(gmt_create)
(PARTITION p0 VALUES LESS THAN ('2015-01-01 00:00:00’), PARTITION p1 VALUES LESS THAN ('2016-01-01 00:00:00’), PARTITION p2 VALUES LESS THAN ('2017-01-01 00:00:00’), PARTITION p3 VALUES LESS THAN (MAXVALUE));
生成列分区
CREATE TABLE gc_part_t(t_key varchar(10) PRIMARY KEY, gc_user_id VARCHAR(4) GENERATED ALWAYS AS (SUBSTRING(t_key, 1, 4)) VIRTUAL, c3 INT)
PARTITION BY KEY(gc_user_id) PARTITIONS 10;
二级分区相当于在一级分区的基础上,又从第二个维度进行了拆分。最常用的地方就是类似用户账单领域,会按照 user_id 做 HASH 分区,按照账单创建时间做 RANGE 分区。
MySQL 模式
Oracle 模式
二级分区支持的分区方式
对于 RANGE 分区的分区操作 add/drop,必须是 RANGE 分区做为一级分区的方式。所以强烈建议用 RANGE + HASH 的分区方式,而不是 HASH + RANGE。
分区管理
增加分区
对于按时间范围分区的表,有时需要作过期数据清理 -> ADD PARTITION
语法: ALTER TABLE … ADD PARTITION
删除分区
伴随数据量增长,range分区需要能够扩展 -> DROP PARTITION
语法: ALTER TABLE … DROP PARTITION
ALTER TABLE members ADD PARTITION(PARTITION p3 VALUES LESS THAN(2000));
ALTER TABLE members DROP PARTITION(P3);
分区表最佳实践
更新分区键注意事项
obclient> create table t_part(id number not null , c1 varchar2(10) not null, c2 varchar2(100), primary key(id,c1)) partition by hash(c1) partitions 8; Query OK, 0 rows affected (0.29 sec) obclient> insert into t_part(id,c1,c2) values(1,'A','aaaaaaaa'),(2,'B','bbbbbbbbb'),(3,'C','ccccccccc'),(4,'D','dddddddd’); Query OK, 4 rows affected (0.04 sec) Records: 4 Duplicates: 0 Warnings: 0 obclient> select * from t_part; +----+----+-----------+ | ID | C1 | C2 | +----+----+-----------+ | 3 | C | ccccccccc | | 2 | B | bbbbbbbbb | | 4 | D | dddddddd | | 1 | A | aaaaaaaa | +----+----+-----------+ 4 rows in set (0.05 sec) obclient> update t_part set c1='CC' where c1='C*’; ORA-14402: updating partition key column would cause a partition change
自增列和序列均提供顺序递增的唯一值
Oracle模式不支持自增列(同Oracle),可以使用序列(sequence)实现自增列的功能
MySQL模式(3.2版本及以上)既支持自增列(identity),又支持序列(sequence)。自增列功能和表强绑定,提供了两个独特的特性:
因为存在切主等导致自增列缓存被动刷新的场景,自增列会跳变,建议使用BIGINT类型来定义自增列。
自增列的属性由租户变量统计管理:
在分区表中,自增列保证分区内有序,不能保证分区间有序
目前OceanBase中序列仅支持两种模式
CREATE SEQUENCE sequence_name
[MINVALUE value | NOMINVALUE]
[MAXVALUE value | NOMAXVALUE]
[START WITH value]
[INCREMENT BY value]
[CACHE value | NOCACHE]
[ORDER | NOORDER]
[CYCLE | NOCYCLE];
模式 Oracle 数据库 | OceanBase 数据库 |
---|---|
NOCACHE with ORDER | 所有 Instance 不缓存任何序列,使用时从全局 CACHE 中获取,CACHE 根据请求的先后顺序返回序列值。 所有 Instance 不缓存任何序列,使用时从全局 CACHE 中获取,CACHE 根据请求的先后顺序返回序列值。 |
NOCACHE with NOORDER | 所有 Instance 不缓存任何序列,使用时从全局 CACHE 中获取,CACHE 可以根据繁忙程度延迟满足一些请求,导致 NOORDER。 仅语法兼容,实际效果与 NOCACHE with ORDER 相同。 |
CACHE with ORDER | 每个 Instance 都缓存相同的序列,使用之前需要通过全局锁来同步序列中的下一个可用位置。 仅语法兼容,实际效果与 NOCACHE with ORDER 相同。 |
CACHE with NOORDER | 每个 Instance 都缓存不同的序列,并且不需要全局同步 CACHE 状态。此时的值自然是 NOORDER。 每个 Instance 都缓存不同的序列,并且不需要全局同步 CACHE 状态。此时的值自然是 NOORDER。 |
出于性能考虑,OceanBase 数据库建议使用默认的 CACHE with NOORDER方式。
OceanBase 数据库中,不建议使用 ORDER with NO CACHE。这种模式下,每次调用 NEXTVAL 都会触发一次内部表 SELECT 与 UPDATE 操作,会影响数据库的性能。
在创建序列时,由于默认的 CACHE 值只有 20,需要手动声明一个比较大的值。CACHE 每次耗尽后,都会触发一次网络缓存刷新。对于单机 TPS 为 100 时,CACHE SIZE 建议设置为 360000。
在分布式系统中使用 Sequence 时,如果使用了 CACHE + NOORDER 选项,那么连接到不同机器时获得的序列不是有序递增的,但是可以保证唯一。
传统的“非”分区表中,主表和索引的对应关系:
主表的所有数据都保存在一个完整的数据结构中,主表上的每一个索引也对应一个完整的数据结构(比如最常见的B+ Tree),主表的 数据结构和索引的数据结构之间是一对一的关系,如下图所展示,在 employee表中,以 emp_创建的索引:
Oracle为B树,Mysql为B+树。
对于OB而言,由于分区表的特性,情况发生了变化:
主表的数据按照分区键(Partitioning Key)的值被分成了多个分区,每个分区 都是独立的数据结构,分区之间的数据没有交集。这样一来,索引所依赖的单一数据结构不复存在。
这就引入了“局部索引”和“全局索引”两个概念。
局部索引又名分区索引,创建索引的分区关键字是LOCAL;分区键等同于表的分区键,分区数等同于表的分区数;局部索引的分区机制和表的分区机制一样。
全局索引的创建规则是在索引属性中指定GLOBAL关键字;全局索引最大的特点是全局索引的分区规则跟表分区是相互独立的;全局索引允许指定自己的分区规则和分区个数,不一定 需要跟表分区规则保持一致。
分区表的局部索引和非分区表的索引类似,索引的数据结构还是和主表的数据结构保持一对一的关系,但由于主表已经做了分区,主表的“每一个分区”都会有自己单独的索引数据结构。 局部索引的结构如下图所示:
分区表的全局索引不再和主表的分区保持一对一的关系,而是将所有主表分区的数据合成一个整体来建立全局索引。更进一步,全局索引可以定义自己独立的数据分布模式,既可以选择非分区模式也可以选择分区模式
全局非分区索引与全局分区索引的比较
全局非分区索引:
此时索引的结构和“非分区”表没有区别,只有一个完整的索引树,自然保证唯一性。
因为只有一个完整的索引树,自然没有多分区扫描的问题。
全局分区索引:
数据只可能落在一个固定的索引分区中,因此每一个索引分区内保证唯一性约束,就能在全表范围内保证唯一性约束。
全局索引能保证某一个索引键的数据只落在一个固定的索引分区中,所以无论是针对固定键值的索引扫描,还是针对一个键值范围的索引扫描,都可以直接定位出需要扫描的一个或者几个分区。
局部索引与全局索引的取舍
如果查询条件里“包含完整的分区键”,使用本地索引是最高效的。
如果需要“不包含完整分区键”的唯一约束,
其它情况:
如果数据量较大,或者容易出现索引热点,可考虑创建全局分区索引。
如果全局索引的分区规则和主表的分区规则相同并且分区数相同,这时推荐创建一个局部索引。
非必要情况下,不推荐使用全局索引:一方面是因为全局索引的维护代价更大;另一方面是因为全局索引无法 保证和主表分区的物理位置相同,除非将其和主表指定在一个表组中。
创建索引
OceanBase 数据库支持在非分区表和分区表上创建索引,索引可以是局部索引或全局索引,也可以是唯一索引或 普通索引。如果是分区表的唯一索引,则唯一索引必须包含表分区的拆分键。
可以对一张表的单列或多列创建索引来提高表查询速度。创建合适的索引,能够减少对磁盘的读写
CREATE [UNIQUE] INDEX index_name ON table_name ( column_list ) [LOCAL | GLOBAL] [ PARTITION BY column_list PARTITIONS N ] ;
OB高效索引实践
OB索引属性
条件的先后顺序不影响索引能效,如where A = ? and B = ? 和 where B = ? and A = ? 效果相同 从索引能效来看: 【Where A =? And B=? and C=?】>【Where A=? and B=? 】> 【Where A=? and C=?】
创建索引-范围查询
常见的范围查询有: 大于、小于、大于等于、小于等于、between…and 、 in(?,?)
遇到第一个范围查询字段后,后续的字段不参与索引过滤(不走索引)
如【where A > ? and B > ? and C < ?】、【where A > ? and B > ?】 、【where A > ? and C < ?】 只能走A字段的索引
创建索引-等值和范围查询
遇到第一个范围查询字段后,后续的字段不参与索引过滤(不走索引)
从索引能效看:【where A = ? and B = ? and C > ?】>【where A = ? and B > ? and C > ?】 【where A = ? and B > ? and C = ?】=【where A = ? and B > ? and C > ?】
租户是OB特有的设计。
将数据库集群按指定规格(CPU、内存、存储、TPS、QPS)划分 成多个资源池,分配给不同的租户;
租户资源隔离策略:内存物理隔离;CPU逻辑隔离,数据隔离;
一般一个应用占用一个租户。
创建租户一般要三个步骤:
步骤一、创建“资源单元规格”,create resource unit命令,指定资源单元的规格;
CREATE RESOURCE UNIT unit1
max_cpu = 4,
max_memory = 10737418240, -- 10GB min_memory = 10737418240, -- 10GB max_iops = 1000,
min_iops = 128,
max_session_num = 300,
max_disk_size = 21474836480 -- 20GB ;
步骤二、创建“资源池”,create resource pool命令,根据资源单元规格的定义创建资源单元,并赋给一个新的资源池;
CREATE RESOURCE POOL pool1
UNIT = 'unit1',
UNIT_NUM = 1,
ZONE_LIST = ('zone1', 'zone2', 'zone3');
步骤三、 创建租户,create tenant命令,将资源池赋给一个新的租户;
CREATE TENANT oracle_tenant
RESOURCE_POOL_LIST = ('pool1'),
primary_zone = 'zone1,zone2,zone3'
set ob_tcp_invited_nodes = '%', ob_compatibility_mode = 'oracle', recyclebin = off, ob_timestamp_service = 'GTS’;
Oceanase的Oracle模式:兼容Oracle的视图、基础数据类型、SQL功能、数据库对象和PL功能。(兼容90%以上的内容)
Oceanase的MySQL模式:OceanBase 4.0 版本之前兼容 MySQL 5.7,4.0 版本之后兼容MySQL 8.0。
主要的不兼容项功能有(以OceanBase 3.2.3 版本为例):
如果是Oracle租户,可以直接使用连接串进行连接:
$ obclient -h192.168.1.101 -usys@t_oracle0_91#obdoc -P2883 -pabcABC123 -c -A sys
-h:OceanBase数据库连接的IP,通常是一个 OBProxy 或OBserver地址。
-u:租户的连接帐户,有两种格式:“用户名@租户名#集群名或者“集群名:租户名:用户名”。Oracle 租户的管理员用户名默认是sys。
-P:OceanBase 数据库连接端口,也是 OBProxy 的监听端口,默认是 2883,可自定义。
-p:帐户密码。为了安全可以不提供,改为在后面提示符下输入,密码文本不可见。
-c:表示在将 SQL 语句中的注释发往数据库端。
-A:表示在连接数据库时不去获取全部表信息,可以使登录数据库速度最快。 sys:访问的数据库名,可以改为业务数据库
需要注意的是,在yaml配置数据库连接的时候,最好明确指定是Oracle模式,不然可能会出现问题(行内某系统因为分页查询出现过生产问题,指定Oracle模式得以解决,原因是框架的兼容问题)。配置信息如下:
OceanBase 开发者中心(OceanBase Developer Center,ODC)是为 OceanBase 数据库量身打造的企业级数据库 开发平台。ODC 支持连接 OceanBase 中 MySQL 和 Oracle 模式下的数据库,同时为数据库开发者提供了数据库日常开发操作、WebSQL、SQL 诊断、会话管理和数据导入导出等功能。
进入 ODC 首页后,在右上角单击“新建连接 ”按钮进行连接配置,首页的连接列表中可查看已保存的数据库连接。
单击上方导航栏中的 工作台 标签,在弹出下拉菜单中单击 SQL 窗口 以完成新建。 SQL 窗口中提供了可编辑脚本的 SQL 编辑区域,显示运行结果的执行记录页签与结果页签,同时也支持运行 PL 语句。
单击上方导航栏中的 工作台 标签,在弹出下拉菜单中单击 命令行窗口 (最多同时新建 3 个命令行窗口)以完成新建。 打开的窗口会自动连接到当前实例并显示一段默认代码展示连接的 ID、版本信息和帮助信息。
ODC提供的各种工具功能会生成对应的任务,可在任务中心查看对应的任务状态和任务详情信息。 登录 ODC 后,单击上方导航栏中的 任务 按钮会弹出 任务中心 面板,在面板中可查看对应任务的详细信息。
创建批量导入和单表导入任务后,可以进入目标数据库连接,单击上方导航栏中的任务标签弹出任务中心面板,在面板中单击导入页签展示任务列表。
任务列表仅会展示最近 48 小时内的任务,导入任务最大支持 3 个 并行,后续任务在队列中等待运行。
任务状态用于展示任务的当前状态,有 运行中、已终止、完成 和 失败 几种状态,不同状态可以对应 查看、重试、终止和删除 等不同的任务管理操作。
单击操作列中的查看按钮弹出目标任务的任务详情面板,在面板的右上角单击任务信息标签查看任务基本信息、导入文件信息和导入对象信息;单击 任务日志 标签查看任务的全部日志和告警日志,有 INFO、ERROR 和 WARN几种级别。
创建异步执行任务后,可以进入目标数据库连接,单击上方导航栏中的 任务 标签弹出任务中心面板,在面板中单击 模 拟数据 页签展示任务列表。
任务状态用于展示任务的当前状态,有 运行中、已终止、完成 和 失败 几种状态,不同状态可以对应 下载、查看、终 止 和 删除 等不同的任务管理操作。
单击操作列中的 查看 按钮弹出目标任务的任务详情面板,在面板的右上角单击任务信息标签查看任务基本信息和模 拟数据设置信息;单击 任务日志 标签查看任务的全部日志和告警日志,有 INFO、ERROR 和 WARN几种级别。
这个需要有管理员权限。
应用与数据库的连接被称为一个会话,在 ODC 会话管理页面可以查看连接到当前数据库所有会话的详细信息。 进入 ODC 对应的数据库连接后,单击页面上方导航栏的 会话 按钮,可选择进入 会话管理 页面。 在会话管理页面您可以查看连接到当前数据库的所有会话以及会话ID、用户、发起地址、数据库名称、会话状态、执行 命令类型、SQL执行时间、SQL语句、代理地址等。
进入 ODC 对应的数据库连接后,单击页面上方导航栏的 会话 按钮,可选择进入 会话属性 页面。 会话属性即数据库变量,ODC 提供的可视化界面可以清晰直观的查看和修改当前数据库支持的会话变量和全局变量:
在 ODC 中单击连接名进入连接后,在左导航栏中单击表标签可以查看表列表。 在表列表中双击表名进入表管理页面,可以在表管理页面的数据页签查看和修改表的数据,或在属性页签查看表的基本信息、列、分区、索引、约束和 DDL 等属性信息。
新建表
步骤一:设置基本信息
步骤二:设置列
步骤三:设置分区规则(可选)
步骤四:设置索引(可选)
步骤五:设置约束(可选)
当然也可以在SQL窗口通过create
表属性管理
左侧导航栏中单击表标签可查看表列表,双击表名进入表管理页面,单击上方导航栏中的 属性按钮进入属性页签。
表的基本信息
列信息
索引信息
约束信息
DDL语句信息
表数据管理
左侧导航栏中单击表标签可查看表列表,双击表名进入表管理页面,单击上方导航栏中的 数据按钮进入数据页签。 可对当前表中的数据进行查看、新增、修改和删除操作。
导出导入格式
ODC 支持的数据导出格式有 SQL 格式和 CSV 格式。
只读模式是可以导出数据的,如果上线涉及数据的导入导出。对于导出,可以找个客户量少的时间进行演练。
数值类型:
字符类型:
时间字段类型:
字符字段类型:
字段数目限制:
业务层面
存储过程、触发器的调用是否成功,前端不可控 。
业务的变更如果涉及到触发器、存储过程、外键等,需要数据库方面额外的操作及流程,不利于前端快速上线 。
触发器
部署在从库上,容易造成从库主从延迟、难于维护、需要考虑冗余成本增加。
部署在主库上,不仅导致系统写入性能受影响,触发器中的SQL在STATEMENT(默认同步模式) 下,不会写 BINLOG同步至从库,也就意味着若要数据同步,从库也得部署触发器,整个系统的性能降低。
触发器存在某些场景及版本下导致主从数据不一致,触发器失效等情况,比如自增主键主从不一致问题。
存储过程
其日志不利于问题追查定位,存储过程中涉及语句较多,而且循环较多。
从性能角度而言,复杂的判断和循环,消耗资源严重。存储过程中有算数运算,也会导致严重的性能问题,如从1 累加到1亿,其耗时将达到到5分钟,是C语言的1000倍
外键
禁止外键和级联:如无特殊情况,禁止使用外键和级联,一切外键必须在应用层解决。
外键与级联更新适用于单机低并发,不适合分布式、高并发集群。
级联更新是强阻塞,存在数据库更新风暴的风险;外键影响数据库的插入速度。 无庸置疑的带来性能上的问题,每次数据变更都需要对外键做检查。
外键给数据恢复带来非常大的困难,因为多个表上的外键依赖,使得数据恢复流程非常复杂。
运维角度
触发器、存储过程、外键等功能的容易使得系统处于异构状态,相对应的数据维护、变更等操作, 无论是研发人员或是DBA,都需要关注集群由此导致的特殊性,需专门记录、维护、操作各个功能所在的具体实例,且操作步骤复 杂,特别是在进行主从切换等操作的时候,也带来了更多的判断操作,极不利于统一运维。
特殊的实例意味着需要更多的冗余成本。
Select语句
DML语句
隐式转换
数字与字符之间的隐式转换。
出现隐式转换的SQL语句对应业务逻辑是没有问题,但在书写SQL时没有关注字段的类型,导致执行计划出现隐式转 换,影响SQL执行效率。主要体现在两类SQL上:
a)字段是数字类型,在查询的时候当成字符在使用 where id=’1’
b)字段是字符类型,在查询的时候当数字在使用where id=1
其中,b种情况会导致无法利用到索引而扫全表。在进行这种字段比值的时候,一定要做书写规范,做到数字=数字, 字符=字符。
JOIN表不推荐超过2个
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。