1 课程目标
• 了解 GBase 8c 分布式版本高级语法涵义和使用方法,掌握并熟练使用。
• 存储引擎
• 分区表的各种组合 • 索引多样化
• 数据压缩
• 子事务
2 存储引擎
—2.1 目前支持
• USTORE,表示表支持Inplace-Update 存储引擎。
• ASTORE,表示表支持Append-Only 存储引擎。
—2.2 支持三种存储方法
• ROW,表示表的数据将以行式存储。
行存储适合于OLTP业务,适用于点查询或者增删操作比较多的场景。
• COLUMN,表示表的数据将以列式存储。
列存储适合于数据仓库业务,此类型的表上会做大量的汇聚计算,且涉及的列操作较少。
• MOT,表示表的数据将以内存的形式存储。
MOT 内存适用于高吞吐事务处理,性能瓶颈加速,消除中间层缓存,大规模流数据提取。
1:创建表时,指定 orientation 参数值为 row,创建行存表。
示例: create table test_astore_row(col text) with (orientation=row) ;
2:创建表时,指定 orientation 参数值为 column,创建列存表。
create table test_astore_column(col text) with (orientation=column);
3:创建表时,create foreign table ... server 为 mot_server时,创建内存表。
create foreign table test_astore_mot(col int) server mot_server ;
4:创建表时,指定 storage_type 参数值为 ustore,创建 ustore 表。
create table test_ustore(col text) with (storage_type=ustore);
当sql语句不做指定时,默认使用 astore 存储引擎,row 存储方法。
—2.3 示例
3 分区表
—3.1 介绍
GBase 8c 需要将数据按照一定规律分布到各个数据节点,目前支持 hash 分片。
在此基础上,分区表功能,支持二级分区,9种分区组合,interval 分区。即 分片+分区 功能。
—3.2 表分片
GBase 8c的数据分片策略:在创建表时,通过关键字distribute/replication 来设置表分片策略。
1:通过distribute by hash 创建 hash 分片表,将数据通过hash算法 均匀存储到每个数据节点。
CREATE TABLE t1_dis(c1 int, c2 int) DISTRIBUTE BY hash(c1);
2:通过distribute by replication 创建 复制表,每个数据节点都会存储一份数据。
CREATE TABLE t1_rep(c1 int, c2 int) DISTRIBUTE BY replication;
备注:在不指定时,默认使用hash分片,分布式键按照顺序为第一个满足hash算法的字段。
示例:
—3.3 hash 分片
hash 分片,hash 一级分区,hash-list,hash-hash,hash-range 二级分区
分区示例如下:
—3.4 range分区
hash 分片,range 一级分区,range-range,range-hash,range-list 二级分区。
分区示例如下:
—3.5 list分区
hash分片,list一级分区,list-list,list-range,list-hash 二级分区
分区示例如下:
—3.6 interval 分区
interval 分区:根据间隔自动创建分区,例如:1 day、1 month。(主备式)
CREATE TABLE 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 day')
( PARTITION p1 VALUES LESS THAN ('2019-02-01 00:00:00'),
PARTITION p2 VALUES LESS THAN ('2019-02-02 00:00:00')
);
—3.7 分区自动管理
分区自动管理:根据间隔自动创建分区,例如:1 day、1 month。(分布式)
语法:建表时增加 WITH, 或者通过 ALTER TABLE xxx SET (PERIOD='1 day')来实现。
(其中 PERIOD范围是 1 hour ~ 1 year)。通过ALTER TABLE xxx RESET (PERIOD)来关闭。
限制:仅支持RANGE分区的一级分区表 (其他分区类型,以及带有二级分区的表不支持)
效果:从当前命令时间(向下规约到hour)算起,连续增加能覆盖30个period时间范围 的分区,每个分区大小为period。如果现有分区在待新增的分区范围内,则跳过此新增分 区。且每隔period时间后再次执行此流程。
create table range_auto_1hour_tb01(id int,ip text,time timestamp)
with(PERIOD='1 hour') partition by range(time)( partition p1 values less than ('2022-11-23 14:00:00'));
示例:
4 索引类型
—4.1 介绍
GBase 8c 提供了多种索引类型:hash,B-tree,gist,gin。每一种索引类型使用了一种不同的算 法来适应不同类型的查询。
B-tree —— 适合所有的数据类型,支持排序,支持大于、小于、等于、大于或等于、小于或 等于的搜索。
hash —— 索引存储的是被索引字段VALUE的哈希值,只支持等值查询。
Gist(Generalized Search Tree) —— 即通用搜索树。可处理地理数据、图像,空间,树形图 等场景。
gin —— gin索引是“倒排索引”。应用领域是加速全文搜索。
默认情况下,create index 使用B-tree 索引并适合于大部分情况。
—4.2 B-tree 索引
btree索引常常用来进行例如大于、小于、等于这些操作。 通过语法:create index ... using btree(column) 。指定使用btree索引。
—4.3 gist 索引
地理数据、图像:如果我们想要查询在某个地方是否存在某一点,即判断地理位置的"包含“。
对于空间数据,GiST索引可以使用 R树,以支持相对位置运算符(位于左侧,右侧,包含等)。
对于树形图,R树可以支持相交或包含运算符。
通过语法:create index ... using gist(column) 。指定使用gist索引。
示例:
—4.4 gin 索引
当需要搜索多值类型内的VALUE时,适合多值类型,例如数组、全文检索、TOKEN。 (根据不同的类型,支持相交、包含、大于、在左边、在右边等搜索)。
通过语法:create index ... using gin(column) 。指定使用 gin 索引。
5 数据压缩
行存表 创建表时通过关键字 compresstype,可实现数据压缩,减少磁盘的占用。
create table test_row_compress(col text) with ( compresstype = 2, COMPRESS_LEVEL = 3);
◾ COMPRESSTYPE
行存表参数,设置行存表压缩算法。1代表pglz算法,2代表zstd算法,默认不压缩。(仅支持 ASTORE下的普通表)
取值范围:0~2,默认值为0。
◾ COMPRESS_LEVEL
行存表参数,设置行存表压缩算法等级,仅当COMPRESS_TYPE为2时生效。压缩等级越高,表 的压缩效果越好,表的访问速度越慢。(仅支持ASTORE下的普通表)
取值范围:-31~31,默认值为0。
示例:
列存表 创建表时通过关键字 compression,可实现数据压缩,减少磁盘的占用。
示例:create table test_compress(col text) with (orientation=column,compression=high);
◾ COMPRESSION:
指定表数据的压缩级别,它决定了表数据的压缩比以及压缩时间。一般来讲,压缩级别越高,压 缩比也越大,压缩时间也越长;反之亦然。实际压缩比取决于加载的表数据的分布特征。行存表 不支持压缩。
取值范围:
列存表的有效值为YES/NO/LOW/MIDDLE/HIGH,默认值为LOW。
示例:
6 子事务
子事务允许你回滚部分已经事务中完成的工作。可通过关键字 SAVEPOINT,EXCEPTION, Autonomous Transaction 启动子事务。
7 自治事务
自治事务(Autonomous Transaction),在主事务执行过程中新启的独立的事务。自治事 务的提交和回滚不会影响已提交的数据,同时 自治事务也不受主事务的影响。
自治事务在存储过程,函数和匿名块中定义, 用 PARAGMA AUTONOMOUS_TRANSACTION 关键字来 声明。
8 操作示例
/* ***************************************************** 以下命令为 linux 命令 ************************************************** */ --- su 命令切换到数据库用户 gbase,如果当前用户已为 gbase 用户,则忽略此条命令。 su - gbase --- linux 命令:在安装节点(即执行gha_ctl start/stop 所在的节点) 执行 gs_guc 命令 修改数据库参数 gs_guc reload -Z coordinator -N all -I all -c "enable_incremental_checkpoint=off" gs_guc reload -Z datanode -N all -I all -c "enable_incremental_checkpoint=off" gs_guc reload -Z gtm -N all -I all -c "enable_incremental_checkpoint=off" gs_guc reload -Z coordinator -N all -I all -c "enable_gbase_mot=on" gs_guc reload -Z datanode -N all -I all -c "enable_gbase_mot=on" gs_guc reload -Z gtm -N all -I all -c "enable_gbase_mot=on" --- linux 命令:重启数据库加载数据库参数 gha_ctl stop all -l http://192.168.1.2:2379 gha_ctl start all -l http://192.168.1.2:2379 --- linux 命令:gsql 使用默认端口 连接数据库 gsql -d postgres -r -p 15432 /* ****************************************************** 以下都为sql命令 ******************************************************* */ --- gsql 连接成功后,将以下 sql 逐条在gsql中执行,进行验证。(若使用dbeaver工具,dbeaver 连接成功后,复制粘贴以下sql 执行进行验证) ---------存储引擎 ---astore drop table if exists test_astore_row ; drop table if exists test_astore_column ; drop foreign table if exists test_astore_mot ; --- 创建 astore 行存表 create table test_astore_row(col text) with (orientation=row) ; --- 创建 astore 列存表 create table test_astore_column(col text) with (orientation=column); --- 创建 astore 内存表 create foreign table test_astore_mot(col int) server mot_server ; ---ustore drop table if exists test_ustore ; create table test_ustore(col text)with(storage_type=ustore); --- GBase 8c的数据分片策略:在创建表时,通过关键字distribute/replication 来设置表分片策略。 --- 1:通过distribute by hash 创建 hash 分片表,将数据通过hash算法 均匀存储到每个数据节点。创建hash分片 drop table if exists t1_dis ; CREATE TABLE t1_dis(c1 int, c2 int) DISTRIBUTE BY hash(c1); --- 2:通过distribute by replication 创建 复制表,每个数据节点都会存储一份数据。 drop table if exists t1_rep ; CREATE TABLE t1_rep(c1 int, c2 int) DISTRIBUTE BY replication; -- 分区表 -- 一级 hash 分区 drop table if exists mea_hash cascade; create table mea_hash ( city_id int,logdate timestamp,id int ) partition by hash(id) ( partition p1 , partition p2 ); --二级分区 hash-list,hash-hash, hash-range drop table if exists mea_hash_list cascade; create table mea_hash_list ( city_id int,logdate timestamp,id int) partition by hash(id) subpartition by list(city_id) ( partition p1 (subpartition p12 values (10),subpartition p13 values (20) )); drop table if exists mea_hash_hash cascade; create table mea_hash_hash ( city_id int,logdate timestamp,id int) partition by hash(id) subpartition by hash(city_id) ( partition id_1 (subpartition p12 ,subpartition p13) ); drop table if exists mea_hash_range cascade; create table mea_hash_range ( city_id int,logdate timestamp,id int) partition by hash(id) subpartition by range(logdate) ( partition meas_y2021 (subpartition p12 values less than ('2021-02-04 12:00:00'),subpartition p13 values less than ('2021-02-04 20:00:00') )); -- 一级 range 分区 drop table if exists mea_range cascade; create table mea_range ( city_id int,logdate timestamp) partition by range(logdate) ( partition meas_y2021 values less than ('2021-01-01') ); --二级 range-range, range-hash,range-list drop table if exists mea_range_range cascade; create table mea_range_range ( city_id int,logdate timestamp,id int) partition by range(logdate) subpartition by range(id) ( partition meas_y2021 values less than ('2021-02-04 21:00:00') (subpartition p12 values less than (1),subpartition p13 values less than (10) )); drop table if exists mea_range_hash cascade; create table mea_range_hash ( city_id int,logdate timestamp,id int) partition by range(logdate) subpartition by hash(city_id) ( partition id_1 values less than ('2021-02-01 01:00:00') (subpartition p12,subpartition p13) ); drop table if exists mea_range_list cascade; create table mea_range_list ( city_id int,logdate timestamp,id int) partition by range(logdate) subpartition by list(city_id) ( partition p1 values less than ('2021-02-01 01:00:00') (subpartition p12 values (1),subpartition p13 values (20) )); -- 一级 list 分区 drop table if exists mea_list cascade; create table mea_list ( city_id int,logdate timestamp,id int ) partition by list(id) ( partition p1 values (1), partition p2 values (2) ); --期望支持.成功执行 -- 二级 list-list,list-range,list-hash 分区 drop table if exists mea_list_list cascade; create table mea_list_list ( city_id int,logdate timestamp,id int) partition by list(id) subpartition by list(city_id) ( partition p1 values (1) (subpartition p12 values (10),subpartition p13 values (20) )); drop table if exists mea_list_range cascade; create table mea_list_range ( city_id int,logdate timestamp,id int) partition by list(id) subpartition by range(logdate) ( partition meas_y2021 values ('202102') (subpartition p12 values less than ('2021-02-04 12:00:00'),subpartition p13 values less than ('2021-02-04 20:00:00') )); drop table if exists mea_list_hash cascade; create table mea_list_hash ( city_id int,logdate timestamp,id int) partition by list(id) subpartition by hash(city_id) ( partition id_1 values (2021) (subpartition p12,subpartition p13) ); ------------数据库分区查看 with RECURSIVE temp_partition as( SELECT t1.oid, t1.relname, partstrategy, boundaries,t1.parttype FROM pg_partition t1, pg_class t2 WHERE t1.parentid = t2.oid AND t2.relname = 'mea_hash_hash' union SELECT t1.oid, t1.relname, t1.partstrategy, t1.boundaries,t1.parttype FROM pg_partition t1 join temp_partition t2 on t1.parentid = t2.oid where t2.parttype='p') select t1.relname, t1.partstrategy, t1.boundaries,t1.parttype from temp_partition t1; --- 自动分区功能,请注意:创建分表时,子分区必须要有一个 大于当前时间 2小时的 分区。时间需按照实际时间 进行修改。 create table range_auto_1hour_tb01(id int,ip text,time timestamp) with(PERIOD='1 hour') partition by range(time)( partition p1 values less than ('2023-02-23 19:00')); select * from dba_tab_partitions where table_name = 'RANGE_AUTO_1HOUR_TB01'; insert into range_auto_1hour_tb01 values(1,'12','2023-2-18 09:00:00'); insert into range_auto_1hour_tb01 values(2,'10','2023-2-18 10:00:00'); insert into range_auto_1hour_tb01 values(2,'10','2023-2-19 18:00:00'); insert into range_auto_1hour_tb01 values(2,'10','2023-2-19 19:00:00'); --多种索引 --hash 索引 create table rw_split(col int,name text); insert into rw_split select generate_series(1,50000), md5(random()::text)::text; create index rw_split_col_hash on rw_split using hash(col); explain select * from rw_split where col =2; -----------------btree 索引 drop index rw_split_col_hash; create index rw_split_col_btree on rw_split using btree(col); explain select * from rw_split where col =2; ---------------gist 索引 drop table if exists t_gist; create table t_gist(id int,p point); insert into t_gist select generate_series(1,10000),point(round((random()*1000)::numeric,2),round((random()*1000)::numeric,2)); select * from t_gist limit 2; create index on t_gist using gist(p); explain (analyze,buffers) select * from t_gist where circle '((100,100) 1)' @> p order by p <-> '(100,100)' limit 10; ---在 100,100 点,半径10 以内的点。 ---------------gin索引 drop table if exists t_gin; create table t_gin(doc text, doc_tsv tsvector); insert into t_gin(doc) values ('Can a sheet slitter slit sheets?'), ('How many sheets could a sheet slitter slit?'), ('I slit a sheet, a sheet I slit.'), ('Upon a slitted sheet I sit.'), ('Whoever slit the sheets is a good sheet slitter.'), ('I am a sheet slitter.'), ('I slit sheets.'), ('I am the sleekest sheet slitter that ever slit sheets.'), ('She slits the sheet she sits on.'); update t_gin set doc_tsv = to_tsvector(doc); create index on t_gin using gin(doc_tsv); --- 为了效果,手动关闭顺序扫描。 set enable_seqscan=off; explain(costs off) select doc from t_gin where doc_tsv @@ to_tsquery('many & slitter'); --------------表达式索引 create table test_expression(col int, name varchar(64)); insert into test_expression select 1,'ASDD'; insert into test_expression select 2,'ASDD'; insert into test_expression select 3,'AS'; insert into test_expression select 4,'ASsda'; insert into test_expression select 5,'ASdssa'; insert into test_expression select 6,'Asds'; insert into test_expression select 7,'Assa'; insert into test_expression select 8,'as'; explain select * from test_expression where lower(name) ='as'; create index on test_expression (name); create index test_expression_lower on test_expression (lower(name)); explain select * from test_expression where lower(name) ='as'; -----------数据压缩 ---- 行存压缩 drop table if exists test_row_compress; create table test_row_compress(col text); insert into test_row_compress select md5(random()::text) from generate_series(1,1000000); select * from pg_size_pretty(pg_catalog.pg_table_size('test_row_compress')); drop table if exists test_row_compress; create table test_row_compress(col text) with (compresstype = 2,compress_level= 3); insert into test_row_compress select md5(random()::text) from generate_series(1,1000000); select * from pg_size_pretty(pg_catalog.pg_table_size('test_row_compress')); ---- 列存压缩 drop table test_column_compress; create table test_column_compress(col text) with (orientation=column,compression=no); insert into test_column_compress select md5(random()::text) from generate_series(1,1000000); select * from pg_size_pretty(pg_catalog.pg_table_size('test_column_compress')); drop table test_column_compress; create table test_column_compress(col text) with (orientation=column,compression=high); insert into test_column_compress select md5(random()::text) from generate_series(1,1000000); select * from pg_size_pretty(pg_catalog.pg_table_size('test_column_compress')); ----------------------子事务 -----自治事务 create table t2(a int,b int); insert into t2 values(1,2); select * from t2; create or replace procedure autonomus_4(a int ,b int) as declare num3 int =a; num4 int =b; pragma autonomous_transaction; begin insert into t2 values (num3,num4); end; / create or replace procedure autonomus_5(a int ,b int) as declare begin insert into t2 values (444,55);autonomus_4(a,b);rollback; end; / select autonomus_5(11,22); select * from t2; -----------savepoint --设置保存点 --创建表 drop table if exists savepoint_test; create table savepoint_test(a int primary key,b int) ; --开始事务 start transaction; --插入数据 insert into savepoint_test values(1,2); --创建保存点 savepoint test_savepoint; --插入数据 insert into savepoint_test values(2,2); --查看表中数据 select * from savepoint_test; --回滚保存点 rollback to savepoint test_savepoint; --查看表中数据(只能查到(1,1),(2,2)被回滚) select * from savepoint_test; --插入数据 insert into savepoint_test values(3,3); --提交事务 commit; --查看表中数据(=能查到(1,1)、(3,3),(2,2)被回滚) select * from savepoint_test; --删除测试表savepoint_test drop table savepoint_test; --------exception create type type_test as (a int,b int); create or replace procedure p1 as c int; begin select a into c from type_test; exception when others then raise 'NULL' ; end; / call p1();