华为云用户手册

  • 闪回恢复 闪回恢复功能是数据库恢复技术的一环,可以有选择性的撤销一个已提交事务的影响,将数据从人为不正确的操作中进行恢复。在采用闪回技术之前,只能通过备份恢复、PITR等手段找回已提交的数据库修改,恢复时长需要数分钟甚至数小时。采用闪回技术后,通过闪回Drop和闪回Truncate恢复已提交的数据库Drop/Truncate的数据,只需要秒级,而且恢复时间和数据库大小无关。 Astore引擎暂不支持闪回功能。 备机不支持闪回操作。 用户可以根据需要开启闪回功能,开启后会带来一定的性能劣化。 闪回查询 闪回表 闪回DROP/TRUNCATE 父主题: Ustore存储引擎
  • 向间隔分区表新增分区 不支持通过ALTER TABLE ADD PARTITION命令向间隔分区表新增分区。当用户插入数据超出现有间隔分区表范围时,数据库会自动根据间隔分区的INTERVAL值创建一个分区。 例如,对间隔分区表interval_sales插入如下数据后,数据库会创建一个分区,该分区范围为['2020-07-01', '2020-08-01'),间隔分区的新增分区命名从sys_p1开始递增。 INSERT INTO interval_sales VALUES (263722,42819872,'2020-07-09','E',432072,213,17); 父主题: 新增分区
  • 分区表DML查询语句 由于分区的实现完全体现在数据库内核中,用户对分区表查询、非分区表查询在语法上除了指定分区的查询操作以外没有区别。 出于分区表的易用性考虑,GaussDB Kernel支持指定分区的查询操作,指定分区可以通过PARTITION (partname)或者PARTITION FOR (partvalue)来进行,对于二级分区表还可以通过SUBPARTITION (subpartname)或者SUBPARTITION FOR (subpartvalue)指定具体的二级分区。指定分区DML支持以下几类语法: 查询(SELECT) 插入(INSERT) 更新(UPDATE) 删除(DELETE) 插入或更新(UPSERT) 合并(MERGE INTO) 下面给出了指定分区做DML的示例: /* 创建二级分区表 list_list_02 */ gaussdb=# CREATE TABLE IF NOT EXISTS list_list_02 ( id INT, role VARCHAR(100), data VARCHAR(100) ) PARTITION BY LIST (id) SUBPARTITION BY LIST (role) ( PARTITION p_list_2 VALUES(0,1,2,3,4,5,6,7,8,9) ( SUBPARTITION p_list_2_1 VALUES ( 0,1,2,3,4,5,6,7,8,9 ), SUBPARTITION p_list_2_2 VALUES ( DEFAULT ), SUBPARTITION p_list_2_3 VALUES ( 10,11,12,13,14,15,16,17,18,19), SUBPARTITION p_list_2_4 VALUES ( 20,21,22,23,24,25,26,27,28,29 ), SUBPARTITION p_list_2_5 VALUES ( 30,31,32,33,34,35,36,37,38,39 ) ), PARTITION p_list_3 VALUES(10,11,12,13,14,15,16,17,18,19) ( SUBPARTITION p_list_3_2 VALUES ( DEFAULT ) ), PARTITION p_list_4 VALUES( DEFAULT ), PARTITION p_list_5 VALUES(20,21,22,23,24,25,26,27,28,29) ( SUBPARTITION p_list_5_1 VALUES ( 0,1,2,3,4,5,6,7,8,9 ), SUBPARTITION p_list_5_2 VALUES ( DEFAULT ), SUBPARTITION p_list_5_3 VALUES ( 10,11,12,13,14,15,16,17,18,19), SUBPARTITION p_list_5_4 VALUES ( 20,21,22,23,24,25,26,27,28,29 ), SUBPARTITION p_list_5_5 VALUES ( 30,31,32,33,34,35,36,37,38,39 ) ), PARTITION p_list_6 VALUES(30,31,32,33,34,35,36,37,38,39), PARTITION p_list_7 VALUES(40,41,42,43,44,45,46,47,48,49) ( SUBPARTITION p_list_7_1 VALUES ( DEFAULT ) ) ) ENABLE ROW MOVEMENT; /* 导入数据 */ INSERT INTO list_list_02 VALUES(null, 'alice', 'alice data'); INSERT INTO list_list_02 VALUES(2, null, 'bob data'); INSERT INTO list_list_02 VALUES(null, null, 'peter data'); /* 对指定分区进行查询 */ -- 查询分区表全部数据 gaussdb=# SELECT * FROM list_list_02 ORDER BY data; id | role | data ----+-------+------------ | alice | alice data 2 | | bob data | | peter data (3 rows) -- 查询分区p_list_4数据 gaussdb=# SELECT * FROM list_list_02 PARTITION (p_list_4) ORDER BY data; id | role | data ----+-------+------------ | alice | alice data | | peter data (2 rows) -- 查询(100, 100)所对应的二级分区的数据,即二级分区p_list_4_subpartdefault1 gaussdb=# SELECT * FROM list_list_02 SUBPARTITION FOR(100, 100) ORDER BY data; id | role | data ----+-------+------------ | alice | alice data | | peter data (2 rows) -- 查询分区p_list_2 数据 gaussdb=# SELECT * FROM list_list_02 PARTITION (p_list_2) ORDER BY data; id | role | data ----+------+---------- 2 | | bob data (1 row) -- 查询(0, 100)所对应的二级分区的数据,即二级分区p_list_2_2 gaussdb=# SELECT * FROM list_list_02 SUBPARTITION FOR (0, 100) ORDER BY data; id | role | data ----+------+---------- 2 | | bob data (1 row) /* 对指定分区做IUD */ -- 删除分区p_list_5中的全部数据 gaussdb=# DELETE FROM list_list_02 PARTITION (p_list_5); -- 指定分区p_list_7_1插入数据,由于数据不符合该分区约束,插入报错 gaussdb=# INSERT INTO list_list_02 SUBPARTITION (p_list_7_1) VALUES(null, 'cherry', 'cherry data'); ERROR: inserted subpartition key does not map to the table subpartition -- 将一级分区值100所属分区的数据进行更新 gaussdb=# UPDATE list_list_02 PARTITION FOR (100) SET id = 1; --upsert gaussdb=# INSERT INTO list_list_02 (id, role, data) VALUES (1, 'test', 'testdata') ON DUPLICATE KEY UPDATE role = VALUES(role), data = VALUES(data); --merge into gaussdb=# CREATE TABLE IF NOT EXISTS list_tmp ( id INT, role VARCHAR(100), data VARCHAR(100) ) PARTITION BY LIST (id) ( PARTITION p_list_2 VALUES(0,1,2,3,4,5,6,7,8,9), PARTITION p_list_3 VALUES(10,11,12,13,14,15,16,17,18,19), PARTITION p_list_4 VALUES( DEFAULT ), PARTITION p_list_5 VALUES(20,21,22,23,24,25,26,27,28,29), PARTITION p_list_6 VALUES(30,31,32,33,34,35,36,37,38,39), PARTITION p_list_7 VALUES(40,41,42,43,44,45,46,47,48,49)) ENABLE ROW MOVEMENT; gaussdb=# MERGE INTO list_tmp target USING list_list_02 source ON (target.id = source.id) WHEN MATCHED THEN UPDATE SET target.data = source.data, target.role = source.role WHEN NOT MATCHED THEN INSERT (id, role, data) VALUES (source.id, source.role, source.data); --清理示例 gaussdb=# DROP TABLE list_tmp; gaussdb=# DROP TABLE list_list_02; 父主题: 分区基本使用
  • DQL/DML-DDL同分区并发 GaussDB Kernel不支持同分区的DQL/DML-DDL并发,后触发业务会被先触发业务阻塞。 原则上,不建议用户在进行分区DDL时,同时对该分区进行DQL/DML操作,因为目标分区存在一个状态的突变过程,可能会导致业务的查询结果不符合预期。 如果由于业务模型不合理、无法剪枝等场景导致的DQL/DML和DDL作用分区有重叠时,考虑两种场景: 场景一:先触发DQL/DML,再触发DDL。DDL会被阻塞,等DQL/DML提交后再进行。 场景二:先触发DDL,再触发DQL/DML。DQL/DML会被阻塞,等DDL提交后再进行,由于分区元信息发生了变更,可能导致预期不合理。为了保证数据一致性,预期结果按照如下规则制定。 ADD分区 ADD分区会产生一个新的分区,这个新分区对期间触发的DQL/DML操作均是不可见的,无阻塞期。 DROP分区 DROP分区会将已有分区进行删除,期间触发的目标分区DQL/DML操作会被阻塞,阻塞完成后跳过对该分区的处理。 TRUNCATE分区 TRUNCATE分区会将已有分区清空数据,期间触发的目标分区DQL/DML操作会被阻塞,阻塞完成后继续对该分区进行处理。 注意期间触发的目标分区查询是查不到数据的,因为TRUNCATE操作提交后目标分区中不存有任何数据。 EXCHANGE分区 EXCHANGE分区会将一个已有分区与普通表进行交换,期间触发的目标分区DQL/DML操作会被阻塞,阻塞完成后继续对该分区进行处理,该分区的实际数据对应原普通表。 例外:如果分区表上存在GLOBAL索引,EXCHANGE命令带来UPDATE GLOBAL INDEX子句,且期间触发的分区表查询使用了GLOBAL索引,由于无法查询到交换后分区上的数据,在阻塞完成后查询业务会报错。 ERROR: partition xxxxxx does not exist on relation "xxxxxx" DETAIL: this partition may have already been dropped by cocurrent DDL operations EXCHANGE PARTITION SPLIT分区 SPLIT分区会将一个分区分割为多个分区,即使其中一个新分区与旧分区名字相同,也视为不同的分区。期间触发的目标分区DQL/DML操作会被阻塞,阻塞完成后业务报错。 ERROR: partition xxxxxx does not exist on relation "xxxxxx" DETAIL: this partition may have already been dropped by cocurrent DDL operations SPLIT PARTITION MERGE分区 MERGE分区会将多个分区合并为一个分区,如果合并后的分区与其中一个旧分区A名字相同,逻辑上视为相同分区。期间触发的目标分区DQL/DML操作会被阻塞,阻塞完成后,根据目标分区类型判断,如果目标分区是旧分区A,则作用于新分区;如果目标分区为其他旧分区,则业务报错。 ERROR: partition xxxxxx does not exist on relation "xxxxxx" DETAIL: this partition may have already been dropped by cocurrent DDL operations MERGE PARTITION RENAME分区 RENAME分区不会变更分区结构信息,期间触发的DQL/DML操作不会出现任何异常,但会被阻塞,直到RENAME操作提交。 MOVE分区 MOVE分区不会变更分区结构信息,期间触发的DQL/DML操作不会出现任何异常,但会被阻塞,直到MOVE操作提交。
  • 数据分区运维管理 分区表技术为数据生命周期管理(DLM)提供了灵活性的支持,数据生命周期管理是一组用于在数据的整个使用寿命中管理数据的过程和策略。其中一个重要组成部分是确定在数据生命周期的任何时间点存储数据的最合适和最经济高效的介质:日常操作中使用的较新数据存储在最快、可用性最高的存储层上,而不经常访问的较旧数据可能存储在成本较低、效率较低的存储层。较旧的数据也可能更新的频率较低,因此将数据压缩并存储为只读是有意义的。 分区表为实施DLM解决方案提供了理想的环境,通过不同分区使用不同表空间,最大限度在确保易用性的同时,实现了有效的数据生命周期的成本优化。这部分的设置由数据库运维人员在服务端设置操作完成,实际用户并不感知这一层面的优化设置,对用户而言逻辑上仍然是对同一张表的查询操作。此外不同分区可以分别实施备份、恢复、索引重建等运维性质的操作,能够对单个数据集不同子类进行分治操作,满足用户业务场景的差异化需求。 父主题: 大容量数据库
  • 对二级分区表清空二级分区 使用ALTER TABLE TRUNCATE SUBPARTITION可以清空二级分区表的一个二级分区。 例如,通过指定分区名清空二级分区表range_list_sales的二级分区date_202005_channel1,并更新Global索引。 ALTER TABLE range_list_sales TRUNCATE SUBPARTITION date_202005_channel1 UPDATE GLOBAL INDEX; 或者,通过指定分区值来清空二级分区表range_list_sales中('2020-05-08', '0')所对应的二级分区。由于不带UPDATE GLOBAL INDEX子句,执行该命令后Global索引会失效。 ALTER TABLE range_list_sales TRUNCATE SUBPARTITION FOR ('2020-05-08', '0'); 父主题: 清空分区
  • PbRCR(Page base Row Consistency Read) Heap多版本管理 Heap的多版本管理是基于Tuple的行级多版本管理。 事务修改记录时,会将历史数据记录到Undo Row中。 在Tuple中的td_id上记录产生的Undo Row地址(zone_id, block no, page offset)。 将新的数据覆盖写入Heap页面。 每次对数据的修改都会产生Undo,同一记录的undo通过block prev串联。 父主题: Relation
  • 分区策略 分区策略在使用DDL语句建表语句时通过PARTITION BY语句的语法指定,分区策略描述了在分区表中数据和分区路由映射规则。常见的分区类型有基于条件的Range分区/Interval分区、基于哈希散列函数的Hash分区、基于数据枚举的List列表分区: CREATE TABLE table_name (…) PARTITION BY partition_strategy (partition_key) (…) 范围分区 间隔分区 哈希分区 列表分区 二级分区 分区表对导入操作的性能影响 父主题: 分区表介绍
  • 分区表(母表) 实际对用户体现的表,用户对该表进行常规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; 父主题: 基本概念
  • 示例 --准备数据。 gaussdb=# CREATE TABLE t1(c1 int, c2 int); gaussdb=# INSERT INTO t1 VALUES(1, 1); gaussdb=# INSERT INTO t1 VALUES(2, 2); --创建增量物化视图。 gaussdb=# CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT * FROM t1; CREATE MATERIALIZED VIEW --插入数据。 gaussdb=# INSERT INTO t1 VALUES(3, 3); INSERT 0 1 --增量刷新物化视图。 gaussdb=# REFRESH INCREMENTAL MATERIALIZED VIEW mv; REFRESH MATERIALIZED VIEW --查询物化视图结果。 gaussdb=# SELECT * FROM mv; c1 | c2 ----+---- 1 | 1 2 | 2 3 | 3 (3 rows) --插入数据。 gaussdb=# INSERT INTO t1 VALUES(4, 4); INSERT 0 1 --全量刷新物化视图。 gaussdb=# REFRESH MATERIALIZED VIEW mv; REFRESH MATERIALIZED VIEW --查询物化视图结果。 gaussdb=# select * from mv; c1 | c2 ----+---- 1 | 1 2 | 2 3 | 3 4 | 4 (4 rows) --删除物化视图。 gaussdb=# DROP MATERIALIZED VIEW mv; DROP MATERIALIZED VIEW
  • 语法格式 创建增量物化视图 CREATE INCREMENTAL MATERIALIZED VIEW [ view_name ] AS { query_block }; 全量刷新物化视图 REFRESH MATERIALIZED VIEW [ view_name ]; 增量刷新物化视图 REFRESH INCREMENTAL MATERIALIZED VIEW [ view_name ]; 删除物化视图 DROP MATERIALIZED VIEW [ view_name ]; 查询物化视图 SELECT * FROM [ view_name ];
  • 使用Ustore进行测试 创建Ustore表 使用CREATE TABLE语句创建Ustore表。 gaussdb=# CREATE TABLE ustore_table(a INT PRIMARY KEY, b CHAR (20)) WITH (STORAGE_TYPE=USTORE); NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "ustore_table_pkey" for table "ustore_table" CREATE TABLE gaussdb=# \d+ ustore_table Table "public.ustore_table" Column | Type | Modifiers | Storage | Stats target | Description --------+---------------+-----------+----------+--------------+------------- a | integer | not null | plain | | b | character(20) | | extended | | Indexes: "ustore_table_pkey" PRIMARY KEY, ubtree (a) WITH (storage_type=USTORE) TABLESPACE pg_default Has OIDs: no Options: orientation=row, storage_type=ustore, compression=no 为Ustore表创建索引 Ustore当前仅支持B-tree类型的多版本索引,在一些场景中,为了区别于Astore的B-tree索引,我们也会将Ustore表的多版本B-tree索引称为UB-tree(Ustore B-tree,UB-tree介绍详见Index章节)。用户可以参照以下方式使用CREATE INDEX语句为Ustore表的 “a” 属性创建一个UB-tree索引。 Ustore表不指定创建索引类型,默认创建的是UB-tree索引: gaussdb=# CREATE INDEX UB-tree_index ON ustore_table(a); CREATE INDEX gaussdb=# \d+ ustore_table Table "public.ustore_table" Column | Type | Modifiers | Storage | Stats target | Description --------+---------------+-----------+----------+--------------+------------- a | integer | not null | plain | | b | character(20) | | extended | | Indexes: "ustore_table_pkey" PRIMARY KEY, ubtree (a) WITH (storage_type=USTORE) TABLESPACE pg_default "ubtree_index" ubtree (a) WITH (storage_type=USTORE) TABLESPACE pg_default Has OIDs: no Options: orientation=row, storage_type=ustore, compression=no 父主题: Ustore简介
  • 分区表动态剪枝 对于检索条件中存在带有变量的分区表查询语句,由于优化器阶段无法获取用户的绑定参数,因此优化器阶段仅能完成indexscan、bitmapindexscan、indexonlyscan等算子检索条件的解析,后续会在执行器阶段获得绑定参数后,完成分区筛选。算子包含的检索条件中需要至少包含一个分区键字段,对于含有多个分区键的分区表,包含任意分区键子集即可。目前分区表动态剪枝仅支持PBE场景和参数化路径场景。 PBE动态剪枝 参数化路径动态剪枝 父主题: 分区剪枝
  • 分区表运维管理 分区表运维管理包括分区管理、分区表管理、分区索引管理和分区表业务并发支持等。 分区管理:也称分区级DDL,包括新增(Add)、删除(Drop)、交换(Exchange)、清空(Truncate)、分割(Split)、合并(Merge)、移动(Move)、重命名(Rename)共8种。 对于哈希分区,涉及分区数的变更会导致数据re-shuffling,故当前GaussDB Kernel不支持导致Hash分区数变更的操作,包括新增(Add)、删除(Drop)、分割(Split)、合并(Merge)这4种。 涉及分区数据变更的操作会使得Global索引失效,可以通过UPDATE GLOBAL INDEX子句来同步更新Global索引,包括删除(Drop)、交换(Exchange)、清空(Truncate)、分割(Split)、合并(Merge)这5种。 大部分分区DDL支持partition/subpartition和partition/subpartition for指定分区两种写法,前者需要指定分区名,后者需要指定分区定义范围内的任一分区值。比如假设分区part1的范围定义为[100, 200),那么partition part1和partition for(150)这两种写法是等价的。 不同分区DDL的执行代价各不相同,由于在执行分区DDL过程中目标分区会被锁住,用户需要评估其代价以及对业务的影响。一般而言,分割(Split)、合并(Merge)的执行代价远大于其他分区DDL,与源分区的大小正相关;交换(Exchange)的代价主要源于Global索引的重建和validation校验;移动(Move)的代价限制于磁盘I/O;其余分区DDL的执行代价都很低。 分区表管理:除了继承普通表的功能外,还支持开启/关闭分区表行迁移的功能。 分区索引管理:支持用户设置索引/索引分区不可用,或者重建不可用的索引/索引分区,比如由于分区管理操作导致的Global索引失效场景。 分区表业务并发支持:当分区级DDL与分区DQL/DML作用于不同分区时,支持二者执行层面的并发。 新增分区 删除分区 交换分区 清空分区 分割分区 合并分区 移动分区 重命名分区 分区表行迁移 分区表索引重建/不可用 父主题: 分区表
  • 场景描述 当对分区表使用min/max函数时,通常SQL引擎的实现方式是先通过Partition Iterator + PartitionScan对分区表做全量扫描然后进行Sort + Limit操作。如果分区是索引扫描,可以先对每个分区进行Limit操作,求出min/max值,最后在分区表上做Sort + Limit操作。这样分区表上做Sort时,由于每个分区已经求出min/max值,所以Sort的数据量跟分区数相同,这时极大的减少了Sort的开销。
  • 对范围分区表分割分区 使用ALTER TABLE SPLIT PARTITION可以对范围分区表分割分区。 例如,假设范围分区表range_sales的分区date_202001定义范围为['2020-01-01', '2020-02-01')。可以指定分割点'2020-01-16'将分区date_202001分割为两个分区,并更新Global索引。 ALTER TABLE range_sales SPLIT PARTITION date_202001 AT ('2020-01-16') INTO ( PARTITION date_202001_p1, --第一个分区上界是'2020-01-16' PARTITION date_202001_p2 --第二个分区上界是'2020-02-01' ) UPDATE GLOBAL INDEX; 或者,不指定分割点,将分区date_202001分割为多个分区,并更新Global索引。 ALTER TABLE range_sales SPLIT PARTITION date_202001 INTO ( PARTITION date_202001_p1 VALUES LESS THAN ('2020-01-11'), PARTITION date_202001_p2 VALUES LESS THAN ('2020-01-21'), PARTITION date_202001_p3 --第三个分区上界是'2020-02-01' )UPDATE GLOBAL INDEX; 又或者,通过指定分区值而不是指定分区名来分割分区。 ALTER TABLE range_sales SPLIT PARTITION FOR ('2020-01-15') AT ('2020-01-16') INTO ( PARTITION date_202001_p1, --第一个分区上界是'2020-01-16' PARTITION date_202001_p2 --第二个分区上界是'2020-02-01' ) UPDATE GLOBAL INDEX; 若对MAXVALUE分区进行分割,前面几个分区不能申明MAXVALUE范围,最后一个分区会继承MAXVALUE分区范围。 父主题: 分割分区
  • 对二级分区表清空一级分区 使用ALTER TABLE TRUNCATE PARTITION可以清空二级分区表的一个一级分区,数据库会将这个一级分区下的所有二级分区都进行清空。 例如,通过指定分区名清空二级分区表range_list_sales的一级分区date_202005,并更新Global索引。 ALTER TABLE range_list_sales TRUNCATE PARTITION date_202005 UPDATE GLOBAL INDEX; 或者,通过指定分区值来清空二级分区表range_list_sales中('2020-05-08')所对应的一级分区。由于不带UPDATE GLOBAL INDEX子句,执行该命令后Global索引会失效。 ALTER TABLE range_list_sales TRUNCATE PARTITION FOR ('2020-05-08'); 父主题: 清空分区
  • 使用示例 示例: 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); CREATE TABLE --查询csn gaussdb=# select int8in(xidout(next_csn)) from gs_get_next_xid_csn(); int8in ---------- 79351682 (1 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 [, ...] ) ]}
  • 对二级分区表交换二级分区 使用ALTER TABLE EXCHANGE SUBPARTITION可以对二级分区表交换二级分区。 例如,通过指定分区名将二级分区表range_list_sales的二级分区date_202001_channel1和普通表exchange_sales进行交换,不进行分区键校验,并更新Global索引。 ALTER TABLE range_list_sales EXCHANGE SUBPARTITION (date_202001_channel1) WITH TABLE exchange_sales WITHOUT VALIDATION UPDATE GLOBAL INDEX; 或者,通过指定分区值将二级分区表range_list_sales中('2020-01-08', '0')所对应的二级分区和普通表exchange_sales进行交换,进行分区校验并将不满足目标分区约束的数据插入到分区表的其他分区中。由于不带UPDATE GLOBAL INDEX子句,执行该命令后Global索引会失效。 ALTER TABLE range_list_sales EXCHANGE SUBPARTITION FOR ('2020-01-08', '0') WITH TABLE exchange_sales WITH VALIDATION VERBOSE; 不支持对二级分区表的一级分区交换分区。 父主题: 交换分区
  • 使用Astore的优势 Astore没有回滚段,而Ustore有回滚段。对于Ustore来说,回滚段是非常重要的,回滚段损坏,会导致数据丢失甚至数据库无法启动的严重问题;且Ustore恢复时同步需要Redo和Undo。由于Astore没有回滚段,旧数据都是记录在原先的文件中,所以当数据库异常crash后,恢复时,不会像Ustore数据库那样进行那么复杂的恢复。 由于旧的数据是直接记录在数据文件中,而不是回滚段中,所以不会经常报Snapshot Too Old错误。 回滚可以很快完成,因为回滚并不删除数据,但回滚时很复杂,在事务回滚时必须清理该事务所进行的修改,插入的记录要删除,更新的记录要更新回来,同时回滚的过程也会再次产生大量的Redo日志。 WAL日志要简单一些,仅需要记录数据文件的变化,不需要记录回滚段的变化。
  • 事务提交 隐式事务。单条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事务模型
  • 整体流程 在使用全密态数据库的过程中,主要流程包括如下五个阶段,本节介绍整体流程,使用gsql操作密态数据库、使用JDBC操作密态数据库章节介绍详细使用流程。 准备阶段:首先,用户需在外部密钥管理中生成主密钥。外部密钥管理包括华为云密钥服务,根据使用场景选择其中一种。 配置阶段:在应用中,通过环境变量或数据库驱动参数设置访问外部密钥管理的信息,在后续操作中,数据库驱动需使用本阶段的配置信息访问外部密钥管理。 执行DDL阶段:在本阶段,用户需先使用密态数据库的密钥语法定义主密钥和列密钥,然后定义表并指定表中某列为加密列。 执行DML阶段:在创建加密表后,用户可直接执行包含但不限于INSERT、SELECT、UPDATE、DELETE等语法,数据库驱动会自动根据上一阶段的加密定义自动对加密列中的数据进行加解密。 清理阶段:依次删除加密表、列密钥和主密钥。
  • 准备阶段 首次使用密态数据库需要执行准备阶段步骤,后续跳过该阶段即可。 密态数据库支持使用不同的外部密钥来管理主密钥,根据场景选择其中一种即可。 华为云场景 用户需先在打开华为云官网,注册账号,登录账号。 在华为云中搜索“统一身份认证服务”,进入该服务,如图所示选择“用户”功能,并创建一个IAM用户,为IAM用户设置IAM密码,并为新的IAM用户设置使用“数据加密服务”的权限。 接下来,请重新回到登录页面,登录方式选择为“IAM用户”,使用新创建的IAM用户进行登录。后续操作均由该IAM用户完成。 在华为云中搜索“数据加密服务”,进入该服务,如下图所示,选择“密钥管理”功能,并通过“创建密钥”按钮创建密钥,密钥创建成功后,可看到每个密钥都具有1个密钥ID。请记住该密钥ID,在后续执行DDL阶段中创建主密钥语法时,需使用该密钥ID。 本步生成的密钥即密态数据库中使用的主密钥,该密钥将由华为云密钥管理服务存储。以后执行与加解密相关的SQL语句时,数据库驱动会通过华为云的restful接口自动访问该密钥。
  • 配置阶段 配置访问外部密钥的参数 华为云场景 通过环境变量配置如下信息: [terminal] # export HUAWEI_KMS_INFO='iamUrl=https://iam.{项目}.myhuaweicloud.com/v3/auth/tokens, iamUser={IAM用户名}, iamPassword={IAM用户密钥}, iamDomain={账号名}, kmsProject={项目}' 在华为云控制台中,点击右上角用户名,并进入“我的凭证”,可看到下图所示页面,该页面可获取上述所需参数:项目、IAM用户名、账号名。另外,请记住本页面的项目ID,在后续执行DDL阶段中创建主密钥语法时,需使用该项目ID。 图1 华为云参数获取页面 # 示例 [terminal] # export HUAWEI_KMS_INFO='iamUrl=https://iam.cn-north-4.myhuaweicloud.com/v3/auth/tokens, iamUser=test_user, iamPassword=**********, iamDomain=test_account, kmsProject=cn-north-4'
  • 执行加密表的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语句存在强约束,仅能在事务中通过预编译方式执行。
  • 执行密态等值查询加密表相关的语句 // 创建加密表 _, 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")
  • 对*-LIST二级分区表分割二级分区 使用ALTER TABLE SPLIT SUBPARTITION可以对*-LIST二级分区表分割二级分区。 例如,假设*-LIST二级分区表hash_list_sales的二级分区product2_channel2的定义范围为DEFAULT。可以指定分割点将其分割为两个分区,并更新Global索引。 ALTER TABLE hash_list_sales SPLIT SUBPARTITION product2_channel2 VALUES ('6', '7', '8', '9') INTO ( SUBPARTITION product2_channel2_p1, --第一个分区范围是('6', '7', '8', '9') SUBPARTITION product2_channel2_p2 --第二个分区范围是DEFAULT ) UPDATE GLOBAL INDEX; 或者,不指定分割点,将分区product2_channel2分割为多个分区,并更新Global索引。 ALTER TABLE hash_list_sales SPLIT SUBPARTITION product2_channel2 INTO ( SUBPARTITION product2_channel2_p1 VALUES ('6', '7', '8'), SUBPARTITION product2_channel2_p2 VALUES ('9', '10'), SUBPARTITION product2_channel2_p3 --第三个分区范围是DEFAULT ) UPDATE GLOBAL INDEX; 又或者,通过指定分区值而不是指定分区名来分割分区。 ALTER TABLE hash_list_sales SPLIT SUBPARTITION FOR (1200, '6') VALUES ('6', '7', '8', '9') INTO ( SUBPARTITION product2_channel2_p1, --第一个分区范围是('6', '7', '8', '9') SUBPARTITION product2_channel2_p2 --第二个分区范围是DEFAULT ) UPDATE GLOBAL INDEX; 若对DEFAULT分区进行分割,前面几个分区不能申明DEFAULT范围,最后一个分区会继承DEFAULT分区范围。 父主题: 分割分区
  • GaussDB Kernel 503版本 - Ustore适配分布式/并行查询/Global Temp Table/Vacuum full/列约束DEFERRABLE以及INITIALLY DEFERRED。 - Ustore增加在线重建索引。 - Ustore增加增强版本B-tree空页面估算,提升优化器代价估算准确度。 - Ustore增加存储引擎可靠性验证框架,Dignose Page/Page Verify。 - Ustore增强存储引擎相关的解析/检测/修复视图。 - Ustore增强基于WAL日志的定位能力,新增gs_redo_upage系统视图,支持对单页面的不断重放,获取并打印该页面的任何一个历史版本,加速页面损坏类问题的定位。 - Ustore扩展事务槽TD物理格式,为事务内空间复用做好铺垫。 - Ustore增加在线创建索引。 - Ustore适配闪回功能(for Ustore)/极致RTO。 父主题: 存储引擎更新说明
共100000条