• [技术解读] GaussDB支持和约束
    GaussDB支持场景● 通常全量物化视图所支持的查询范围与CREATE TABLE AS语句一致。● 全量物化视图上支持创建索引。● 支持analyze、explain不支持场景物化视图不支持增删改操作,只支持查询语句。约束全量物化视图的刷新、删除过程中会给基表加高级别锁,若物化视图的定义涉及多张表,需要注意业务逻辑,避免死锁产生。
  • [技术解读] GaussDB全量物化视图
    GaussDB概述全量物化视图仅支持对已创建的物化视图进行全量更新,而不支持进行增量更新。创建全量物化视图语法和CREATE TABLE AS语法类似。使用语法格式● 创建全量物化视图CREATE MATERIALIZED VIEW [ view_name ] AS { query_block };● 刷新全量物化视图REFRESH MATERIALIZED VIEW [ view_name ];● 删除物化视图DROP MATERIALIZED VIEW [ view_name ];● 查询物化视图SELECT * FROM [ view_name ];示例--准备数据。gaussdb=# CREATE TABLE t1(c1 int, c2 int);gaussdb=# INSERT INTO t1 VALUES(1, 1);gaussdb=# INSERT INTO t1 VALUES(2, 2);--创建全量物化视图。gaussdb=# CREATE MATERIALIZED VIEW mv AS select count(*) from t1;CREATE MATERIALIZED VIEW 1--查询物化视图结果。gaussdb=# SELECT * FROM mv; count------- 2(1 row)--向物化视图中基表插入数据。gaussdb=# INSERT INTO t1 VALUES(3, 3);INSERT 0 1--对全量物化视图做全量刷新。gaussdb=# REFRESH MATERIALIZED VIEW mv;REFRESH MATERIALIZED VIEW--查询物化视图结果。gaussdb=# SELECT * FROM mv; count-------3(1 row)--删除物化视图。gaussdb=# DROP MATERIALIZED VIEW mv;DROP MATERIALIZED VIEW
  • [技术干货] GaussDB关键技术原理:高弹性(五)
    书接上文GaussDB关键技术原理:高弹性(四)从扩容流程框架方面对hashbucket扩容技术进行了解读,本篇将从日志多流和事务相关方面继续介绍GaussDB高弹性技术。4.2 日志多流本节介绍日志多流技术,hashbucket扩容的思路仍然是基线数据加增量数据,其中基线数据为bucket物理文件和bucket级CLOG文件,增量数据采用搬迁增量XLOG并回放日志的方式进行追增。日志多流只在hashbucket扩容期间动态的产生和使用,扩容框架会根据当前正在搬迁的bucket列表,解析并生成对应的日志流用来进行后续的数据追增。4.2.1 日志多流总体流程日志多流总体流程由gs_redis_bucket工具下发的MOVE BUCKETS语句触发,ALTER DATABASE database_name MOVE BUCKETS (bucket_list) FROM sender_dn TO receiver_dn;MOVE BUCKETS语句中包含如下信息:正在进行扩容重分布的库database_name,本批搬迁bucket列表的bucketlist,老节点为sender_dn,新节点receiver_dn。如图所示为日志多流示意图。主要涉及三个角色:老节点主DN(下简称老DN),新节点主DN(简称新DN),新节点备DN(简称备DN)。CN收到MOVE BUCKETS命令后转发给老DN和新DN。图1  日志多流示意图新DN收到MOVE BUCKETS命令后启动receiver线程,receiver线程负责与其他节点进行数据传输。receiver线程与老DN建立连接,老DN启动sender线程;receiver与备DN建立连接,备DN启动standby线程。sender、standby线程也负责与其他节点进行数据传输。建连后,receiver向sender发送BUCKETBASE请求,sender将对应于bucketlist的基线数据(包括bucket数据文件、CLOG文件等)发送给receiver。receiver再将基线数据转发给standby。另一方面,老DN收到MOVE BUCKETS命令后启动parser线程,将bucketlist对应的增量XLOG日志筛选出来放在bucketxlog目录下。待基线数据传输完成后,sender将增量XLOG日志发送给receiver,receiver转发给standby。日志传输完成后,新DN和备DN拉起startup线程,进入日志回放逻辑,通过回放增量xlog日志的方式,追加增量数据。因此,追增完成的判断分为两部分,一部分是parser解析到老DNbucketlist对应的最新LSN,另一部分新DN和备DN回放完所有存量bucketxlog。4.2.2 基线数据传输sender收到receiver的BUCKETBASE请求后向receiver传输基线数据。按照tablespaceoid map、bucket数据文件、CLOG文件的顺序进行传输。若包含备机,基线数据部分都需要传输到备机。tablespaceoid map包含sender节点上tablespace的name与oid的对应关系。由于sender和receiver分别在不同的DN上,同一个tablespace在不同DN上的tablespaceid可能是不同值,因此在日志回放前需要将日志中的tablespaceid及dbid替换成本地的tablespaceid及dbid。receiver根据name通过tablespaceoid map查到本地的tablespaceoid,在后续XLOG解析阶段进行替换。tablespaceid的映射关系需要传到备机。bucket数据文件是位于对应database的数据目录下形如 *_b* 的文件,如:/base/db_oid目录或/pg_tblspc/tblspc_oid/db_oid目录下的2_b1,2_b1.1,2_b1_fsm,2_b1_vm等。CLOG文件按bucket粒度拆分,在基线数据搬迁时,sender将对应bucket的所有CLOG文件均传输给receiver。CLOG搬迁涉及事务提交状态及可见性等问题,详见"事务相关" 小节。另外,在接收完成基线数据后,遍历有CBI索引的表,扫描对应bucket上的heap页面,插入索引作为基线数据,详见"CBI索引相关处理"小节。至此基线数据传输阶段完成,进入日志传输与回放阶段。4.2.3 日志传输与回放增量数据通过XLOG日志传输和日志回放的方式进行追增。首先sender节点的parser线程挑选出需要回放的日志并写入bucket_xlog目录。sender线程收到receiver的BUCKETXLOG请求后,从bucket_xlog目录读取日志传输给receiver。receiver节点的receiver线程将收到的XLOG日志转发给standby并写入bucket_xlog目录。最后startup线程启动回放工作线程进行回放。standby节点与receiver节点同理。4.2.3.1 日志流的处理(1)parser挑选bucketlist对应日志DML日志只涉及一个bucket,在发送和接收时只需要根据bucketlist过滤即可。而commit/abort日志则可能包含多个bucket,因此需要特殊处理:commit/abort日志只涉及一个bucket写日志时,则与DML日志一样,在header部分写入bucketid,在receiver回放时直接进行回放;commit/abort日志包含多个bucket,则在header部分写入一个特殊的id(ComboBktId),在receiver回放时,将无关的bucketid给过滤掉,只回放bucketlist中的bucketid。(2)日志格式修改将bucket日志从原来的XLOG中挑出来写到新的日志文件后,原来的LSN信息丢失了,这导致后面回放时LSN校验失败。为了保留原始的LSN值,在解析日志时将原始的LSN值写在bucket日志的后面,在回放前,用这个LSN值去替换日志的LSN。图2为日志格式修改示意图。图2 日志格式修改示意图(3)日志中元数据的处理日志多流技术中,新节点上的数据可能来自于不同的老节点,相同的tablespace及database在不同DN上对应的tablespaceid及dbid很可能是不同的,因此在日志回放前需要将日志中的tablespaceid及dbid替换成本地的tablespaceid及dbid。替换方法:dbid: 在进行重分布前,在内核中记录各个节点本次要重分布的dbid,在日志回放的解析日志阶段,把日志里所有的block里的dbid进行替换。tablespaceid: 由于tablespaceid可能会有多个,sender会把tablespace的name与id的对应关系传给receiver,receiver再根据name查出本地的tablespaceid,然后在解析阶段进行替换。tablespaceid的映射关系需要传到备机。4.2.3.2 回放的处理startup线程会拉起回放工作线程,包括pageredo线程、bucketwriter线程和bucketflush线程。同时使用私有缓冲区隔离,避免未上线前污染共有缓冲区。图3为日志回放示意图。图3 日志回放示意图pageredo线程负责日志回放,bucketwriter线程负责将私有缓冲区中的内容注册给bucketflush线程,bucketflush线程负责刷脏工作。同时新增共享变量,记录需要落盘的页面信息。bucketwriter线程负责把缓冲区中的所有内容记录到共享变量中,在后台轮询工作。bucketflush线程启动时会初始化本地hash表,bucketflush线程从共享变量中拷贝需要刷盘的信息到本地hash表中,完成落盘操作。以上所有操作均在startup线程存在期间完成,扩容上线逻辑会判断bucketwriter线程是否完成刷页,bucketwriter线程会等待bucketflush线程完成落盘,因此上线提交时能够保证所有页面已经完成落盘。如果此时发生故障,上线事务回滚,下次重入时本批bucket重新进行move bucket全逻辑,以保证数据正确性。4.2.4 CBI索引相关处理GaussDB针对hashbucket表有两种索引,bucket全局索引(跨bucket索引,cross-bucket index, CBI)和bucket本地索引(local-bucket index, LBI)。CBI索引为段页式存储,表现为只有一个bucketnode为1024的relation,索引元组中额外存储tablebucketid,从而缩小扫描范围;LBI索引为hashbucket类型的特殊段页式存储,同hashbucket表,pg_class中虽只有一条记录,存储层有bucketnode为[0-1023]的fake relation存在,索引扫描时需逐个遍历bucket索引。CBI索引比LBI索引少一层顺序遍历bucket的扫描,故查询性能显著提升。但由于CBI索引为段页式表,不会通过物理文件搬迁和bucket日志回放的方式进行重分布,故需对其进行特殊处理,思路仍然是基线数据+增量数据。图4为CBI索引基线数据构建与日志追增示意图。图4 CBI索引基线构建与追增示意图基线数据搬迁完后,启动cbi_insert_worker线程,使用私有缓冲区。遍历有CBI索引的表,扫描对应bucket上的heap页面,插入索引作为基线数据。全部CBI索引基线数据构建完成后,完成基线数据搬迁阶段,进入日志传输与回放阶段。CBI索引相关XLOG记录特殊bucketid,扩容时随日志流传输,作为扩容期间CBI增量数据的标记。启动回放线程时启动cbi_insert_worker线程解析CBI索引相关的记录了特殊bucketid的XLOG日志,提取数据后插入索引。4.3 事务相关4.3.1 CLOG拆分4.3.1.1 事务ID分配及CLOG/CSNLOG为了在数据库内部区别不同的写事务,GaussDB会为它们分配唯一的标识符,即事务id(transaction id,缩写xid),xid是uint64单调递增的序列,从FIRST_NORMAL_XACT_ID (3)开始分配。对于页面上的元组,xmin记录插入时的xid,xmax记录删除时的xid。当事务结束后,使用CLOG记录是否提交。对于每个xid,一共有4种状态:事务未开始或还在运行中、已经提交、已经回滚、子事务已经commit而父事务状态未知。可以用2个bit记录一个xid状态,所以8K的页面可以记录32K个xid状态。使用CSNLOG(commit sequence number log)记录该事务提交的序列,用于可见性判断。CSN是uint64单调递增的序列,从COMMITSEQNO_FIRST_NORMAL(3)开始分配。一个CSN占用8字节,所以一个8K的页面可以记录1K个xid状态。CSNLOG以及CLOG均采用了SLRU(simple least recently used,简单最近最少使用)机制来实现文件的读取及刷盘操作。4.3.1.2 CLOG拆分背景xid是由各个DN自己维护的。在hashbucket扩容中,不同源DN的CLOG可能会搬迁到同一个新DN。同一个xid在不同DN记录的提交状态可能不一样,无法用同一个CLOG去表示不同bucket的提交状态。例如DN1、DN2为源节点,DN3为新节点,扩容重分布过程中会把DN1和DN2中的CLOG日志搬到DN3。xid100的状态在DN1是已提交,在DN2是已回滚。因此,CLOG需要按bucket粒度拆分。拆分后的CLOG目录如下图5,路径为数据目录/pg_clog。子目录名1表示bucketid,文件名000000000000表示对应的CLOG段文件。对于非hashbucket表,每SLRU_PAGES_PER_SEGMENT(2048)个页面切分一个段文件,文件名长度为8;对于bucket子目录下的CLOG文件,每SLRU_CLOG_PAGES_PER_SEGMENT(4)个页面切分一个段文件,文件名长度为10。文件名长度不同是为了方便解析工具判断段文件最多可容纳的页面数。图5 CLOG磁盘目录4.3.1.3 CLOG拆分处理可见性判断图6 快照可见性判断流程图snapshot.xmin:获取快照时记录当前活跃的最小的xidsnapshot.snapshotcsn:当前最新提交的CSN号 + 1如上图6所示,xid对于当前快照是否可见的简化有步骤如下:(1) xid < snapshot.xmin,事务在快照开始前已经结束,根据CLOG状态判断是否提交:CLOG显示已提交,可见;否则,不可见。(2) xid≥snapshot.xmin,事务在快照开始前未结束,根据CSNLOG读取xid对应的CSN。(3) 如果CSN已提交,即CSN≥3,没有子事务标志,没有正在提交标志。如果CSN< snapshot.snapshotcsn,则可见,否则不可见。(4) 如果CSN正在提交,则等待事务结束,重入(3)判断。(5) 其他情况,不可见。图7 新节点快照可见性判断流程图图7为新节点快照可见性判断流程图。bucketxid:bucket粒度,在当前库,新节点产生的最小xidbucketcsn:bucket粒度,在当前库,来自源节点的最大CSNbucket上线后,CLOG和数据文件已搬迁,CSNLOG未搬迁。CLOG拆分后对可见性判断:老快照判断迁移数据的可见性:报错。因为CSNLOG未搬迁,无法读取CSN号;老快照判断新数据的可见性:元组是在bucket上线后插入的,即tuple.xmin > bucketxid。不可见;新快照判断迁移数据的可见性:通过CLOG;新快照判断新数据的可见性:正常可见性判断逻辑;4.3.2 xid调整4.3.2.1 xid调整背景图8 源节点、新节点xid范围示意图如上图8所示,新节点的每个bucket粒度的xid可以看成两段。左边一段是从源节点迁移过来的,也就是搬迁的CLOG中记录的。它的最大值next_xid是源节点下一个写事务分配的xid,最小值是最小活跃xid , 是源节点当前最小的需要通过CLOG读取事务状态的xid。Vaccum操作会清理掉页面中小于最小活跃xid的值,如果事务提交,则改为FROZEN_XACT_ID(2),表示对所有快照可见。如果事务回滚,则清理掉对应元组。右边一段是新节点业务生成的,最小的xid是bucket在第一个库的上线事务对应的id,记为bucketxid。这个值可以在pg_hashbucket系统表的bucketxid列获取。如果不调整xid, 那么新节点业务生成的xid和从源节搬迁过来的xid就有重合的问题,导致可见性判断错误。例如DN1为源节点,DN2为新节点。重分布前,bucket1的xid100的状态在DN1是已提交。DN2的xid没有调整,是从3开始分配的。bucket1在DN2上线后,使用xid100,并且状态为已回滚。那么在DN2读取迁移数据中的xid100提交状态错误。4.3.2.2 xid调整流程在加节点过程中,会调整新节点下一个要分配的xid,图9为xid调整流程图。图9  xid调整流程图根据源节点下一个要分配的xid(对应图中的next_xid)和业务对xid的消耗量计算新节点的预期xid计算exp_xid。计算下一步调整到的xid为next_step_xid = min(exp_xid, 新节点next_xid + 10亿)。这里需要分步调整xid。页面的xid取值范围依赖当前的最小活跃xid。如果一次设置为预期值,最小活跃事务号没有办法及时更新,则新设置的xid可能会超过已有页面的xid合法表达范围,出现写业务报错。如果新节点next_xid < exp_xid,设置新节点next_xid为next_step_xid,并等待当前活跃事务的最小值推进,更新next_step_xid,直到next_xid不小于预期值。4.3.3 bucket锁类似于常规锁的表锁,对于hashbucket表,物理文件是库级bucket化的,扩容过程也是按照bucket级别上线的,因此引入一种新型的锁——bucket锁,每个bucket对应一把锁。只有用户业务的场景,DML和DDL业务间的并发仍然通过表锁实现,所有业务都拿bucket的一级锁。当用户扩容时,此时会发生bucket文件的搬迁,同时实现元数据从老节点下线,新节点上线的动作,此时需要通过bucket锁对用户业务做互斥。因此,bucket锁主要用在hashbucket在线扩容期间bucket在新节点上线时和在线业务做互斥,保证业务数据正确。新增如下的语法来实现这一功能:LOCK BUCKETS(bucketlist) IN LOCK_MODE [CANCELABLE];其中,bucketlist如0,1,2,3表示次轮上线的bucket桶号,取值范围0-1023;LOCK_MODE只有两种级别:ACCESS SHARE MODE和ACCESS EXCLUSIVE MODE增加可选项[CANCELABLE]表示是否通过cancel用户业务而保证扩容拿到锁。在线业务和扩容的交互如下图10所示:图10  xid调整流程图t1时刻:对bucket 0操作的DML在上线事务之前的拿锁成功,数据重分布上线事务拿bucket 0的8级锁处于等待状态,排在数据重分布上线事务之后其它线程对于bucket 0的访问等在上线事务的8级锁上。t2时刻:排在上线事务之前的用户业务放锁,上线事务持8级锁成功,之后所有访问bucket 0的用户业务均阻塞。t3时刻:bucket 0在老节点下线,新节点上线,用户业务拿到bucket 0的锁获取最新的数据分布方式。如果CN上能确定当前操作的bucket,则在CN上拿对应bucket的1级锁,如果不能确定则在DN上拿锁,通过前文提到过的pg_hashbucket记录的bucketlist进行过滤。扩容上线的LOCK BUCKETS语句现在执行CN拿锁成功再发送到其它所有CN和DN拿锁,全部成功则成功。以上内容从hashbucket扩容方面对GaussDB高弹性能力进行了解读,下篇将从扩容实践方面继续介绍GaussDB高弹性技术,敬请期待! 
  • [技术解读] GaussDB关键技术原理:高弹性(四)
    书接上文GaussDB关键技术原理:高弹性(三)从段页式技术方面对GaussDB高弹性能力进行了解读,本篇将从hashbucket扩容方面继续介绍GaussDB高弹性技术。4 hashbucket扩容基于hashbucket表的扩容整体流程主要包含三个步骤:基线数据搬迁:生成扩容搬迁计划,根据搬迁计划中对涉及的库中的bucket文件进行跨节点文件搬迁。包含库级别的数据文件和实例级别的事务日志。bucket日志流追增:识别bucket扩容过程中的增量修改,将对应的日志发送到目的节点并在目的端进行增量修改的日志回放。bucket元数据切换:当bucket日志流追增完成后,原节点和目的节点的bucket数据达到一致状态,可以对原节点的bucket进行下线删除,对目的节点的bucket进行上线操作,同时修改CN上的bucket map映射使新的业务能够路由到正确的DN节点。如下图1所示以DN节点2扩3为例描述hashbucket扩容的详细流程:图1  hashbucket扩容流程(以DN由2扩3为例)(1) CN从扩容工具测处收到MOVE BUCKETS搬迁命令;(2) CN解析后分别给DN1、DN2、DN3(目标DN)下发搬迁命令;(3) DN1/DN2将迁移bucket目录(包含数据及事务日志)拷贝到目标DN3上;    (4) DN3收到命令后,进入receiver逻辑,与DN1/DN2建立连接,DN1/DN2进入sender逻辑,将相关bucket的日志解析出来发送给DN3;(5) bucket目录拷贝完成后,DN3回放收到的bucket日志,进行追增;(6) 完成最后一轮的追增后CN上切换bucket group,DN1/DN2上的旧bucket进行清除。4.1 扩容流程框架  本节详细介绍hashbucket扩容流程框架,其主流程在gs_redis_bucket工具中实现,主要包括扩容迁移计划、扩容期间元数据处理、扩容状态与统计信息、扩容上线策略等部分。进入重分布流程首先做一些前置处理,从系统表读取并设置重分布参数,以便后续扩容流程使用。在内核中记录本次重分布的database信息,以便后续解析日志使用。调用CHECKPOINT进行一次刷盘,作为后续日志回放的起始点。4.1.1 获取扩容迁移计划 介绍扩容迁移计划前首先介绍NodeGroup相关概念。PGXC_GROUP系统表存储节点组信息,其每一行均为一个NodeGroup相关信息,其中与扩容迁移计划相关的字段如表1所示。表1 系统表PGXC_GROUP部分字段 名称类型描述oidoid行标识符(隐含字段,必须明确选择)。group_namename节点组名称。in_redistribution"char"是否需要重分布。取值包括n,y,t。n:表示NodeGroup没有再进行重分布。y:表示NodeGroup是重分布过程中的源节点组。group_membersoidvector_extend节点组的节点OID列表。group_bucketstext分布数据桶所在节点编号的集合。is_installationboolean是否安装子集群。t(true):表示安装。f(false):表示不安装。bucket_maptext物理bucket与逻辑bucket的映射关系。首先介绍物理bucket和逻辑bucket的概念。GaussDB中数据分布在16384个bucket中,记为逻辑bucket。为减少文件数量过多资源浪费问题,引入物理bucket概念,DN内部存储采用物理1024个bucket。如图2所示为3DN集群的物理逻辑bucket映射关系示意图,每一个方格代表一个逻辑bucket,用 ',' 分隔;每一行代表一个物理bucket,用 ';' 分隔;同一行的逻辑bucket组成一个物理bucket。    图2 物理逻辑bucket映射关系示意图group_buckets为一个16384长度的数组,表示每个逻辑bucket所在节点的编号,可以表示数据在节点上的分布。工具根据当前绑定NodeGroup与目标NodeGroup中bucket分布(group_buckets)的差异,即可计算出所有需要迁移的buckets。再将这些待迁移的bucket按照扩容链路(即从哪个原DN迁移到哪个新DN)分类,即可得到迁移计划。图3为2DN扩3DN的搬迁计划与bucket分布示意图。    图3 2DN扩3DN迁移计划与bucket分布示意图4.1.2 扩容主流程相关线程 在获取迁移计划后,工具开始当前database的扩容主流程。扩容重分布过程涉及gs_redis_bucket工具的三个线程:主线程、监控线程、上线事务线程。图4为gs_redis_bucket工具中扩容流程相关线程示意图。图4  扩容流程工具相关线程示意图(1)主线程根据迁移计划向内核发送MOVE BUCKETS命令,其格式为:ALTER DATABASE database_name MOVE BUCKETS (bucket_list) FROM sender_dn TO receiver_dn;例如:ALTER DATABASE my_database MOVE BUCKETS (0,1,2) FROM dn_6001_6002_6003 TO dn_6010_6011_6012;MOVE BUCKETS命令是hashbucket扩容重分布的核心命令,完成了基线数据搬迁和日志追增,MOVE BUCKETS命令在内核中的实现详见“日志多流”小节。其中单次MOVE BUCKETS命令搬迁bucket的个数(即bucket_list长度)越小对业务影响越小。同时为降低扩容重分布对业务的影响,sender DN和receiver DN的并发度均为1,即sender DN同一时刻最多只能处理一条MOVE BUCKETS语句,receiver DN同一时刻最多只能处理一条MOVE BUCKETS语句。主线程根据迁移计划与内核建立连接链路并发送MOVE BUCKETS命令,当有MOVE BUCKETS执行完毕退出后,主线程会检查是否可以发送新的MOVE BUCKETS命令(优先继续发送原链路剩余的buckets;如原链路已发送完毕,则选择新链路发送),直到迁移计划中的所有bucket全部通过MOVE BUCKETS命令完成迁移。以2DN扩5DN为例,其扩容计划可以用下图来简要表示。假设当前设置单次搬迁个数为150,则主线程会首先发送【DN1àDN3, (0,1,…,149)】与【DN2àDN4, (512,513,…,614)】到内核(此时另外两条链路由于并发度限制无法发送)。假设第一条命令首先执行完毕返回,由于此时该链路上还有剩余buckets,因此会继续发送【DN1àDN3, (150,151,…,204)】。假设【DN2àDN4】命令随后执行完毕返回,由于该链路所有bucket已发送完毕,则选择新链路命令【DN2àDN5, (615,616,…,764)】发送(此时【DN1àDN4】不满足DN1并发度限制)。  图5  2DN扩5DN迁移计划示意图需要注意的是,MOVE BUCKETS命令并不会自行结束返回,需要与上线事务线程配合,等待该命令中的所有BUCKETS完成迁移并上线后才会返回。(2)监控线程由主线程创建,在主线程发送MOVE BUCKETS命令后开始运行。其主要任务有二:一是通过调用扩容统计信息函数定期轮询(1s)监测每个bucket的迁移状态和业务负载等信息;二是根据上线策略判断是否有某些bucket处于可上线状态(见“扩容上线策略”部分),若是,则创建上线事务线程进完成这些bucket的新节点上线。当全部bucket均已上线时退出监控线程。(3)上线事务线程在监控线程判断某些bucket可以进行上线时由监控线程创建,用于完成上述bucket的上线步骤。首先获取这些待上线的bucket的bucket锁(详见“bucket锁”小节),阻塞相应bucket上的所有业务,确保没有增量日志产生,然后完成最后的日志追增且保证回放数据全部落盘,最后切换NodeGroup完成上述buckets上线。在上线事务线程中,可能会出现两种异常场景导致上线失败:拿锁超时与持锁超时。拿锁超时指的是在给定时间阈值内无法成功拿到bucket级锁而终止此次上线;持锁超时指的是在拿到bucket级锁之后在给定时间阈值内无法完成日志追增与私有缓冲区落盘,为避免长时间阻塞业务而终止此次上线。若出现拿锁超时或持锁超时,上线事务线程会退出,此时监控线程将对这一事件进行记录。对于这些bucket将被惩罚在一段时间内不再尝试上线(见“扩容上线策略”部分)。进一步地,当存在bucket超过最大拿锁超时次数或持锁超时次数时,gs_redis_bucket将主动退出自动重入。对于上线事务线程的LOCK BUCKET语句,如果参数enable_cancel设置为true且存在至少一个bucket的拿锁超时的次数或持锁超时的次数不小于相应最大超时次数的1/2(向下取整),则LOCK BUCKETS语句将添加CANCELABLE关键字,会尝试主动取消业务。如果参数enable_cancel设置为false,则LOCK BUCKETS语句永远不会添加CANCELABLE关键字。   4.1.3 扩容期间元数据处理(1) 更新SegmentHeaderhashbucket扩容方案中,新DN是由CN build出来的,新DN上hashbucket表元数据在新DN 大段页式1号文件中的类型是SegmentHead且没有对应小段页式1号文件SegmentHead所在的页号,无法进行对应bucket的数据管理。且新DN上hashbucket表在pg_class中的relbucket列为1而不是3,需要在日志回放前统一修改元数据支持扩容。(2) 更新反向指针hashbucket表扩容后新DN上小段页式数据文件中SegmentHead反向指针记录所属的owner可能不正确,应该修改为新DN主表的relfilenode。在扩容工具gs_redis_bucket中,某一批bucket上线前执行更新操作。更新的方式特殊处理,从新DN获取hashbucket表的relfilenode作为反向指针的owner,在源DN执行更新操作,只记录XLOG不实际更新,通过日志流的方式同步到新DN。新DN通过日志回放,完成反向指针更新。4.1.4 扩容状态与信息统计   gs_redis_bucket通过gs_redis_get_bucket_statistics(扩容统计信息)系统函数在扩容期间查询每个bucket的迁移状态与业务负载情况,系统函数返回值如下表所示。表2 扩容统计信息函数返回值 名称类型描述bucket_idOIDbucket idredis_stateINT1bucket的扩容状态,0表示扩容未开始,1表示扩容基线数据已完成。xlog_countINT8bucket在当前database扩容开始后,在原DN产生的XLOG数量。sndr_latest_lsnINT8bucket在当前database扩容开始后,在原DN产生的最新LSN。parser_latest_lsnINT8bucket在当前database扩容开始后,被原DN的扩容相关线程解析到的最新LSN。parser_latest_lsn_newINT8bucket在当前database扩容开始后,被原DN的扩容相关线程解析到bucketxlog的最新LSN。rcvr_redo_latest_lsnINT8bucket在当前database扩容开始后,被新DN的扩容相关线程回放到的最新LSN。rcvr_redo_latest_lsn_newINT8bucket在当前database扩容开始后,被原DN的扩容相关线程解析到bucketxlog的最新LSN。rcvr_checkpointINT8bucket在当前database扩容开始后的CHECKPOINT点。rcvr_redo_start_lsnINT8bucket在当前database扩容开始后,回放开始的原始LSN。上述扩容相关信息在GaussDB内核中的全局变量中存储与更新。gs_redis_bucket通过在定时轮询扩容统计信息系统函数来获取各bucket的以上信息。redis_state字段可以用来指示当前bucket是否完成基线迁移;xlog_count字段的值随时间的变化可以反映当前bucket的业务负载情况;而LSN相关字段则可以反映当前bucket的日志追增情况。具体来说,bucket的日志追增剩余量由两部分组成:第一部分为sndr_latest_lsn到parser_latest_lsn的差值,该部分对应原DN的parser线程尚未解析的日志;第二部分为parser_latest_lsn_new到rcvr_redo_latest_lsn_new,该部分对应原DN的parser线程已解析但尚未被新DN回放的日志。需要说明的是,parser_latest_lsn_new与rcvr_redo_latest_lsn_new是为日志多流传输框架要传输的bucket日志流封装的一层新LSN,以过滤掉其他bucket或非bucket模式的日志。以上信息可以帮助判断bucket的上线时机并检验bucket是否完成日志追增。   4.1.5 扩容上线策略扩容上线策略主要用来在监控线程中判断哪些bucket在扩容期间进入日志追增阶段后可以准备上线。可以准备上线的buckets需要满足以下四个条件:已完成基线搬迁且已执行更新反向指针操作、处于业务低负载时间、日志追增框架剩余追增量小、bucket不在上次上线失败后的惩罚时间内。(1) bucket是否已完成基线搬迁通过扩容统计信息系统函数返回的redis_state获取,其值会在receiver端完成基线文件传输后赋值,便于判断元数据处理的时机。此外,bucket还需要在监控线程基线传输完成后完成更新反向指针的操作。(2) bucket是否处于业务低负载时间通过记录每个bucket的历史负载来判断。扩容上线策略在监控线程中定期轮询所有扩容中的buckets的统计信息(即xlog_count)并记录。因此,监控线程可以掌握每个bucket在扩容期间的历史负载情况。由于bucket上线需要对其上锁,为减小对业务的影响,扩容上线策略应当尽量选择在bucket低历史负载期间进行上线操作。(3) 日志剩余追增量通过统计信息系统函数返回的LSN相关字段来计算,即(parser_latest_lsn - sndr_latest_lsn) + (rcvr_redo_latest_lsn_new - parser_latest_lsn_ new)。当追增量小于给定阈值时,判断其满足条件。(4) 若当前bucket在此前的上线事务线程中由于拿锁超时或持锁超时而终止上线,则会为该bucket指定一段惩罚时间,在惩罚时间内不允许该bucket上线。监控线程的上线策略在上线事务线程未在运行时选择满足上述(1)-(4)条件的所有buckets,并创建上线事务线程完成这些buckets的上线,上线事务线程会完成这些buckets的上线。随后监控线程会继续选择新的满足上线策略的buckets,并再次创建上线事务线程完成新一轮的上线,重复动作直到所有buckets均上线完成。以上内容从hashbucket扩容技术方面对GaussDB高弹性能力进行了解读,下篇将从日志多流和事务相关方面继续介绍GaussDB高弹性技术,敬请期待! 
  • [技术解读] GaussDB SQL 中的BOOLEAN表达式介绍
    一、前言SQL是用于访问和处理数据库的标准计算机语言。GaussDB支持的SQL标准(默认支持SQL2、SQL3和SQL4的主要特性)。本系列将以《云数据库GaussDB—SQL参考》为主线进行介绍。二、GaussDB SQL 中的BOOLEAN表达式介绍1、概念 在GaussDB数据库中,BOOLEAN表达式是一种很常见的表达式类型,它用于比较两个条件,来确定其是否为真或假。BOOLEAN表达式可以用于条件判断或在循环语句中作为终止条件。其语法非常简单,只需要使用逻辑运算符对两个条件进行比较。GaussDB SQL支持AND、OR等逻辑运算符,这些运算符可以将结果组合成更复杂的布尔表达式。2、组成 运算符:比较运算符(如=、<>、<、>、<=、>=)和逻辑运算符(如AND、OR、NOT等)。 操作数:用于比较的字段值或常量。 3、语法示例 如下截图是游标使用中的SQL部分,SQL中涉及到BOOLEA表达式用于条件判断和循环语句部分,可参考:1)条件判断,见红色方框“v_salary>=20000”,在这个例子中,当v_salary >= 20000 时,则执行THEN 后面的 UPDATE语句。2)循环语句,见蓝色方框“%NOTFOUND”,是游标的属性之一,用于控制程序流程或者了解程序的状态。当最近的DML(数据操作语言)操作(如INSERT,UPDATE,DELETE等)没有影响任何行时,该属性为真。'EXIT WHEN c1%NOTFOUND;' 就会执行。三、在GaussDB SQL中的基础应用 使用布尔表达式可以根据特定条件对结果进行过滤,只返回满足条件的数据。以下是一些在SELECT列表中使用布尔表达式的示例。1、示例1,使用比较运算符 --根据工资是否大于2w判断其是否为高工资,返回TRUE或FALSESELECT * ,(salary > 20000) AS high_salary FROM company;上述SQL示例中,我们从company表中选择name、age、address、salary和一个布尔表达式(salary > 20000),该表达式用于判断员工的工资是否高收入。 结果集中的high_salary列将显示布尔值TRUE或FALSE。2、示例2,使用逻辑运算符 --根据年龄是否在18-60之间,判断其是否为有效年龄,返回TRUE或FALSESELECT * ,(age >= 18 AND age <= 60) AS valid_age FROM company;上述SQL示例中,我们从company表中选择name、age、address、salary和一个布尔表达式(age >= 18 AND age <= 60),该表达式用于判断员工的年龄是否有效。 结果集中的valid_age列将显示布尔值TRUE或FALSE。3、示例3,使用IS NOT NULL运算符 --判断地址是否为空,返回TRUE或FALSESELECT * ,(address IS NOT NULL) AS null_address FROM company;上述SQL示例中,我们从company表中选择name、age、address、salary和一个布尔表达式(address IS NOT NULL),该表达式用于判断员工的地址是否为空值。 结果集中的null_address列将显示布尔值TRUE或FALSE。4、示例4,使用like模式匹配操作符 LIKE:判断字符串是否能匹配上LIKE后的模式字符串。如果字符串与提供的模式匹配,则LIKE表达式返回为真(NOT LIKE表达式返回假),否则返回为假(NOT LIKE表达式返回真)。--判断地址是否是CN,返回TRUE或FALSESELECT * ,(address LIKE 'CN%') AS c_address FROM company;上述SQL示例中,我们从company表中选择name、age、address、salary和一个布尔表达式(address LIKE 'CN%'),该表达式用于判断员工的地址是否在CN。 结果集中的c_address列将显示布尔值TRUE或FALSE。附:在GaussDB SQL中还有一个模式匹配操作符SIMILAR TO。描述:SIMILAR TO操作符根据自己的模式是否匹配给定串而返回真或者假。他和LIKE非常类似,只不过他使用SQL标准定义的正则表达式理解模式。四、小结BOOLEAN表达式在SQL中非常常用,它们允许开发人员构建逻辑语句,这些语句能够对表中的数据进行复杂的过滤和选择。通过使用布尔表达式,查询结果可以缩小到满足特定条件的行,或者可以根据这些条件对数据进行聚合和分组。总之,布尔表达式可以帮助我们进行逻辑判断和循环控制,提高代码的可读性。 熟练掌握BOOLEAN表达式的使用,在GaussDB SQL等开发过程中非常重要。——结束​
  • [运维管理] max_prepared_transactions这个参数的值小于max_connections这个参数的值有什么影响吗
    max_prepared_transactions这个参数的值小于max_connections这个参数的值有什么影响吗?备节点不会执行语句?还是会直接报错?可确保每个会话都有一个等待中的预备事务。什么是预备事务?
  • [技术解读] GaussDB选择分布列
    Hash分布表的分布列选取至关重要,需要满足以下原则:列值应比较离散,以便数据能够均匀分布到各个DN。例如,考虑选择表的主键为分布列,如在人员信息表中选择身份证号码为分布列。在满足第一条原则的情况下尽量不要选取存在常量filter的列。例如,表t1相关的部分查询中出现t1的列zqdh存在常量的约束(例如zqdh=’000001’),那么就应当尽量不用zqdh做分布列。在满足前两条原则的情况,考虑选择查询中的连接条件为分布列,以便Join任务能够下推到DN中执行,且减少DN之间的通信数据量。对于Hash分表策略,如果分布列选择不当,可能导致数据倾斜,查询时出现部分DN的I/O短板,从而影响整体查询性能。因此在采用Hash分表策略之后需对表的数据进行数据倾斜性检查,以确保数据在各个DN上是均匀分布的。可以使用以下SQL检查数据倾斜性select xc_node_id, count(1) from tablename group by xc_node_id order by xc_node_id desc;其中xc_node_id对应DN,一般来说,不同DN的数据量相差5%以上即可视为倾斜,如果相差10%以上就必须要调整分布列。GaussDB支持多分布列特性,可以更好地满足数据分布的均匀性要求。
  • [技术解读] GaussDB使用分区表
    分区表是把逻辑上的一张表根据某种方案分成几张物理块进行存储。这张逻辑上的表称之为分区表,物理块称之为分区。分区表是一张逻辑表,不存储数据,数据实际是存储在分区上的。分区表和普通表相比具有以下优点:改善查询性能:对分区对象的查询可以仅搜索自己关心的分区,提高检索效率。增强可用性:如果分区表的某个分区出现故障,表在其他分区的数据仍然可用。方便维护:如果分区表的某个分区出现故障,需要修复数据,只修复该分区即可。GaussDB支持的分区表为范围分区表。范围分区表:将数据基于范围映射到每一个分区。这个范围是由创建分区表时指定的分区键决定的。分区键经常采用日期,例如将销售数据按照月份进行分区。
  • [技术解读] GaussDB产品优势
    高安全GaussDB拥有TOP级的商业数据库安全特性:数据动态脱敏,TDE透明加密,行级访问控制,密态计算。能够满足政企&金融级客户的核心安全诉求。健全的工具与服务化能力GaussDB已经拥有华为云,商用服务化部署能力,同时支持DAS、DRS等生态工具。有效保障用户开发、运维、优化、监控、迁移等日常工作需要。全栈自研GaussDB基于鲲鹏生态,是当前国内唯一能够做到全栈自主可控的国产品牌。同时GaussDB能够基于硬件优势在底层不断进行优化,提升产品综合性能。开源生态GaussDB已经支持开源社区,并提供主备版版本下载。
  • [技术解读] GaussDB权限
    默认情况下,管理员创建的IAM用户没有任何权限,需要将其加入用户组,并给用户组授予策略或角色,才能使得用户组中的用户获得对应的权限,这一过程称为授权。授权后,用户就可以基于被授予的权限对云服务进行操作。GaussDB部署时通过物理区域划分,为项目级服务。授权时,“作用范围”需要选择“区域级项目”,然后在指定区域(如华北-北京1)对应的项目(cn-north-1)中设置相关权限,并且该权限仅对此项目生效;如果在“所有项目”中设置权限,则该权限在所有区域项目中都生效。访问GaussDB时,需要先切换至授权区域。根据授权精细程度分为角色和策略。角色:IAM最初提供的一种根据用户的工作职能定义权限的粗粒度授权机制。该机制以服务为粒度,提供有限的服务相关角色用于授权。由于华为云各服务之间存在业务依赖关系,因此给用户授予角色时,可能需要一并授予依赖的其他角色,才能正确完成业务。角色并不能满足用户对精细化授权的要求,无法完全达到企业对权限最小化的安全管控要求。策略:IAM最新提供的一种细粒度授权的能力,可以精确到具体服务的操作、资源以及请求条件等。基于策略的授权是一种更加灵活的授权方式,能够满足企业对权限最小化的安全管控要求。例如:针对GaussDB服务,管理员能够控制IAM用户仅能对某一类数据库资源进行指定的管理操作。多数细粒度策略以API接口为粒度进行权限拆分。
  • [技术干货] GaussDB模式匹配操作符详细介绍
    本文作者:墨竹GaussDB模式匹配操作符详细介绍GaussDB数据库目前提供了三种独立的实现模式匹配的方法,分别为LIKE操作符、SIMILAR TO操作符和POSIX-风格的正则表达式 。除了这些基本的操作符外,还有一些函数可用于提取或替换匹配子串并在匹配位置分离一个串。1、likelike应该是我们经常使用的方式,判断字符串是否能匹配上LIKE后的模式字符串,如果匹配,则LIKE表达式返回为真(NOT LIKE表达式返回假),否则返回为假(NOT LIKE表达式返回真)。如果不添加%或_,即全部字符串匹配相当于=;如果要匹配在字符串内的任何位置,该模式必须以%开头和结尾。规则说明%任意字符串的通配符_(匹配)任何单个字符\\ 、%、\_转义字符,查询的内容中需要匹配%、_、\,需要在前面添加\like大小写敏感即区分大小写ilike大小写不敏感即不区分大小写通配符openGauss=# SELECT 'abc' LIKE 'abc' AS RESULT; result -------- t (1 row) openGauss=# SELECT 'abc' LIKE 'a%' AS RESULT; result -------- t (1 row) openGauss=# SELECT 'abc' LIKE '%b%' AS RESULT; result -------- t (1 row) openGauss=# SELECT 'abc' LIKE '_b_' AS RESULT; result -------- t (1 row) openGauss=# SELECT 'abc' LIKE 'c' AS RESULT; result -------- f (1 row) 是否区分大小写openGauss=# select 'abc' like 'A%' as result; result -------- f (1 row) openGauss=# select 'abc' ilike 'A%' as result; result -------- t (1 row) ESCAPE子句指定其他逃逸字符下面案例中的模式字符串’abc$%%’,第一个%由于自定义了逃逸字符$,因此$%作为一个普通字符存在,只需要匹配查询的内容中包含有%;最后一个%则是通配符作用openGauss=# with tmp as (select 'abc%def' as result union all select 'abcdef' as result) openGauss-# select * from tmp where result like 'abc$%%' escape '$'; result --------- abc%def (1 row) 2、SIMILAR TOSIMILAR TO的用法和LIK非常类似,其结果也是根据匹配结果返回真假。另外比较特殊的就是支持使用SQL标准定义的正则表达式理解模式,支持的规则除了%和_之外,也支持下面这些从POSIX正则表达式借用的模式匹配元字符。元字符含义|表示选择(两个候选之一)*表示重复前面的项零次或更多次,可以理解为任意次+表示重复前面的项一次或更多次?表示重复前面的项零次或一次{m}表示重复前面的项刚好m次。{m,}表示重复前面的项m次或更多次{m,n}表示重复前面的项至少m次并且不超过n次()把多个项组合成一个逻辑项,就相当于把整个()内的内容作为匹配项[…]声明一个字符类,就像POSIX正则表达式一样针对上述描述重复的次数,是指元字符修饰的字符或者字符组重复多少次,不要理解为该字符或字符组可以和源字符串可以匹配多少次常见元字符使用--|元字符 openGauss=# SELECT 'abc' SIMILAR TO '%(af|bc)%' AS RESULT; result -------- t (1 row) --*元字符 --当前的*时,即使没有可匹配的内容,也返回的是true openGauss=# SELECT 'abc' SIMILAR TO '%(o)*%' AS RESULT; result -------- t (1 row) openGauss=# SELECT 'abcdefosp' SIMILAR TO '%(o)*%' AS RESULT; result -------- t (1 row) --+元字符,该示例由于一次也未匹配到,所以返回false openGauss=# SELECT 'abc' SIMILAR TO '%(o)+%' AS RESULT; result -------- f (1 row) --+元字符,该示例匹配到多次o,所以返回true openGauss=# SELECT 'abcdefooosp' SIMILAR TO '%(o)+%' AS RESULT; result -------- t (1 row) --?元字符,,该示例未匹配,返回结果也是true openGauss=# SELECT 'abc' SIMILAR TO '%(o)?%' AS RESULT; result -------- t (1 row) --{m,n}元字符,对于字符组oo,需要至少匹配2次,即为oooo,可知原字符串不符合结果,返回结果为false。 openGauss=# SELECT 'abcoodefoooosp' SIMILAR TO '%(oo){2,3}%' AS RESULT; result -------- f (1 row) SELECT 'abcoodefoooosp' SIMILAR TO '%(oo){2,3}%' AS RESULT; 3、POSIX正则表达式正则表达式是一个字符序列,它是定义一个串集合(一个正则集)的缩写。 如果一个串是正则表达式描述的正则集中的一员时, 我们就说这个串匹配该正则表达式。 POSIX正则表达式提供了比LIKE和SIMILAR TO操作符更强大的含义。列出了所有可用于POSIX正则表达式模式匹配的操作符。正则表达式匹配操作符操作符描述例子~匹配正则表达式,大小写敏感,等价与like‘thomas’ ~ ‘.thomas.’~*匹配正则表达式,大小写不敏感,等价与ilike‘thomas’ ~* ‘.Thomas.’!~不匹配正则表达式,大小写敏感,等价与not like‘thomas’ !~ ‘.Thomas.’!~*不匹配正则表达式,大小写不敏感,等价与not ilike‘thomas’ !~* ‘.vadim.’--匹配正则表达式,大小写敏感 openGauss=# SELECT 'abc' ~ 'Abc' AS RESULT; result -------- f (1 row) --匹配正则表达式,大小写不敏感 openGauss=# SELECT 'abc' ~* 'Abc' AS RESULT; result -------- t (1 row) --不匹配正则表达式,大小写敏感 openGauss=# SELECT 'abc' !~ 'Abc' AS RESULT; result -------- t (1 row) --不匹配正则表达式,大小写不敏感 openGauss=# SELECT 'abc'!~* 'Abc' AS RESULT; result -------- f (1 row) 匹配规则与LIKE不同,正则表达式允许匹配串里的任何位置,除非该正则表达式显式地挂接在串的开头或者结尾。除了上文提到的元字符外, POSIX正则表达式还支持下列模式匹配元字符。元字符含义\转义字符^表示串开头的匹配$表示串末尾的匹配.匹配任意单个字符(abc)把多个字符组合成一个匹配原子,就相当于把整个()内的内容作为匹配项[abc]匹配abc中的任何一个字符,内部可以嵌套(abc),然后这个做一个原子,比如:[abc(de)][^abc]负值字符集合。匹配未包含的任意字符。例如,[^abc]可以匹配“plain”中的“plin”任一字符。|表示选择(两个候选之一)例如: a|b\d匹配任何数字,就像 [[:digit:]]\s匹配任何空白字符,就像 [[:space:]] ,包括空格、制表符和换行\w匹配任何单词字符,就像 [[:word:]]\D匹配任何非数字,就像 [^[:digit:]]\S匹配任何非空白字符,就像 [^[:space:]]\W匹配任何非单词字符,就像 [^[:word:]]\A只在串开头匹配(与^的不同)\m只在一个词的开头匹配\M只在一个词的末尾匹配\y只在一个词的开头或末尾匹配\Y只在一个词的不是开头或末尾的点上匹配\Z只在串的末尾匹配(与$的不同)\r回车常见元字符使用--()匹配规则 openGauss=# select 'abc' ~ '(ab|ac)' as result; result -------- t (1 row) --[]匹配规则,其中的任何一个字符匹配到源字符串就返回true openGauss=# select 'abc' ~ '[bef]' as result; result -------- t (1 row) --[^abc],只要源字符串含有非限定范围的字符,就返回true openGauss=# select 'china' ~ '[^abc]' as result; result -------- t (1 row) --匹配空白字符 openGauss=# select 'china ' ~ '\s' as result; result -------- t (1 row) 匹配两个词组查询场景下面的案例主要就是查询数据库会话中使用is not null或者is null语法的场景--如果两个词组中间只包含空格,可以直接添加\s,另外还需要考虑有多个空白的时候,因此也需要添加量词来修饰,可以添加+ openGauss=# select 'select * from t1 where is not null' ~ '(is)\s+(not)' as result; result -------- t (1 row) --如果两个词组中间包含不固定的字符且至少有一个字符,可以添加 .+来指定任意字符; openGauss=# select 'select * from t1 where is not null' ~ '(is).*(null)' as result; result -------- t (1 row) --如果两个词组中间,可能存在not字符串且不存在其他字符串,可以适用((not)?\s+)修饰not字符串的匹配规则,外层的括号可以不需要。 --外层的括号只是为了方便区分匹配的分组 openGauss=# select 'select * from t1 where is not null' ~ '(is)\s+((not)?\s+)(null)' as result; result -------- t (1 row) --去掉括号后的结果和之前是一致的 openGauss=# select 'select * from t1 where is not null' ~ '(is)\s+(not)?\s+(null)' as result; result -------- t (1 row) 匹配规则,是否需要考虑换行匹配多个词组的时候,目前验证,对于空格、制表符、换行,都按照匹配任何空白字符处理即可。create table t1 (id int,context varchar(1000)); insert into t1 values(1,'select * from t1 where is not null'); insert into t1 values(2,'select * from t1 where is null'); insert into t1 values(3,'select * from t1 where 1=2'); insert into t1 values(4,'not else'); insert into t1 values(5,'ifnot else'); insert into t1 values(6,'notrr else'); insert into t1 values(7,'select * from t1 where is not null'); --查询 openGauss=> select * from t1 where regexp_like(context,'(is)\s+(not)?\s?(null)','i'); id | context ----+------------------------------------ 1 | select * from t1 \r + | where is \r + | not null 2 | select * from t1 where is \r + | null 7 | select * from t1 where is not null (3 rows) --插入 insert into t1 values(8,'where group by '); insert into t1 values(9,'where group by '); --匹配换行\r openGauss=> select * from t1 where regexp_like(context,'(group)\r+','i'); id | context ----+--------------- 8 | where group\r+ | by (1 row) --匹配任何空白字符\s,根据结果可知,\s是包含换行信息的 openGauss=> select * from t1 where regexp_like(context,'(group)\s+','i'); id | context ----+----------------- 8 | where group\r + | by 9 | where group by (2 rows) 按照词组匹配,精确查找我们在查询匹配关键字的时候,一般需要精确查找匹配,而不需要那些包含有查询关键字的数据行--通过正则表达式约束\m和\M来限定一个词的开头和结尾匹配 openGauss=> select * from t1 where regexp_like(context,'\mnot\M','i'); id | context ----+------------------------------------ 1 | select * from t1 \r + | where is \r + | not null 4 | not else 7 | select * from t1 where is not null (3 rows) --\m一个词的开头匹配 openGauss=> select * from t1 where regexp_like(context,'\mnot','i'); id | context ----+------------------------------------ 1 | select * from t1 \r + | where is \r + | not null 4 | not else 6 | notrr else 7 | select * from t1 where is not null (4 rows) --\M一个词的末尾匹配 openGauss=> select * from t1 where regexp_like(context,'not\M','i'); id | context ----+------------------------------------ 1 | select * from t1 \r + | where is \r + | not null 4 | not else 5 | ifnot else 7 | select * from t1 where is not null (4 rows) ?和*量词的区别在查询匹配场景下,我个人理解应该是一致的,但是对于一些替换场景则是有区别的--?是匹配0或1次,所以(o)?b匹配的子串为ob,替换为了foearbaz openGauss=> SELECT regexp_replace('foobarobaz', '(o)?b', 'e'); regexp_replace ---------------- foearobaz (1 row) --*是匹配0或更多次,所以(o)?b匹配的子串为oob,替换为了e,结果为fearbaz openGauss=> SELECT regexp_replace('foobarobaz', '(o)*b', 'e'); regexp_replace ---------------- fearobaz (1 row) --对于flat参数,i表示进行大小写无关的匹配,g表示替换每一个匹配的子字符串而不仅仅是第一个 openGauss=> SELECT regexp_replace('foobarobaz', '(o)*b', 'e','g'); regexp_replace ---------------- feareaz (1 row)正则表达式支持的函数对于具体的正则函数的使用,本文不做详细介绍,后续再写文章详细介绍。正则表达式支持的函数如下,substring(string from pattern) 描述:截取匹配POSIX正则表达式的子字符串。如果没有匹配它返回空值,否则返回文本中匹配模式的那部分。 regexp_count(string text, pattern text [, position int [, flags text]]) 描述:获取满足匹配的子串个数 regexp_instr(string text, pattern text [, position int [, occurrence int [, return_opt int [, flags text]]]]) 描述:获取满足匹配条件的子串位置(从1开始)。如果没有匹配的子串,则返回0。 regexp_substr(string text, pattern text [, position int [, occurrence int [, flags text]]]) 描述:正则表达式的抽取子串函数。与substr功能相似,正则表达式出现多个并列的括号时,也全部处理 regexp_replace(string, pattern, replacement [,flags ]) 描述:替换匹配POSIX正则表达式的子字符串。如果没有匹配pattern,那么返回不加修改的string串。如果有匹配,则返回的string串里面的匹配子串将被replacement串替换掉。 replacement串可以包含\n,其中\n是1到9,表明string串里匹配模式里第n个圆括号子表达式的子串应该被插入,并且它可以包含\&表示应该插入匹配整个模式的子串。 可选的flags参数包含零个或多个改变函数行为的单字母标记。flags 支持的选项值及含义描述如表1 flags 支持的选项值所示。返回值类型:varchar regexp_matches(string text, pattern text [, flags text]) 描述:返回string中所有匹配POSIX正则表达式的子字符串。如果pattern不匹配,该函数不返回行。如果模式不包含圆括号子表达式,则每一个被返回的行都是一个单一元素的文本数组,其中包括匹配整个模式的子串。如果模式包含圆括号子表达式,该函数返回一个文本数组,它的第n个元素是匹配模式的第n个圆括号子表达式的子串。 flags参数为可选参数,包含零个或多个改变函数行为的单字母标记。i表示进行大小写无关的匹配,g表示替换每一个匹配的子字符串而不仅仅是第一个。 regexp_split_to_array(string text, pattern text [, flags text ]) 描述:用POSIX正则表达式作为分隔符,分隔string。和regexp_split_to_table相同,不过regexp_split_to_array会把它的结果以一个text数组的形式返回。返回值类型:text[] regexp_split_to_table(string text, pattern text [, flags text]) 描述:用POSIX正则表达式作为分隔符,分隔string。如果没有与pattern的匹配,该函数返回string。如果有至少有一个匹配,对每一个匹配它都返回从上一个匹配的末尾(或者串的开头)到这次匹配开头之间的文本。当没有更多匹配时,它返回从上一次匹配的末尾到串末尾之间的文本。 flags参数包含零个或多个改变函数行为的单字母标记。i表示进行大小写无关的匹配。返回值类型:setof text regexp_like(text,text,text) 描述:正则表达式的模式匹配函数。返回值类型:bool总结本文中整理的正则匹配规则为比较常见的规则,相对来说上手还是比较容易的,这些规则对于我们的日常运维开发应该是足够使用的。另外这三种模式匹配,其实使用场景也是稍微有所不同。1、like常用于简单的模糊匹配查询2、SIMILAR TO语法可以支持正则模式匹配,适用于大部分场景3、正则表达式相比SIMILAR TO,支持一些正则函数的使用并且支持一些其他特殊的匹配规则总之,正则表达式是一种强大的工具,它在文本处理领域具有广泛的应用,并且具有灵活性、通用性和高效性等优点。通过掌握正则表达式,开发或运维人员能够更高效地处理文本数据。上述的整理,是通过查看GaussDB的官网文档并结合PG官网资料整理常用的正则表达式。如果个别内容有误,望各位大佬多多指正。
  • [技术解读] GaussDB 导出实例基本信息
    通过GRANT把角色授予用户后,用户即具有了角色的所有权限。推荐使用角色进行高效权限分配。例如,可以为设计、开发和维护人员创建不同的角色,将角色GRANT给用户后,再向每个角色中的用户授予其工作所需数据的差异权限。在角色级别授予或撤消权限时,这些更改将作用到角色下的所有成员。       GaussDB提供了一个隐式定义的拥有所有角色的组PUBLIC,所有创建的用户和角色默认拥有PUBLIC所拥有的权限。关于PUBLIC默认拥有的权限请参考GRANT。要撤销或重新授予用户和角色对PUBLIC的权限,可通过在GRANT和REVOKE指定关键字PUBLIC实现。       要查看所有角色,请查询系统表PG_ROLES:创建、修改和删除角色非三权分立时,只有系统管理员和具有CREATEROLE属性的用户才能创建、修改或删除角色。三权分立下,只有初始用户和具有CREATEROLE属性的用户才能创建、修改或删除角色。要创建角色,请使用CREATE ROLE。要在现有角色中添加或删除用户,请使用ALTER ROLE。要删除角色,请使用DROP ROLE。DROP ROLE只会删除角色,并不会删除角色中的成员用户账户。内置角色提供了一组默认角色,以gs_role_开头命名。它们提供对特定的、通常需要高权限的操作的访问,可以将这些角色GRANT给数据库内的其他用户或角色,让这些用户能够使用特定的功能。在授予这些角色时应当非常小心,以确保它们被用在需要的地方。表1描述了内置角色允许的权限范围:关于内置角色的管理有如下约束:以gs_role_开头的角色名作为数据库的内置角色保留名,禁止新建以“gs_role_”开头的用户/角色/模式,也禁止将已有的用户/角色/模式重命名为以“gs_role_”开头;禁止对内置角色的ALTER和DROP操作;内置角色默认没有LOGIN权限,不设预置密码;gsql元命令\du和\dg不显示内置角色的相关信息,但若显示指定了pattern为特定内置角色则会显示。三权分立关闭时,初始用户、具有SYSADMIN权限的用户和具有内置角色ADMIN OPTION权限的用户有权对内置角色执行GRANT/REVOKE管理。三权分立打开时,初始用户和具有内置角色ADMIN OPTION权限的用户有权对内置角色执行GRANT/REVOKE管理。
  • GaussDB的角色
     通过GRANT把角色授予用户后,用户即具有了角色的所有权限。推荐使用角色进行高效权限分配。例如,可以为设计、开发和维护人员创建不同的角色,将角色GRANT给用户后,再向每个角色中的用户授予其工作所需数据的差异权限。在角色级别授予或撤消权限时,这些更改将作用到角色下的所有成员。       GaussDB提供了一个隐式定义的拥有所有角色的组PUBLIC,所有创建的用户和角色默认拥有PUBLIC所拥有的权限。关于PUBLIC默认拥有的权限请参考GRANT。要撤销或重新授予用户和角色对PUBLIC的权限,可通过在GRANT和REVOKE指定关键字PUBLIC实现。       要查看所有角色,请查询系统表PG_ROLES:创建、修改和删除角色非三权分立时,只有系统管理员和具有CREATEROLE属性的用户才能创建、修改或删除角色。三权分立下,只有初始用户和具有CREATEROLE属性的用户才能创建、修改或删除角色。要创建角色,请使用CREATE ROLE。要在现有角色中添加或删除用户,请使用ALTER ROLE。要删除角色,请使用DROP ROLE。DROP ROLE只会删除角色,并不会删除角色中的成员用户账户。内置角色提供了一组默认角色,以gs_role_开头命名。它们提供对特定的、通常需要高权限的操作的访问,可以将这些角色GRANT给数据库内的其他用户或角色,让这些用户能够使用特定的功能。在授予这些角色时应当非常小心,以确保它们被用在需要的地方。表1描述了内置角色允许的权限范围:关于内置角色的管理有如下约束:以gs_role_开头的角色名作为数据库的内置角色保留名,禁止新建以“gs_role_”开头的用户/角色/模式,也禁止将已有的用户/角色/模式重命名为以“gs_role_”开头;禁止对内置角色的ALTER和DROP操作;内置角色默认没有LOGIN权限,不设预置密码;gsql元命令\du和\dg不显示内置角色的相关信息,但若显示指定了pattern为特定内置角色则会显示。三权分立关闭时,初始用户、具有SYSADMIN权限的用户和具有内置角色ADMIN OPTION权限的用户有权对内置角色执行GRANT/REVOKE管理。三权分立打开时,初始用户和具有内置角色ADMIN OPTION权限的用户有权对内置角色执行GRANT/REVOKE管理。
  • [问题求助] 4C4D4副本中的4C4副本代表什么?
    4D是意思我知道,是代表4个DataNode。4副本的意义是有4个数据分片吗?4C的意思是4的CN节点吗?
  • [其他问题] GaussDB、DWS、GaussDB A、GaussDB T、openGauss概念理解
    小白入门,在搜索文档的时候被这些概念绕晕了,这些说的都是一个东西吗?比如:我看有的地方说是GaussDB,有的地方又说是GaussDB(DWS),有没有大佬解释一下?
总条数:1672 到第 页
上滑加载中