华为云用户手册

  • RCR UBTree空间管理 当前Astore的索引依赖AutoVacuum和Free Space Map(FSM)进行空间管理,存在回收不及时的问题,而Ustore的索引使用其特有的URQ(UBTree Recycle Queue,一种基于循环队列的数据结构,即双循环队列)对索引空闲空间进行管理。双循环队列是指有两个循环队列,一个潜在空页队列,另一个可用空页队列。在DML过程中完成索引的空间管理,能有效地缓解DML过程中造成的空间急剧膨胀问题。 索引回收队列单独储存在B-tree索引对应的FSM文件中。 如上图所示,索引页面在双循环队列间流动如下: 索引空页流动到潜在队列 索引页尾字段中记录了页面上活跃元组个数(activeTupleCount)。在DML过程中,删空一个页面的所有元组,即activeTupleCount为零时会将索引页放入潜在队列中。 潜在队列流动到可用队列 潜在队列到可用队列的转化主要是达到一个潜在队列收支平衡以及可用队列在拿页时有页可拿的目的。即当从可用队列拿出一个索引空页用完后,建议从潜在队列转化至少一个索引页面到可用队列中,以及每当潜在队列新加入一个索引页面时,能从潜在队列中移除至少一个索引页插入可用队列中,达到潜在队列的收支平衡,以及可用队列有页可用的目的。 可用队列流动到索引空页 索引在分裂等获取一个索引空页面时,会先从可用队列中进行查找是否有可以复用的索引页,如果找到则直接进行复用,没有可复用页面则进行物理扩页。 父主题: RCR UBTree
  • 静态编译架构 从整个数据库服务的组成构架来看,存储引擎向上对接SQL引擎,为SQL引擎提供或接收标准化的数据格式(元组或向量数组);存储引擎向下对接存储介质,按照特定的数据组织方式,以页面、压缩单元(Compress Unit)或其他形式为单位,通过存储介质提供的特定接口,对存储介质中的数据完成读写操作。GaussDB通过静态编译使数据库专业人员可以为特定的应用程序需求选择专用的存储引擎。为了减少对执行引擎的干扰,提供行存访问接口层TableAM,用来屏蔽底层行存引擎带来的差异,使得不同行存引擎可以分别独立演进。如下图所示。 在此基础之上,存储引擎通过日志系统提供数据的持久化和可靠性能力。通过并发控制(事务)系统保证同时执行的、多个读写操作之间的原子性、一致性和隔离性,通过索引系统提供对特定数据的加速寻址和查询能力,通过主备复制系统提供整个数据库服务的高可用能力。 行存引擎主要面向OLTP(OnLine Transaction Processing)类业务应用场景,适合高并发、小数据量的单点或小范围数据读写操作。行存引擎向上为SQL引擎提供元组形式的读写接口,向下以页面为单位通过可扩展的介质管理器对存储介质进行读写操作,并通过页面粒度的共享缓冲区来优化读写操作的效率。对于读写并发操作,采用多版本并发控制(MVCC,Multi-Version Concurrency Control);对于写写并发操作,采用基于两阶段锁协议(2PL,Two-Phase Locking)的悲观并发控制(PCC,Pessimistic Concurrency Control)。当前,行存引擎默认的介质管理器采用磁盘文件系统接口,后续可扩展支持块设备等其他类型的存储介质。GaussDB行存引擎可以选择基于Append update 的Astore或基于In-place update的Ustore。 父主题: 存储引擎体系架构概述
  • 事务回滚 回滚是在事务运行的过程中发生了故障等异常情形下,事务不能继续执行,系统需要将事务中已完成的修改操作进行撤销。Astore、Ubtree没有回滚段,自然没有这个专门的回滚动作。Ustore为了性能考虑,它的回滚流程结合了同步、异步和页面级回滚等3种形式。 同步回滚 有三种情况会触发事务的同步回滚: 事务块中的ROLLBACK关键字会触发同步回滚。 事务运行过程中如果发生ERROR级别报错,此时的COMMIT关键字与ROLLBACK功能相同,也会触发同步回滚。 事务运行过程中如果发生FATAL/PANIC级别报错,在线程退出前会尝试将该线程绑定的事务进行一次同步回滚。 异步回滚 同步回滚失败或者在系统宕机后再次重启时,会由Undo回收线程为未回滚完成的事务发起异步回滚任务,立即对外提供服务。由异步回滚任务发起线程undo launch负责拉起异步回滚工作线程undo worker,再由异步回滚工作线程实际执行回滚任务。undo launch线程最多可以同时拉起5个undo worker线程。 页面级回滚 当事务需要回滚但还未回滚到本页面时,如果其他事务需要复用该事务所占用的TD,就会在复用前对该事务在本页面的所有修改执行页面级回滚。页面级回滚只负责回滚事务在本页面的修改,不涉及其他页面。 Ustore子事务的回滚由ROLLBACK TO SAVEPOINT语句控制,子事务回滚后父事务可以继续运行,子事务的回滚不影响父事务的事务状态。如果一个事务在回滚时还存在未释放的子事务,该事务回滚前会先执行子事务的回滚,所有子事务回滚完毕后才会进行父事务的回滚。 父主题: Ustore事务模型
  • 向列表分区表新增分区 使用ALTER TABLE ADD PARTITION可以在列表分区表中新增分区,新增分区的枚举值不能与已有的任一个分区的枚举值重复。 例如,对列表分区表list_sales新增一个分区。 ALTER TABLE list_sales ADD PARTITION channel5 VALUES ('X') TABLESPACE tb1; 当列表分区表有DEFAULT分区时,无法新增分区。可以使用ALTER TABLE SPLIT PARTITION命令分割分区。 父主题: 新增分区
  • Ustore事务模型 GaussDB事务基础: 事务启动时不会自动分配XID,该事务中的第一条DML/DDL语句运行时才会真正为该事务分配XID。 事务结束时,会产生代表事务提交状态的CLOG(Commit Log),CLOG共有四种状态:事务运行中、事务提交、事务同步回滚、子事务提交。每个事务的 CLOG状态位为2 bits,CLOG页面上每个字节可以表示四个事务的提交状态。 事务结束时,还会产生代表事务提交顺序的CSN(Commit sequence number)。CSN为实例级变量,每个XID都有自己对应的唯一CSN。CSN可以标记事务的以下状态:事务提交中、事务提交、事务回滚、事务已冻结等。 事务提交 事务回滚 父主题: Ustore存储引擎
  • 交换分区 用户可以使用交换分区的命令来将分区与普通表的数据进行交换。交换分区可以快速将数据导入/导出分区表,实现数据高效加载的目的。在业务迁移的场景,使用交换分区比常规导入会快很多。交换分区可以通过指定分区名或者分区值来进行。 执行交换分区命令会使得Global索引失效,可以通过UPDATE GLOBAL INDEX子句来同步更新Global索引,或者用户自行重建Global索引。 执行交换分区时,可以申明WITH/WITHOUT VALIDATION,表明是否校验普通表数据满足目标分区的分区键约束规则(默认校验)。数据校验活动开销较大,如果能确保交换的数据属于目标分区,可以申明WITHOUT VALIDATION来提高交换性能。 可以申明WITH VALIDATION VERBOSE,此时数据库会校验普通表的每一行,将不满足目标分区的分区键约束规则的数据,插入到分区表的其他分区中,最后再进行普通表与目标分区的交换。 例如,给出如下分区定义和普通表exchange_sales的数据分布,并将分区DATE_202001和普通表exchange_sales做交换,则根据申明子句的不同,存在以下三种行为: 申明WITHOUT VALIDATION,数据全部交换到分区DATE_202001中,由于'2020-02-03', '2020-04-08'不满足分区DATE_202001的范围约束,后续业务可能会出现异常。 申明WITH VALIDATION,由于'2020-02-03', '2020-04-08'不满足分区DATE_202001的范围约束,数据库给出相应的报错。 申明WITH VALIDATION VERBOSE,数据库会将'2020-02-03'插入分区DATE_202002,将'2020-04-08'插入分区DATE_202004,再将剩下的数据交换到分区DATE_202001中。 --分区定义 PARTITION DATE_202001 VALUES LESS THAN ('2020-02-01'), PARTITION DATE_202002 VALUES LESS THAN ('2020-03-01'), PARTITION DATE_202003 VALUES LESS THAN ('2020-04-01'), PARTITION DATE_202004 VALUES LESS THAN ('2020-05-01') -- exchange_sales的数据分布 ('2020-01-15', '2020-01-17', '2020-01-23', '2020-02-03', '2020-04-08') 如果交换的数据不完全属于目标分区,请不要申明WITHOUT VALIDATION交换分区,否则会破坏分区约束规则,导致分区表后续DML业务结果异常。 进行交换的普通表和分区必须满足如下条件: 普通表和分区的列数目相同,对应列的信息严格一致。 普通表和分区的表压缩信息严格一致。 普通表索引和分区Local索引个数相同,且对应索引的信息严格一致。 普通表和分区的表约束个数相同,且对应表约束的信息严格一致。 普通表不可以是临时表。 普通表和分区表上不可以有动态数据脱敏,行访问控制约束。 使用ALTER TABLE EXCHANGE PARTITION可以对分区表交换分区。 例如,通过指定分区名将范围分区表range_sales的分区date_202001和普通表exchange_sales进行交换,不进行分区键校验,并更新Global索引。 ALTER TABLE range_sales EXCHANGE PARTITION (date_202001) WITH TABLE exchange_sales WITHOUT VALIDATION UPDATE GLOBAL INDEX; 或者,通过指定分区值将范围分区表range_sales中'2020-01-08'所对应的分区和普通表exchange_sales进行交换,进行分区校验并将不满足目标分区约束的数据插入到分区表的其他分区中。由于不带UPDATE GLOBAL INDEX子句,执行该命令后Global索引会失效。 ALTER TABLE range_sales EXCHANGE PARTITION FOR ('2020-01-08') WITH TABLE exchange_sales WITH VALIDATION VERBOSE; 父主题: 分区表运维管理
  • 维护窗口参数配置 RETENTION_TIME:评估与压缩记录的保留时长,单位天,默认值30。用户可根据自己存储容量自行调节。 EXECUTION_INTERVAL:评估任务的执行频率,单位分钟,默认值15。用户可根据自己维护窗口期间业务与资源情况调节。该参数与ABS_JOBLIMIT相互影响。单日单线程最大可产生的I/O为WIND_DURATION/EXECUTION_INTERVAL*JOB_SIZELIMIT。 JOB_SIZELIMIT:控制单个压缩Job可以处理的最大字节数,单位兆,默认值1024。压缩带宽约为100MB/秒,每个压缩Job限制I/O为1GB时,最多10秒完成。用户可根据自己业务闲时情况以及需要压缩的数据量自行调节。 ABS_JOBLIMIT:控制一次评估最多生成多少个压缩Job。用户可根据自己设置策略的分区及表数量自己调节。建议最大不超过10,可以使用“select count(*) from gs_adm_ilmobjects where enabled = true”命令查询。 POLICY_TIME:控制判定冷行的条件单位是天还是秒,秒仅用来做测试用。取值为:ILM_POLICY_IN_SECONDS或ILM_POLICY_IN_DAYS(默认值)。 WIND_DURATION:维护窗口持续时长,单位分钟,默认240分钟(4小时)。维护窗口默认从北京时间22点开始持续240分钟,用户可根据自己业务闲时情况自行调节。 BLOCK_LIMITS:控制实例级的行存压缩速率上限,默认是40,取值范围是0到10000(0表示不限制),单位是block/ms,表示每毫秒最多压缩多少个block。速率上限计算方法:BLOCK_LIMITS*1000*BLOCKSIZE,以默认值40为例,其速率上限为:40*1000*8KB=320000KB/s。 示例分析: EXECUTION_INTERVAL:15 JOB_SIZELIMIT:10240 WIND_DURATION:240 BLOCK_LIMITS:0 此配置下单表分区在一个维护窗口期间可完成240/15*10240MB=160GB数据的评估压缩。压缩带宽为100MB/秒,实际压缩仅耗时160GB/(100MB/秒)=27分钟。其他时间对业务无影响。用户可根据自己业务闲时可支配给压缩的时长来调节参数。 父主题: 数据生命周期管理-OLTP表压缩
  • 分区表介绍 分区表(Partitioned Table)指在单节点内对表数据内容按照分区键以及围绕分区键的分区策略对表进行逻辑切分。从数据分区的角度来看是一种水平分区(horizontal partition)策略方式。分区表增强了数据库应用程序的性能、可管理性和可用性,并有助于降低存储大量数据的总体拥有成本。分区允许将表、索引和索引组织的表细分为更小的部分,使这些数据库对象能够在更精细的粒度级别上进行管理和访问。GaussDB提供了丰富的分区策略和扩展,以满足不同业务场景的需求。由于分区策略的实现完全由数据库内部实现,对用户是完全透明的,因此它几乎可以在实施分区表优化策略以后做平滑迁移,无需潜在耗费人力物力的应用程序更改。本章围绕GaussDB分区表的基本概念从以下几个方面展开介绍: 分区表基本概念:从表分区的基本概念出发,介绍分区表的catalog存储方式以及内部对应原理。 分区策略:从分区表所支持的基本类型出发,介绍各种分区模式下对应的特性以及能够达到的优化特点和效果。 基本概念 分区策略 分区基本使用 父主题: 分区表
  • 清空分区 用户可以使用清空分区的命令来快速清空分区的数据。与删除分区功能类似,区别在于清空分区只会删除分区中的数据,分区的定义和物理文件都会保留。清空分区可以通过指定分区名或者分区值来进行。 执行清空分区命令会使得Global索引失效,可以通过UPDATE GLOBAL INDEX子句来同步更新Global索引,或者用户自行重建Global索引。 使用ALTER TABLE TRUNCATE PARTITION可以清空指定分区表的任何一个分区。 例如,通过指定分区名清空范围分区表range_sales的分区date_202005,并更新Global索引。 ALTER TABLE range_sales TRUNCATE PARTITION date_202005 UPDATE GLOBAL INDEX; 或者,通过指定分区值来清空范围分区表range_sales中'2020-05-08'所对应的分区。由于不带UPDATE GLOBAL INDEX子句,执行该命令后Global索引会失效。 ALTER TABLE range_sales TRUNCATE PARTITION FOR ('2020-05-08'); 父主题: 分区表运维管理
  • 表分区技术 表分区技术(Table-Partitioning)通过将非常大的表或者索引从逻辑上切分为更小、更易管理的逻辑单元(分区),能够让对用户对表查询、变更等语句操作具备更小的影响范围,能够让用户通过分区键(Partition Key)快速定位到数据所在的分区,从而避免在数据库中对大表的全量扫描,能够在不同的分区上并发进行DDL、DML操作。从用户使用的角度来看,表分区技术主要有以下三个方面能力: 提升大容量数据场景查询效率:由于表内数据按照分区键进行逻辑分区,查询结果可以通过访问分区的子集而不是整个表来实现。这种分区剪枝技术可以提供数量级的性能增益。 降低运维与查询的并发操作影响:降低DML语句、DDL语句并发场景的相互影响,在对一些大数据量以时间维度进行分区的场景下会明显受益。例如,新数据分区进行入库、实时点查操作,老数据分区进行数据清洗、分区合并等运维性质操作。 提供大容量场景下灵活的数据运维管理方式:由于分区表从物理上对不同分区的数据做了表文件层面的隔离,每个分区可以具有单独的物理属性,如启用或禁用压缩、物理存储设置和表空间。同时它支持数据管理操作,如数据加载、索引创建和重建,以及分区级别的备份和恢复,而不是对整个表进行操作,从而减少了操作时间。 父主题: 大容量数据库
  • 闪回恢复 闪回恢复功能是数据库恢复技术的一环,可以有选择性地撤销一个已提交事务的影响,将数据从人为不正确的操作中进行恢复。在采用闪回技术之前,只能通过备份恢复、PITR等手段找回已提交的数据库修改,恢复时长需要数分钟甚至数小时。采用闪回技术后,通过闪回Drop和闪回Truncate恢复已提交的数据库Drop/Truncate的数据,只需要秒级,而且恢复时间和数据库大小无关。 ASTORE引擎只支持闪回DROP/TRUNCATE功能。 备机不支持闪回操作。 用户可以根据需要开启闪回功能,开启后会带来一定的性能劣化。 闪回查询 闪回表 闪回DROP/TRUNCATE 父主题: Ustore存储引擎
  • 特性规格 TPCC只开启策略、不开调度对原有业务无影响。 TPCC不开启压缩策略对原有业务无影响。 TPCC.bmsql_order_line设置ILM策略(只识别完成派送的订单为冷行)不调度,TPmC劣化不高于2%(56核CPU370GB内存+3TB SSD硬盘,350GB SharedBuffer)。 TPCC.bmsql_order_line设置ILM策略(只识别完成派送的订单为冷行)后台默认参数调度时,TPmC劣化不高于5%(56核CPU370GB内存+3TB SSD硬盘,350GB SharedBuffer)。 单线程ILM Job带宽约100MB/秒(56核CPU370GB内存+3TB SSD硬盘,350GB SharedBuffer)。 度量方式:根据执行压缩的开始时间和结束时间以及压缩的页面个数计算带宽。 get查询访问压缩数据比非压缩数据性能劣化,驱动侧不高于10%,plsql侧不高于15%(32MB SharedBuffer,6万页面数据)。 multi-get查询访问压缩数据比非压缩数据性能劣化,驱动侧不高于30%,plsql侧不高于40%(32MB SharedBuffer,6万页面数据)。 table-scan查询访问压缩数据比非压缩数据性能劣化,驱动侧不高于30%,plsql侧不高于40%(32MB SharedBuffer,6万页面数据)。 TPCH.lineitem表压缩比(全冷行)不小于2:1。 对于TPC-C的Orderline表,以及TPC-H的Lineitem、Orders、Customer、Part表的测试表明,数值型字段较多时,压缩率高于LZ4和ZLIB;而文本型字段较多时,压缩率介于LZ类和LZ+Huffman组合类的压缩算法之间。 父主题: 数据生命周期管理-OLTP表压缩
  • 使用和管理分区表 分区表支持大部分非分区表的相关功能,具体可以参考《开发者指南》中常规表的各类操作语法相关资料。 除此之外,分区表还支持大量的分区级操作命令,包括分区级DQL/DML(如SELECT、INSERT、UPDATE、DELETE、UPSERT、MERGE INTO)、分区级DDL(如ADD、DROP、TRUNCATE、EXCHANGE、SPLIT、MERGE、MOVE、RENAME)、分区VACUUM/ANALYZE、分类分区索引等。相关命令使用方法请参见分区表DQL/DML、分区索引、分区表运维管理、以及《开发者指南》中各个语法命令对应的章节。 分区级操作命令一般通过指定分区名或者分区值的方式进行,比如语法命令可能是如下情形: sql_action [ t_name ] { PARTITION | SUBPARTITION } { p_name | (p_name) }; sql_action [ t_name ] { PARTITION | SUBPARTITION } FOR (p_value); 通过指定分区名p_name或指定分区值p_value来定向操作某个特定分区,此时业务只会作用于对象分区,而不会影响其他任何分区。如果通过指定分区名p_name来执行业务,数据库会匹配p_name对应的分区,该分区不存在则业务抛出异常;如果通过指定分区值p_value来执行业务,数据库会匹配p_value值所属分区。 比如定义有如下的分区表: gaussdb=# CREATE TABLE list_01 ( id INT, role VARCHAR(100), data VARCHAR(100) ) PARTITION BY LIST (id) ( PARTITION p_list_1 VALUES(0,1,2,3,4), PARTITION p_list_2 VALUES(5,6,7,8,9), PARTITION p_list_3 VALUES(DEFAULT) ); -- 清理示例 gaussdb=# DROP TABLE list_01; 指定分区业务中,PARTITION p_list_1与PARTITION FOR (4)等价,为同一个分区;PARTITION p_list_3与PARTITION FOR (12)等价,为同一个分区。 父主题: 分区基本使用
  • 使用Ustore的优势 最新版本和历史版本分离存储,相比Astore扫描范围小。去除Astore的HOT chain,非索引列/索引列更新,Heap均可原位更新,ROWID可保持不变。历史版本可批量回收,空间膨胀可控。 B-tree索引增加了事务信息,能够独立进行MVCC,增加了IndexOnlyScan的比例,大大减少回表次数。 不依赖Vacuum进行旧版本清理。独立的空间回收能力,索引与堆表解耦,可独立清理,IO平稳度更优。 大并发更新同一行的场景,相对于Astore的ROWID会偏移,Ustore的原位更新机制保证了元组ROWID稳定,先到先得,更新时延相对稳定。 支持闪回功能。 Ustore DML在修改数据页面时,也需要同步生成Undo,因此更新操作开销会稍大一些。此外单条Tuple扫描开销由于需要复制(Astore返回指针)也会大一些。
  • 合并分区 用户可以使用合并分区的命令来将多个分区合并为一个分区。合并分区只能通过指定分区名来进行,不支持指定分区值的写法。 合并分区不能作用于哈希分区上。 执行合并分区命令会使得Global索引失效,可以通过UPDATE GLOBAL INDEX子句来同步更新Global索引,或者用户自行重建Global索引。 合并前的分区如果包含分类索引则不支持合并。 合并后的新分区,对于范围分区,可以与最后一个源分区名字相同,比如将p1,p2合并为p2;对于列表分区,可以与任一源分区名字相同,比如将p1,p2合并为p1。 如果新分区与源分区名字相同,数据库会将新分区视为对源分区的继承。 使用ALTER TABLE MERGE PARTITIONS可以将多个分区合并为一个分区。 例如,将范围分区表range_sales的分区date_202001和date_202002合并为一个新的分区,并更新Global索引。 ALTER TABLE range_sales MERGE PARTITIONS date_202001, date_202002 INTO PARTITION date_2020_old UPDATE GLOBAL INDEX; 父主题: 分区表运维管理
  • 分区剪枝 分区剪枝是GaussDB提供的一种分区表查询优化技术,数据库SQL引擎会根据查询条件,只扫描特定的部分分区。分区剪枝是自动触发的,当分区表查询条件符合剪枝场景时,会自动触发分区剪枝。根据剪枝阶段的不同,分区剪枝分为静态剪枝和动态剪枝,静态剪枝在优化器阶段进行,在生成计划之前,数据库已经知道需要访问的分区信息;动态剪枝在执行器阶段进行(执行开始/执行过程中),在生成计划时,数据库并不知道需要访问的分区信息,只是判断“可以进行分区剪枝”,具体的剪枝信息由执行器决定。 只有分区表页面扫描和Local索引扫描才会触发分区剪枝,Global索引没有分区的概念,不需要进行剪枝。 分区表静态剪枝 分区表动态剪枝 父主题: 分区表查询优化
  • 使用示例 示例(需将undo_retention_time参数设置为大于0的值): gaussdb=# DROP TABLE IF EXISTS "public".flashtest; NOTICE: table "flashtest" does not exist, skipping DROP TABLE --创建表flashtest。 gaussdb=# CREATE TABLE "public".flashtest (col1 INT,col2 TEXT) with(storage_type=ustore); NOTICE: The 'DISTRIBUTE BY' clause is not specified. Using 'col1' as the distribution column by default. HINT: Please use 'DISTRIBUTE BY' clause to specify suitable data distribution column. CREATE TABLE --查询csn。 gaussdb=# SELECT int8in(xidout(next_csn)) FROM gs_get_next_xid_csn(); int8in ---------- 79351682 79351682 79351682 79351682 79351682 79351682 (6 rows) --查询当前时间戳。 gaussdb=# SELECT now(); now ------------------------------- 2023-09-13 19:35:26.011986+08 (1 row) --插入数据。 gaussdb=# INSERT INTO flashtest VALUES(1,'INSERT1'),(2,'INSERT2'),(3,'INSERT3'),(4,'INSERT4'),(5,'INSERT5'),(6,'INSERT6'); INSERT 0 6 gaussdb=# SELECT * FROM flashtest; col1 | col2 ------+--------- 3 | INSERT3 1 | INSERT1 2 | INSERT2 4 | INSERT4 5 | INSERT5 6 | INSERT6 (6 rows) --闪回查询某个csn处的表。 gaussdb=# SELECT * FROM flashtest TIMECAPSULE CSN 79351682; col1 | col2 ------+------ (0 rows) gaussdb=# SELECT * FROM flashtest; col1 | col2 ------+--------- 1 | INSERT1 2 | INSERT2 4 | INSERT4 5 | INSERT5 3 | INSERT3 6 | INSERT6 (6 rows) --闪回查询某个时间戳处的表。 gaussdb=# SELECT * FROM flashtest TIMECAPSULE TIMESTAMP '2023-09-13 19:35:26.011986'; col1 | col2 ------+------ (0 rows) gaussdb=# SELECT * FROM flashtest; col1 | col2 ------+--------- 1 | INSERT1 2 | INSERT2 4 | INSERT4 5 | INSERT5 3 | INSERT3 6 | INSERT6 (6 rows) --闪回查询某个时间戳处的表。 gaussdb=# SELECT * FROM flashtest TIMECAPSULE TIMESTAMP to_timestamp ('2023-09-13 19:35:26.011986', 'YYYY-MM-DD HH24:MI:SS.FF'); col1 | col2 ------+------ (0 rows) --闪回查询某个csn处的表,并对表进行重命名。 gaussdb=# SELECT * FROM flashtest AS ft TIMECAPSULE CSN 79351682; col1 | col2 ------+------ (0 rows) gaussdb=# DROP TABLE IF EXISTS "public".flashtest; DROP TABLE
  • 语法 {[ ONLY ] table_name [ * ] [ partition_clause ] [ [ AS ] alias [ ( column_alias [, ...] ) ] ] [ TABLESAMPLE sampling_method ( argument [, ...] ) [ REPEATABLE ( seed ) ] ] [TIMECAPSULE { TIMESTAMP | CSN } expression ] |( select ) [ AS ] alias [ ( column_alias [, ...] ) ] |with_query_name [ [ AS ] alias [ ( column_alias [, ...] ) ] ] |function_name ( [ argument [, ...] ] ) [ AS ] alias [ ( column_alias [, ...] | column_definition [, ...] ) ] |function_name ( [ argument [, ...] ] ) AS ( column_definition [, ...] ) |from_item [ NATURAL ] join_type from_item [ ON join_condition | USING ( join_column [, ...] ) ]}
  • RCR UBTree增删改查 Insert操作:Ubtree的插入逻辑基本不变,只需增加索引插入时直接获取事务信息填写xmin字段。 Delete操作:Ubtree额外增加了索引删除流程。索引删除主要步骤与插入相似,获取事务信息填写xmax字段(B-tree索引不维护版本信息,不需要删除操作),同时更新页面上的active_tuple_count。若active_tuple_count被减为0,则尝试页面回收。 Update操作:对于Ustore而言,数据更新对Ubtree索引列的操作也与Astore有所不同。数据更新包含两种情况:索引列和非索引列更新,下图给出了Ubtree在数据发生更新时的处理。 上图展示Ubtree在索引列和非索引列更新的差异: 在非索引列更新的情况下,索引不发生任何变化。index tuple仍指向第一次插入的data tuple,Uheap不会插入新的data tuple,而是修改当下data tuple并将历史数据存入Undo中。 在索引列更新的情况下,Ubtree也会插入新的index tuple,但是会指向同一个data linepointer和同一个data tuple。扫描旧版本的数据则需要从Undo中读取。 Scan操作:用户在读取数据时,可通过使用索引扫描加速,Ubtree支持索引数据的多版本管理及可见性检查,索引层的可见性检查使得索引扫描(Index Scan)及仅索引扫描(IndexOnly Scan)性能有所提升。 对于索引扫描: 若索引列包含所有扫描列(IndexOnly Scan),则通过扫描条件在索引上进行二分查找,找到符合条件元组即可返回数据。 若索引列不包含所有扫描列(Index Scan),则通过扫描条件在索引上进行二分查找,找到符合条件元组的TID,再通过TID到数据表上查找对应的数据元组。如下图所示。 父主题: RCR UBTree
  • 示例 -- 修改表的默认类型 gaussdb=# set enable_default_ustore_table=off; -- 准备数据 CREATE TABLE t1(c1 int, c2 int); INSERT INTO t1 VALUES(1, 1); INSERT INTO t1 VALUES(2, 2); -- 创建全量物化视图 gaussdb=# CREATE MATERIALIZED VIEW mv AS select count(*) from t1; CREATE MATERIALIZED VIEW -- 查询物化视图结果 gaussdb=# SELECT * FROM mv; count ------- 2 (1 row) -- 再次向物化视图中基表插入数据 gaussdb=# INSERT INTO t1 VALUES(3, 3); -- 对全量物化视图做全量刷新 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=# DROP TABLE t1; DROP TABLE
  • 分区(分区子表、子分区) 分区表中实际保存数据的表,对应的entry通常保存在pg_partition中,各个子分区的parentid作为外键关联其分区母表在pg_class表中的OID列。 示例:t1_hash为一个分区表: gaussdb=# CREATE TABLE t1_hash (c1 INT, c2 INT, c3 INT) PARTITION BY HASH(c1) ( PARTITION p0, PARTITION p1, PARTITION p2, PARTITION p3, PARTITION p4, PARTITION p5, PARTITION p6, PARTITION p7, PARTITION p8, PARTITION p9 ); --查询t1_hash分区类型。 gaussdb=# SELECT oid, relname, parttype FROM pg_class WHERE relname = 't1_hash'; oid | relname | parttype -------+---------+---------- 16685 | t1_hash | p (1 row) --查询t1_hash的分区信息。 gaussdb=# SELECT oid, relname, parttype, parentid FROM pg_partition WHERE parentid = 16685; oid | relname | parttype | parentid -------+---------+----------+---------- 16688 | t1_hash | r | 16685 16689 | p0 | p | 16685 16690 | p1 | p | 16685 16691 | p2 | p | 16685 16692 | p3 | p | 16685 16693 | p4 | p | 16685 16694 | p5 | p | 16685 16695 | p6 | p | 16685 16696 | p7 | p | 16685 16697 | p8 | p | 16685 16698 | p9 | p | 16685 (11 rows) --删除t1_hash gaussdb=# DROP TABLE t1_hash; 父主题: 基本概念
  • 空间管理 Undo子系统依赖后台回收线程进行空闲空间回收。负责主机上Undo模块的空间回收,备机通过回放xLog进行回收。回收线程遍历使用中的undo zone,对该zone中的txn page扫描,依据xid从小到大的顺序进行遍历。回收已提交或者已回滚完成的事务,且该事务的提交时间应早于$(current_time-undo_retention_time)。对于遍历过程中需要回滚的事务,后台回收线程会为该事务添加异步回滚任务。 当数据库中存在运行时间长、修改数据量大的事务,或者开启闪回时间较长的时候,可能出现undo空间持续膨胀的情况。当undo占用空间接近undo_space_limit_size时,就会触发强制回收。只要事务已提交或者已回滚完成,即使事务提交时间晚于$(current_time-undo_retention_time),在这种情况下也可能被回收掉。 父主题: Undo
  • Enhanced Toast相关DDL操作 Enhanced Toast表的创建 建表时指定Toast表的存储类型为Enhanced Toast或者Toast: gaussdb=# CREATE TABLE test_toast (id int, content text) with(toast.toast_storage_type=toast); CREATE TABLE gaussdb=# \d+ test_toast Table "public.test_toast" Column | Type | Modifiers | Storage | Stats target | Description ---------+---------+-----------+----------+--------------+------------- id | integer | | plain | | content | text | | extended | | Has OIDs: no Distribute By: HASH(a) Location Nodes: ALL DATANODES Options: orientation=row, compression=no, storage_type=USTORE, segment=off, toast.storage_type=USTORE, toast.toast_storage_type=toast gaussdb=# DROP TABLE test_toast; DROP TABLE gaussdb=# CREATE TABLE test_toast (id int, content text) with(toast.toast_storage_type=enhanced_toast); CREATE TABLE gaussdb=# \d+ test_toast Table "public.test_toast" Column | Type | Modifiers | Storage | Stats target | Description ---------+---------+-----------+----------+--------------+------------- id | integer | | plain | | content | text | | extended | | Has OIDs: no Distribute By: HASH(a) Location Nodes: ALL DATANODES Options: orientation=row, compression=no, storage_type=USTORE, segment=off, toast.storage_type=USTORE, toast.toast_storage_type=enhanced_toast gaussdb=# DROP TABLE test_toast; DROP TABLE 建表时不指定线外存储表的类型,则创建线外存储表类型依赖于GUC参数enable_enhance_toast_table: -- 根据“Enhanced Toast使用”章节打开GUC gaussdb=# show enable_enhance_toast_table; enable_enhance_toast_table ---------------------------- on (1 row) gaussdb=# CREATE TABLE test_toast (id int, content text); CREATE TABLE gaussdb=# \d+ test_toast Table "public.test_toast" Column | Type | Modifiers | Storage | Stats target | Description ---------+---------+-----------+----------+--------------+------------- id | integer | | plain | | content | text | | extended | | Has OIDs: no Distribute By: HASH(a) Location Nodes: ALL DATANODES Options: orientation=row, compression=no, storage_type=USTORE, segment=off, toast.storage_type=USTORE, toast.toast_storage_type=enhanced_toast gaussdb=# DROP TABLE test_toast; DROP TABLE gaussdb=# SET enable_enhance_toast_table = off; SET gaussdb=# show enable_enhance_toast_table; enable_enhance_toast_table ---------------------------- off (1 row) gaussdb=# CREATE TABLE test_toast (id int, content text); CREATE TABLE gaussdb=# \d+ test_toast Table "public.test_toast" Column | Type | Modifiers | Storage | Stats target | Description ---------+---------+-----------+----------+--------------+------------- id | integer | | plain | | content | text | | extended | | Has OIDs: no Distribute By: HASH(a) Location Nodes: ALL DATANODES Options: orientation=row, compression=no, storage_type=USTORE, segment=off, toast.storage_type=USTORE, toast.toast_storage_type=toast gaussdb=# DROP TABLE test_toast; DROP TABLE 线外存储表结构的升级 当GUC参数“enable_enhance_toast_table=on”时,线外存储表支持通过Vacuum Full操作将Toast升级为Enhanced Toast结构。 gaussdb=# CREATE TABLE test_toast (id int, content text); CREATE TABLE gaussdb=# \d+ test_toast Table "public.test_toast" Column | Type | Modifiers | Storage | Stats target | Description ---------+---------+-----------+----------+--------------+------------- id | integer | | plain | | content | text | | extended | | Has OIDs: no Distribute By: HASH(a) Location Nodes: ALL DATANODES Options: orientation=row, compression=no, storage_type=USTORE, segment=off, toast.storage_type=USTORE, toast.toast_storage_type=toast gaussdb=# VACUUM FULL test_toast; VACUUM gaussdb=# \d+ test_toast Table "public.test_toast" Column | Type | Modifiers | Storage | Stats target | Description ---------+---------+-----------+----------+--------------+------------- id | integer | | plain | | content | text | | extended | | Has OIDs: no Distribute By: HASH(a) Location Nodes: ALL DATANODES Options: orientation=row, compression=no, storage_type=USTORE, segment=off, toast.storage_type=USTORE, toast.toast_storage_type=enhanced_toast gaussdb=# DROP TABLE test_toast; DROP TABLE 分区表merge操作 支持将分区表的分区间不同的线外存储表类型进行合并操作。 对于相同类型的线外存储分区,合并与原有逻辑保持一致,进行物理合并。 对于不同类型的线外存储分区,合并后的分区线外存储表为Enhanced Toast表,需要进行逻辑合并,性能劣于物理合并。 gaussdb=# CREATE TABLE test_partition_table(a int, b text)PARTITION BY range(a)(partition p1 values less than (2000),partition p2 values less than (3000)); gaussdb=# SELECT relfilenode FROM pg_partition WHERE relname='p1'; relfilenode ------------- 17529 (1 row) gaussdb=# \d+ pg_toast.pg_toast_part_17529 TOAST table "pg_toast.pg_toast_part_17529" Column | Type | Storage ------------+---------+--------- chunk_id | oid | plain chunk_seq | integer | plain chunk_data | bytea | plain Options: storage_type=ustore, toast_storage_type=toast gaussdb=# SELECT relfilenode FROM pg_partition WHERE relname='p2'; relfilenode ------------- 17528 (1 row) gaussdb=# \d+ pg_toast.pg_toast_part_17528 TOAST table "pg_toast.pg_toast_part_17528" Column | Type | Storage ------------+---------+--------- chunk_seq | integer | plain next_chunk | tid | plain chunk_data | bytea | plain Options: storage_type=ustore, toast_storage_type=enhanced_toast gaussdb=# ALTER TABLE test_partition_table MERGE PARTITIONS p1,p2 INTO partition p1_p2; ALTER TABLE gaussdb=# SELECT reltoastrelid::regclass FROM pg_partition where relname='p1_p2'; reltoastrelid ------------------------------ pg_toast.pg_toast_part_17559 (1 row) gaussdb=# \d+ pg_toast.pg_toast_part_17559 TOAST table "pg_toast.pg_toast_part_17559" Column | Type | Storage ------------+---------+--------- chunk_seq | integer | plain next_chunk | tid | plain chunk_data | bytea | plain Options: storage_type=ustore, toast_storage_type=enhanced_toast gaussdb=# DROP TABLE test_partition_table; DROP TABLE 父主题: Enhanced Toast
  • 分区表运维管理 分区表运维管理包括分区管理、分区表管理、分区索引管理和分区表业务并发支持等。 分区管理:也称分区级DDL,包括新增(Add)、删除(Drop)、交换(Exchange)、清空(Truncate)、分割(Split)、合并(Merge)、移动(Move)、重命名(Rename)共8种。 对于哈希分区,涉及分区数的变更会导致数据re-shuffling,故当前GaussDB不支持导致Hash分区数变更的操作,包括新增(Add)、删除(Drop)、分割(Split)、合并(Merge)这4种。 涉及分区数据变更的操作会使得Global索引失效,可以通过UPDATE GLOBAL INDEX子句来同步更新Global索引,包括删除(Drop)、交换(Exchange)、清空(Truncate)、分割(Split)、合并(Merge)这5种。 大部分分区DDL支持partition和partition for指定分区两种写法,前者需要指定分区名,后者需要指定分区定义范围内的任一分区值。比如假设分区part1的范围定义为[100, 200),那么partition part1和partition for(150)这两种写法是等价的。 不同分区DDL的执行代价各不相同,由于在执行分区DDL过程中目标分区会被锁住,用户需要评估其代价以及对业务的影响。一般而言,分割(Split)、合并(Merge)的执行代价远大于其他分区DDL,与源分区的大小正相关;交换(Exchange)的代价主要源于Global索引的重建和validation校验;移动(Move)的代价限制于磁盘I/O;其余分区DDL的执行代价都很低。 分区表管理:除了继承普通表的功能外,还支持开启/关闭分区表行迁移的功能。 分区索引管理:支持用户设置索引/索引分区不可用,或者重建不可用的索引/索引分区,比如由于分区管理操作导致的Global索引失效场景。 分区表业务并发支持:分布式分区表的DDL操作会锁全表,不支持跨分区DDL-DQL/DML并发。 新增分区 删除分区 交换分区 清空分区 分割分区 合并分区 移动分区 重命名分区 分区表行迁移 分区表索引重建/不可用 父主题: 分区表
  • RCR Uheap多版本管理 Ustore对其使用的heap做了如下重要的增强,简称Uheap。 Ustore RCR(Row Consistency Read)的多版本管理是基于数据行的行级多版本管理。不过Ustore将XID记录在了页面的TD(Transaction Directory)区域区别于常见的将XID存储在数据行上,节省了页面空间。事务修改记录时,会将历史数据记录到Undo Row中,在Tuple中的td_id指向的TD槽上记录产生的Undo Row地址(zone_id, block no, page offset),并将新的数据覆盖写入页面。访问元组时,沿着版本链还原该元组,直到找到自己对应的版本。 父主题: RCR Uheap
  • 索引重建/不可用 使用ALTER INDEX可以设置索引是否可用。 例如,假设分区表range_ sales上存在索引range_sales_idx,可以通过如下命令设置其不可用。 ALTER INDEX range_sales_idx UNUSABLE; 可以通过如下命令重建索引range_sales_idx。 ALTER INDEX range_sales_idx REBUILD; 父主题: 分区表索引重建/不可用
  • 概述 Enhanced Toast是一种用于处理超大字段的技术。首先,减少了Toast Pointer中的冗余信息,存储支持单表超长字段列数超过500列。其次,优化了主表与线外存储表之间的映射关系,无需通过pg_toast_index来存储主表数据与线外存储表数据的关系,降低了用户存储空间。最后,Enhanced Toast技术通过让分割数据自链接,消除了Oid分配的依赖,极大地加快了写入效率。 Astore存储引擎不支持Enhanced Toast。 不支持对Enhanced Toast类型的线外存储表单独进行Vacuum Full操作。 父主题: Enhanced Toast
  • 问题分析 在开启并行回放或串行回放的情况下(查询GUC参数recovery_parse_workers和recovery_max_workers均是1为串行回放;recovery_parse_workers是1,recovery_max_workers大于1为并行回放),备机的查询线程在做索引扫描时,会先对索引页面加读锁,每当扫到一个元组时会去判可见性。如果该元组对应的事务处于committing状态,需要等待该事务提交后再判断。而备机上的事务提交是依赖日志回放线程推进的,这个过程中会对索引页面进行修改,因此需要加锁。查询线程在等待过程中会释放索引页面的锁,否则会出现查询线程等待回放线程进行事务提交,而回放线程在等待查询线程释放锁。 该报错仅出现在查询与回放都需要访问同一个索引页面的场景下,查询线程在释放锁并等待事务结束过程中,访问的页面出现被修改的情况。具体流程图如下图1所示: 备机查询在扫到committing状态的元组时,需要等待事务提交是因为事务提交的顺序与产生日志的顺序可能是乱序的。例如主机上tx_1的事务比tx_2先提交,而备机上tx_1的commit日志在tx_2的commit日志之后回放,按照事务提交顺序来看tx_1对tx_2应当是可见的,所以需要等待事务提交。 备机查询在扫描索引页面时,发现页面元组数量(包含死元组)发生变化后不可重试,是因为在扫描时可能为正向或反向扫描,而举例来说页面发生分裂后一部分元组移动到右页面,在反向扫描的情况下即使重试只能向左扫描读取,无法再保证结果的正确性,并且由于无法分辨发生分裂或者插入,所以不可重试。 图1 问题分析
  • 示例 创建分区表并插入数据 gaussdb=# CREATE TABLE t1_range_int ( c1 INT, c2 INT, c3 INT, c4 INT ) PARTITION BY RANGE(c1) ( PARTITION range_p00 VALUES LESS THAN(10), PARTITION range_p01 VALUES LESS THAN(20), PARTITION range_p02 VALUES LESS THAN(30), PARTITION range_p03 VALUES LESS THAN(40), PARTITION range_p04 VALUES LESS THAN(50) ); gaussdb=# INSERT INTO t1_range_int SELECT v,v,v,v FROM generate_series(0, 49) AS v; 级联收集统计信息 gaussdb=# ANALYZE t1_range_int WITH ALL; 查看分区级统计信息 gaussdb=# SELECT relname, parttype, relpages, reltuples FROM pg_partition WHERE parentid=(SELECT oid FROM pg_class WHERE relname='t1_range_int') ORDER BY relname; relname | parttype | relpages | reltuples --------------+----------+----------+----------- range_p00 | p | 4 | 9 range_p01 | p | 7 | 17 range_p02 | p | 6 | 13 range_p03 | p | 2 | 5 range_p04 | p | 4 | 9 t1_range_int | r | 0 | 0 (6 rows) gaussdb=# SELECT schemaname,tablename,partitionname,subpartitionname,attname,inherited,null_frac,avg_width,n_distinct,n_dndistinct,most_common_vals,most_common_freqs,histogram_bounds FROM pg_stats WHERE tablename='t1_range_int' ORDER BY tablename, partitionname, attname; schemaname | tablename | partitionname | subpartitionname | attname | inherited | null_frac | avg_width | n_distinct | n_dndistinct | most_common_vals | most_common_freqs | histogram_bounds ------------+--------------+---------------+------------------+---------+-----------+-----------+-----------+------------+--------------+------------------+-------------------+---------------------------------------------------------------------------------------------- ------------------------------------------------- public | t1_range_int | range_p00 | | c1 | f | 0 | 4 | -1 | -1 | | | {0,1,2,3,4,5,6,7,8,9} public | t1_range_int | range_p00 | | c2 | f | 0 | 4 | -1 | -1 | | | {0,1,2,3,4,5,6,7,8,9} public | t1_range_int | range_p00 | | c3 | f | 0 | 4 | -1 | -1 | | | {0,1,2,3,4,5,6,7,8,9} public | t1_range_int | range_p00 | | c4 | f | 0 | 4 | -1 | -1 | | | {0,1,2,3,4,5,6,7,8,9} public | t1_range_int | range_p01 | | c1 | f | 0 | 4 | -1 | -1 | | | {10,11,12,13,14,15,16,17,18,19} public | t1_range_int | range_p01 | | c2 | f | 0 | 4 | -1 | -1 | | | {10,11,12,13,14,15,16,17,18,19} public | t1_range_int | range_p01 | | c3 | f | 0 | 4 | -1 | -1 | | | {10,11,12,13,14,15,16,17,18,19} public | t1_range_int | range_p01 | | c4 | f | 0 | 4 | -1 | -1 | | | {10,11,12,13,14,15,16,17,18,19} public | t1_range_int | range_p02 | | c1 | f | 0 | 4 | -1 | -1 | | | {20,21,22,23,24,25,26,27,28,29} public | t1_range_int | range_p02 | | c2 | f | 0 | 4 | -1 | -1 | | | {20,21,22,23,24,25,26,27,28,29} public | t1_range_int | range_p02 | | c3 | f | 0 | 4 | -1 | -1 | | | {20,21,22,23,24,25,26,27,28,29} public | t1_range_int | range_p02 | | c4 | f | 0 | 4 | -1 | -1 | | | {20,21,22,23,24,25,26,27,28,29} public | t1_range_int | range_p03 | | c1 | f | 0 | 4 | -1 | -1 | | | {30,31,32,33,34,35,36,37,38,39} public | t1_range_int | range_p03 | | c2 | f | 0 | 4 | -1 | -1 | | | {30,31,32,33,34,35,36,37,38,39} public | t1_range_int | range_p03 | | c3 | f | 0 | 4 | -1 | -1 | | | {30,31,32,33,34,35,36,37,38,39} public | t1_range_int | range_p03 | | c4 | f | 0 | 4 | -1 | -1 | | | {30,31,32,33,34,35,36,37,38,39} public | t1_range_int | range_p04 | | c1 | f | 0 | 4 | -1 | -1 | | | {40,41,42,43,44,45,46,47,48,49} public | t1_range_int | range_p04 | | c2 | f | 0 | 4 | -1 | -1 | | | {40,41,42,43,44,45,46,47,48,49} public | t1_range_int | range_p04 | | c3 | f | 0 | 4 | -1 | -1 | | | {40,41,42,43,44,45,46,47,48,49} public | t1_range_int | range_p04 | | c4 | f | 0 | 4 | -1 | -1 | | | {40,41,42,43,44,45,46,47,48,49} public | t1_range_int | | | c1 | f | 0 | 4 | -1 | -1 | | | {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33, 34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49} public | t1_range_int | | | c2 | f | 0 | 4 | -1 | -1 | | | {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33, 34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49} public | t1_range_int | | | c3 | f | 0 | 4 | -1 | -1 | | | {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33, 34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49} public | t1_range_int | | | c4 | f | 0 | 4 | -1 | -1 | | | {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33, 34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49} (24 rows) 生成多列数据的分区级统计信息 gaussdb=# ALTER TABLE t1_range_int ADD STATISTICS ((c2, c3)); gaussdb=# ANALYZE t1_range_int WITH ALL; 查看多列数据的分区级统计信息 gaussdb=# SELECT schemaname,tablename,partitionname,subpartitionname,attname,inherited,null_frac,avg_width,n_distinct,n_dndistinct,most_common_vals,most_common_freqs,histogram_bounds FROM pg_ext_stats WHERE tablename='t1_range_int' ORDER BY tablename,partitionname,attname; schemaname | tablename | partitionname | subpartitionname | attname | inherited | null_frac | avg_width | n_distinct | n_dndistinct | most_common_vals | most_common_freqs | histogram_bounds ------------+--------------+---------------+------------------+---------+-----------+-----------+-----------+------------+--------------+------------------+-------------------+------------------ public | t1_range_int | range_p00 | | 2 3 | f | 0 | 8 | -1 | -1 | | | public | t1_range_int | range_p01 | | 2 3 | f | 0 | 8 | -1 | -1 | | | public | t1_range_int | range_p02 | | 2 3 | f | 0 | 8 | -1 | -1 | | | public | t1_range_int | range_p03 | | 2 3 | f | 0 | 8 | -1 | -1 | | | public | t1_range_int | range_p04 | | 2 3 | f | 0 | 8 | -1 | -1 | | | public | t1_range_int | | | 2 3 | f | 0 | 8 | -1 | -1 | | | (6 rows) 创建表达式索引并生成对应的分区级统计信息 gaussdb=# CREATE INDEX t1_range_int_index ON t1_range_int(text(c1)) LOCAL; gaussdb=# ANALYZE t1_range_int WITH ALL; 查看表达式索引的分区级统计信息 gaussdb=# SELECT schemaname,tablename,partitionname,subpartitionname,attname,inherited,null_frac,avg_width,n_distinct,n_dndistinct,most_common_vals,most_common_freqs,histogram_bounds FROM pg_stats WHERE tablename='t1_range_int_index' ORDER BY tablename,partitionname,attname; schemaname | tablename | partitionname | subpartitionname | attname | inherited | null_frac | avg_width | n_distinct | n_dndistinct | most_common_vals | most_common_freqs | histogram_bounds ------------+--------------------+--------------------+------------------+---------+-----------+-----------+-----------+------------+--------------+------------------+-------------------+----------------------------------------------------------------------------------- ------------------------------------------------------------ public | t1_range_int_index | range_p00_text_idx | | text | f | 0 | 5 | -1 | 0 | | | {0,1,2,3,4,5,6,7,8,9} public | t1_range_int_index | range_p01_text_idx | | text | f | 0 | 6 | -1 | 0 | | | {10,11,12,13,14,15,16,17,18,19} public | t1_range_int_index | range_p02_text_idx | | text | f | 0 | 6 | -1 | 0 | | | {20,21,22,23,24,25,26,27,28,29} public | t1_range_int_index | range_p03_text_idx | | text | f | 0 | 6 | -1 | 0 | | | {30,31,32,33,34,35,36,37,38,39} public | t1_range_int_index | range_p04_text_idx | | text | f | 0 | 6 | -1 | 0 | | | {40,41,42,43,44,45,46,47,48,49} public | t1_range_int_index | | | text | f | 0 | 5 | -1 | 0 | | | {0,1,10,11,12,13,14,15,16,17,18,19,2,20,21,22,23,24,25,26,27,28,29,3,30,31,32,33,3 4,35,36,37,38,39,4,40,41,42,43,44,45,46,47,48,49,5,6,7,8,9} (6 rows) 删除分区表 gaussdb=# DROP TABLE t1_range_int;
  • 文件组织结构 如需查询当前回滚段使用的存储方式是页式或段页式,可以查询系统表。当前仅支持页式。 示例: gaussdb=# SELECT * FROM gs_global_config where name like '%undostoragetype%'; name | value -----------------+--------- undostoragetype | page (1 row) 当回滚段使用的存储方式为页式: txn page所在文件组织结构: $node_dir/undo/{permanent|unlogged|temp}/$undo_zone_id.meta.$segno undo row所在文件组织结构: $node_dir/undo/{permanent|unlogged|temp}/$undo_zone_id.$segno 父主题: Undo
共100000条