华为云用户手册

  • 常规锁设计 分区表通过表锁+分区锁两重设计,在表和分区上分别施加8个不同级别的常规锁,来保证DQL、DML、DDL并发过程中的合理行为控制。下表给出了不同级别锁的相容行为,标记为√的两种常规锁互不阻塞,可以并行。 表1 常规锁相容行为 - AC CES S_SHARE ROW_SHARE ROW_EXCLUSIVE SHARE_UPDATE_EXCLUSIVE SHARE SHARE_ROW_EXCLUSIVE EXCLUSIVE ACCESS_EXCLUSIVE ACCESS_SHARE √ √ √ √ √ √ √ × ROW_SHARE √ √ √ √ √ √ × × ROW_EXCLUSIVE √ √ √ √ × × × × SHARE_UPDATE_EXCLUSIVE √ √ √ × × × × × SHARE √ √ × × √ × × × SHARE_ROW_EXCLUSIVE √ √ × × × × × × EXCLUSIVE √ × × × × × × × ACCESS_EXCLUSIVE × × × × × × × × 分区表的不同业务最终都是作用于目标分区上,数据库会给分区表和目标分区施加不同级别的表锁+分区锁,来控制并发行为。表2给出了不同业务的锁粒度控制。其中数字1~8分别代表表1给出的ACCESS_SHARE、ROW_SHARE、ROW_EXCLUSIVE、SHARE_UPDATE_EXCLUSIVE、SHARE、SHARE_ROW_EXCLUSIVE、EXCLUSIVE、ACCESS_EXCLUSIVE这8种级别的常规锁。 表2 分区表业务锁粒度 业务模型 分区表锁级别(表锁+分区锁) SELECT 1-1 SELECT FOR UPDATE 2-2 DML业务,包括INSERT、UPDATE、DELETE、UPSERT、MERGE INTO、COPY 3-3 大部分分区DDL,包括ADD、DROP、EXCHANGE、TRUNCATE、MOVE、RENAME 4-8 CREATE INDEX(非分类索引)、REBUILD INDEX 5-5 CREATE INDEX(分类索引) 3-5 REBUILD INDEX PARTITION 1-5 ANALYZE、VACUUM 4-4 其他分区表DDL,包括SPLIT/MERGE这两种分区DDL 8-8 如果业务执行施加的表锁和分区锁均满足表1,则可以支持业务并行操作,如果表锁和分区锁有任一不相容,则二者不支持业务并行。 DDL (ADD/DROP/TRUNCATE/EXCHANGE/MOVE/RENAME) 操作对分区表施加的表锁级别受GUC参数enable_partition_ddl_lowlevel_lock控制,当GUC参数enable_partition_ddl_lowlevel_lock设置为on时,对表施加4级锁;当GUC参数enable_partition_ddl_lowlevel_lock设置为off时,对表施加8级锁。 父主题: 分区并发控制
  • 查看动态数据脱敏基本配置 设置并查看动态数据脱敏功能是否已开启。 gs_guc reload -Z coordinator -N all -I all -c "enable_security_policy=on" enable_security_policy取值为on时表示开启,取值为off时表示关闭。 gaussdb=# SHOW enable_security_policy; enable_security_policy ----------------------- on (1 row)
  • 使用规格 SMP场景下的Full Partition-wise Join的使用规格: 支持一级HASH分区表和一级RANGE分区表。 Hash分区表的分区策略完全相同是指分区键类型相同、分区数相同。 Range分区表的分区策略完全相同是指分区键类型相同、分区数相同、分区键数量相同、每个分区的边界值相同。 仅支持Stream计划。 仅支持分区键和分布键完全一致的场景。 仅支持Join算子在单DN内完成计算,即Join算子的数据不跨节点。 支持Hash Join和Merge Join。 支持Seqscan、Indexscan、Indexonlyscan、Imcvscan。其中,对于Indexscan和Indexonlyscan,只支持分区Local索引,且索引类型为BTREE或UBTREE。 相关规格继承SMP规格,不支持SMP场景下的IUD操作。 需要开启SMP功能,且设置query_dop的值大于1。
  • 使用规格 非SMP场景下的Partition-wise Join的使用规格: 只支持一级RANGE分区。 支持Hash Join、Nestloop Join、Merge Join。 只支持Inner Join。 需要设置query_dop的值为1。 由于非SMP场景下的Partition-wise Join为规则选择,所以Partition-wise Join计划可能造成性能下降,需要用户自行决定是否启用。 仅支持FQS计划。
  • Partition-wise Join Partition-wise Join是一种分区级并行的优化技术,是指在符合一定条件的情况下,将两张表之间的Join,分解为两张表中对应的两个分区之间的Join。通过并发执行、减少数据通信量等方式,提升分区表的Join查询的性能。 Partition-wise Join分为SMP场景和非SMP场景。 非SMP场景下的Partition-wise Join SMP场景下的Full Partition-wise Join 父主题: 分区表查询优化
  • 约束 解析的WAL日志级别为logical。 数据表的复制标识必须为FULL,否则UPDATE和DELETE操作涉及到的被修改行不是全字段。 WAL日志记录的数据修改操作所对应的业务表,从找回起始位置到目前不能执行VACUUM FULL操作,否则该表VACUUM FULL之前的DML操作不会被数据找回。 每条WAL日志不能超过500MB。 不支持扩容前的Xlog日志数据找回。 集群的每个分片都会生成一个结果文件,多个文件不会进行合并。 仅支持归档数据找回,且需要开启归档,若数据尚未归档,则无法通过本接口找回。 OM_Agent在下载之前会验证本地已用空间是否大于总空间的80%,如果大于则会会报错(需要额外空间用于存放解码文件),报错信息为:"no enough space left on device, available space must be greater than 20%"。 下载失败或解码失败后,都会将下载的WAL日志文件进行清理,如果清理不成功,不会强制结束程序,只会把错误信息记录到DN的日志中。 由用户传入的时间,起始时间不能超出系统表gs_txn_lsn_time的最大时间,终止时间不能超过系统表gs_txn_lsn_time的最小时间,否则将会报错。 不支持同一节点并发调用数据找回接口。 如果进行了节点替换,不支持节点替换前的数据找回。 只支持直连DN方式的数据找回。 旧版本升级提交到新版本时,如果未基线化,则需要执行基线化后才可以使用数据找回功能,且只支持对基线化后新产生的Xlog日志进行数据找回,升级前产生的Xlog日志无法解析。 默认支持1年内的数据找回,超过1年的数据将被自动清除。如需找回超过1年的数据,需在清理前调整GUC参数logical_replication_dictionary_retention_time的值。
  • 使用步骤 逻辑解码特性需提前设置GUC参数wal_level为logical,该参数需要重启生效。 gs_guc set -Z datanode -D $node_dir -c "wal_level = logical" 其中,$node_dir为数据库节点路径,用户可根据实际情况替换。 以具有REPLICATION权限的用户登录 GaussDB数据库 主节点,使用如下命令连接数据库。 gsql -U user1 -W password -d db1 -p 16000 -r 其中,user1为用户名,password为密码,db1为需要连接的数据库名称,16000为数据库端口号,用户可根据实际情况替换。 创建名称为slot1的逻辑复制槽。 1 2 3 4 5 gaussdb=# SELECT * FROM pg_create_logical_replication_slot('slot1', 'mppdb_decoding'); slotname | xlog_position ----------+--------------- slot1 | 0/3764C788 (1 row) 在数据库中创建Package。 1 2 3 4 5 6 gaussdb=# CREATE OR REPLACE PACKAGE ldp_pkg1 IS var1 int:=1; --公有变量 var2 int:=2; PROCEDURE testpro1(var3 int); --公有存储过程,可以被外部调用 END ldp_pkg1; / 读取复制槽slot1解码结果,可通过JDBC接口或者pg_logical_slot_peek_changes推进复制槽。 逻辑解码选项请参见逻辑解码选项和新增控制参数。 并行解码中,在JDBC接口中改变参数decode_style可以决定解码格式: 通过配置选项decode-style,指定解码格式。其取值为char型的字符'j'、't'或'b',分别代表JSON格式、TEXT格式及二进制格式。 1 2 3 4 5 6 7 gaussdb=# SELECT data FROM pg_logical_slot_peek_changes('slot1', NULL, NULL, 'enable-ddl-decoding', 'true', 'enable-ddl-json-format', 'false') WHERE data not like 'BEGIN%' AND data not like 'COMMIT%' AND data not like '%dbe_pldeveloper.gs_source%'; data -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- {"TDDL":"CREATE OR REPLACE PACKAGE public.ldp_pkg1 AUTHID CURRENT_USER IS var1 int:=1; --公有变量\n var2 int:=2;\n PROCEDURE testpro1(var3 int); --公有存储过程,可以被外部调用\nEND ldp_pkg1; \n /"} (1 row) 删除逻辑复制槽slot1,删除package ldp_pkg1。 1 2 3 4 5 6 7 8 9 gaussdb=# SELECT * FROM pg_drop_replication_slot('slot1'); pg_drop_replication_slot -------------------------- (1 row) gaussdb=# DROP PACKAGE ldp_pkg1; NOTICE: drop cascades to function public.testpro1(integer) DROP PACKAGE
  • 功能描述 数据库在执行DML的时候,存储引擎会生成对应的DML日志,用于进行恢复,对这些DML日志进行解码,即可还原对应的DML语句,生成逻辑日志。而对于DDL语句,数据库并不记录DDL原语句的日志,而是记录DDL语句涉及的系统表的DML日志。DDL种类多样、语法复杂,逻辑复制要支持DDL语句,通过这些系统表的DML日志来解码原DDL语句是非常困难的。新增DDL日志记录原DDL信息,并在解码时通过DDL日志可以得到DDL原语句。 在DDL语句执行过程中,SQL引擎解析器会对原语句进行语法、词法解析,并生成解析树(不同的DDL语法会生成不同类型的解析树,解析树中包含DDL语句的全部信息)。随后,执行器通过这些信息执行对应操作,生成、修改对应元信息。 本节通过新增DDL日志的方式,来支持逻辑解码DDL,其内容由解析器结果(解析树)以及执行器结果生成,并在执行器执行完成后生成该日志。 从语法树反解析出DDL,DDL反解析能够将DDL命令转换为JSON格式的语句,并提供必要的信息在目标位置重建DDL命令。与原始DDL命令字符串相比,使用DDL反解析的好处包括: 解析出来的每个数据库对象都带有Schema,因此如果使用不同的search_path,也不会有歧义。 结构化的JSON和格式化的输出能支持异构数据库。如果用户使用的是不同的数据库版本,并且存在某些DDL语法差异,需要在应用之前解决这些差异。 反解析输出的结果是规范化后的形式,结果与用户输入等价,不保证完全相同,例如: 示例1:在函数体中没有单引号'时,函数体的分隔符$$会被解析为单引号'。 原始SQL语句: CREATE FUNCTION func(a INT) RETURNS INT AS $$ BEGIN a:= a+1; CREATE TABLE test(col1 INT); INSERT INTO test VALUES(1); DROP TABLE test; RETURN a; END; $$ LANGUAGE plpgsql; 反解析结果: CREATE FUNCTION public.func ( IN a pg_catalog.int4 ) RETURNS pg_catalog.int4 LANGUAGE plpgsql VOLATILE CALLED ON NULL INPUT SECURITY INVOKER COST 100 AS ' BEGIN a:= a+1; CREATE TABLE test(col1 INT); INSERT INTO test VALUES(1); DROP TABLE test; RETURN a; END; '; 示例3:“ALTER INDEX "Alter_Index_Index" REBUILD PARTITION "CA_ADDRESS_SK_index2"”会被反解析为“REINDEX INDEX public."Alter_Index_Index" PARTITION "CA_ADDRESS_SK_index2"”。 示例4:创建/修改范围分区表,START END语法格式均解码转化为LESS THAN语句: gaussdb=# CREATE TABLE test_create_table_partition2 (c1 INT, c2 INT) PARTITION BY RANGE (c2) ( PARTITION p1 START(1) END(1000) EVERY(200) , PARTITION p2 END(2000), PARTITION p3 START(2000) END(2500), PARTITION p4 START(2500), PARTITION p5 START(3000) END(5000) EVERY(1000) ); 会被反解析为: gaussdb=# CREATE TABLE test_create_table_partition2 (c1 INT, c2 INT) PARTITION BY RANGE (c2) ( PARTITION p1_0 VALUES LESS THAN ('1'), PARTITION p1_1 VALUES LESS THAN ('201'), PARTITION p1_2 VALUES LESS THAN ('401'), PARTITION p1_3 VALUES LESS THAN ('601'), PARTITION p1_4 VALUES LESS THAN ('801'), PARTITION p1_5 VALUES LESS THAN ('1000'), PARTITION p2 VALUES LESS THAN ('2000'), PARTITION p3 VALUES LESS THAN ('2500'), PARTITION p4 VALUES LESS THAN ('3000'), PARTITION p5_1 VALUES LESS THAN ('4000'), PARTITION p5_2 VALUES LESS THAN ('5000') );
  • 规格约束 逻辑解码支持DDL规格: 纯DDL逻辑解码性能标准环境下约为100MB/S,DDL/DML混合事务逻辑解码性能标准环境下约为100MB/S。 开启此功能后(设置wal_level=logical且enable_logical_replication_ddl=on),对DDL语句影响性能下降小于15%。 解码通用约束(串行和并行): 不支持解码本地临时对象的DDL操作。 不支持FOREIGN TABLE场景的DDL解码。 alter table add column的default值不支持stable类型和volatile类型的函数;create table和alter table的column的check表达式不支持stable类型和volatile类型的函数;alter table如果有多条子语句,只要其中一条子语句存在上述两种情况,则该条alter table整条语句不反解析。 gaussdb=# ALTER TABLE tbl_28 ADD COLUMN b1 TIMESTAMP DEFAULT NOW(); -- 's' NOT DEPARSE gaussdb=# ALTER TABLE tbl_28 ADD COLUMN b2 INT DEFAULT RANDOM(); -- 'v' NOT DEPARSE gaussdb=# ALTER TABLE tbl_28 ADD COLUMN b3 INT DEFAULT ABS(1); -- 'i' DEPARSE 不支持分布式CREATE MATERIALIZED VIEW的DDL解码。 不支持CREATE/ALTER/DROP VIEW、COMMENT ON VIEW的DDL解码。 不支持REINDEX DATABASE/SYSTEM的DDL解码。 不支持视图上触发器相关的DDL解码。 不支持CONCURRENTLY相关语句的DDL解码。 创建对象时语句中存在IF NOT EXISTS时,如果对象已存在,则不进行解码。删除对象时语句中存在IF EXISTS时,如果对象不存在,则不进行解码。 不对ALTER PACKAGE COMPILE语句进行解码,但会解码实例化内容中包含的DDL/DML语句。如果PACKAGE里没有DDL或DML部分的实例化内容,则alter package compile会被逻辑解码忽略。 仅支持本版本之前版本的商用DDL语法,以下SQL语句不支持逻辑解码。 创建行存表,设置ILM策略。 原始SQL语句: gaussdb=# CREATE TABLE IF NOT EXISTS tb3 (c1 int) with (storage_type=USTORE,ORIENTATION=ROW) ILM ADD POLICY ROW STORE COMPRESS ADVANCED ROW AFTER 7 day OF NO MODIFICATION; 反解析结果: gaussdb=# CREATE TABLE IF NOT EXISTS public.tb3 (c1 pg_catalog.int4) WITH (storage_type = 'ustore', orientation = 'row', compression = 'no') NOCOMPRESS; 逻辑解码不支持DDL(DCL)/DML混合事务,混合事务中DDL之后的DML解码不支持。 -- 均不反解析,DCL为不支持语句故不解析,DML处于DCL之后也不反解析 gaussdb=# BEGIN; gaussdb=# GAINT ALL PRIVILEGES to u01; gaussdb=# INSERT INTO test1(col1) values(1); gaussdb=# COMMIT; -- 只反解析第一句和第三句SQL语句 gaussdb=# BEGIN; gaussdb=# CREATE TABLE mix_tran_t4(id int); gaussdb=# INSERT INTO mix_tran_t4 VALUES(111); gaussdb=# CREATE TABLE mix_tran_t5(id int); gaussdb=# COMMIT; -- 只反解析第一句和第二句SQL语句 gaussdb=# BEGIN; gaussdb=# INSERT INTO mix_tran_t4 VALUES(111); gaussdb=# CREATE TABLE mix_tran_t6(id int); gaussdb=# INSERT INTO mix_tran_t4 VALUES(111); gaussdb=# COMMIT; -- 全反解析 gaussdb=# BEGIN; gaussdb=# INSERT INTO mix_tran_t4 VALUES(111); gaussdb=# CREATE TABLE mix_tran_t7(id int); gaussdb=# CREATE TABLE mix_tran_t8(id int); gaussdb=# COMMIT; -- 只反解析第一句和第三句SQL语句 gaussdb=# BEGIN; gaussdb=# CREATE TABLE mix_tran_t7(id int); gaussdb=# CREATE TYPE compfoo AS (f1 int, f2 text); gaussdb=# CREATE TABLE mix_tran_t8(id int); gaussdb=# COMMIT; -- 全反解析 gaussdb=# BEGIN; gaussdb=# INSERT INTO mix_tran_t4 VALUES(111); gaussdb=# INSERT INTO mix_tran_t4 VALUES(111); gaussdb=# INSERT INTO mix_tran_t4 VALUES(111); gaussdb=# COMMIT; -- 只反解析第一句SQL语句 gaussdb=# BEGIN; gaussdb=# INSERT INTO mix_tran_t4 VALUES(111); gaussdb=# CREATE TYPE compfoo AS (f1 int, f2 text); gaussdb=# INSERT INTO mix_tran_t4 VALUES(111); gaussdb=# COMMIT; -- 只反解析第一句和第三句SQL语句 gaussdb=# BEGIN; gaussdb=# INSERT INTO mix_tran_t4 VALUES(111); gaussdb=# CREATE TYPE compfoo AS (f1 int, f2 text); gaussdb=# CREATE TABLE mix_tran_t9(id int); gaussdb=# COMMIT; 逻辑解码语句CREATE TABLE AS SELECT、SELECT INTO和CREATE TABLE AS仅能解码出CREATE TABLE语句,暂不支持解码INSERT语句。 对于CTAS创建的表,仍会解码其ALTER和DROP语句。 示例: 原始SQL语句: CREATE TABLE IF NOT EXISTS tb35_2 (c1 int) with (storage_type=USTORE,ORIENTATION=ROW); INSERT INTO tb35_2 VALUES (6); CREATE TABLE tb35_1 with (storage_type=USTORE,ORIENTATION=ROW) AS SELECT * FROM tb35_2; 最后一句SQL语句反解析结果: CREATE TABLE public.tb35_1 (c1 pg_catalog.int4) WITH (storage_type = 'ustore', orientation = 'row', compression = 'no') NOCOMPRESS; 执行存储过程/函数/高级包时,若其本身包含DDL/DML混合事务或者其本身与同事务内其他语句组成DDL/DML混合事务,则按照混合事务原则执行解码。 逻辑解码不支持账本数据库功能,创建账本数据库的DDL语句解码结果中会包含hash列。 原始语句: CREATE SCHEMA blockchain_schema WITH BLOCKCHAIN; CREATE TABLE blockchain_schema.blockchain_table(mes int); 解码结果: CREATE SCHEMA blockchain_schema WITH BLOCKCHAIN; CREATE TABLE blockchain_schema.blockchain_table (mes pg_catalog.int4, hash_a1d895 pg_catalog.hash16); -- 此语句无法在目标端回放。 需要在目标端手动关闭blockchain_schema的防篡改属性后,才可以正常回放,此时目标端的blockchain_table等同于一张普通表,再次执行DML命令可以正常回放。 SQL命令: ALTER SCHEMA blockchain_schema WITHOUT BLOCKCHAIN; CREATE TABLE blockchain_schema.blockchain_table (mes pg_catalog.int4, hash_a1d895 pg_catalog.hash16); MYSQL兼容模式不支持ALTER SCHEMA schema_name WITHOUT/WITH BLOCKCHAIN语法反解析。 串行逻辑解码支持DDL特有约束: sql_decoding插件不支持JSON格式的DDL。
  • 解码格式 JSON格式 对于输入的DDL语句,SQL引擎解析器会通过语法、词法分析将其分解为解析树,解析树节点中包含了DDL的全部信息,并且执行器会根据解析树内容,执行系统元信息的修改。在执行器执行完成之后,便可以获取到DDL操作数据对象的search_path。本特性在执行器执行成功之后,对解析树信息以及执行器结果进行反解析,以还原出DDL原语句的全部信息。反解析的方式可以分解整个DDL语句,以方便输出JSON格式的DDL,用以适配异构数据库场景。 CREATE TABLE语句在经过词法、语法分析之后,得到对应的CreateStmt解析树节点,节点中包含了表信息、列信息、分布式信息(DistributeBy结构体)、分区信息(PartitionState结构)等。通过反解析后,可输出的JSON格式如下: {"JDDL":{"fmt":"CREATE %{persistence}s TABLE %{if_not_exists}s %{identity}D %{table_elements}s %{with_clause}s %{compression}s","identity":{"object_name":"test_create_table_a","schema_name":"public"},"compression":"NOCOMPRESS","persistence":"","with_clause":{"fmt":"WITH (%{with:, }s)","with":[{"fmt":"%{label}s = %{value}L","label":{"fmt":"%{label}I","label":"orientation"},"value":"row"},{"fmt":"%{label}s = %{value}L","label":{"fmt":"%{label}I","label":"compression"},"value":"no"}]},"if_not_exists":"","table_elements":{"fmt":"(%{elements:, }s)","elements":[{"fmt":"%{name}I %{column_type}T","name":"a","column_type":{"typmod":"","typarray":false,"type_name":"int4","schema_name":"pg_catalog"}}]}}} 可以看到,JSON格式中包含对象的search_path,其中的identity键标识schema为public,表名为test_create_table_a,其中%{persistence}s对应的字段如下,此SQL语句不含此字段所以为空。 [ [ GLOBAL | LOCAL ] [ TEMPORARY | TEMP ] | UN LOG GED ] %{if_not_exists}s对应SQL语句中的字段,不含此字段所以为空: [ IF NOT EXISTS ] %{identity}D对应SQL语句中的字段: table_name %{table_elements}s对应SQL语句中的字段: (column_name data_type) %{with_clause}s对应SQL语句中的字段: [ WITH ( {storage_parameter = value} [, ... ] ) ] %{compression}s对应SQL语句中的字段: [ COMPRESS | NOCOMPRESS ] decode-style指定格式 输出的格式由decode-style参数控制,如当decode-style='j'时,输出格式如下: {"TDDL":"CREATE TABLE public.test_create_table_a (a pg_catalog.int4) WITH (orientation = 'row', compression = 'no') NOCOMPRESS"} 其中语句中也包含Schema名称。
  • 接口设计 新增控制参数 新增逻辑解码控制参数,用于控制DDL的反解析流程以及输出形式。可通过JDBC接口或者pg_logical_slot_peek_changes开启。 enable-ddl-decoding:默认false,不开启DDL语句的逻辑解码;值为true时,开启DDL语句的逻辑解码。 enable-ddl-json-format:默认false,传送TEXT格式的DDL反解析结果;值为true时,传送JSON格式的DDL反解析结果。 新增GUC参数 enable_logical_replication_ddl:默认为ON,ON状态下,逻辑复制可支持DDL,否则,不支持DDL。只有当ON状态下,才会对DDL执行结果进行反解析,并生成DDL的WAL日志。否则,不反解析也不生成WAL日志。 enable_logical_replication_ddl的开关日志,以证明是否是用户修改了该参数导致逻辑解码不支持DDL。 新增日志 新增DDL日志xl_logical_ddl_message,其类型为RM_LOGICALDDLMSG_ID。其定义如下: 名称 类型 意义 db_id OID 数据库ID rel_id OID 表ID csn CommitSeqNo CS N快照 cid CommandId Command ID tag_type NodeTag DDL类型 message_size Size 日志内容长度 filter_message_size Size 日志中白名单过滤信息长度 message char * DDL内容
  • 使用file_fdw 创建服务器对象:CREATE SERVER。 创建用户映射:CREATE USER MAPPING。 创建外表:CREATE FOREIGN TABLE。 外表的表结构需要与指定的文件的数据保持一致。 对外表做查询操作,写操作不被允许。 删除外表:DROP FOREIGN TABLE。 删除用户映射:DROP USER MAPPING。 删除服务器对象:DROP SERVER。
  • 维护窗口参数配置 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。 ENABLE_META_COMPRESSION:是否开启header压缩,默认为0,取值范围为0(关闭)和1(开启)。用户可根据自己的实际情况来进行开启或关闭。 SAMPLE_MIN:常量编码和等值编码采样步长最小值,默认为10,取值范围[1, 100],支持小数输入,小数会自动向下取整。用户可根据自己的实际情况来设置具体值。 SAMPLE_MAX:常量编码和等值编码采样步长最大值,默认为10,取值范围[1, 100],支持小数输入,小数会自动向下取整。用户可根据自己的实际情况来设置具体值。 CONST_PRIO:常量编码优先级,默认为40,取值范围[0, 100],100表示关闭常量编码,支持小数输入,小数会自动向下取整。用户可根据自己的实际情况来设置具体值。 CONST_THRESHOLD:常量编码阈值,默认为90,取值范围[1, 100],表示一列常量值的占比超过该阈值时进行常量编码,支持小数输入,小数会自动向下取整。用户可根据自己的实际情况来设置具体值。 EQVALUE_PRIO:等值编码优先级,默认为60,取值范围[0, 100],100表示关闭等值编码,支持小数输入,小数会自动向下取整。用户可根据自己的实际情况来设置具体值。 EQVALUE_THRESHOLD:等值编码阈值,默认为80,取值范围[1, 100],表示两列数据的等值比例超过该阈值时进行等值编码,支持小数输入,小数会自动向下取整。用户可根据自己的实际情况来设置具体值。 ENABLE_DELTA_ENCODE_SWITCH:差值编码开关,默认为1,支持小数输入,0表示关闭,1表示开启,小数会自动向下取整。用户可根据自己的实际情况来设置具体值。 LZ4_COMPRESSION_LEVEL:lz4压缩等级,默认为0,取值范围[0, 16],支持小数输入,小数会自动向下取整。用户可根据自己的实际情况来设置具体值。 ENABLE_LZ4_PARTIAL_DECOMPRESSION:部分解压开关,默认为1,支持小数输入,0表示关闭,1表示开启,小数会自动向下取整。用户可根据自己的实际情况来进行开启或关闭。 示例分析: EXECUTION_INTERVAL:15 JOB_SIZELIMIT:10240 WIND_DURATION:240 BLOCK_LIMITS:0 此配置下单表分区在一个维护窗口期间可完成240/15*10240MB=160GB数据的评估压缩。压缩带宽为100MB/秒,实际压缩仅耗时160GB/(100MB/秒)=27分钟。其他时间对业务无影响。用户可根据自己业务闲时可支配给压缩的时长来调节参数。 父主题: 数据生命周期管理-OLTP表压缩
  • 特性规格 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表压缩
  • 特性约束 不支持系统表、内存表、全局临时表、本地临时表和序列表,不支持Ustore段页式表,不支持unlogged表,不支持压缩toast数据。 仅在ORA兼容模式、PG模式以及B兼容模式下有效。 Ustore不支持编解码,压缩率低于Astore。 普通表开启压缩时,扩容空间预留需按照解压后的大小评估。 扩容期间不支持压缩调度。 扩容前请确认当前是否有正在执行的压缩任务,如果有的话,要么等待压缩任务结束,要么执行DBE_ILM.STOP_ILM或DBE_ILM_ADMIN.DISABLE_ILM停掉,扩容完成后再执行DBE_ILM_ADMIN.ENABLE_ILM开启。 由于当前版本新增了部分解压特性,会导致部分极小的表在判断压缩收益时不通过,从而不进行压缩。但此前没有部分解压的版本可以压缩。例如:单表单字段int1类型的数据从当前版本开始无法进行压缩。 父主题: 数据生命周期管理-OLTP表压缩
  • 问题分析 在开启并行回放或串行回放的情况下(查询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 问题分析
  • 常用视图工具 视图类型 类型 功能描述 使用场景 函数名称 解析 全类型 用于解析指定表页面,并返回存放解析内容的路径。 查看页面信息。 查看元组(非用户数据)信息。 页面或者元组损坏。 元组可见性问题。 校验报错问题。 gs_parse_page_bypath 索引回收队列(URQ) 用于解析UB-tree索引回收队列关键信息。 UB-tree索引空间膨胀。 UB-tree索引空间回收异常。 校验报错问题。 gs_urq_dump_stat 回滚段(Undo) 用于解析指定Undo Record的内容,不包含旧版本元组的数据。 undo空间膨胀。 undo回收异常。 回滚异常。 日常巡检。 校验报错。 可见性判断异常。 修改参数。 gs_undo_dump_record 用于解析指定事务生成的所有Undo Record,不包含旧版本元组的数据。 gs_undo_dump_xid 用于解析指定UndoZone中所有Transaction Slot信息。 gs_undo_translot_dump_slot 用于解析指定事务对应Transaction Slot信息,包括事务XID和该事务生成的Undo Record范围. gs_undo_translot_dump_xid 用于解析指定Undo Zone的元信息,显示Undo Record和Transaction Slot指针使用情况。 gs_undo_meta_dump_zone 用于解析指定Undo Zone对应Undo Space的元信息,显示Undo Record文件使用情况。 gs_undo_meta_dump_spaces 用于解析指定Undo Zone对应Slot Space的元信息,显示Transaction Slot文件使用情况。 gs_undo_meta_dump_slot 用于解析数据页和数据页上数据的所有历史版本,并返回存放解析内容的路径。 gs_undo_dump_parsepage_mv 预写日志 (WAL) 用于解析指定LSN范围之内的xLog日志,并返回存放解析内容的路径。可以通过pg_current_xlog_location()获取当前xLog位置。 WAL日志出错。 日志回放出错。 页面损坏。 gs_xlogdump_lsn 用于解析指定XID的xLog日志,并返回存放解析内容的路径。可以通过txid_current()获取当前事务ID。 gs_xlogdump_xid 用于解析指定表页面对应的日志,并返回存放解析内容的路径。 gs_xlogdump_tablepath 用于解析指定表页面和表页面对应的日志,并返回存放解析内容的路径。可以看做一次执行gs_parse_page_bypath和gs_xlogdump_tablepath。该函数执行的前置条件是表文件存在。如果想查看已删除的表的相关日志,请直接调用gs_xlogdump_tablepath。 gs_xlogdump_parsepage_tablepath 统计 回滚段(Undo) 用于显示Undo模块的统计信息,包括Undo Zone使用情况、Undo链使用情况、Undo模块文件创建删除情况和Undo模块参数设置推荐值。 Undo空间膨胀。 Undo资源监控。 gs_stat_undo 预写日志 (WAL) 用于统计预写日志(WAL)写盘时的内存状态表内容。 WAL写/刷盘监控。 WAL写/刷盘hang住。 gs_stat_wal_entrytable 用于统计预写日志(WAL)刷盘状态、位置统计信息。 gs_walwriter_flush_position 用于统计预写日志(WAL)写刷盘次数频率、数据量以及刷盘文件统计信息。 gs_walwriter_flush_stat 校验 堆表/索引 用于离线校验表或者索引文件磁盘页面数据是否异常。 页面损坏或者元组损坏。 可见性问题。 日志回放出错问题。 ANALYZE VERIFY 用于校验当前实例当前库物理文件是否存在丢失。 文件丢失。 gs_verify_data_file 索引回收队列(URQ) 用于校验UB-tree索引回收队列(潜在队列/可用队列/单页面)数据是否异常。 UB-tree索引空间膨胀。 UB-tree索引空间回收异常。 gs_verify_urq 回滚段(Undo) 用于离线校验Undo Record数据是否存在异常。 Undo Record异常或者损坏。 可见性问题。 回滚出错或者异常。 gs_verify_undo_record 用于离线校验Transaction Slot数据是否存在异常。 Undo Record异常或者损坏。 可见性问题。 回滚出错或者异常。 gs_verify_undo_slot 用于离线校验Undo元信息数据是否存在异常。 因Undo meta引起的节点无法启动问题。 Undo空间回收异常。 Snapshot too old问题。 gs_verify_undo_meta 修复 堆表/索引/Undo文件 用于基于备机修复主机丢失的物理文件。 堆表/索引/Undo文件丢失。 gs_repair_file 堆表/索引/Undo页面 用于校验并基于备机修复主机受损页面。 堆表/索引/Undo页面损坏。 gs_verify_and_tryrepair_page 用于基于备机页面直接修复主机页面。 gs_repair_page 用于基于偏移量对页面的备份进行字节修改。 gs_edit_page_bypath 用于将修改后的页面覆盖写入到目标页面。 gs_repair_page_bypath 回滚段(Undo) 用于重建Undo元信息,如果校验发现Undo元信息没有问题则不重建。 Undo元信息异常或者损坏。 gs_repair_undo_byzone 索引回收队列(URQ) 用于重建UB-tree索引回收队列。 索引回收队列异常或者损坏。 gs_repair_urq 父主题: Ustore存储引擎
  • 相关语法 删除表 DROP TABLE table_name [PURGE] 清理回收站对象 PURGE { TABLE { table_name } | INDEX { index_name } | RECYCLEBIN } 闪回被删除的表 TIMECAPSULE TABLE { table_name } TO BEFORE DROP [RENAME TO new_tablename] 截断表 TRUNCATE TABLE { table_name } [ PURGE ] 闪回截断的表 TIMECAPSULE TABLE { table_name } TO BEFORE TRUNCATE
  • 参数说明 DROP/TRUNCATE TABLE table_name PURGE 默认将表数据放入回收站中,PURGE直接清理。 PURGE RECYCLEBIN 表示清理回收站对象。 TO BEFORE DROP 使用这个子句检索回收站中已删除的表及其子对象。 可以指定原始用户指定的表的名称,或对象删除时数据库分配的系统生成名称。 回收站中系统生成的对象名称是唯一的。因此,如果指定系统生成名称,那么数据库检索指定的对象。使用“select * from gs_recyclebin;”语句查看回收站中的内容。 在指定了用户指定的名称且回收站中包含多个该名称的对象的情况下,数据库检索回收站中最近移动的对象,如果想要检索更早版本的表,可以执行如下操作: 指定你想要检索的表的系统生成名称。 执行TIMECAPSULE TABLE ... TO BEFORE DROP语句,直到你要检索的表。 恢复DROP表时,只恢复基表名,其他子对象名均保持回收站对象名。用户可根据需要,执行DDL命令手工调整子对象名。 回收站对象不支持DML、DCL、DDL等写操作,不支持DQL查询操作(后续支持)。 闪回点和当前点之间,执行过修改表结构或影响物理结构的语句,闪回失败。执行过DDL的表进行闪回操作报错:“ERROR:The table definition of %s has been changed. ”。涉及namespace、表名改变等操作的DDL执行闪回操作报错: ERROR: recycle object %s desired does not exist; 开启enable_recyclebin参数,启用回收站时,如果表上有truncate trigger、truncate表时,无法触发trigger。 RENAME TO 为从回收站中检索的表指定一个新名称。 TO BEFORE TRUNCATE 闪回到TRUNCATE之前。
  • 背景信息 闪回DROP:可以恢复意外删除的表,从回收站(recyclebin)中恢复被删除的表及其附属结构如索引、表约束等。闪回drop是基于回收站机制,通过还原回收站中记录的表的物理文件,实现已drop表的恢复。 闪回TRUNCATE:可以恢复误操作或意外被进行truncate的表,从回收站中恢复被truncate的表及索引的物理数据。闪回truncate基于回收站机制,通过还原回收站中记录的表的物理文件,实现已truncate表的恢复。
  • 语法示例 -- PURGE TABLE table_name; -- --查看回收站 gaussdb=# SELECT * FROM gs_recyclebin; rcybaseid | rcydbid | rcyrelid | rcyname | rcyoriginname | rcyoperation | rcytype | rcyrecyclecsn | rcyrecycletime | rcycreatecsn | rcychangecsn | rcynamespace | rcyowner | rcytablespace | rcyrelfilenode | rcycanrestore | rcycanpurge | rcyfrozenxid | rcyfrozenxid64 | rcybucket -----------+---------+----------+---------+---------------+--------------+---------+---------------+----------------+--------------+--------------+--------------+----------+-------------- -+----------------+---------------+-------------+--------------+----------------+----------- (0 rows) gaussdb=# DROP TABLE IF EXISTS flashtest; NOTICE: table "flashtest" does not exist, skipping DROP TABLE gaussdb=# SELECT * FROM gs_recyclebin; rcybaseid | rcydbid | rcyrelid | rcyname | rcyoriginname | rcyoperation | rcytype | rcyrecyclecsn | rcyrecycletime | rcycreatecsn | rcychangecsn | rcynamespace | rcyowner | rcytablespace | rcyrelfilenode | rcycanrestore | rcycanpurge | rcyfrozenxid | rcyfrozenxid64 | rcybucket -----------+---------+----------+---------+---------------+--------------+---------+---------------+----------------+--------------+--------------+--------------+----------+-------------- -+----------------+---------------+-------------+--------------+----------------+----------- (0 rows) --创建表flashtest gaussdb=# CREATE TABLE IF NOT EXISTS flashtest(id int, name text) with (storage_type = ustore); NOTICE: The 'DISTRIBUTE BY' clause is not specified. Using 'id' as the distribution column by default. HINT: Please use 'DISTRIBUTE BY' clause to specify suitable data distribution column. CREATE TABLE --插入数据 gaussdb=# INSERT INTO flashtest VALUES(1, 'A'); INSERT 0 1 gaussdb=# SELECT * FROM flashtest; id | name ----+------ 1 | A (1 row) --DROP表flashtest gaussdb=# DROP TABLE IF EXISTS flashtest; DROP TABLE --查看回收站,删除的表被放入回收站 gaussdb=# SELECT * FROM gs_recyclebin; rcybaseid | rcydbid | rcyrelid | rcyname | rcyoriginname | rcyoperation | rcytype | rcyrecyclecsn | rcyrecycletime | rcycreatecsn | rcychangecs n | rcynamespace | rcyowner | rcytablespace | rcyrelfilenode | rcycanrestore | rcycanpurge | rcyfrozenxid | rcyfrozenxid64 | rcybucket -----------+---------+----------+------------------------------+----------------------+--------------+---------+---------------+-------------------------------+--------------+------------ --+--------------+----------+---------------+----------------+---------------+-------------+--------------+----------------+----------- 18591 | 12737 | 18585 | BIN$31C14EB4899$9737$0==$0 | flashtest | d | 0 | 79352606 | 2023-09-13 20:01:28.640664+08 | 79352595 | 7935259 5 | 2200 | 10 | 0 | 18585 | t | t | 225492 | 225492 | 18591 | 12737 | 18588 | BIN$31C14EB489C$12D1BF60==$0 | pg_toast_18585 | d | 2 | 79352606 | 2023-09-13 20:01:28.641018+08 | 0 | 0 | 99 | 10 | 0 | 18588 | f | f | 225492 | 225492 | (2 rows) --查看表flashtest,表不存在 gaussdb=# SELECT * FROM flashtest; ERROR: relation "flashtest" does not exist LINE 1: SELECT * FROM flashtest; ^ --PURGE表,将回收站中的表删除 gaussdb=# PURGE TABLE flashtest; PURGE TABLE --查看回收站,回收站中的表被删除 gaussdb=# SELECT * FROM gs_recyclebin; rcybaseid | rcydbid | rcyrelid | rcyname | rcyoriginname | rcyoperation | rcytype | rcyrecyclecsn | rcyrecycletime | rcycreatecsn | rcychangecsn | rcynamespace | rcyowner | rcytablespace | rcyrelfilenode | rcycanrestore | rcycanpurge | rcyfrozenxid | rcyfrozenxid64 | rcybucket -----------+---------+----------+---------+---------------+--------------+---------+---------------+----------------+--------------+--------------+--------------+----------+-------------- -+----------------+---------------+-------------+--------------+----------------+----------- (0 rows) -- PURGE INDEX index_name; -- gaussdb=# DROP TABLE IF EXISTS flashtest; NOTICE: table "flashtest" does not exist, skipping DROP TABLE --创建表flashtest gaussdb=# CREATE TABLE IF NOT EXISTS flashtest(id int, name text) WITH (storage_type = ustore); NOTICE: The 'DISTRIBUTE BY' clause is not specified. Using 'id' as the distribution column by default. HINT: Please use 'DISTRIBUTE BY' clause to specify suitable data distribution column. CREATE TABLE --为表flashtest创建索引flashtest_index gaussdb=# CREATE INDEX flashtest_index ON flashtest(id); CREATE INDEX --查看flashtest表的基本信息 gaussdb=# \d+ flashtest Table "public.flashtest" Column | Type | Modifiers | Storage | Stats target | Description --------+---------+-----------+----------+--------------+------------- id | integer | | plain | | name | text | | extended | | Indexes: "flashtest_index" ubtree (id) WITH (storage_type=USTORE) TABLESPACE pg_default Has OIDs: no Distribute By: HASH(id) Location Nodes: ALL DATANODES Options: orientation=row, storage_type=ustore, compression=no, segment=off,toast.storage_type=ustore, toast.toast_storage_type=enhanced_toast --DROP表 gaussdb=# DROP TABLE IF EXISTS flashtest; DROP TABLE --查看回收站 gaussdb=# SELECT * FROM gs_recyclebin; rcybaseid | rcydbid | rcyrelid | rcyname | rcyoriginname | rcyoperation | rcytype | rcyrecyclecsn | rcyrecycletime | rcycreatecsn | rcychangecs n | rcynamespace | rcyowner | rcytablespace | rcyrelfilenode | rcycanrestore | rcycanpurge | rcyfrozenxid | rcyfrozenxid64 | rcybucket -----------+---------+----------+------------------------------+----------------------+--------------+---------+---------------+-------------------------------+--------------+------------ --+--------------+----------+---------------+----------------+---------------+-------------+--------------+----------------+----------- 18648 | 12737 | 18641 | BIN$31C14EB48D1$9A85$0==$0 | flashtest | d | 0 | 79354509 | 2023-09-13 20:40:11.360638+08 | 79354506 | 7935450 8 | 2200 | 10 | 0 | 18641 | t | t | 226642 | 226642 | 18648 | 12737 | 18644 | BIN$31C14EB48D4$12E236A0==$0 | pg_toast_18641 | d | 2 | 79354509 | 2023-09-13 20:40:11.36112+08 | 0 | 0 | 99 | 10 | 0 | 18644 | f | f | 226642 | 226642 | 18648 | 12737 | 18647 | BIN$31C14EB48D7$9A85$0==$0 | flashtest_index | d | 1 | 79354509 | 2023-09-13 20:40:11.361246+08 | 79354508 | 7935450 8 | 2200 | 10 | 0 | 18647 | f | t | 0 | 0 | (3 rows) --PURGE索引flashtest_index gaussdb=# PURGE INDEX flashtest_index; PURGE INDEX --查看回收站,回收站中的索引flashtest_index被删除 gaussdb=# SELECT * FROM gs_recyclebin; rcybaseid | rcydbid | rcyrelid | rcyname | rcyoriginname | rcyoperation | rcytype | rcyrecyclecsn | rcyrecycletime | rcycreatecsn | rcychangecs n | rcynamespace | rcyowner | rcytablespace | rcyrelfilenode | rcycanrestore | rcycanpurge | rcyfrozenxid | rcyfrozenxid64 | rcybucket -----------+---------+----------+------------------------------+----------------------+--------------+---------+---------------+-------------------------------+--------------+------------ --+--------------+----------+---------------+----------------+---------------+-------------+--------------+----------------+----------- 18648 | 12737 | 18641 | BIN$31C14EB48D1$9A85$0==$0 | flashtest | d | 0 | 79354509 | 2023-09-13 20:40:11.360638+08 | 79354506 | 7935450 8 | 2200 | 10 | 0 | 18641 | t | t | 226642 | 226642 | 18648 | 12737 | 18644 | BIN$31C14EB48D4$12E236A0==$0 | pg_toast_18641 | d | 2 | 79354509 | 2023-09-13 20:40:11.36112+08 | 0 | 0 | 99 | 10 | 0 | 18644 | f | f | 226642 | 226642 | (2 rows) -- PURGE RECYCLEBIN -- --PURGE回收站 gaussdb=# PURGE RECYCLEBIN; PURGE RECYCLEBIN --查看回收站,回收站被清空 gaussdb=# SELECT * FROM gs_recyclebin; rcybaseid | rcydbid | rcyrelid | rcyname | rcyoriginname | rcyoperation | rcytype | rcyrecyclecsn | rcyrecycletime | rcycreatecsn | rcychangecsn | rcynamespace | rcyowner | rcytablespace | rcyrelfilenode | rcycanrestore | rcycanpurge | rcyfrozenxid | rcyfrozenxid64 | rcybucket -----------+---------+----------+---------+---------------+--------------+---------+---------------+----------------+--------------+--------------+--------------+----------+-------------- -+----------------+---------------+-------------+--------------+----------------+----------- (0 rows) -- TIMECAPSULE TABLE { table_name } TO BEFORE DROP [RENAME TO new_tablename] -- gaussdb=# DROP TABLE IF EXISTS flashtest; NOTICE: table "flashtest" does not exist, skipping DROP TABLE --创建表flashtest gaussdb=# CREATE TABLE IF NOT EXISTS flashtest(id int, name text) with (storage_type = ustore); NOTICE: The 'DISTRIBUTE BY' clause is not specified. Using 'id' as the distribution column by default. HINT: Please use 'DISTRIBUTE BY' clause to specify suitable data distribution column. CREATE TABLE --插入数据 gaussdb=# INSERT INTO flashtest VALUES(1, 'A'); INSERT 0 1 gaussdb=# SELECT * FROM flashtest; id | name ----+------ 1 | A (1 row) --DROP表 gaussdb=# DROP TABLE IF EXISTS flashtest; DROP TABLE --查看回收站,表被放入回收站 gaussdb=# SELECT * FROM gs_recyclebin; rcybaseid | rcydbid | rcyrelid | rcyname | rcyoriginname | rcyoperation | rcytype | rcyrecyclecsn | rcyrecycletime | rcycreatecsn | rcychangecs n | rcynamespace | rcyowner | rcytablespace | rcyrelfilenode | rcycanrestore | rcycanpurge | rcyfrozenxid | rcyfrozenxid64 | rcybucket -----------+---------+----------+------------------------------+----------------------+--------------+---------+---------------+-------------------------------+--------------+------------ --+--------------+----------+---------------+----------------+---------------+-------------+--------------+----------------+----------- 18658 | 12737 | 18652 | BIN$31C14EB48DC$9B2B$0==$0 | flashtest | d | 0 | 79354760 | 2023-09-13 20:47:57.075907+08 | 79354753 | 7935475 3 | 2200 | 10 | 0 | 18652 | t | t | 226824 | 226824 | 18658 | 12737 | 18655 | BIN$31C14EB48DF$12E46400==$0 | pg_toast_18652 | d | 2 | 79354760 | 2023-09-13 20:47:57.07621+08 | 0 | 0 | 99 | 10 | 0 | 18655 | f | f | 226824 | 226824 | (2 rows) --查看表,表不存在 gaussdb=# SELECT * FROM flashtest; ERROR: relation "flashtest" does not exist LINE 1: select * from flashtest; ^ --闪回drop表 gaussdb=# TIMECAPSULE TABLE flashtest to before drop; TimeCapsule Table --查看表,表被恢复到drop之前 gaussdb=# SELECT * FROM flashtest; id | name ----+------ 1 | A (1 row) --查看回收站,回收站中的表被删除 gaussdb=# SELECT * FROM gs_recyclebin; rcybaseid | rcydbid | rcyrelid | rcyname | rcyoriginname | rcyoperation | rcytype | rcyrecyclecsn | rcyrecycletime | rcycreatecsn | rcychangecsn | rcynamespace | rcyowner | rcytablespace | rcyrelfilenode | rcycanrestore | rcycanpurge | rcyfrozenxid | rcyfrozenxid64 | rcybucket -----------+---------+----------+---------+---------------+--------------+---------+---------------+----------------+--------------+--------------+--------------+----------+-------------- -+----------------+---------------+-------------+--------------+----------------+----------- (0 rows) --DROP表 gaussdb=# DROP TABLE IF EXISTS flashtest; DROP TABLE gaussdb=# SELECT * FROM flashtest; ERROR: relation "flashtest" does not exist LINE 1: SELECT * FROM flashtest; ^ --查看回收站,表被放入回收站 gaussdb=# SELECT * FROM gs_recyclebin; rcybaseid | rcydbid | rcyrelid | rcyname | rcyoriginname | rcyoperation | rcytype | rcyrecyclecsn | rcyrecycletime | rcycreatecsn | rcy changecsn | rcynamespace | rcyowner | rcytablespace | rcyrelfilenode | rcycanrestore | rcycanpurge | rcyfrozenxid | rcyfrozenxid64 | rcybucket -----------+---------+----------+------------------------------+------------------------------+--------------+---------+---------------+-------------------------------+--------------+---- ----------+--------------+----------+---------------+----------------+---------------+-------------+--------------+----------------+----------- 18664 | 12737 | 18652 | BIN$31C14EB48DC$9B4E$0==$0 | flashtest | d | 0 | 79354845 | 2023-09-13 20:49:17.762977+08 | 79354753 | 79354753 | 2200 | 10 | 0 | 18652 | t | t | 226824 | 226824 | 18664 | 12737 | 18657 | BIN$31C14EB48E1$12E680A8==$0 | BIN$31C14EB48E1$12E45E00==$0 | d | 3 | 79354845 | 2023-09-13 20:49:17.763271+08 | 79354753 | 79354753 | 99 | 10 | 0 | 18657 | f | f | 0 | 0 | 18664 | 12737 | 18655 | BIN$31C14EB48DF$12E68698==$0 | BIN$31C14EB48DF$12E46400==$0 | d | 2 | 79354845 | 2023-09-13 20:49:17.763343+08 | 0 | 0 | 99 | 10 | 0 | 18655 | f | f | 226824 | 226824 | (3 rows) --闪回drop表,表名用回收站中的rcyname gaussdb=# TIMECAPSULE TABLE "BIN$31C14EB48DC$9B4E$0==$0" to before drop; TimeCapsule Table ----查看回收站,回收站中的表被删除 gaussdb=# SELECT * FROM gs_recyclebin; rcybaseid | rcydbid | rcyrelid | rcyname | rcyoriginname | rcyoperation | rcytype | rcyrecyclecsn | rcyrecycletime | rcycreatecsn | rcychangecsn | rcynamespace | rcyowner | rcytablespace | rcyrelfilenode | rcycanrestore | rcycanpurge | rcyfrozenxid | rcyfrozenxid64 | rcybucket -----------+---------+----------+---------+---------------+--------------+---------+---------------+----------------+--------------+--------------+--------------+----------+-------------- -+----------------+---------------+-------------+--------------+----------------+----------- (0 rows) gaussdb=# SELECT * FROM flashtest; id | name ----+------ 1 | A (1 row) --DROP表 gaussdb=# DROP TABLE IF EXISTS flashtest; DROP TABLE ----查看回收站,表被放入回收站 gaussdb=# SELECT * FROM gs_recyclebin; rcybaseid | rcydbid | rcyrelid | rcyname | rcyoriginname | rcyoperation | rcytype | rcyrecyclecsn | rcyrecycletime | rcycreatecsn | rcy changecsn | rcynamespace | rcyowner | rcytablespace | rcyrelfilenode | rcycanrestore | rcycanpurge | rcyfrozenxid | rcyfrozenxid64 | rcybucket -----------+---------+----------+------------------------------+------------------------------+--------------+---------+---------------+-------------------------------+--------------+---- ----------+--------------+----------+---------------+----------------+---------------+-------------+--------------+----------------+----------- 18667 | 12737 | 18652 | BIN$31C14EB48DC$9B8D$0==$0 | flashtest | d | 0 | 79354943 | 2023-09-13 20:52:14.525946+08 | 79354753 | 79354753 | 2200 | 10 | 0 | 18652 | t | t | 226824 | 226824 | 18667 | 12737 | 18657 | BIN$31C14EB48E1$1320B4F0==$0 | BIN$31C14EB48E1$12E680A8==$0 | d | 3 | 79354943 | 2023-09-13 20:52:14.526319+08 | 79354753 | 79354753 | 99 | 10 | 0 | 18657 | f | f | 0 | 0 | 18667 | 12737 | 18655 | BIN$31C14EB48DF$1320BAE0==$0 | BIN$31C14EB48DF$12E68698==$0 | d | 2 | 79354943 | 2023-09-13 20:52:14.526423+08 | 0 | 0 | 99 | 10 | 0 | 18655 | f | f | 226824 | 226824 | (3 rows) --查看表,表不存在 gaussdb=# SELECT * FROM flashtest; ERROR: relation "flashtest" does not exist LINE 1: SELECT * FROM flashtest; ^ --闪回drop表,并重命名表 gaussdb=# TIMECAPSULE TABLE flashtest to before drop rename to flashtest_rename; TimeCapsule Table --查看原表,表不存在 gaussdb=# SELECT * FROM flashtest; ERROR: relation "flashtest" does not exist LINE 1: SELECT * FROM flashtest; ^ --查看重命名后的表,表存在 gaussdb=# SELECT * FROM flashtest_rename; id | name ----+------ 1 | A (1 row) --查看回收站,回收站中的表被删除 gaussdb=# SELECT * FROM gs_recyclebin; rcybaseid | rcydbid | rcyrelid | rcyname | rcyoriginname | rcyoperation | rcytype | rcyrecyclecsn | rcyrecycletime | rcycreatecsn | rcychangecsn | rcynamespace | rcyowner | rcytablespace | rcyrelfilenode | rcycanrestore | rcycanpurge | rcyfrozenxid | rcyfrozenxid64 | rcybucket -----------+---------+----------+---------+---------------+--------------+---------+---------------+----------------+--------------+--------------+--------------+----------+-------------- -+----------------+---------------+-------------+--------------+----------------+----------- (0 rows) --drop表 gaussdb=# DROP TABLE IF EXISTS flashtest_rename; DROP TABLE --清空回收站 gaussdb=# PURGE RECYCLEBIN; PURGE RECYCLEBIN --查看回收站,回收站被清空 gaussdb=# SELECT * FROM gs_recyclebin; rcybaseid | rcydbid | rcyrelid | rcyname | rcyoriginname | rcyoperation | rcytype | rcyrecyclecsn | rcyrecycletime | rcycreatecsn | rcychangecsn | rcynamespace | rcyowner | rcytablespace | rcyrelfilenode | rcycanrestore | rcycanpurge | rcyfrozenxid | rcyfrozenxid64 | rcybucket -----------+---------+----------+---------+---------------+--------------+---------+---------------+----------------+--------------+--------------+--------------+----------+-------------- -+----------------+---------------+-------------+--------------+----------------+----------- (0 rows) -- TIMECAPSULE TABLE { table_name } TO BEFORE TRUNCATE -- gaussdb=# DROP TABLE IF EXISTS flashtest; NOTICE: table "flashtest" does not exist, skipping DROP TABLE --创建表flashtest gaussdb=# CREATE TABLE IF NOT EXISTS flashtest(id int, name text) WITH (storage_type = ustore); NOTICE: The 'DISTRIBUTE BY' clause is not specified. Using 'id' as the distribution column by default. HINT: Please use 'DISTRIBUTE BY' clause to specify suitable data distribution column. CREATE TABLE --插入数据 gaussdb=# INSERT INTO flashtest VALUES(1, 'A'); INSERT 0 1 gaussdb=# SELECT * FROM flashtest; id | name ----+------ 1 | A (1 row) --truncate表 gaussdb=# TRUNCATE TABLE flashtest; TRUNCATE TABLE --查看回收站,表的数据被放入回收站 gaussdb=# SELECT * FROM gs_recyclebin; rcybaseid | rcydbid | rcyrelid | rcyname | rcyoriginname | rcyoperation | rcytype | rcyrecyclecsn | rcyrecycletime | rcycreatecsn | rcychangecs n | rcynamespace | rcyowner | rcytablespace | rcyrelfilenode | rcycanrestore | rcycanpurge | rcyfrozenxid | rcyfrozenxid64 | rcybucket -----------+---------+----------+------------------------------+----------------------+--------------+---------+---------------+-------------------------------+--------------+------------ --+--------------+----------+---------------+----------------+---------------+-------------+--------------+----------------+----------- 18703 | 12737 | 18697 | BIN$31C14EB4909$9E4C$0==$0 | flashtest | t | 0 | 79356608 | 2023-09-13 21:24:42.819863+08 | 79356606 | 7935660 6 | 2200 | 10 | 0 | 18697 | t | t | 227927 | 227927 | 18703 | 12737 | 18700 | BIN$31C14EB490C$132FE3F0==$0 | pg_toast_18697 | t | 2 | 79356608 | 2023-09-13 21:24:42.820358+08 | 0 | 0 | 99 | 10 | 0 | 18700 | f | f | 227927 | 227927 | (2 rows) --查看表,表中的数据为空 gaussdb=# SELECT * FROM flashtest; id | name ----+------ (0 rows) --闪回truncate表 gaussdb=# TIMECAPSULE TABLE flashtest to before truncate; TimeCapsule Table --查看表,表中的数据被恢复 gaussdb=# SELECT * FROM flashtest; id | name ----+------ 1 | A (1 row) --查看回收站 gaussdb=# SELECT * FROM gs_recyclebin; rcybaseid | rcydbid | rcyrelid | rcyname | rcyoriginname | rcyoperation | rcytype | rcyrecyclecsn | rcyrecycletime | rcycreatecsn | rcychangecs n | rcynamespace | rcyowner | rcytablespace | rcyrelfilenode | rcycanrestore | rcycanpurge | rcyfrozenxid | rcyfrozenxid64 | rcybucket -----------+---------+----------+------------------------------+----------------------+--------------+---------+---------------+-------------------------------+--------------+------------ --+--------------+----------+---------------+----------------+---------------+-------------+--------------+----------------+----------- 18703 | 12737 | 18700 | BIN$31C14EB490C$13300228==$0 | pg_toast_18697 | t | 2 | 79356610 | 2023-09-13 21:24:42.872732+08 | 0 | 0 | 99 | 10 | 0 | 18706 | f | f | 0 | 227928 | 18703 | 12737 | 18697 | BIN$31C14EB4909$9E4D$0==$0 | flashtest | t | 0 | 79356610 | 2023-09-13 21:24:42.872792+08 | 79356606 | 7935660 6 | 2200 | 10 | 0 | 18704 | t | t | 0 | 227928 | (2 rows) --drop表 gaussdb=# DROP TABLE IF EXISTS flashtest; DROP TABLE --清空回收站 gaussdb=# PURGE RECYCLEBIN; PURGE RECYCLEBIN --查看回收站,回收站被清空 gaussdb=# SELECT * FROM gs_recyclebin; rcybaseid | rcydbid | rcyrelid | rcyname | rcyoriginname | rcyoperation | rcytype | rcyrecyclecsn | rcyrecycletime | rcycreatecsn | rcychangecsn | rcynamespace | rcyowner | rcytablespace | rcyrelfilenode | rcycanrestore | rcycanpurge | rcyfrozenxid | rcyfrozenxid64 | rcybucket -----------+---------+----------+---------+---------------+--------------+---------+---------------+----------------+--------------+--------------+--------------+----------+-------------- -+----------------+---------------+-------------+--------------+----------------+----------- (0 rows)
  • 使用示例 gaussdb=# DROP TABLE IF EXISTS "public".flashtest; NOTICE: table "flashtest" does not exist, skipping DROP TABLE --创建表 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 ---------- 79352065 79352065 79352065 79352065 79352065 79352065 (6 rows) --查询当前的时间戳 gaussdb=# SELECT now(); now ------------------------------- 2023-09-13 19:46:34.102863+08 (1 row) --查看表flashtest gaussdb=# SELECT * FROM flashtest; col1 | col2 ------+------ (0 rows) --插入数据 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=# TIMECAPSULE TABLE flashtest TO CSN 79352065; TimeCapsule Table gaussdb=# SELECT * FROM flashtest; col1 | col2 ------+------ (0 rows) gaussdb=# SELECT now(); now ------------------------------- 2023-09-13 19:52:21.551028+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 6 | INSERT6 1 | INSERT1 2 | INSERT2 4 | INSERT4 5 | INSERT5 (6 rows) --闪回表至此刻之前的特定时间戳 gaussdb=# TIMECAPSULE TABLE flashtest TO TIMESTAMP to_timestamp ('2023-09-13 19:52:21.551028', 'YYYY-MM-DD HH24:MI:SS.FF'); TimeCapsule Table gaussdb=# SELECT * FROM flashtest; col1 | col2 ------+------ (0 rows) gaussdb=# select now(); now ------------------------------- 2023-09-13 19:54:00.641506+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 6 | INSERT6 1 | INSERT1 2 | INSERT2 4 | INSERT4 5 | INSERT5 (6 rows) --闪回表至此刻之后的特定时间戳 gaussdb=# TIMECAPSULE TABLE flashtest TO TIMESTAMP '2023-09-13 20:54:00.641506'; ERROR: The specified timestamp is invalid. gaussdb=# SELECT * FROM flashtest; col1 | col2 ------+------ 3 | INSERT3 6 | INSERT6 1 | INSERT1 2 | INSERT2 4 | INSERT4 5 | INSERT5 (6 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 [, ...] ) ]}
  • 使用示例 示例(需将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
  • 闪回恢复 闪回恢复功能是数据库恢复技术的一环,可以有选择性地撤销一个已提交事务的影响,将数据从人为不正确的操作中进行恢复。在采用闪回技术之前,只能通过备份恢复、PITR等手段找回已提交的数据库修改,恢复时长需要数分钟甚至数小时。采用闪回技术后,通过闪回Drop和闪回Truncate恢复已提交的数据库Drop/Truncate的数据,只需要秒级,而且恢复时间和数据库大小无关。 ASTORE引擎只支持闪回DROP/TRUNCATE功能。 备机不支持闪回操作。 用户可以根据需要开启闪回功能,开启后会带来一定的性能劣化。 闪回查询 闪回表 闪回DROP/TRUNCATE 父主题: 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事务模型
  • 事务提交 针对隐式事务和显式事务,其提交策略如下所示: 隐式事务。单条DML/DDL语句自动触发隐式事务,这种事务没有显式的事务块控制语句(START TRANSACTION/BEGIN/COMMIT/END),DML语句结束后自动提交。 显式事务。显式事务由显式的START TRANSACTION/BEGIN语句控制事务的开始,由COMMIT/END语句控制事务的提交。 子事务必须存在于显式事务或存储过程中,由SAVEPOINT语句控制子事务开始,由RELEASE SAVEPOINT语句控制子事务结束。如果一个事务在提交时还存在未释放的子事务,该事务提交前会先执行子事务的提交,所有子事务提交完毕后才会进行父事务的提交。 Ustore支持读已提交隔离级别。语句在执行开始时,获取当前系统的CSN作为当前语句的查询CSN。整个语句的可见结果由语句开始那一刻决定,不受后续其他事务修改影响。Ustore中read committed默认是保持一致性读的。Ustore也支持标准的2PC事务。 父主题: Ustore事务模型
  • Ustore事务模型 GaussDB 事务基础: 事务启动时不会自动分配XID,该事务中的第一条DML/DDL语句运行时才会真正为该事务分配XID。 事务结束时,会产生代表事务提交状态的CLOG(Commit Log),CLOG共有四种状态:事务运行中、事务提交、事务同步回滚、子事务提交。每个事务的 CLOG状态位为2 bits,CLOG页面上每个字节可以表示四个事务的提交状态。 事务结束时,还会产生代表事务提交顺序的CSN(Commit sequence number)。CSN为实例级变量,每个XID都有自己对应的唯一CSN。CSN可以标记事务的以下状态:事务提交中、事务提交、事务回滚、事务已冻结等。 事务提交 事务回滚 父主题: Ustore存储引擎
  • Enhanced Toast运维管理 通过gs_parse_page_bypath解析主表中的ToastPointer信息。 gaussdb=# SELECT ctid,next_chunk,chunk_seq FROM pg_toast.pg_toast_part_17559; ctid | next_chunk | chunk_seq -------+------------+----------- (0,1) | (0,0) | 1 (0,2) | (0,1) | 0 (0,3) | (0,0) | 1 (0,4) | (0,3) | 0 (4 rows) gaussdb=# SELECT gs_parse_page_bypath((SELECT * FROM pg_relation_filepath('test_toast')),0,'uheap',false); gs_parse_page_bypath ------------------------------------------------------------------ ${data_dir}/gs_log/dump/1663_13113_17603_0.page (1 row) 解析文件1663_13113_17603_0.page中存储了ToastPointer的相关信息,具体如下: Toast_Pointer: column_index: 1 toast_relation_oid: 17608 --线外存储表OID信息 ctid: (4, 1) --线外存储数据链,头指针 bucket id: -1 --bucket id信息 column_index: 2 toast_relation_oid: 17608 ctid: (2, 1) bucket id: -1 Enhanced Toast数据查询,通过直接查询到的Enhanced Toast表数据可以判断其链式结构的完整性。 gaussdb=# SELECT ctid,next_chunk,chunk_seq FROM pg_toast.pg_toast_part_17559; ctid | next_chunk | chunk_seq -------+------------+----------- (0,1) | (0,0) | 1 (0,2) | (0,1) | 0 (0,3) | (0,0) | 1 (0,4) | (0,3) | 0 (4 rows) 父主题: Enhanced Toast
  • 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
共100000条
提示

您即将访问非华为云网站,请注意账号财产安全