华为云用户手册

  • 操作步骤 创建防篡改模式。 例如,创建防篡改模式ledgernsp。 1 gaussdb=# CREATE SCHEMA ledgernsp WITH BLOCKCHAIN; 如果需要创建防篡改模式或更改普通模式为防篡改模式,则需设置enable_ledger参数为on。enable_ledger默认参数为off。 在防篡改模式下创建防篡改用户表。 例如,创建防篡改用户表ledgernsp.usertable。 gaussdb=# CREATE TABLE ledgernsp.usertable(id int, name text); 查看防篡改用户表结构及其对应的用户历史表结构。 gaussdb=# \d+ ledgernsp.usertable; gaussdb=# \d+ blockchain.ledgernsp_usertable_hist; 执行结果如下: gaussdb=# \d+ ledgernsp.usertable; Table "ledgernsp.usertable" Column | Type | Modifiers | Storage | Stats target | Description --------+---------+-----------+----------+--------------+------------- id | integer | | plain | | name | text | | extended | | hash_69dd43 | hash16 | | plain | | Has OIDs: no Options: orientation=row, compression=no History table name: ledgernsp_usertable_hist gaussdb=# \d+ blockchain.ledgernsp_usertable_hist; Table "blockchain.ledgernsp_usertable_hist" Column | Type | Modifiers | Storage | Stats target | Description ----------+--------+-----------+---------+--------------+------------- rec_num | bigint | | plain | | hash_ins | hash16 | | plain | | hash_del | hash16 | | plain | | pre_hash | hash32 | | plain | | Indexes: "gs_hist_69dd43_index" PRIMARY KEY, btree (rec_num int4_ops) TABLESPACE pg_default Has OIDs: no Options: internal_mask=263 防篡改表在创建时会自动增加一个名为hash的系统列,所以防篡改表单表最大列数为1599。 修改防篡改用户表数据。 例如,对防篡改用户表执行INSERT、UPDATE、DELETE操作。 gaussdb=# INSERT INTO ledgernsp.usertable VALUES(1, 'alex'), (2, 'bob'), (3, 'peter'); INSERT 0 3 gaussdb=# SELECT *, hash_69dd43 FROM ledgernsp.usertable ORDER BY id; id | name | hash_69dd43 ----+-------+------------------ 1 | alex | 1f2e543c580cb8c5 2 | bob | 8fcd74a8a6a4b484 3 | peter | f51b4b1b12d0354b (3 rows) gaussdb=# UPDATE ledgernsp.usertable SET name = 'bob2' WHERE id = 2; UPDATE 1 gaussdb=# SELECT *, hash_69dd43 FROM ledgernsp.usertable ORDER BY id; id | name | hash_69dd43 ----+-------+------------------ 1 | alex | 1f2e543c580cb8c5 2 | bob2 | 437761affbb7c605 3 | peter | f51b4b1b12d0354b (3 rows) gaussdb=# DELETE FROM ledgernsp.usertable WHERE id = 3; DELETE 1 gaussdb=# SELECT *, hash_69dd43 FROM ledgernsp.usertable ORDER BY id; id | name | hash_69dd43 ----+------+------------------ 1 | alex | 1f2e543c580cb8c5 2 | bob2 | 437761affbb7c605 (2 rows) 删除表和模式。 若要执行其他账本数据库章节的示例,请在执行完之后再执行当前步骤,否则请直接执行当前步骤。 gaussdb=# DROP TABLE ledgernsp.usertable; DROP TABLE gaussdb=# DROP SCHEMA ledgernsp; DROP SCHEMA
  • Partition-wise Join Partition-wise Join是一种分区级并行的优化技术,是指在符合一定条件的情况下,将两张表之间的Join,分解为两张表中对应的两个分区之间的Join。通过并发执行、减少数据通信量等方式,提升分区表的Join查询的性能。 Partition-wise Join分为SMP场景和非SMP场景。 非SMP场景下的Partition-wise Join SMP场景下的Full Partition-wise Join SMP场景下的Partial Partition-wise Join 父主题: 分区表查询优化
  • 背景信息 账本数据库校验功能目前提供两种校验接口,分别为:ledger_hist_check(text, text)和ledger_gchain_check(text, text)。普通用户调用校验接口,仅能校验自己有权限访问的表。 校验防篡改用户表和用户历史表的接口为pg_catalog.ledger_hist_check,操作为: SELECT pg_catalog.ledger_hist_check(schema_name text,table_name text); 如果校验通过,函数返回t,反之则提示失败原因并返回f。 校验防篡改用户表、用户历史表和全局区块表三者是否一致的接口为pg_catalog.ledger_gchain_check,操作为: SELECT pg_catalog.ledger_gchain_check(schema_name text, table_name text); 如果校验通过,函数返回t,反之则提示失败原因并返回f。
  • 操作步骤 校验防篡改用户表ledgernsp.usertable与其对应的历史表是否一致。 1 gaussdb=# SELECT pg_catalog.ledger_hist_check('ledgernsp', 'usertable'); 查询结果如下: ledger_hist_check ------------------- t (1 row) 该结果表明防篡改用户表和用户历史表中记录的结果能够一一对应,保持一致。 查询防篡改用户表ledgernsp.usertable与其对应的历史表以及全局区块表中关于该表的记录是否一致。 1 gaussdb=# SELECT pg_catalog.ledger_gchain_check('ledgernsp', 'usertable'); 查询结果如下: ledger_gchain_check --------------------- t (1 row) 查询结果显示,上述三表中关于ledgernsp.usertable的记录保持一致,未发生篡改行为。
  • 操作加密表 创建加密表。 创建表时,通过在WITH子句中设置enable_tde=on参数,即可设置该表为加密表。 数据库默认使用'AES_128_CTR'算法对加密表进行加密,如需使用其他算法,可通过encrypt_algo参数设置。 gaussdb=# CREATE TABLE t1 (c1 INT, c2 TEXT) WITH (enable_tde = on); CREATE TABLE gaussdb=# CREATE TABLE t2 (c1 INT, c2 TEXT) WITH (enable_tde = on, encrypt_algo = 'SM4_CTR'); CREATE TABLE 查看加密表基本信息。 加密表基本信息存储在pg_class系统表中的reloptions字段中。其中,dek_cipher为数据密钥密文,由数据库自动生成,并由密钥管理服务加密。每个加密表都有1个独立的数据密钥。 gaussdb=# SELECT relname,reloptions FROM pg_class WHERE relname = 't1'; relname | reloptions ---------+----------------------------------------------------------------------------------------------------------------------- t1 | {orientation=row,enable_tde=on,encrypt_algo=AES_128_CTR,compression=no,storage_type=USTORE,key_type=...,dek_cipher=... 向加密表写入数据。 操作加密表与非加密表的语法一致。数据库将表中数据写入磁盘前,才会自动对加密表的数据进行加密。 gaussdb=# INSERT INTO t1 VALUES (1, 'tde plain 123'); INSERT 0 1 从加密表查询数据。 对于合法用户而言,查询加密表与非加密表的语法一致,加解密操作由数据库自动实现。如果攻击者绕过数据库,直接读取磁盘上加密表对应的数据文件,会发现文件中的数据均已被加密。 gaussdb=# SELECT * FROM t1; c1 | c2 ----+--------------- 1 | tde plain 123 (1 row) 轮转加密表的密钥。 为提高安全性,建议定期使用以下语法轮转加密表的数据密钥,即使用新的密钥对数据进行加密。 gaussdb=# ALTER TABLE t1 ENCRYPTION KEY ROTATION; ALTER TABLE 轮转密钥后,数据库仍可以正常解密由旧密钥加密的数据。 加密表与非加密表转换。 透明加密支持将加密表转换为非加密表,以及将非加密表转换为加密表。建议在每次转换后,手动执行VACUUM FULL tablename命令,以强制同步转换表中所有数据。 gaussdb=# CREATE TABLE t3 (c1 INT, c2 TEXT); CREATE TABLE gaussdb=# ALTER TABLE t3 SET (enable_tde = on); ALTER TABLE gaussdb=# VACUUM FULL t3; VACUUM gaussdb=# ALTER TABLE t3 SET (enable_tde = off); ALTER TABLE gaussdb=# VACUUM FULL t3; VACUUM 删除加密表。 gaussdb=# DROP TABLE IF EXISTS t1, t2, t3; DROP TABLE
  • 操作加密索引 创建加密表。 创建索引的基表,需确保基表也是加密表。 gaussdb=# CREATE TABLE t1 (c1 INT, c2 TEXT) WITH (enable_tde = on); CREATE TABLE 创建加密索引。 与创建加密表的方式相同,通过在WITH子句中设置enable_tde=on参数,即将索引设置为加密索引。 索引与基表使用相同的加密算法和密钥,对基表进行密钥轮转时,索引也会使用新密钥。 gaussdb=# CREATE INDEX i1 ON t1(c2) WITH (enable_tde = on); CREATE INDEX 查看加密索引基本信息。 与加密表一样,索引基本信息也存储在pg_class系统表中的reloptions字段中,索引的dek_cipher、encrypt_algo等参数与基表保持一致。 gaussdb=# SELECT relname,reloptions FROM pg_class WHERE relname = 'i1'; relname | reloptions ---------+----------------------------------------------------------------------------------------------------------------------- i1 | {orientation=row,enable_tde=on,encrypt_algo=AES_128_CTR,compression=no,storage_type=USTORE,key_type=...,dek_cipher=... 加密索引与非加密索引转换。 透明加密支持将非加密索引转换为加密索引,将加密索引转换为非加密索引。 gaussdb=# CREATE TABLE t2 (c1 INT, c2 TEXT) WITH (enable_tde = on); ALTER TABLE gaussdb=# CREATE INDEX i2 ON t2(c2); CREATE INDEX gaussdb=# ALTER INDEX i2 SET (enable_tde = on); ALTER INDEX gaussdb=# ALTER INDEX i2 SET (enable_tde = off); ALTER INDEX 自动对索引进行加密。 默认情况下,主动设置enable_tde参数才可创建加密索引。当设置GUC参数tde_index_default_encrypt=on,且以加密表为基表创建索引时,数据库会自动将索引转换为加密索引。示例如下: gaussdb=# CREATE TABLE t3 (c1 INT, c2 TEXT) WITH (enable_tde = on); ALTER TABLE gaussdb=# CREATE INDEX i3 ON t3(c2); CREATE INDEX gaussdb=# SELECT relname,reloptions FROM pg_class WHERE relname = 'i3'; relname | reloptions ---------+----------------------------------------------------------------------------------------------------------------------- i1 | {orientation=row,enable_tde=on,encrypt_algo=AES_128_CTR,compression=no,storage_type=USTORE,key_type=...,dek_cipher=... -- 解释:虽然未指定i3为加密索引,但是开启了tde_index_default_encrypt=on,且基表t3是加密表,数据库自动将i3转换为加密索引 删除加密表和索引。 gaussdb=# DROP TABLE IF EXISTS t1, t2, t3; DROP TABLE
  • 查看透明加密基本配置 查看透明加密功能是否已开启。 enable_tde取值为on时表示开启,取值为off是表示关闭。该参数由管理员设置。 gaussdb=# SHOW enable_tde; enable_tde ------------ on (1 row) 查看是否已设置访问密钥管理服务的参数。 tde_key_info参数为空时表示未设置,tde_key_info不为空时表示已设置。该参数由管理员设置。 gaussdb=# show tde_key_info; tde_key_info ------------------------- keyType=...
  • 物化视图 物化视图是一种特殊的物理表,物化视图是相对普通视图而言的。普通视图是虚拟表,应用的局限性较大,任何对视图的查询实际上都是转换为对SQL语句的查询,性能并没有实际提高。物化视图实际上就是存储SQL执行语句的结果,起到缓存的效果。物化视图常用的操作包括创建、查询、删除和刷新。 根据创建规则,物化视图分为全量物化视图和增量物化视图。全量物化视图只支持全量刷新;增量物化视图支持全量刷新和增量刷新两种方式。全量刷新会将基表中的数据全部重新刷入物化视图中,而增量刷新只会将两次刷新间隔期间的基表产生的增量数据刷入物化视图中。 目前Ustore引擎不支持创建、使用物化视图。 全量物化视图 增量物化视图
  • 使用规格 SMP场景下的Partition-wise Join的使用规格: 只支持一级HASH分区表和一级RANGE分区表。 Hash分区表的分区策略完全相同是指分区键类型相同、分区数相同。 Range分区表的分区策略完全相同是指分区键类型相同、分区数相同、分区键数量相同、每个分区的边界值相同。 支持Hash Join和Merge Join。 支持Seqscan、Indexscan、Indexonlyscan、Imcvscan。其中,对于Indexscan和Indexonlyscan,只支持分区Local索引,且索引类型为BTREE或UBTREE。 相关规格继承SMP规格。不支持SMP场景下的IUD操作。 需要开启SMP功能,且设置query_dop的值大于1。
  • 逻辑复制 GaussDB 对数据复制能力的支持情况为: 支持通过数据迁移工具定期向异构数据库(如Oracle等)进行数据同步,不具备实时数据复制能力,因此不足以支撑与异构数据库间并网运行实时数据同步的诉求。 GaussDB提供了逻辑解码功能,通过反解xLog的方式生成逻辑日志。目标数据库解析逻辑日志以实时进行数据复制。具体如图 逻辑复制所示。逻辑复制降低了对目标数据库的形态限制,支持异构数据库、同构异形数据库对数据的同步,支持目标库进行数据同步期间的数据可读写,数据同步时延低。 图1 逻辑复制 逻辑复制由两部分组成:逻辑解码和数据复制。逻辑解码会输出以事务为单位组织的逻辑日志。业务或数据库中间件将会对逻辑日志进行解析并最终实现数据复制。 逻辑解码
  • 操作步骤 对指定用户历史表进行归档操作。 1 gaussdb=# SELECT pg_catalog.ledger_hist_archive('ledgernsp', 'usertable'); 执行结果如下: ledger_hist_archive --------------------- t (1 row) 用户历史表将归档为一条数据: gaussdb=# SELECT * FROM blockchain.ledgernsp_usertable_hist; rec_num | hash_ins | hash_del | pre_hash ---------+------------------+------------------+---------------------------------- 3 | e78e75b00d396899 | 8fcd74a8a6a4b484 | fd61cb772033da297d10c4e658e898d7 (1 row) 该结果表明当前节点用户历史表导出成功。 执行全局区块表导出操作。 1 gaussdb=# SELECT pg_catalog.ledger_gchain_archive(); 执行结果如下: ledger_gchain_archive ----------------------- t (1 row) 全局历史表将以用户表为单位归档为N(用户表数量)条数据: gaussdb=# SELECT * FROM gs_global_chain; blocknum | dbname | username | starttime | relid | relnsp | relname | relhash | globalhash | txcommand ----------+----------+----------+-------------------------------+-------+-----------+-----------+------------------+----------------------------------+----------- 1 | testdb | libc | 2021-05-10 19:59:38.619472+08 | 16388 | ledgernsp | usertable | 57c101076694b415 | be82f98ee68b2bc4e375f69209345406 | Archived. (1 row) 该结果表明,当前节点全局区块表导出成功。
  • 背景信息 账本数据库归档功能目前提供两种校验接口,分别为:ledger_hist_archive(text, text)和ledger_gchain_archive(text, text)。账本数据库接口仅审计管理员可以调用。 归档用户历史表的接口为pg_catalog.ledger_hist_archive,操作为: SELECT pg_catalog.ledger_hist_archive(schema_name text,table_name text); 如果归档成功,函数返回t,反之则提示失败原因并返回f。 归档全局区块表的接口为pg_catalog.ledger_gchain_archive,操作为: SELECT pg_catalog.ledger_gchain_archive(); 如果归档成功,函数返回t,反之则提示失败原因并返回f。
  • 约束 解析的WAL日志级别为logical。 数据表的复制标识必须为FULL,否则UPDATE和DELETE操作涉及到的被修改行不是全字段。 WAL日志记录的数据修改操作所对应的业务表,从找回起始位置到目前不能执行VACUUM FULL操作,否则该表VACUUM FULL之前的DML操作不会被数据找回。 WAL日志记录的数据修改操作所对应的业务表,从找回起始位置到目前,结构只能发生以下变化: 业务表结构不发生变化,即无DDL操作。 业务表在最后一列增加字段,且字段类型不能为带有默认值超过124字符长度的varchar类型。 业务表删除某一列字段。 varchar字段增加原有长度。 其余表结构变更导致该表relfilenode发生变化的场景不支持,表结构变更前的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的最小时间,否则将会报错。 每次下载的xlog日志量不超过3GB。 每次解码数据量不超过max_process_memory 的10%。 不支持同一节点并发调用数据找回接口。
  • 大容量数据库背景介绍 随着处理数据量的日益增长和使用场景的多样化,数据库越来越多地面对容量大、数据多样化的场景。在过去数据库业界发展的20多年时间里,数据量从最初的MB、GB级数据量逐渐发展到现在的TB级数据量,在如此数据大规模、数据多样化的客观背景下,数据库管理系统(DBMS)在数据查询、数据管理方面提出了更高的要求,客观上要求数据库能够支持多种优化查找策略和管理运维方式。 在计算机科学经典的算法中,人们通常使用分治法(Divide and Conquer)解决场景和规模较大的问题。其基本思想就是把一个复杂的问题分成两个或更多的相同或相似的子问题,再把子问题分成更小的子问题直到最后子问题可以简单的直接求解,原问题的解可看成子问题的解的合并。对于大容量数据场景,数据库提供对数据进行“分治处理”的方式即分区,将逻辑数据库或其组成元素划分为不同的独立部分,每一个分区维护逻辑上存在相类似属性的数据,这样就把庞大的数据整体进行了切分,有利于数据的管理、查找和维护。 父主题: 大容量数据库
  • 向范围分区表新增分区 使用ALTER TABLE ADD PARTITION可以将分区添加到现有分区表的最后面,新增分区的上界值必须大于当前最后一个分区的上界值。 例如,对范围分区表range_sales新增一个分区。 ALTER TABLE range_sales ADD PARTITION date_202005 VALUES LESS THAN ('2020-06-01') TABLESPACE tb1; 当范围分区表有MAXVALUE分区时,无法新增分区。可以使用ALTER TABLE SPLIT PARTITION命令分割分区。分割分区同样适用于需要在现有分区表的前面/中间添加分区的情形,请参见对范围分区表分割分区。 父主题: 新增分区
  • 数据分区运维管理 分区表技术为数据生命周期管理(Data Life Cycle Management,DLM)提供了灵活性的支持,数据生命周期管理是一组用于在数据的整个使用寿命中管理数据的过程和策略。其中一个重要组成部分是确定在数据生命周期的任何时间点存储数据的最合适和最经济高效的介质:日常操作中使用的较新数据存储在最快、可用性最高的存储层上,而不经常访问的较旧数据可能存储在成本较低、效率较低的存储层。较旧的数据也可能更新的频率较低,因此将数据压缩并存储为只读是有意义的。 分区表为实施DLM解决方案提供了理想的环境,通过不同分区使用不同表空间,最大限度在确保易用性的同时,实现了有效的数据生命周期的成本优化。这部分的设置由数据库运维人员在服务端设置操作完成,实际用户并不感知这一层面的优化设置,对用户而言逻辑上仍然是对同一张表的查询操作。此外不同分区可以分别实施备份、恢复、索引重建等运维性质的操作,能够对单个数据集不同子类进行分治操作,满足用户业务场景的差异化需求。 父主题: 大容量数据库
  • Ustore事务模型 GaussDB事务基础: 事务启动时不会自动分配XID,该事务中的第一条DML/DDL语句运行时才会真正为该事务分配XID。 事务结束时,会产生代表事务提交状态的C LOG (Commit Log),CLOG共有四种状态:事务运行中、事务提交、事务同步回滚、子事务提交。每个事务的 CLOG状态位为2 bits,CLOG页面上每个字节可以表示四个事务的提交状态。 事务结束时,还会产生代表事务提交顺序的 CS N(Commit sequence number),CSN为实例级变量,每个XID都有自己对应的唯一CSN。CSN可以标记事务的以下状态:事务提交中、事务提交、事务回滚、事务已冻结等。 事务提交 事务回滚 父主题: Ustore存储引擎
  • Enhanced Toast增删改查 Insert操作:触发Enhanced Toast的写入条件保持与原有Toast一致,除了数据写入时增加了数据间的链接信息之外,插入基本逻辑保持不变。 Delete操作:Enhanced Toast的数据删除流程不再依赖Toast数据索引,仅依靠数据间的链接信息将对应的数据进行遍历删除。 Update操作:Enhanced Toast的更新流程与原有Toast保持一致。 父主题: Enhanced Toast
  • 分区表DQL/DML 由于分区的实现完全体现在数据库内核中,用户对分区表的DQL/DML与非分区表相比,在语法上没有任何区别。 出于分区表的易用性考虑,GaussDB支持指定分区的DQL/DML操作,指定分区可以通过PARTITION (partname)或者PARTITION FOR (partvalue)来实现,对于二级分区表还可以通过SUBPARTITION (subpartname)或者SUBPARTITION FOR (subpartvalue)指定具体的二级分区。指定分区执行DQL/DML时,若插入的数据不属于目标分区,则业务会产生报错;若查询的数据不属于目标分区,则会跳过该数据的处理。 指定分区DQL/DML支持以下几类语法: 查询(SELECT) 插入(INSERT) 更新(UPDATE) 删除(DELETE) 插入或更新(UPSERT) 合并(MERGE INTO) 指定分区做DQL/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,这个分区是在p_list_4下自动创建的一个分区范围定义为DEFAULT的分区 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; DROP TABLE list_list_02; 父主题: 分区基本使用
  • 合并分区 用户可以使用合并分区的命令来将多个分区合并为一个分区。合并分区只能通过指定分区名来进行,不支持指定分区值的写法。 合并分区不能作用于哈希分区上。 执行合并分区命令会使得Global索引失效,可以通过UPDATE GLOBAL INDEX子句来同步更新Global索引,或者用户自行重建Global索引。 合并前的分区如果包含分类索引则不支持合并。 合并后的新分区,对于范围/间隔分区,可以与最后一个源分区名字相同,比如将p1,p2合并为p2;对于列表分区,可以与任一源分区名字相同,比如将p1,p2合并为p1。 如果新分区与源分区名字相同,数据库会将新分区视为对源分区的继承,这会影响合并期间对源分区查询的行为,具体请参见DQL/DML-DDL并发。 对一级分区表合并分区 对二级分区表合并二级分区 父主题: 分区表运维管理
  • 对列表分区表分割分区 使用ALTER TABLE SPLIT PARTITION可以对列表分区表分割分区。 例如,假设列表分区表list_sales的分区channel2定义范围为('6', '7', '8', '9')。可以指定分割点('6', '7')将分区channel2分割为两个分区,并更新Global索引。 ALTER TABLE list_sales SPLIT PARTITION channel2 VALUES ('6', '7') INTO ( PARTITION channel2_1, --第一个分区范围是('6', '7') PARTITION channel2_2 --第二个分区范围是('8', '9') ) UPDATE GLOBAL INDEX; 或者,不指定分割点,将分区channel2分割为多个分区,并更新Global索引。 ALTER TABLE list_sales SPLIT PARTITION channel2 INTO ( PARTITION channel2_1 VALUES ('6'), PARTITION channel2_2 VALUES ('8'), PARTITION channel2_3 --第三个分区范围是('7', '9') )UPDATE GLOBAL INDEX; 又或者,通过指定分区值而不是指定分区名来分割分区。 ALTER TABLE list_sales SPLIT PARTITION FOR ('6') VALUES ('6', '7') INTO ( PARTITION channel2_1, --第一个分区范围是('6', '7') PARTITION channel2_2 --第二个分区范围是('8', '9') ) UPDATE GLOBAL INDEX; 若对DEFAULT分区进行分割,前面几个分区不能申明DEFAULT范围,最后一个分区会继承DEFAULT分区范围。 父主题: 分割分区
  • 语法示例 -- 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); 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); CREATE TABLE --为表flashtest创建索引flashtest_index gaussdb=# CREATE INDEX flashtest_index ON flashtest(id); CREATE INDEX --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); 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); 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)
  • 背景信息 闪回DROP:可以恢复意外删除的表,从回收站(recyclebin)中恢复被删除的表及其附属结构如索引、表约束等。闪回drop是基于回收站机制,通过还原回收站中记录的表的物理文件,实现已drop表的恢复。 闪回TRUNCATE:可以恢复误操作或意外被进行truncate的表,从回收站中恢复被truncate的表及索引的物理数据。闪回truncate基于回收站机制,通过还原回收站中记录的表的物理文件,实现已truncate表的恢复。
  • 常规锁设计 分区表通过表锁+分区锁两重设计,在表和分区上分别施加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 × × × × × × × × 分区表的不同业务最终都是作用于目标分区上,数据库会给分区表和目标分区施加不同级别的表锁+分区锁,来控制并发行为。下表给出了不同业务的锁粒度控制。其中数字1~8代表上表给出的8种级别常规锁。 表2 分区表业务锁粒度 业务模型 一级分区表锁级别(表锁+分区锁) 二级分区表锁级别(表锁+一级分区锁+二级分区锁) SELECT 1-1 1-1-1 SELECT FOR UPDATE 2-2 2-2-2 DML业务,包括INSERT、UPDATE、DELETE、UPSERT、MERGE INTO、COPY 3-3 3-3-3 分区DDL,包括ADD、DROP、EXCHANGE、TRUNCATE、SPLIT、MERGE、MOVE、RENAME;打开/关闭分区自动扩展 4-8 4-8-8(作用二级分区表的一级分区) 4-4-8 (作用二级分区表的二级分区) CREATE INDEX(非分类索引)、REBUILD INDEX 5-5 5-5-5 CREATE INDEX(分类索引) 3-5 3-3-5 REBUILD INDEX PARTITION 1-5 1-5-5 ANALYZE、VACUUM 4-4 4-4-4 其他分区表DDL 8-8 8-8-8 父主题: 分区并发控制
  • 前置建表相关信息 前置建表: CREATE TABLE test_range_pt (a INT, b INT, c INT) PARTITION BY RANGE (a) ( PARTITION p1 VALUES LESS THAN (2000), PARTITION p2 VALUES LESS THAN (3000), PARTITION p3 VALUES LESS THAN (4000), PARTITION p4 VALUES LESS THAN (5000), PARTITION p5 VALUES LESS THAN (MAXVALUE) )ENABLE ROW MOVEMENT; 查看分区表OID: SELECT oid FROM pg_class WHERE relname = 'test_range_pt'; oid ------- 49290 (1 row) 查看分区信息: SELECT oid,relname,parttype,parentid,boundaries FROM pg_partition WHERE parentid = 49290; oid | relname | parttype | parentid | boundaries -------+---------------+----------+----------+------------ 49293 | test_range_pt | r | 49290 | 49294 | p1 | p | 49290 | {2000} 49295 | p2 | p | 49290 | {3000} 49296 | p3 | p | 49290 | {4000} 49297 | p4 | p | 49290 | {5000} 49298 | p5 | p | 49290 | {NULL} (6 rows) 创建索引: CREATE INDEX idx_range_a ON test_range_pt(a) LOCAL; CREATE INDEX --查看分区索引oid SELECT oid FROM pg_class WHERE relname = 'idx_range_a'; oid ------- 90250 (1 row) 查看索引分区信息: SELECT oid,relname,parttype,parentid,boundaries,indextblid FROM pg_partition WHERE parentid = 90250; oid | relname | parttype | parentid | boundaries | indextblid -------+----------+----------+----------+------------+------------ 90255 | p5_a_idx | x | 90250 | | 49298 90254 | p4_a_idx | x | 90250 | | 49297 90253 | p3_a_idx | x | 90250 | | 49296 90252 | p2_a_idx | x | 90250 | | 49295 90251 | p1_a_idx | x | 90250 | | 49294 (5 rows)
  • 工具函数示例 pg_get_tabledef获取分区表的定义,入参可以为表的OID或者表名。 SELECT pg_get_tabledef('test_range_pt'); pg_get_tabledef ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- SET search_path = public; + CREATE TABLE test_range_pt ( + a integer, + b integer, + c integer + ) + WITH (orientation=row, compression=no, storage_type=USTORE, segment=off) + PARTITION BY RANGE (a) + ( + PARTITION p1 VALUES LESS THAN (2000) TABLESPACE pg_default, + PARTITION p2 VALUES LESS THAN (3000) TABLESPACE pg_default, + PARTITION p3 VALUES LESS THAN (4000) TABLESPACE pg_default, + PARTITION p4 VALUES LESS THAN (5000) TABLESPACE pg_default, + PARTITION p5 VALUES LESS THAN (MAXVALUE) TABLESPACE pg_default + ) + ENABLE ROW MOVEMENT; + CREATE INDEX idx_range_a ON test_range_pt USING ubtree (a) LOCAL(PARTITION p1_a_idx, PARTITION p2_a_idx, PARTITION p3_a_idx, PARTITION p4_a_idx, PARTITION p5_a_idx) WITH (storage_type=USTORE) TABLESPACE pg_default; (1 row) pg_stat_get_partition_tuples_hot_updated返回给定分区id的分区热更新元组数的统计。 在分区p1中插入10条数据并更新,统计分区p1的热更新元组数。 INSERT INTO test_range_pt VALUES(generate_series(1,10),1,1); INSERT 0 10 SELECT pg_stat_get_partition_tuples_hot_updated(49294); pg_stat_get_partition_tuples_hot_updated ------------------------------------------ 0 (1 row) UPDATE test_range_pt SET b = 2; UPDATE 10 SELECT pg_stat_get_partition_tuples_hot_updated(49294); pg_stat_get_partition_tuples_hot_updated ------------------------------------------ 10 (1 row)
  • 分区自动扩展 分区的自动扩展功能是分区表的一种能力增强。当DML业务(INSERT、UPDATE、UPSERT、MERGE INTO、COPY)新增数据无法匹配到已有的任一分区时,会自动创建一个新的分区。此外,以partition/subpartition for partition_value的方式创建分类索引时,若指定的分区不存在,也会自动创建一个新的分区。当前支持范围分区自动扩展和列表分区自动扩展。 范围分区自动扩展 列表分区自动扩展 开启/关闭分区自动扩展 自动扩展分区的创建策略 父主题: 分区表
  • 索引重建/不可用 使用ALTER INDEX可以设置索引是否可用。 例如,假设分区表range_ sales上存在索引range_sales_idx,可以通过如下命令设置其不可用。 ALTER INDEX range_sales_idx UNUSABLE; 可以通过如下命令重建索引range_sales_idx。 ALTER INDEX range_sales_idx REBUILD; 父主题: 分区表索引重建/不可用
  • 一级分区表自动扩展 开启列表分区的自动扩展功能,需要在创建一级列表分区表时指定AUTOMATIC关键字。一级列表分区表自动扩展支持多列分区键。 例如,创建一个支持自动扩展的列表分区表。 gaussdb=# CREATE TABLE auto_list (c1 int, c2 int) PARTITION BY LIST (c1) AUTOMATIC ( PARTITION p1 VALUES (1, 2, 3), PARTITION p2 VALUES (4, 5, 6) ); 当插入数据无法匹配到已有的任意分区时,会自动创建一个新的分区,新分区的范围定义为单key。 --分区键插入数据9,自动创建分区sys_p1,分区定义为VALUES (9) gaussdb=# INSERT INTO auto_list VALUES (9, 0); 这一功能与如下命令等价: ALTER TABLE auto_list ADD PARTITION sys_p1 VALUES (9); INSERT INTO auto_list VALUES (9, 0); gaussdb=# DROP TABLE auto_list; 父主题: 列表分区自动扩展
  • 自动扩展分区的创建策略 分区自动扩展是一个自动提交的过程,当DML插入的数据无法匹配到已有的任意分区或创建分类索引指定的分区不存在时,会触发自治事务执行分区自动扩展。这一过程会对分区表施加短暂的锁定,与其他分区DDL命令相互阻塞。阻塞周期极为短暂,对系统运行或用户操作基本无影响。 分区自动扩展的行为表现如下: 通过DML业务自动扩展的分区不支持回滚,即当前事务回滚后,新建的分区依然存在。可以通过查询系统表PG_PARTITION查看新建的分区。 通过创建分类索引触发自动扩展分区时,若创建索引事务异常回滚,新建的分区可能存在(异常回滚点在触发自动扩展分区之后),也可能不存在(异常回滚点在触发自动扩展分区之前)。可以通过查询系统表PG_PARTITION查看新建的分区。 分区自动扩展与常规分区DQL/DML业务互不阻塞,支持这两类业务的并发。 分区自动扩展过程会短暂施加锁定,系统运行或用户操作基本无影响,支持多个线程因DML/分类索引业务同时触发分区自动扩展场景的并发。 分区自动扩展过程与分区DDL互斥,若有其他线程执行分区DDL且未提交,如果当前线程DML/分类索引业务触发分区自动扩展,则会被阻塞;但若其他线程执行DML/分类索引业务触发分区自动扩展且未提交,则不会阻塞当前线程的分区DDL业务。 部分场景下分区自动扩展依然会在同事务内执行,即采用混合事务的方式,此时不支持逻辑解码。涉及场景如下: 同时触发新增分区或其他自治事务的总连接数超过最大连接数max_concurrent_autonomous_transactions,或max_concurrent_autonomous_transactions设置为0。 分区表/父分区本身由当前事务创建产生。 同事务内同时有对分区表的DDL操作,此时若采用自治事务会触发死锁,回退为混合事务新增分区的模式。 自动扩展分区可以通过以下两种方式创建: DML业务导致的新增数据,无法匹配到任意已有分区,此时会优先基于规则创建一个新的分区,再向新分区插入对应数据。 以PARTITION/SUBPARTITION FOR partition_value的方式创建分类索引,若指定的分区不存在,此时优先基于规则创建一个新的分区,再在新分区上创建分类索引。 父主题: 分区自动扩展
共100000条