华为云用户手册

  • 开启/关闭范围分区自动扩展 使用ALTER TABLE SET INTERVAL可以开启/关闭范围分区自动扩展。 例如,开启范围分区自动扩展。 gaussdb=# CREATE TABLE range_int (c1 int, c2 int) PARTITION BY RANGE (c1) ( PARTITION p1 VALUES LESS THAN (5), PARTITION p2 VALUES LESS THAN (10), PARTITION p3 VALUES LESS THAN (15) ); gaussdb=# ALTER TABLE range_int SET INTERVAL (5); 开启范围分区自动扩展要求分区表中不能存在分区键值为MAXVALUE的分区。 开启范围分区自动扩展只支持一级分区表、单列分区键。 关闭范围分区自动扩展。 gaussdb=# ALTER TABLE range_int SET INTERVAL (); -- 清理示例 gaussdb=# DROP TABLE range_int; 父主题: 开启/关闭分区自动扩展
  • 场景描述 当对分区表使用Max/Min函数时,通常SQL引擎的实现方式是先通过Partition Iterator + PartitionScan对分区表做全量扫描然后进行Sort + Limit操作。如果分区是索引扫描,可以先对每个分区进行Limit操作,计算Max/Min值,最后在分区表上做Sort + Limit操作。这样分区表上做Sort时,由于每个分区已经获取Max/Min值,所以Sort的数据量跟分区数相同,这时极大的减少了Sort开销。
  • 对一级分区表重命名分区 使用ALTER TABLE RENAME PARTITION可以对一级分区表重命名分区。 例如,通过指定分区名将范围分区表range_sales的分区date_202001重命名。 ALTER TABLE range_sales RENAME PARTITION date_202001 TO date_202001_new; 或者,通过指定分区值将列表分区表list_sales中'0'所对应的分区重命名。 ALTER TABLE list_sales RENAME PARTITION FOR ('0') TO channel_new; 父主题: 重命名分区
  • 在线校验功能 在线校验是Ustore特有的,在运行过程中可以有效预防页面因编码逻辑错误导致的逻辑损坏,默认开启UPAGE:UBTREE:UNDO三个模块校验。业务现网请保持开启,性能场景除外。 关闭: gs_guc reload -Z datanode -N all -I all -c "ustore_attr=''" 打开: gs_guc reload -Z datanode -N all -I all -c "ustore_attr='ustore_verify_level=fast;ustore_verify_module=upage:ubtree:undo'" 父主题: Ustore的最佳实践
  • 列表分区 列表分区(List Partition)能够通过在每个分区的描述中为分区键指定离散值列表来显式控制行如何映射到分区。列表分区的优势在于可以以枚举分区值方式对数据进行分区,可以对无序和不相关的数据集进行分组和组织。对于未定义在列表中的分区键值,可以使用默认分区(DEFAULT)来进行数据的保存,这样所有未映射到任何其他分区的行都不会生成错误。示例如下: gaussdb=# CREATE TABLE bmsql_order_line ( ol_w_id INTEGER NOT NULL, ol_d_id INTEGER NOT NULL, ol_o_id INTEGER NOT NULL, ol_number INTEGER NOT NULL, ol_i_id INTEGER NOT NULL, ol_delivery_d TIMESTAMP, ol_amount DECIMAL(6,2), ol_supply_w_id INTEGER, ol_quantity INTEGER, ol_dist_info CHAR(24) ) PARTITION BY LIST(ol_d_id) ( PARTITION p0 VALUES (1,4,7), PARTITION p1 VALUES (2,5,8), PARTITION p2 VALUES (3,6,9), PARTITION p3 VALUES (DEFAULT) ); gaussdb=# DROP TABLE bmsql_order_line; 上述例子和之前给出的哈希分区的例子类似,同样通过ol_d_id列进行分区,但是在List分区中直接通过对ol_d_id的可能取值范围进行限定,不在列表中的数据会进入p3分区(DEFAULT)。相比哈希分区,List列表分区对分区键的可控性更好,往往能够准确的将目标数据保存在预想的分区中,但是如果列表值较多在分区定义时变得麻烦,该情况下推荐使用Hash分区。List、Hash分区往往都是处理无序、不相关的数据集进行分组和组织。 列表分区的分区键最多支持16列。如果分区键定义为1列,子分区定义时List列表中的枚举值不允许为NULL值;如果分区键定义为多列,子分区定义时List列表中的枚举值允许有NULL值。 父主题: 分区策略
  • 分割分区 用户可以使用分割分区的命令来将一个分区分割为两个或多个新分区。当分区数据太大,或者需要对有MAXVALUE的范围分区/DEFAULT的列表分区新增分区时,可以考虑执行该操作。分割分区可以指定分割点将一个分区分割为两个新分区,也可以不指定分割点将一个分区分割为多个新分区。分割分区可以通过指定分区名或者分区值来进行。 分割分区不能作用于哈希分区上。 不支持对二级分区表的一级分区进行分割。 执行分割分区命令会使得Global索引失效,可以通过UPDATE GLOBAL INDEX子句来同步更新Global索引,或者用户自行重建Global索引。 分割的目标分区如果包含分类索引时,该分区不支持分割。 分割后的新分区,可以与源分区名字相同,比如将分区p1分割为p1,p2。但数据库不会将分割前后相同名的分区视为同一个分区,这会影响分割期间对源分区p1查询,具体请参见DQL/DML-DDL并发。 对范围分区表分割分区 对间隔分区表分割分区 对列表分区表分割分区 对*-RANGE二级分区表分割二级分区 对*-LIST二级分区表分割二级分区 父主题: 分区表运维管理
  • 闪回恢复 闪回恢复功能是数据库恢复技术的一环,可以有选择性地撤销一个已提交的事务,将数据从人为不正确的操作中进行恢复。在采用闪回技术之前,只能通过备份恢复、PITR等手段找回已提交的数据库修改,恢复时长需要数分钟甚至数小时。采用闪回技术后,通过闪回Drop和闪回Truncate恢复已提交的数据库Drop/Truncate的数据,只需要秒级,而且恢复时间和数据库大小无关。 Astore引擎只支持闪回DROP/TRUNCATE功能。 备机不支持闪回操作。 用户可以根据需要开启闪回功能,开启后会带来一定的性能劣化。 闪回查询 闪回表 闪回DROP/TRUNCATE 父主题: Ustore存储引擎
  • 执行密态等值查询加密表相关的语句 // 定义加密表 _, err = db.Exec("CREATE TABLE creditcard_info (id_number int, name varchar(50) encrypted with (column_encryption_key = ImgCEK1, encryption_type = DETERMINISTIC), credit_card varchar(19) encrypted with (column_encryption_key = ImgCEK1, encryption_type = DETERMINISTIC));") // 插入数据 _, err = db.Exec("INSERT INTO creditcard_info VALUES (1,'joe','6217986500001288393'), (2,'mike','6217986500001722485'), (3,'joe','6315892300001244581');"); var var1 int var var2 string var var3 string // 查询数据 rows, err := db.Query("select * from creditcard_info where name = 'joe';") defer rows.Close() // 逐行打印 for rows.Next() { err = rows.Scan(&var1, &var2, &var3) if err != nil { log.Fatal(err) } else { fmt.Printf("var1:%v, var2:%v, var3:%v\n", var1, var2, var3) } }
  • 执行加密表的预编译SQL语句 // 调用DB实例的Prepare方法创建预编译对象 delete_stmt, err := db.Prepare("delete from creditcard_info where name = $1;") defer delete_stmt.Close() // 调用预编译对象的Exec方法绑定参数并执行SQL语句 _, err = delete_stmt.Exec("mike")
  • 执行加密表的Copy In操作 // 调用DB实例的Begin、Prepare方法创建事务对象、预编译对象 tx, err := db.Begin() copy_stmt, err := tx.Prepare("Copy creditcard_info from stdin") // 声明并初始化待导入数据 var records = []struct { field1 int field2 string field3 string }{ {4, "james", "6217986500001234567"}, { field1: 5, field2: "john", field3: "6217986500007654321", }, } // 调用预编译对象的Exec方法绑定参数并执行SQL语句 for _, record := range records { _, err = copy_stmt.Exec(record.field1, record.field2, record.field3) if err != nil { log.Fatal(err) } } // 调用事务对象的Commit方法完成事务提交 err = copy_stmt.Close() err = tx.Commit() 当前Go驱动Copy In语句存在强约束,仅能在事务中通过预编译方式执行。
  • 清空分区 用户可以使用清空分区的命令来快速清空分区的数据。与删除分区功能类似,区别在于清空分区只会删除分区中的数据,分区的定义和物理文件都会保留。清空分区可以通过指定分区名或者分区值来进行。 执行清空分区命令会使得Global索引失效,可以通过UPDATE GLOBAL INDEX子句来同步更新Global索引,或者用户自行重建Global索引。 对一级分区表清空分区 对二级分区表清空一级分区 对二级分区表清空二级分区 父主题: 分区表运维管理
  • 概述 Enhanced Toast是一种用于处理超大字段的技术。首先,减少了Toast Pointer中的冗余信息,存储支持单表超长字段列数超过500列。其次,优化了主表与线外存储表之间的映射关系,无需通过pg_toast_index来存储主表数据与线外存储表数据的关系,降低了用户存储空间。最后,Enhanced Toast技术通过让分割数据自链接,消除了Oid分配的依赖,极大地加快了写入效率。 Astore存储引擎不支持Enhanced Toast。 不支持对Enhanced Toast类型的线外存储表单独进行Vacuum Full操作。 父主题: Enhanced Toast
  • 哈希分区 哈希分区(Hash Partition)基于对分区键使用哈希算法将数据映射到分区。使用的哈希算法为 GaussDB 内置哈希算法,在分区键取值范围不倾斜(no data skew)的场景下,哈希算法在分区之间均匀分布行,使分区大小大致相同。因此哈希分区是实现分区间均匀分布数据的理想方法。哈希分区也是范围分区的一种易于使用的替代方法,尤其是当要分区的数据不是历史数据或没有明显的分区键时,示例如下: CREATE TABLE bmsql_order_line ( ol_w_id INTEGER NOT NULL, ol_d_id INTEGER NOT NULL, ol_o_id INTEGER NOT NULL, ol_number INTEGER NOT NULL, ol_i_id INTEGER NOT NULL, ol_delivery_d TIMESTAMP, ol_amount DECIMAL(6,2), ol_supply_w_id INTEGER, ol_quantity INTEGER, ol_dist_info CHAR(24) ) --预先定义100个分区 PARTITION BY HASH(ol_d_id) ( PARTITION p0, PARTITION p1, PARTITION p2, … PARTITION p99 ); 上述例子中,bmsql_order_line表的ol_d_id进行了分区,ol_d_id列是一个identifier性质的属性列,本身并不带有时间或者某一个特定维度上的区分。使用哈希分区策略来对其进行分表处理则是一个较为理想的选择。相比其他分区类型,除了预先确保分区键没有过多数据倾斜(某一、某几个值重复度高),只需要指定分区键和分区数即可创建分区,同时还能够确保每个分区的数据均匀,提升了分区表的易用性。 父主题: 分区策略
  • 注意事项及约束条件 当分区扫描路径为Index/Index Only时,才支持Merge Append执行机制。 当分区剪枝结果大于1时,才支持Merge Append执行机制。 当分区索引全部有效且为Btree索引时,才支持Merge Append执行机制。 当SQL含有Limit子句时,才支持Merge Append执行机制。 当分区扫描时如果存在Filter,不支持Merge Append执行机制。 当GUC参数sql_beta_feature = 'disable_merge_append_partition'时,不再生成Merge Append路径。
  • 场景描述 当对分区表进行全局排序时,通常SQL引擎的实现方式是先通过Partition Iterator + PartitionScan对分区表做全量扫描,然后进行Sort排序操作,这样难以利用数据分区分治的算法思想进行全局排序,假如ORDER BY排序列包含索引,本身局部有序的前提条件则无法利用。针对这类问题,目前分区表支持分区归并排序执行策略,利用Merge Append的执行机制改进分区表的排序机制。
  • 示例 -- 修改表的默认类型 gaussdb=# set enable_default_ustore_table=off; --准备数据。 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 --查询物化视图结果。 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=# DROP TABLE t1; DROP TABLE
  • 分区表(母表) 实际对用户体现的表,用户对该表进行常规DML语句的增、删、查、改操作。通常使用在建表DDL语句显式的使用PARTITION BY语句进行定义,创建成功以后在pg_class表中新增一个entry,并且parttype列内容为'p'(一级分区)或者's'(二级分区),表明该entry为分区表的母表。分区母表通常是一个逻辑形态,对应的表文件并不存放数据。 示例1:t1_hash为一个一级分区表,分区类型为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 ); gaussdb=# \d+ t1_hash Table "public.t1_hash" Column | Type | Modifiers | Storage | Stats target | Description --------+---------+-----------+---------+--------------+------------- c1 | integer | | plain | | c2 | integer | | plain | | c3 | integer | | plain | | Partition By HASH(c1) Number of partitions: 10 (View pg_partition to check each partition range.) Has OIDs: no Options: orientation=row, compression=no, storage_type=USTORE, segment=off --查询t1_hash分区类型 gaussdb=# SELECT relname, parttype FROM pg_class WHERE relname = 't1_hash'; relname | parttype ---------+---------- t1_hash | p (1 row) gaussdb=# DROP TABLE t1_hash; 示例2:t1_sub_rr为一个二级分区表,分区类型为range-list: gaussdb=# CREATE TABLE t1_sub_rr ( c1 INT, c2 INT, c3 INT ) PARTITION BY RANGE (c1) SUBPARTITION BY LIST (c2) ( PARTITION p_2021 VALUES LESS THAN (2022) ( SUBPARTITION p_2021_1 VALUES (1), SUBPARTITION p_2021_2 VALUES (2), SUBPARTITION p_2021_3 VALUES (3) ), PARTITION p_2022 VALUES LESS THAN (2023) ( SUBPARTITION p_2022_1 VALUES (1), SUBPARTITION p_2022_2 VALUES (2), SUBPARTITION p_2022_3 VALUES (3) ), PARTITION p_2023 VALUES LESS THAN (2024) ( SUBPARTITION p_2023_1 VALUES (1), SUBPARTITION p_2023_2 VALUES (2), SUBPARTITION p_2023_3 VALUES (3) ), PARTITION p_2024 VALUES LESS THAN (2025) ( SUBPARTITION p_2024_1 VALUES (1), SUBPARTITION p_2024_2 VALUES (2), SUBPARTITION p_2024_3 VALUES (3) ), PARTITION p_2025 VALUES LESS THAN (2026) ( SUBPARTITION p_2025_1 VALUES (1), SUBPARTITION p_2025_2 VALUES (2), SUBPARTITION p_2025_3 VALUES (3) ), PARTITION p_2026 VALUES LESS THAN (2027) ( SUBPARTITION p_2026_1 VALUES (1), SUBPARTITION p_2026_2 VALUES (2), SUBPARTITION p_2026_3 VALUES (3) ) ); gaussdb=# \d+ t1_sub_rr Table "public.t1_sub_rr" Column | Type | Modifiers | Storage | Stats target | Description --------+---------+-----------+---------+--------------+------------- c1 | integer | | plain | | c2 | integer | | plain | | c3 | integer | | plain | | Partition By RANGE(c1) Subpartition By LIST(c2) Number of partitions: 6 (View pg_partition to check each partition range.) Number of subpartitions: 18 (View pg_partition to check each subpartition range.) Has OIDs: no Options: orientation=row, compression=no, storage_type=USTORE, segment=off --查询t1_sub_rr分区类型 gaussdb=# SELECT relname, parttype FROM pg_class WHERE relname = 't1_sub_rr'; relname | parttype -----------+---------- t1_sub_rr | s (1 row) gaussdb=# DROP TABLE t1_sub_rr; 父主题: 基本概念
  • 示例 --创建server。 gaussdb=# CREATE SERVER file_server FOREIGN DATA WRAPPER file_fdw; CREATE SERVER --创建外表。 gaussdb=# CREATE FOREIGN TABLE file_ft(id int, name text) SERVER file_server OPTIONS(filename '/tmp/1.csv', format 'csv', delimiter ','); CREATE FOREIGN TABLE --删除外表。 gaussdb=# DROP FOREIGN TABLE file_ft; DROP FOREIGN TABLE --删除server。 gaussdb=# DROP SERVER file_server; DROP SERVER
  • 使用file_fdw 创建服务器对象:CREATE SERVER。 创建用户映射:CREATE USER MAPPING。 创建外表:CREATE FOREIGN TABLE。 外表的表结构需要与指定的文件的数据保持一致。 对外表做查询操作,写操作不被允许。 删除外表:DROP FOREIGN TABLE。 删除用户映射:DROP USER MAPPING。 删除服务器对象:DROP SERVER。
  • 指定单分区统计信息收集 当前分区表支持指定单分区统计信息收集,已收集统计信息的分区会在再次收集时自动更新维护。该功能适用于列表分区、哈希分区和范围分区。 gaussdb=# CREATE TABLE only_first_part(id int,name varchar)PARTITION BY RANGE (id) (PARTITION id11 VALUES LESS THAN (1000000), PARTITION id22 VALUES LESS THAN (2000000), PARTITION max_id1 VALUES LESS THAN (MAXVALUE)); gaussdb=# INSERT INTO only_first_part SELECT generate_series(1,5000),'test'; gaussdb=# ANALYZE only_first_part PARTITION (id11); gaussdb=# ANALYZE only_first_part PARTITION (id22); gaussdb=# ANALYZE only_first_part PARTITION (max_id1); gaussdb=# SELECT relname, relpages, reltuples FROM pg_partition WHERE relname IN ('id11', 'id22', 'max_id1'); relname | relpages | reltuples ---------+----------+----------- id11 | 20 | 5000 id22 | 0 | 0 max_id1 | 0 | 0 (3 rows) gaussdb=# \x gaussdb=# SELECT * FROM pg_stats WHERE tablename ='only_first_part' AND partitionname ='id11'; -[ RECORD 1 ]----------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- schemaname | public tablename | only_first_part attname | name inherited | f null_frac | 0 avg_width | 5 n_distinct | 1 n_dndistinct | 0 most_common_vals | {test} most_common_freqs | {1} histogram_bounds | correlation | 1 most_common_elems | most_common_elem_freqs | elem_count_histogram | partitionname | id11 subpartitionname | -[ RECORD 2 ]----------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- schemaname | public tablename | only_first_part attname | id inherited | f null_frac | 0 avg_width | 4 n_distinct | -1 n_dndistinct | 0 most_common_vals | most_common_freqs | histogram_bounds | {1,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,950,1000,1050,1100,1150,1200,1250,1300,1350,1400,1450,1500,1550,1600,1650,1700,1750,1800,1850,1900,1950,2000,2050,2100,2150,2200,2250,2300,2350,2400,2450,2500,2550,2600,2650,2700,2750,2800,2850,2900,2950,3000,3050,3100,3150,3200,3250,3300,3350,3400,3450,3500,3550,3600,3650,3700,3750,3800,3850,3900,3950,4000,4050,4100,4150,4200,4250,4300,4350,4400,4450,4500,4550,4600,4650,4700,4750,4800,4850,4900,4950,5000} correlation | 1 most_common_elems | most_common_elem_freqs | elem_count_histogram | partitionname | id11 subpartitionname | gaussdb=# \x -- 删除分区表 gaussdb=# DROP TABLE only_first_part;
  • 分区表索引重建/不可用 用户可以通过命令使得一个分区表索引或者一个索引分区不可用,此时该索引/索引分区不再维护。使用重建索引命令可以重建分区表索引,恢复索引的正常功能。 此外,部分分区级DDL操作也会使得Global索引失效,包括删除drop、交换exchange、清空truncate、分割split、合并merge。如果在DDL操作中带UPDATE GLOBAL INDEX子句,则会同步更新Global索引,否则需要用户自行重建索引。 索引重建/不可用 Local索引分区重建/不可用 父主题: 分区表运维管理
  • 向二级分区表新增一级分区 使用ALTER TABLE ADD PARTITION可以在二级分区表中新增一个一级分区,这个行为可以作用在一级分区策略为RANGE或者LIST的情况。如果这个新增一级分区下申明了二级分区定义,则数据库会根据定义创建对应的二级分区;如果这个新增一级分区下没有申明二级分区定义,则数据库会自动创建一个默认的二级分区。 例如,对二级分区表range_list_sales新增一个一级分区,并在下面创建四个二级分区。 ALTER TABLE range_list_sales ADD PARTITION date_202005 VALUES LESS THAN ('2020-06-01') TABLESPACE tb1 ( SUBPARTITION date_202005_channel1 VALUES ('0', '1', '2'), SUBPARTITION date_202005_channel2 VALUES ('3', '4', '5') TABLESPACE tb2, SUBPARTITION date_202005_channel3 VALUES ('6', '7'), SUBPARTITION date_202005_channel4 VALUES ('8', '9') ); 或者对二级分区表range_list_sales只进行新增一级分区操作。 ALTER TABLE range_list_sales ADD PARTITION date_202005 VALUES LESS THAN ('2020-06-01') TABLESPACE tb1; 上面这种行为与如下SQL语句等价。 ALTER TABLE range_list_sales ADD PARTITION date_202005 VALUES LESS THAN ('2020-06-01') TABLESPACE tb1 ( SUBPARTITION date_202005_channel1 VALUES (DEFAULT) ); 当二级分区表的一级分区策略为HASH时,不支持通过ALTER TABLE ADD PARTITION命令新增一级分区。 父主题: 新增分区
  • 使用Astore的优势 Astore没有回滚段,而Ustore有回滚段。对于Ustore来说,回滚段是非常重要的,回滚段损坏会导致数据丢失甚至数据库无法启动的严重问题。且Ustore恢复时同步需要Redo和Undo。由于Astore没有回滚段,旧数据都是记录在原先的文件中,所以当数据库异常crash后,恢复时不会像Ustore数据库那样进行复杂的恢复。 由于旧的数据是直接记录在数据文件中,而不是回滚段中,所以不会经常报Snapshot Too Old错误。 回滚可以很快完成,因为回滚并不删除数据。 回滚时很复杂,在事务回滚时必须清理该事务所进行的修改,插入的记录要删除,更新的记录要更新回来,同时回滚的过程也会再次产生大量的Redo日志。 WAL日志要简单一些,仅需要记录数据文件的变化,不需要记录回滚段的变化。 支持回收站(闪回DROP、闪回Truncate)功能。
  • GaussDB内核503版本 Ustore适配分布式/并行查询/Global Temp Table/Vacuum full/列约束DEFERRABLE以及INITIALLY DEFERRED。 Ustore增加在线重建索引。 Ustore增加增强版本B-tree空页面估算,提升优化器代价估算准确度。 Ustore增加存储引擎可靠性验证框架,Diagnose Page/Page Verify。 Ustore增强存储引擎相关的解析/检测/修复视图。 Ustore增强基于WAL日志的定位能力,新增gs_redo_upage系统视图,支持对单页面的不断重放,获取并打印该页面的任何一个历史版本,加速页面损坏类问题的定位。 Ustore扩展事务槽TD物理格式,为事务内空间复用做好铺垫。 Ustore增加在线创建索引。 Ustore适配闪回功能(for Ustore)/极致RTO。 父主题: 存储引擎更新说明
  • 问题分析 在开启并行回放或串行回放的情况下(查询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 问题分析
  • 对二级分区表删除一级分区 使用ALTER TABLE DROP PARTITION可以删除二级分区表的一个一级分区,这个行为可以作用在一级分区策略为RANGE或者LIST的情况。数据库会将这个一级分区,以及一级分区下的所有二级分区都删除。 例如,通过指定分区名删除二级分区表range_list_sales的一级分区date_202005,并更新Global索引。 ALTER TABLE range_list_sales DROP PARTITION date_202005 UPDATE GLOBAL INDEX; 或者,通过指定分区值来删除二级分区表range_list_sales中('2020-05-08')所对应的一级分区。由于不带UPDATE GLOBAL INDEX子句,执行该命令后Global索引会失效。 ALTER TABLE range_list_sales DROP PARTITION FOR ('2020-05-08'); 当二级分区表只有一个一级分区时,不支持通过ALTER TABLE DROP PARTITION命令删除一级分区。 当二级分区表的一级分区策略为HASH时,不支持通过ALTER TABLE DROP PARTITION命令删除一级分区。 父主题: 删除分区
  • RCR Uheap空闲空间管理 Ustore使用Free Space Map(FSM)文件记录了每个数据页的潜在空闲空间,并且以树的结构组织起来。每当用户想要对某个表执行插入操作或者是非原位更新操作时,就会从该表对应的FSM中进行快速查找,查看当前FSM上记录的最大空闲空间是否可以满足插入所需的空间要求。如果满足则返回对应的blocknum用于执行插入操作,否则执行拓展页面逻辑。 每一个表或者分区对应的FSM结构存放在一个独立的FSM文件中,该FSM文件与表数据放在相同的目录下。例如,假设表t1对应的数据文件为32181,则其对应的FSM文件为32181_fsm。FSM内部同样是以数据块的格式存储,这里称为FSM block,FSM block之间的逻辑结构组成了一棵有三层节点的树,树的节点在逻辑上是大顶堆关系。每次在FSM上查找时从根节点进行,一直查找到叶子节点,然后在叶子节点内搜索到一个可用的页面并返回给业务用于执行后续操作。 该结构不保证和数据页实际可用空间保持实时一致,会在DML的执行过程中进行维护。Ustore会在Auto Vacuum的过程中概率性对该FSM进行修复重建。当用户执行插入类型的DML语句,类似Insert/Non-Inplace Update(新页面)/Multi Insert时,会查询FSM结构,寻找到一个可以插入当前记录的空间。用户执行完DML操作后会根据当前页面的潜在空闲空间与实际空闲空间的差值来决定是否将该页面的空闲空间刷新到FSM上。该差值越大,即潜在空间大于实际空间越多,则该页面被更新至FSM的几率越大。FSM上会记录数据页的潜在空闲空间 ,在用户执行插入操作找到一个页面时,如果该页面上的空闲空间较大则直接插入,否则如果潜在空间较大则对页面执行清理后插入,最后如果空间不够则重新搜索FSM结构或者拓展总页面数量。更新FSM结构主要有以下几个位置,DML、页面清理、vacuum、拓展页面、分区合并、页面扫描等。 父主题: RCR Uheap
  • 范围分区自动扩展 范围分区的自动扩展即间隔分区。开启范围分区自动扩展功能,需要在创建分区时明确指定INTERVAL子句。当前只支持一级间隔分区表,且只支持单列分区键。 -- 创建分区表并指定INTERVAL子句,表示支持范围分区自动扩展。 gaussdb=# CREATE TABLE interval_int (c1 int, c2 int) PARTITION BY RANGE (c1) INTERVAL (5) ( PARTITION p1 VALUES LESS THAN (5), PARTITION p2 VALUES LESS THAN (10), PARTITION p3 VALUES LESS THAN (15) ); 当插入数据无法匹配到已有的任意分区时,会自动创建一个新的分区,新分区的范围定义由上一个分区范围和INTERVAL值决定。 -- 分区键插入数据23,自动创建分区sys_p1,分区范围定义为[20, 25)。 gaussdb=# INSERT INTO interval_int VALUES (23, 0); -- 清理示例 gaussdb=# DROP TABLE interval_int; 父主题: 分区自动扩展
  • 使用Ustore的优势 最新版本和历史版本分离存储,相比Astore扫描范围小。去除Astore的HOT chain,非索引列/索引列更新,Heap均可原位更新,ROWID可保持不变。历史版本可批量回收,空间膨胀可控。 B-tree索引增加了事务信息,能够独立进行MVCC。增加了IndexOnlyScan的比例,大大减少回表次数。 不依赖Vacuum进行旧版本清理。独立的空间回收能力,索引与堆表解耦,可独立清理,I/O平稳度更优。 大并发更新同一行的场景,相对于Astore的ROWID会偏移,Ustore的原位更新机制保证了元组ROWID稳定,先到先得,更新时延相对稳定。 支持闪回功能。 Ustore DML在修改数据页面时,也需要同步生成Undo,因此更新操作开销会稍大一些。此外单条Tuple扫描开销由于需要复制(Astore返回指针)也会大一些。
  • 文件组织结构 如需查询当前回滚段使用的存储方式是页式或段页式,可以查询系统表。当前仅支持页式。 示例: 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条