华为云用户手册

  • 二级分区 二级分区(Sub Partition,也叫组合分区)是基本数据分区类型的组合,将表通过一种数据分布方法进行分区,然后使用第二种数据分布方式将每个分区进一步细分为子分区。给定分区的所有子分区表示数据的逻辑子集。常见的二级分区组合如下所示: Range-Range Range-List Range-Hash List-Range List-List List-Hash Hash-Range Hash-List Hash-Hash 示例如下: gaussdb=# --Range-Range CREATE TABLE t_range_range ( c1 INT, c2 INT, c3 INT ) PARTITION BY RANGE (c1) SUBPARTITION BY RANGE (c2) ( PARTITION p1 VALUES LESS THAN (10) ( SUBPARTITION p1sp1 VALUES LESS THAN (5), SUBPARTITION p1sp2 VALUES LESS THAN (10) ), PARTITION p2 VALUES LESS THAN (20) ( SUBPARTITION p2sp1 VALUES LESS THAN (15), SUBPARTITION p2sp2 VALUES LESS THAN (20) ) ); DROP TABLE t_range_range; --Range-List CREATE TABLE t_range_list ( c1 INT, c2 INT, c3 INT ) PARTITION BY RANGE (c1) SUBPARTITION BY LIST (c2) ( PARTITION p1 VALUES LESS THAN (10) ( SUBPARTITION p1sp1 VALUES (1, 2), SUBPARTITION p1sp2 VALUES (3, 4) ), PARTITION p2 VALUES LESS THAN (20) ( SUBPARTITION p2sp1 VALUES (1, 2), SUBPARTITION p2sp2 VALUES (3, 4) ) ); DROP TABLE t_range_list; --Range-Hash CREATE TABLE t_range_hash ( c1 INT, c2 INT, c3 INT ) PARTITION BY RANGE (c1) SUBPARTITION BY HASH (c2) SUBPARTITIONS 2 ( PARTITION p1 VALUES LESS THAN (10), PARTITION p2 VALUES LESS THAN (20) ); DROP TABLE t_range_hash; --List-Range CREATE TABLE t_list_range ( c1 INT, c2 INT, c3 INT ) PARTITION BY LIST (c1) SUBPARTITION BY RANGE (c2) ( PARTITION p1 VALUES (1, 2) ( SUBPARTITION p1sp1 VALUES LESS THAN (5), SUBPARTITION p1sp2 VALUES LESS THAN (10) ), PARTITION p2 VALUES (3, 4) ( SUBPARTITION p2sp1 VALUES LESS THAN (5), SUBPARTITION p2sp2 VALUES LESS THAN (10) ) ); DROP TABLE t_list_range; --List-List CREATE TABLE t_list_list ( c1 INT, c2 INT, c3 INT ) PARTITION BY LIST (c1) SUBPARTITION BY LIST (c2) ( PARTITION p1 VALUES (1, 2) ( SUBPARTITION p1sp1 VALUES (1, 2), SUBPARTITION p1sp2 VALUES (3, 4) ), PARTITION p2 VALUES (3, 4) ( SUBPARTITION p2sp1 VALUES (1, 2), SUBPARTITION p2sp2 VALUES (3, 4) ) ); DROP TABLE t_list_list; --List-Hash CREATE TABLE t_list_hash ( c1 INT, c2 INT, c3 INT ) PARTITION BY LIST (c1) SUBPARTITION BY HASH (c2) SUBPARTITIONS 2 ( PARTITION p1 VALUES (1, 2), PARTITION p2 VALUES (3, 4) ); DROP TABLE t_list_hash; --Hash-Range CREATE TABLE t_hash_range ( c1 INT, c2 INT, c3 INT ) PARTITION BY HASH (c1) PARTITIONS 2 SUBPARTITION BY RANGE (c2) ( PARTITION p1 ( SUBPARTITION p1sp1 VALUES LESS THAN (5), SUBPARTITION p1sp2 VALUES LESS THAN (10) ), PARTITION p2 ( SUBPARTITION p2sp1 VALUES LESS THAN (5), SUBPARTITION p2sp2 VALUES LESS THAN (10) ) ); DROP TABLE t_hash_range; --Hash-List CREATE TABLE t_hash_list ( c1 INT, c2 INT, c3 INT ) PARTITION BY HASH (c1) PARTITIONS 2 SUBPARTITION BY LIST (c2) ( PARTITION p1 ( SUBPARTITION p1sp1 VALUES (1, 2), SUBPARTITION p1sp2 VALUES (3, 4) ), PARTITION p2 ( SUBPARTITION p2sp1 VALUES (1, 2), SUBPARTITION p2sp2 VALUES (3, 4) ) ); DROP TABLE t_hash_list; --Hash-Hash CREATE TABLE t_hash_hash ( c1 INT, c2 INT, c3 INT ) PARTITION BY HASH (c1) PARTITIONS 2 SUBPARTITION BY HASH (c2) SUBPARTITIONS 2 ( PARTITION p1, PARTITION p2 ); DROP TABLE t_hash_hash; -- list-list CREATE TABLE list_list ( month_code VARCHAR2 ( 30 ) NOT NULL , dept_code VARCHAR2 ( 30 ) NOT NULL , user_no VARCHAR2 ( 30 ) NOT NULL , sales_amt int ) PARTITION BY LIST (month_code) SUBPARTITION BY LIST (dept_code, user_no) ( PARTITION p_201901 VALUES ( '201902' ), PARTITION p_201902 VALUES ( '201903' ) ( SUBPARTITION p_201902_a VALUES (('1','120')), SUBPARTITION p_201902_b VALUES (('2','240')) ) ); SELECT * FROM pg_get_tabledef('list_list'); INSERT INTO list_list VALUES('201902', '1', '120', 1); INSERT INTO list_list VALUES('201902', '2', '240', 1); INSERT INTO list_list VALUES('201902', '1', '120', 1); INSERT INTO list_list VALUES('201903', '2', '240', 1); INSERT INTO list_list VALUES('201903', '1', '120', 1); INSERT INTO list_list VALUES('201903', '2', '240', 1); SELECT * FROM list_list ORDER BY month_code; DROP TABLE list_list; -- hash-range CREATE TABLE hash_range ( month_code VARCHAR2 ( 30 ) NOT NULL , dept_code VARCHAR2 ( 30 ) NOT NULL , user_no VARCHAR2 ( 30 ) NOT NULL , sales_amt int ) PARTITION BY hash (month_code) SUBPARTITION BY range (dept_code,user_no) ( PARTITION p_201901, PARTITION p_201902 ( SUBPARTITION p_201902_a VALUES LESS THAN ( '2' ,'2'), SUBPARTITION p_201902_b VALUES LESS THAN ( '3' ,'4') ) ); INSERT INTO hash_range VALUES('201901', '1', '1', 1); INSERT INTO hash_range VALUES('201901', '2', '1', 1); INSERT INTO hash_range VALUES('201901', '1', '1', 1); INSERT INTO hash_range VALUES('201903', '2', '1', 1); INSERT INTO hash_range VALUES('201903', '1', '1', 1); INSERT INTO hash_range VALUES('201903', '2', '1', 1); SELECT * FROM hash_range; DROP TABLE hash_range; Interval分区看成是范围分区的一种特殊形式,目前不支持二级分区场景中定义Interval分区。 父主题: 分区策略
  • 间隔分区 间隔分区(Interval Partition)可以看成是范围分区的一种增强和扩展方式,相比之下间隔分区定义分区时无需为新增的每个分区指定上限和下限值,只需要确定每个分区的长度,实际插入的过程中会自动进行分区的创建和扩展。间隔分区在创建初始时必须至少指定一个范围分区,范围分区键值确定范围分区的高值称为转换点,数据库为值超出该转换点的数据自动创建间隔分区。每个区间分区的下边界是先前范围或区间分区的非包容性上边界。示例如下: gaussdb=# CREATE TABLE interval_sales ( prod_id NUMBER(6), cust_id NUMBER, time_id DATE, channel_id CHAR(1), promo_id NUMBER(6), quantity_sold NUMBER(3), amount_sold NUMBER(10, 2) ) PARTITION BY RANGE (time_id) INTERVAL ('1 month') ( PARTITION date_2015 VALUES LESS THAN ('2016-01-01'), PARTITION date_2016 VALUES LESS THAN ('2017-01-01'), PARTITION date_2017 VALUES LESS THAN ('2018-01-01'), PARTITION date_2018 VALUES LESS THAN ('2019-01-01'), PARTITION date_2019 VALUES LESS THAN ('2020-01-01') ); gaussdb=# DROP TABLE interval_sales; 上述例子中,初始创建分区以2015年到2019年以年为单位创建分区,当数据插入到2020-01-01以后的数据时,由于超过的预先定义Range分区的上边界,会自动创建一个分区。 间隔分区仅支持数值类型和日期/时间类型,不支持字符类型和其他类型。支持类型白名单如下: INT1/UINT1、INT2/UINT2、INT4/UINT4、INT8/UINT8、FLOAT4、FLOAT8、NUMERIC、DATE、TIMESTAMP、TIMESTAMP WITH TIME ZONE。 父主题: 分区策略
  • 特性规格 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表压缩
  • 示例 创建分区表并插入数据 gaussdb=# CREATE TABLE t1_range_int ( c1 INT, c2 INT, c3 INT, c4 INT ) PARTITION BY RANGE(c1) ( PARTITION range_p00 VALUES LESS THAN(10), PARTITION range_p01 VALUES LESS THAN(20), PARTITION range_p02 VALUES LESS THAN(30), PARTITION range_p03 VALUES LESS THAN(40), PARTITION range_p04 VALUES LESS THAN(50) ); gaussdb=# INSERT INTO t1_range_int SELECT v,v,v,v FROM generate_series(0, 49) AS v; 级联收集统计信息 gaussdb=# ANALYZE t1_range_int WITH ALL; 查看分区级统计信息 gaussdb=# SELECT relname, parttype, relpages, reltuples FROM pg_partition WHERE parentid=(SELECT oid FROM pg_class WHERE relname='t1_range_int') ORDER BY relname; relname | parttype | relpages | reltuples --------------+----------+----------+----------- range_p00 | p | 1 | 10 range_p01 | p | 1 | 10 range_p02 | p | 1 | 10 range_p03 | p | 1 | 10 range_p04 | p | 1 | 10 t1_range_int | r | 0 | 0 (6 rows) gaussdb=# SELECT schemaname,tablename,partitionname,subpartitionname,attname,inherited,null_frac,avg_width,n_distinct,n_dndistinct,most_common_vals,most_common_freqs,histogram_bounds FROM pg_stats WHERE tablename='t1_range_int' ORDER BY tablename, partitionname, attname; schemaname | tablename | partitionname | subpartitionname | attname | inherited | null_frac | avg_width | n_distinct | n_dndistinct | most_common_vals | most_common_freqs | histogram_bounds ------------+--------------+---------------+------------------+---------+-----------+-----------+-----------+------------+--------------+------------------+-------------------+---------------------------------------------------------------------------------------------- ------------------------------------------------- public | t1_range_int | range_p00 | | c1 | f | 0 | 4 | -1 | 0 | | | {0,1,2,3,4,5,6,7,8,9} public | t1_range_int | range_p00 | | c2 | f | 0 | 4 | -1 | 0 | | | {0,1,2,3,4,5,6,7,8,9} public | t1_range_int | range_p00 | | c3 | f | 0 | 4 | -1 | 0 | | | {0,1,2,3,4,5,6,7,8,9} public | t1_range_int | range_p00 | | c4 | f | 0 | 4 | -1 | 0 | | | {0,1,2,3,4,5,6,7,8,9} public | t1_range_int | range_p01 | | c1 | f | 0 | 4 | -1 | 0 | | | {10,11,12,13,14,15,16,17,18,19} public | t1_range_int | range_p01 | | c2 | f | 0 | 4 | -1 | 0 | | | {10,11,12,13,14,15,16,17,18,19} public | t1_range_int | range_p01 | | c3 | f | 0 | 4 | -1 | 0 | | | {10,11,12,13,14,15,16,17,18,19} public | t1_range_int | range_p01 | | c4 | f | 0 | 4 | -1 | 0 | | | {10,11,12,13,14,15,16,17,18,19} public | t1_range_int | range_p02 | | c1 | f | 0 | 4 | -1 | 0 | | | {20,21,22,23,24,25,26,27,28,29} public | t1_range_int | range_p02 | | c2 | f | 0 | 4 | -1 | 0 | | | {20,21,22,23,24,25,26,27,28,29} public | t1_range_int | range_p02 | | c3 | f | 0 | 4 | -1 | 0 | | | {20,21,22,23,24,25,26,27,28,29} public | t1_range_int | range_p02 | | c4 | f | 0 | 4 | -1 | 0 | | | {20,21,22,23,24,25,26,27,28,29} public | t1_range_int | range_p03 | | c1 | f | 0 | 4 | -1 | 0 | | | {30,31,32,33,34,35,36,37,38,39} public | t1_range_int | range_p03 | | c2 | f | 0 | 4 | -1 | 0 | | | {30,31,32,33,34,35,36,37,38,39} public | t1_range_int | range_p03 | | c3 | f | 0 | 4 | -1 | 0 | | | {30,31,32,33,34,35,36,37,38,39} public | t1_range_int | range_p03 | | c4 | f | 0 | 4 | -1 | 0 | | | {30,31,32,33,34,35,36,37,38,39} public | t1_range_int | range_p04 | | c1 | f | 0 | 4 | -1 | 0 | | | {40,41,42,43,44,45,46,47,48,49} public | t1_range_int | range_p04 | | c2 | f | 0 | 4 | -1 | 0 | | | {40,41,42,43,44,45,46,47,48,49} public | t1_range_int | range_p04 | | c3 | f | 0 | 4 | -1 | 0 | | | {40,41,42,43,44,45,46,47,48,49} public | t1_range_int | range_p04 | | c4 | f | 0 | 4 | -1 | 0 | | | {40,41,42,43,44,45,46,47,48,49} public | t1_range_int | | | c1 | f | 0 | 4 | -1 | 0 | | | {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33, 34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49} public | t1_range_int | | | c2 | f | 0 | 4 | -1 | 0 | | | {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33, 34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49} public | t1_range_int | | | c3 | f | 0 | 4 | -1 | 0 | | | {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33, 34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49} public | t1_range_int | | | c4 | f | 0 | 4 | -1 | 0 | | | {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33, 34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49} (24 rows) 生成多列数据的分区级统计信息 gaussdb=# ALTER TABLE t1_range_int ADD STATIS TICS ((c2, c3)); gaussdb=# ANALYZE t1_range_int WITH ALL; 查看多列数据的分区级统计信息 gaussdb=# SELECT schemaname,tablename,partitionname,subpartitionname,attname,inherited,null_frac,avg_width,n_distinct,n_dndistinct,most_common_vals,most_common_freqs,histogram_bounds FROM pg_ext_stats WHERE tablename='t1_range_int' ORDER BY tablename,partitionname,attname; schemaname | tablename | partitionname | subpartitionname | attname | inherited | null_frac | avg_width | n_distinct | n_dndistinct | most_common_vals | most_common_freqs | histogram_bounds ------------+--------------+---------------+------------------+---------+-----------+-----------+-----------+------------+--------------+------------------+-------------------+------------------ public | t1_range_int | range_p00 | | 2 3 | f | 0 | 8 | -1 | 0 | | | public | t1_range_int | range_p01 | | 2 3 | f | 0 | 8 | -1 | 0 | | | public | t1_range_int | range_p02 | | 2 3 | f | 0 | 8 | -1 | 0 | | | public | t1_range_int | range_p03 | | 2 3 | f | 0 | 8 | -1 | 0 | | | public | t1_range_int | range_p04 | | 2 3 | f | 0 | 8 | -1 | 0 | | | public | t1_range_int | | | 2 3 | f | 0 | 8 | -1 | 0 | | | (6 rows) 创建表达式索引并生成对应的分区级统计信息 gaussdb=# CREATE INDEX t1_range_int_index ON t1_range_int(text(c1)) LOCAL; gaussdb=# ANALYZE t1_range_int WITH ALL; 查看表达式索引的分区级统计信息 gaussdb=# SELECT schemaname,tablename,partitionname,subpartitionname,attname,inherited,null_frac,avg_width,n_distinct,n_dndistinct,most_common_vals,most_common_freqs,histogram_bounds FROM pg_stats WHERE tablename='t1_range_int_index' ORDER BY tablename,partitionname,attname; schemaname | tablename | partitionname | subpartitionname | attname | inherited | null_frac | avg_width | n_distinct | n_dndistinct | most_common_vals | most_common_freqs | histogram_bounds ------------+--------------------+--------------------+------------------+---------+-----------+-----------+-----------+------------+--------------+------------------+-------------------+----------------------------------------------------------------------------------- ------------------------------------------------------------ public | t1_range_int_index | range_p00_text_idx | | text | f | 0 | 5 | -1 | 0 | | | {0,1,2,3,4,5,6,7,8,9} public | t1_range_int_index | range_p01_text_idx | | text | f | 0 | 6 | -1 | 0 | | | {10,11,12,13,14,15,16,17,18,19} public | t1_range_int_index | range_p02_text_idx | | text | f | 0 | 6 | -1 | 0 | | | {20,21,22,23,24,25,26,27,28,29} public | t1_range_int_index | range_p03_text_idx | | text | f | 0 | 6 | -1 | 0 | | | {30,31,32,33,34,35,36,37,38,39} public | t1_range_int_index | range_p04_text_idx | | text | f | 0 | 6 | -1 | 0 | | | {40,41,42,43,44,45,46,47,48,49} public | t1_range_int_index | | | text | f | 0 | 5 | -1 | 0 | | | {0,1,10,11,12,13,14,15,16,17,18,19,2,20,21,22,23,24,25,26,27,28,29,3,30,31,32,33,3 4,35,36,37,38,39,4,40,41,42,43,44,45,46,47,48,49,5,6,7,8,9} (6 rows) 删除分区表 gaussdb=# DROP TABLE t1_range_int;
  • 分区表行迁移 用户可以使用ALTER TABLE ENABLE/DISABLE ROW MOVEMENT来开启/关闭分区表行迁移。 开启行迁移时,允许通过更新操作将一个分区中的数据迁移到另一个分区中;关闭行迁移时,如果出现这种更新行为,则业务报错。 如果业务明确不允许对分区键所在列进行更新操作,建议关闭分区表行迁移。 例如,创建列表分区表,并开启分区表行迁移,此时可以跨分区更新分区键所在列;关闭分区表行迁移后,对分区键所在列进行跨分区更新会业务报错。 CREATE TABLE list_sales ( product_id INT4 NOT NULL, customer_id INT4 PRIMARY KEY, time_id DATE, channel_id CHAR(1), type_id INT4, quantity_sold NUMERIC(3), amount_sold NUMERIC(10,2) ) PARTITION BY LIST (channel_id) ( PARTITION channel1 VALUES ('0', '1', '2'), PARTITION channel2 VALUES ('3', '4', '5'), PARTITION channel3 VALUES ('6', '7'), PARTITION channel4 VALUES ('8', '9') ) ENABLE ROW MOVEMENT; INSERT INTO list_sales VALUES (153241,65143129,'2021-05-07','0',864134,89,34); --跨分区更新成功,数据从分区channel1迁移到分区channel2 UPDATE list_sales SET channel_id = '3' WHERE channel_id = '0'; --关闭分区表行迁移 ALTER TABLE list_sales DISABLE ROW MOVEMENT; --跨分区更新失败,报错fail to update partitioned table "list_sales" UPDATE list_sales SET channel_id = '0' WHERE channel_id = '3'; --分区内更新依然成功 UPDATE list_sales SET channel_id = '4' WHERE channel_id = '3'; 父主题: 分区表运维管理
  • 语法 {[ ONLY ] table_name [ * ] [ partition_clause ] [ [ AS ] alias [ ( column_alias [, ...] ) ] ] [ TABLESAMPLE sampling_method ( argument [, ...] ) [ REPEATABLE ( seed ) ] ] [TIMECAPSULE { TIMESTAMP | CS N } 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); 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
  • 对二级分区表移动二级分区 使用ALTER TABLE MOVE SUBPARTITION可以对二级分区表移动二级分区。 例如,通过指定分区名将二级分区表range_list_sales的分区date_202001_channel1移动到表空间tb1中。 ALTER TABLE range_list_sales MOVE SUBPARTITION date_202001_channel1 TABLESPACE tb1; 或者,通过指定分区值将二级分区表range_list_sales中('2020-01-08', '0')所对应的分区移动到表空间tb1中。 ALTER TABLE range_list_sales MOVE SUBPARTITION FOR ('2020-01-08', '0') TABLESPACE tb1; 父主题: 移动分区
  • 注意事项及约束条件 GUC参数partition_iterator_elimination开启后,且优化器剪枝结果只有一个分区时,目标场景优化才能生效。 支持cplan,支持部分gplan场景,如分区键a = $1(即优化器阶段可以剪枝到一个分区的场景)。 支持SeqScan、Indexscan、Indexonlyscan、Bitmapscan、RowToVec、Tidscan算子。 支持行存,astore/ustore存储引擎,支持SQLBypass。
  • 场景描述 在当前分区表架构中,执行器通过Partition Iterator算子去迭代访问每一个分区。当分区剪枝结果只有一个分区时,Partition Iterator算子已经失去了迭代器的作用,在此情况下消除Partition Iterator算子,可以避免执行时一些不必要的开销。由于执行器的PIPELINE架构,Partition Iterator算子会重复执行,在数据量较大的场景下消除Partition Iterator算子的收益十分可观。
  • 对二级分区表合并二级分区 使用ALTER TABLE MERGE SUBPARTITIONS可以将多个二级分区合并为一个分区。 例如,将二级分区表hash_list_sales的分区product1_channel1、product1_channel2、product1_channel3合并为一个新的分区,并更新Global索引。 ALTER TABLE hash_list_sales MERGE SUBPARTITIONS product1_channel1, product1_channel2, product1_channel3 INTO SUBPARTITION product1_channel1 UPDATE GLOBAL INDEX; 父主题: 合并分区
  • 前向兼容 在上文中,支持通过key_info设置访问外部密钥管理的参数: 使用gsql时,通过元命令\key_info xxx设置。 使用JDBC时,通过连接参数conn.setProperty(“key_info”, “xxx”)设置 为保持前向兼容,还支持通过环境变量等方式设置访问主密钥的参数。 第一次配置使用密态数据库时,可忽略下述方法。如果以前使用下述方法配置密态数据库,建议改用’key_info’配置 使用系统级环境变量配置的方式如下: export HUAWEI_KMS_INFO='iamUrl=https://iam.{项目}.myhuaweicloud.com/v3/auth/tokens,iamUser={ IAM 用户名},iamPassword={IAM用户密码},iamDomain={账号名},kmsProject={项目}' # 该方法中操作系统日志可能会记录环境变量中的敏感信息,使用过程中注意及时清理。 还可通过标准库接口设置进程级环境变量,不同语言设置方法如下: C/C++ setenv("HIS_KMS_INFO", "xxx"); GO os.Setenv("HIS_KMS_INFO", "xxx");
  • 外部密钥服务的身份验证 当数据库驱动访问华为云密钥管理服务时,为避免攻击者伪装为密钥服务,在数据库驱动与密钥服务建立https连接的过程中,可通过CA证书验证密钥服务器的合法性。为此,需提前配置CA证书,如果未配置,将不会验证密钥服务的身份。本节介绍如何下载与配置CA证书。 配置方法 在key_info参数的中,增加证书相关参数即可。 使用gsql时 gaussdb=# \key_info keyType=huawei_kms,iamUrl=https://iam.example.com/v3/auth/tokens,iamUser={IAM用户名},iamPassword={IAM用户密码},iamDomain={账号名},kmsProject={项目},iamCaCert=/路径/IAM的CA证书文件,kmsCaCert=/路径/KMS的CA证书文件 gaussdb=# \key_info keyType=huawei_kms,kmsProjectId={项目ID},ak={AK},sk={SK},kmsCaCert=/路径/KMS的CA证书文件 使用JDBC时 conn.setProperty("key_info", "keyType=huawei_kms," + "iamUrl=https://iam.example.com/v3/auth/tokens," + "iamUser={IAM用户名}," + "iamPassword={IAM用户密码}," + "iamDomain={账号名}," + "kmsProject={项目}," + "iamCaCert=/路径/IAM的CA证书文件," + "kmsCaCert=/路径/KMS的CA证书文件"); conn.setProperty("key_info", "keyType=huawei_kms, kmsProjectId={项目ID}, ak={AK}, sk={SK}, kmsCaCert=/路径/KMS的CA证书文件"); 获取证书 大部分浏览器均会自动下载网站对应的CA证书,并提供证书导出功能。虽然,诸如https://www.ssleye.com/ssltool/certs_down.html等很多网站也提供自动下载CA证书的功能,但可能因本地环境中存在代理或网关,导致CA证书无法正常使用。所以,建议借助浏览器下载CA证书。下载方式如下: 由于使用restful接口访问密钥服务,当在浏览器输入接口对应的url时,可忽略下述2中的失败页面,因为即使在失败的情况下,浏览器也早已提前自动下载CA证书。 输入 域名 :打开浏览器,在华为云场景中,分别输入IAM服务器地址和KMS服务器地址,地址获取方式参见:生成主密钥阶段。 查找证书:在每次输入域名后,找到SSL连接相关信息,单击后会发现证书,继续单击可查看证书内容。 导出证书:在证书查看页面,可能会看到证书分为很多级,仅需要域名的上一级证书即可,选择该证书并单击导出,便可直接生成证书文件,即需要的证书文件。 上传证书:将导出的证书上传至应用端,并配置到上述参数中即可。
  • 通用数据库服务层 从技术角度来看,存储引擎需要一些基础架构组件,主要包括: 并发:不同存储引擎选择正确的锁可以减少开销,从而提高整体性能。此外提供多版本并发控制或“快照”读取等功能。 事务:均需满足ACID的要求,提供事务状态查询等功能。 内存缓存:不同存储引擎在访问索引和数据时一般会对其进行缓存。缓存池允许直接从内存中处理经常使用的数据,从而加快了处理速度。 检查点:不同存储引擎一般都支持增量checkpoint/double write或全量checkpoint/full page write模式。应用可以根据不同条件进行选择增量或者全量,这个对存储引擎是透明的。 日志: GaussDB 采用的是物理日志,其写入/传输/回放对存储引擎透明。 父主题: 存储引擎体系架构概述
  • 分区剪枝 分区剪枝是GaussDB提供的一种分区表查询优化技术,数据库SQL引擎会根据查询条件,只扫描特定的部分分区。分区剪枝是自动触发的,当分区表查询条件符合剪枝场景时,会自动触发分区剪枝。根据剪枝阶段的不同,分区剪枝分为静态剪枝和动态剪枝,静态剪枝在优化器阶段进行,在生成计划之前,数据库已经知道需要访问的分区信息;动态剪枝在执行器阶段进行(执行开始/执行过程中),在生成计划时,数据库并不知道需要访问的分区信息,只是判断“可以进行分区剪枝”,具体的剪枝信息由执行器决定。 只有分区表页面扫描和Local索引扫描才会触发分区剪枝,Global索引没有分区的概念,不需要进行剪枝。 分区表静态剪枝 分区表动态剪枝 父主题: 分区表查询优化
  • 对*-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分区范围。 父主题: 分割分区
  • 向列表分区表新增分区 使用ALTER TABLE ADD PARTITION可以在列表分区表中新增分区,新增分区的枚举值不能与已有的任一个分区的枚举值重复。 例如,对列表分区表list_sales新增一个分区。 ALTER TABLE list_sales ADD PARTITION channel5 VALUES ('X') TABLESPACE tb1; 当列表分区表有DEFAULT分区时,无法新增分区。可以使用ALTER TABLE SPLIT PARTITION命令分割分区。 父主题: 新增分区
  • RCR UBTree多版本管理 RCR(Row Consistency Read) UBtree的多版本管理是基于数据行的行级多版本管理,将XID记录在了数据行上,会增加Key的大小,索引会有5-20%左右的膨胀。最新版本和历史版本均在btree上,索引没有记录Undo信息。插入或者删除key时按照key + TID的顺序排列,索引列相同的元组按照对应元组的TID作为第二关键字进行排序。会将xmin、xmax追加到key的后面。索引分裂时,多版本信息随着key的迁移而迁移,如图1所示。 图1 RCR UBTree多版本管理
  • RCR UBTree空间管理 当前Astore的索引依赖AutoVacuum和Free Space Map(FSM)进行空间管理,存在回收不及时的问题。而Ustore的索引使用其特有的URQ(UBTree Recycle Queue,一种基于循环队列的数据结构,即双循环队列),对索引空闲空间进行管理。双循环队列是指有两个循环队列,一个潜在空页队列,另一个可用空页队列,在DML过程中完成索引的空间管理,能有效地缓解DML过程中造成的空间急剧膨胀问题。索引回收队列单独储存在BTree索引对应的FSM文件中。 图5 索引页面在双循环队列间流动 如图5所示,索引页面在双循环队列间流动如下: 索引空页流动到潜在队列 索引页尾字段中记录了页面上活跃元组个数(activeTupleCount),在DML过程中,删空一个页面的所有元组,即activeTupleCount为零时会将索引页放入潜在队列中。 潜在队列流动到可用队列 潜在队列到可用队列的转化主要是达到一个潜在队列收支平衡以及可用队列在拿页时有页可拿的目的,即当从可用队列拿出一个索引空页用完后,建议从潜在队列转化至少一个索引页面到可用队列中,以及每当潜在队列新加入一个索引页面时,能从潜在队列中移除至少一个索引页插入可用队列中,达到潜在队列的收支平衡,以及可用队列有页可用的目的。 可用队列流动到索引空页 索引在分裂等获取一个索引空页面时,会先从可用队列中进行查找是否有可以复用的索引页。如果找到则直接进行复用,没有可复用页面则进行物理扩页。
  • RCR UBTree增删改查 Insert操作:UBTree的插入逻辑基本不变,只需增加索引插入时直接获取事务信息填写xmin字段。 Delete操作:UBTree额外增加了索引删除流程,索引删除主要步骤与插入相似,获取事务信息填写xmax字段(BTree索引不维护版本信息,不需要删除操作),同时更新页面上的active_tuple_count,若active_tuple_count被减为0,则尝试页面回收。 Update操作:对于Ustore而言,数据更新对UBTree索引列的操作也与Astore有所不同,数据更新包含两种情况:索引列和非索引列更新,UBTree在数据发生更新时的处理如图3所示。 图3 UBTree在数据发生更新时的处理 图3展示UBTree在索引列和非索引列更新的差异: 在非索引列更新的情况下,索引不发生任何变化。index tuple仍指向第一次插入的data tuple,Uheap不会插入新的data tuple,而是修改当下data tuple并将历史数据存入Undo中。 在索引列更新的情况下,UBTree也会插入新的index tuple,但是会指向同一个data linepointer和同一个data tuple,扫描旧版本的数据则需要从Undo中读取。 Scan操作:用户在读取数据时,可通过使用索引扫描加速。UBTree支持索引数据的多版本管理及可见性检查,索引层的可见性检查使得索引扫描(Index Scan)及仅索引扫描(IndexOnly Scan)性能有所提升。 对于索引扫描: 若索引列包含所有扫描列(IndexOnly Scan),则通过扫描条件在索引上进行二分查找,找到符合条件元组即可返回数据。 若索引列不包含所有扫描列(Index Scan),则通过扫描条件在索引上进行二分查找,找到符合条件元组的TID,再通过TID到数据表上查找对应的数据元组。如图4所示。 图4 对应的数据元组
  • 事务提交 针对隐式事务和显式事务,其提交策略如下所示: 隐式事务。单条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事务模型
  • 常用视图工具 视图类型 类型 功能描述 使用场景 函数名称 解析 全类型 用于解析指定表页面,并返回存放解析内容的路径。 查看页面信息。 查看元组(非用户数据)信息。 页面或者元组损坏。 元组可见性问题。 校验报错问题。 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存储引擎
  • 分区表对导入操作的性能影响 在GaussDB内核实现中,分区表数据插入的处理过程相比非分区表增加分区路由部分的开销,因从整体上分区表场景的数据插入开销主要看成:(1)heap-insert基表插入;(2)partition-routing分区路由两个部分,如图1所示。其中heap基表插入解决tuple入库对应heap表的问题并且该部分普通表和分区表共用,而分区路由部分解决分区路由即tuple元组插入到对应partRel的问题,并且分区路由算法本身作为一级、二级分区共用,不同之处在于二级分区相比一级分区多一层路由操作,对路由算法为两次调用。 图1 普通表&分区表数据插入 因此对数据插入优化的侧重点如下: 分区表基表Heap表插入: 算子底噪优化 heap数据插入 索引插入build优化(带索引) 分区表分区路由: 路由查找算法逻辑优化 路由底噪优化,包括分区表partRel句柄开启、新增的函数调用逻辑开销 分区路由的性能主要通过大数据量的单条INSERT语句体现,UPDATE场景内部包含了查找对应要更新的元组进行DELETE操作然后再进行INSERT,因此不如单条INSERT语句场景直接。 不同分区类型的路由算法逻辑如表1所示: 表1 路由算法逻辑 分区方式 路由算法复杂度 实现概述说明 范围分区(Range Partition) O(logN) 基于二分binary-search实现 间隔分区(Interval Partition) O(logN) 基于二分binary-search实现 哈希分区(Hash-Partition) O(1) 基于key-partOid哈希表实现 列表分区(List-Partition) O(1) 基于key-partOid哈希表实现 二级分区(List/List) O(1) + O(1) 哈希+哈希 二级分区(List/Range) O(1) + O(1) = O(1) 哈希+二分查找 二级分区(List/Hash) O(1) + O(1) = O(1) 哈希+哈希 二级分区(Range/List) O(1) + O(1) = O(1) 二分查找+哈希 二级分区(Range/Range) O(1) + O(1) = O(1) 二分查找+二分查找 二级分区(Range/Hash) O(1) + O(1) = O(1) 二分查找+哈希 二级分区(Hash/List) O(1) + O(1) = O(1) 哈希+哈希 二级分区(Hash/Range) O(1) + O(1) = O(1) 哈希+二分查找 二级分区(Hash/Hash) O(1) + O(1) = O(1) 哈希+哈希 分区路由的主要处理逻辑根据导入数据元组的分区键计算其所在分区的过程,相比非分区表这部分为额外增加的开销,这部分开销在最终数据导入上的具体性能损失和服务器CPU处理能力、表宽度、磁盘/内存的实际容量相关,通常可以粗略认为: x86服务器场景下一级分区表相比普通表的导入性能会略低10%以内,二级分区表比普通表略低20%以内。 ARM服务器场景下为20%、30%,造成x86和ARM指向性能略微差异的主要原因是分区路由为in-memory计算强化场景,主流x86体系CPU在单核指令处理能力上略优于ARM。 父主题: 分区策略
  • 开启/关闭二级列表分区自动扩展 使用ALTER TABLE SET SUBPARTITIONING可以开启/关闭二级列表分区自动扩展功能。 例如: 开启二级列表分区自动扩展。 gaussdb=# CREATE TABLE range_list (c1 int, c2 int) PARTITION BY RANGE (c1) SUBPARTITION BY LIST (c2) ( PARTITION p1 VALUES LESS THAN (5) ( SUBPARTITION sp11 VALUES (1, 2, 3), SUBPARTITION sp12 VALUES (4, 5, 6) ), PARTITION p2 VALUES LESS THAN (10) ( SUBPARTITION sp21 VALUES (1, 2, 3), SUBPARTITION sp22 VALUES (4, 5, 6) ) ); gaussdb=# ALTER TABLE range_list SET SUBPARTITIONING AUTOMATIC; 开启二级列表分区自动扩展要求二级分区中不能存在分区键值为DEFAULT的分区。 关闭二级列表分区自动扩展。 gaussdb=# ALTER TABLE range_list SET SUBPARTITIONING MANUAL; --清理示例 gaussdb=# DROP TABLE range_list; 父主题: 开启/关闭分区自动扩展
  • 分区表运维管理 分区表运维管理包括分区管理、分区表管理、分区索引管理和分区表业务并发支持等。 分区管理:也称分区级DDL,包括新增(Add)、删除(Drop)、交换(Exchange)、清空(Truncate)、分割(Split)、合并(Merge)、移动(Move)、重命名(Rename)共8种。 对于哈希分区,涉及分区数的变更会导致数据re-shuffling,故当前GaussDB不支持导致Hash分区数变更的操作,包括新增(Add)、删除(Drop)、分割(Split)、合并(Merge)这4种。 涉及分区数据变更的操作会使得Global索引失效,可以通过UPDATE GLOBAL INDEX子句来同步更新Global索引,包括删除(Drop)、交换(Exchange)、清空(Truncate)、分割(Split)、合并(Merge)这5种。 大部分分区DDL支持partition/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作用于不同分区时,支持二者执行层面的并发。 新增分区 删除分区 交换分区 清空分区 分割分区 合并分区 移动分区 重命名分区 分区表行迁移 分区表索引重建/不可用 父主题: 分区表
  • 对范围分区表分割分区 使用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分区范围。 父主题: 分割分区
  • 分区表介绍 分区表(Partitioned Table)指在单节点内对表数据内容按照分区键以及围绕分区键的分区策略对表进行逻辑切分。从数据分区的角度来看是一种水平分区(horizontal partition)策略方式。分区表增强了数据库应用程序的性能、可管理性和可用性,并有助于降低存储大量数据的总体拥有成本。分区允许将表、索引和索引组织的表细分为更小的部分,使这些数据库对象能够在更精细的粒度级别上进行管理和访问。GaussDB提供了丰富的分区策略和扩展,以满足不同业务场景的需求。由于分区策略的实现完全由数据库内部实现,对用户是完全透明的,因此它几乎可以在实施分区表优化策略以后做平滑迁移,无需潜在耗费人力物力的应用程序更改。本章围绕GaussDB分区表的基本概念从以下几个方面展开介绍: 分区表基本概念:从表分区的基本概念出发,介绍分区表的catalog存储方式以及内部对应原理。 分区策略:从分区表所支持的基本类型出发,介绍各种分区模式下对应的特性以及能够达到的优化特点和效果。 基本概念 分区策略 分区基本使用 父主题: 分区表
  • 对*-RANGE二级分区表分割二级分区 使用ALTER TABLE SPLIT SUBPARTITION可以对*-RANGE二级分区表分割二级分区。 例如,假设*-RANGE二级分区表list_range_sales的二级分区channel1_customer4的定义范围为[1000, MAXVALUE)。可以指定分割点1200将二级分区channel1_customer4分割为两个分区,并更新Global索引。 ALTER TABLE list_range_sales SPLIT SUBPARTITION channel1_customer4 AT (1200) INTO ( SUBPARTITION channel1_customer4_p1, --第一个分区上界是1200 SUBPARTITION channel1_customer4_p2 --第二个分区上界是MAXVALUE ) UPDATE GLOBAL INDEX; 或者,不指定分割点,将分区channel1_customer4分割为多个分区,并更新Global索引。 ALTER TABLE list_range_sales SPLIT SUBPARTITION channel1_customer4 INTO ( SUBPARTITION channel1_customer4_p1 VALUES LESS THAN (1200), SUBPARTITION channel1_customer4_p2 VALUES LESS THAN (1400), SUBPARTITION channel1_customer4_p3 --第三个分区上界是MAXVALUE )UPDATE GLOBAL INDEX; 又或者,通过指定分区值而不是指定分区名来分割分区。 ALTER TABLE range_sales SPLIT SUBPARTITION FOR ('1', 1200) AT (1200) INTO ( PARTITION channel1_customer4_p1, PARTITION channel1_customer4_p2 ) UPDATE GLOBAL INDEX; 若对MAXVALUE分区进行分割,前面几个分区不能申明MAXVALUE范围,最后一个分区会继承MAXVALUE分区范围。 父主题: 分割分区
  • 空间管理 Undo子系统依赖后台回收线程进行空闲空间回收,负责主机上Undo模块的空间回收,备机通过回放xLog进行回收。回收线程遍历使用中的undo zone,对该zone中的txn page扫描,依据xid从小到大的顺序进行遍历。回收已提交或者已回滚完成的事务,且该事务的提交时间应早于$(current_time-undo_retention_time)。对于遍历过程中需要回滚的事务,后台回收线程会为该事务添加异步回滚任务。 当数据库中存在运行时间长、修改数据量大的事务,或者开启闪回时间较长的时候,可能出现undo空间持续膨胀的情况。当undo占用空间接近undo_space_limit_size时,就会触发强制回收。只要事务已提交或者已回滚完成,即使事务提交时间晚于$(current_time-undo_retention_time),在这种情况下也可能被回收掉。 父主题: Undo
  • 使用示例 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 ---------- 79352065 (1 rows) --查询当前时间戳 gaussdb=# SELECT now(); now ------------------------------- 2023-09-13 19:46:34.102863+08 (1 row) 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 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 19:54:00.641506'; TimeCapsule Table gaussdb=# SELECT * FROM flashtest; col1 | col2 ------+------ (0 rows) gaussdb=# DROP TABLE IF EXISTS "public".flashtest; DROP TABLE
共100000条