华为云用户手册

  • 创建连接故障 gsql: could not connect to server: No route to host 此问题一般是指定了不可达的地址或者端口导致的。请检查-h参数与-p参数是否添加正确。 gsql: FATAL: Invalid username/password,login denied. 此问题一般是输入了错误的用户名和密码导致的,请联系数据库管理员,确认用户名和密码的正确性。 gsql: FATAL: Forbid remote connection with trust method! 数据库由于安全问题,禁止远程登录时使用trust模式。这时需要修改gs_hba.conf里的连接认证信息。请联系管理员处理。 请不要修改gs_hba.conf中数据库集群主机的相关设置,否则可能导致数据库功能故障。建议业务应用部署在数据库集群之外,而非集群内部。 在CN所在的主机连接数据库,添加“-h 127.0.0.1”可以连接,去掉后无法连接问题。 通过执行SQL语句“show unix_socket_directory”检查数据库CN使用的Unix套接字目录,是否与shell中的环境变量$PGHOST一致。 如果检查结果不一致,那么修改PGHOST环境变量到GUC参数unix_socket_directory指向的目录。 The "libpq.so" loaded mismatch the version of gsql, please check it. 此问题是由于环境中使用的libpq.so的版本与gsql的版本不匹配导致的,请通过“ldd gsql”命令确认当前加载的libpq.so的版本,并通过修改LD_LIBRARY_PATH环境变量来加载正确的libpq.so。 gsql: symbol lookup error: xxx/gsql: undefined symbol: libpqVersionString 此问题是由于环境中使用的libpq.so的版本与gsql的版本不匹配导致的(也有可能是环境中存在PostgreSQL的libpq.so),请通过“ldd gsql”命令确认当前加载的libpq.so的版本,并通过修改LD_LIBRARY_PATH环境变量来加载正确的libpq.so。 gsql: connect to server failed: Connection timed out Is the server running on host "xx.xxx.xxx.xxx" and accepting TCP/IP connections on port xxxx? 此问题是由于网络连接故障造成。请检查客户端与数据库服务器间的网络连接。如果发现从客户端无法PING到数据库服务器端,则说明网络连接出现故障。请联系网络管理人员排查解决。 ping -c 4 10.10.10.1 PING 10.10.10.1 (10.10.10.1) 56(84) bytes of data. From 10.10.10.1: icmp_seq=2 Destination Host Unreachable From 10.10.10.1 icmp_seq=2 Destination Host Unreachable From 10.10.10.1 icmp_seq=3 Destination Host Unreachable From 10.10.10.1 icmp_seq=4 Destination Host Unreachable --- 10.10.10.1 ping statistics --- 4 packets transmitted, 0 received, +4 errors, 100% packet loss, time 2999ms gsql: FATAL: permission denied for database "gaussdb" DETAIL: User does not have CONNECT privilege. 此问题是由于用户不具备访问该数据库的权限,可以使用如下方法解决。 使用管理员用户dbadmin连接数据库。 gsql -d gaussdb -U dbadmin -p 8000 赋予该用户访问数据库的权限。 GRANT CONNECT ON DATABASE gaussdb TO user1; 实际上,常见的许多错误操作也可能产生用户无法连接上数据库的现象。如用户连接的数据库不存在,用户名或密码输入错误等。这些错误操作在客户端工具也有相应的提示信息。 gsql -d gaussdb -p 8000 gsql: FATAL: database "gaussdb" does not exist gsql -d gaussdb -U user1 -p 8000 Password for user user1: gsql: FATAL: Invalid username/password,login denied. gsql: FATAL: sorry, too many clients already,active/non-active: 197/3. 此问题是由于系统连接数量超过了最大连接数量。请联系数据库DBA进行会话连接数管理,释放无用会话。 关于查看用户会话连接数的方法如表1。 会话状态可以在视图PG_STAT_ACTIVITY中查看。无用会话可以使用函数pg_terminate_backend进行释放。 select datid,pid,state from pg_stat_activity; datid | pid | state -------+-----------------+-------- 13205 | 139834762094352 | active 13205 | 139834759993104 | idle (2 rows) 其中pid的值即为该会话的线程ID。根据线程ID结束会话。 SELECT PG_TERMINATE_BACKEND(139834759993104); 显示类似如下信息,表示结束会话成功。 PG_TERMINATE_BACKEND ---------------------- t (1 row) 表1 查看会话连接数 描述 命令 查看指定用户的会话连接数上限。 执行如下命令查看连接到指定用户USER1的会话连接数上限。其中-1表示没有对用户user1设置连接数的限制。 SELECT ROLNAME,ROLCONNLIMIT FROM PG_ROLES WHERE ROLNAME='user1'; rolname | rolconnlimit ---------+-------------- user1 | -1 (1 row) 查看指定用户已使用的会话连接数。 执行如下命令查看指定用户USER1已使用的会话连接数。其中,1表示USER1已使用的会话连接数。 SELECT COUNT(*) FROM dv_sessions WHERE USERNAME='user1'; count ------- 1 (1 row) 查看指定数据库的会话连接数上限。 执行如下命令查看连接到指定数据库gaussdb的会话连接数上限。其中-1表示没有对数据库gaussdb设置连接数的限制。 SELECT DATNAME,DATCONNLIMIT FROM PG_DATABASE WHERE DATNAME='gaussdb'; datname | datconnlimit ----------+-------------- gaussdb | -1 (1 row) 查看指定数据库已使用的会话连接数。 执行如下命令查看指定数据库gaussdb上已使用的会话连接数。其中,1表示数据库gaussdb上已使用的会话连接数。 SELECT COUNT(*) FROM PG_STAT_ACTIVITY WHERE DATNAME='gaussdb'; count ------- 1 (1 row) 查看所有用户已使用会话连接数。 执行如下命令查看所有用户已使用的会话连接数。 SELECT COUNT(*) FROM dv_sessions; count ------- 10 (1 row) gsql: wait xxx.xxx.xxx.xxx:xxxx timeout expired gsql在向数据库发起连接的时候,会有5分钟超时机制,如果在这个超时时间内,数据库未能正常的对客户端请求进行校验和身份认证,那么gsql会退出当前会话的连接过程,并报出如上错误。 一般来说,此问题是由于连接时使用的-h参数及-p参数指定的连接主机及端口有误(即错误信息中的xxx部分),导致通信故障;极少数情况是网络故障导致。要排除此问题,请检查数据库的主机名及端口是否正确。 gsql: could not receive data from server: Connection reset by peer. 同时,检查CN日志中出现类似如下日志“ FATAL: cipher file "/data/coordinator/server.key.cipher" has group or world access”,一般是由于数据目录或部分关键文件的权限被误操作篡改导致。请参照其他正常实例下的相关文件权限修改。 gsql: FATAL: GSS authentication method is not allowed because XXXX user password is not disabled. 目标CN的gs_hba.conf里配置了当前客户端IP使用"gss"方式来做认证,该认证算法不支持用作客户端的身份认证,请修改到"sha256"后再试。请联系管理员处理。 请不要修改gs_hba.conf中数据库集群主机的相关设置,否则可能导致数据库功能故障。 建议业务应用部署在数据库集群之外,而非集群内部。
  • 任务示例 使用如下命令连接数据库。 gsql -d gaussdb -p 8000 gaussdb为需要连接的数据库名称,8000为CN的端口号。 连接成功后,系统显示类似如下信息: gsql (( GaussDB Kernel XXX.X.XXX build f521c606) compiled at 2021-09-16 14:55:22 commit 2935 last mr 6385 release) Non-SSL connection (SSL connection is recommended when requiring high-security) Type "help" for help. 查看gsql的帮助信息。具体执行命令请参见表1。 表1 使用gsql联机帮助 描述 示例 查看版权信息 \copyright 查看GaussDB支持的SQL语句的帮助 查看GaussDB支持的SQL语句的帮助 例如,查看GaussDB支持的所有SQL语句: 1 2 3 4 5 6 gaussdb=# \h Available help: ABORT ALTER AGGREGATE ... ... 例如,查看CREATE DATABASE命令的参数可使用下面的命令: 1 2 3 4 5 6 7 8 9 10 11 12 13 gaussdb=# \help CREATE DATABASE Command: CREATE DATABASE Description: create a new database Syntax: CREATE DATABASE database_name [ [ WITH ] {[ OWNER [=] user_name ]| [ TEMPLATE [=] template ]| [ ENCODING [=] encoding ]| [ LC_COLLATE [=] lc_collate ]| [ LC_CTYPE [=] lc_ctype ]| [ DBCOMPATIBILITY [=] compatibility_type ]| [ TABLESPACE [=] tablespace_name ]| [ CONNECTION LIMIT [=] connlimit ]}[...] ]; 查看gsql命令的帮助 例如,查看gsql支持的命令: 1 2 3 4 5 6 7 gaussdb=# \? General \copyright show GaussDB Kernel usage and distribution terms \g [FILE] or ; execute query (and send results to file or |pipe) \h(\help) [NAME] help on syntax of SQL commands, * for all commands \q quit gsql ... ...
  • 操作步骤 连接数据库时,可以使用如下命令获取帮助信息。 gsql --help 显示如下帮助信息: ...... Usage: gsql [OPTION]... [DBNAME [USERNAME]] General options: -c, --command=COMMAND run only single command (SQL or internal) and exit -d, --dbname=DBNAME database name to connect to (default: "omm") -f, --file=FILENAME execute commands from file, then exit ...... 连接到数据库后,可以使用如下命令获取帮助信息。 help 显示如下帮助信息: You are using gsql, the command-line interface to gaussdb. Type: \copyright for distribution terms \h for help with SQL commands \? for help with gsql commands \g or terminate with semicolon to execute query \q to quit
  • 约束 解析的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%。 不支持同一节点并发调用数据找回接口。
  • 背景信息 账本数据库归档功能目前提供两种校验接口,分别为:ledger_hist_archive(text, text)和ledger_gchain_archive(text, text)。账本数据库接口仅审计管理员可以调用。 归档用户历史表的接口为pg_catalog.ledger_hist_archive,表示归档当前DN的用户历史表数据。执行操作为: SELECT pg_catalog.ledger_hist_archive(schema_name text,table_name text); 如果归档成功,函数返回t,反之则提示失败原因并返回f。 归档全局区块表的接口为pg_catalog.ledger_gchain_archive,表示归档当前CN的全局历史表数据。执行操作为: SELECT pg_catalog.ledger_gchain_archive(); 如果归档成功,函数返回t,反之则提示失败原因并返回f。
  • 操作步骤 使用EXECUTE DIRECT对某个DN节点进行归档操作。 1 gaussdb=# EXECUTE DIRECT ON (datanode1) 'select pg_catalog.ledger_hist_archive(''ledgernsp'', ''usertable'');'; 查询结果如下: ledger_hist_archive --------------------- t (1 row) 用户历史表将归档为一条数据: gaussdb=# EXECUTE DIRECT ON (datanode1) 'SELECT * FROM blockchain.ledgernsp_usertable_hist;'; rec_num | hash_ins | hash_del | pre_hash ---------+------------------+------------------+---------------------------------- 3 | e78e75b00d396899 | 8fcd74a8a6a4b484 | fd61cb772033da297d10c4e658e898d7 (1 row) 该结果表明datanode1节点用户历史表导出成功。 连接CN执行全局区块表导出操作。 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) 该结果表明,当前coordinator节点全局区块表导出成功。
  • 背景信息 账本数据库融合了 区块链 思想,将用户操作记录至两种历史表:用户历史表和全局区块表中。当用户创建防篡改用户表时,系统将自动为该表添加一个hash列来保存每行数据的hash摘要信息,同时在blockchain模式下会创建一张用户历史表来记录对应用户表中每条数据的变更行为;而用户对防篡改用户表的每一次修改行为将被记录到全局区块表中。由于历史表具有只可追加不可修改的特点,因此历史表记录串联起来便形成了用户对防篡改用户表的修改历史。
  • 操作步骤 创建防篡改模式。 例如,创建防篡改模式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 Distribute By: HASH(id) Location Nodes: ALL DATANODES 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 Distribute By: HASH(rec_num) Location Nodes: ALL DATANODES Options: internal_mask=263 防篡改模式下仅行存表为防篡改表,临时表、外表、unlog表及非行存表均无防篡改属性。 防篡改表在创建时会自动增加一个用于校验的系统列,所以防篡改表单表最大列数为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
  • 恢复用户表数据和全局区块表数据 以omm用户为例进行操作,步骤如下。 以操作系统用户omm登录数据库主节点。 使用EXECUTE DIRECT对某个DN节点进行历史表修复操作。 1 gaussdb=# EXECUTE DIRECT ON (datanode1) 'select pg_catalog.ledger_hist_repair(''ledgernsp'', ''usertable'');'; 查询结果如下: ledger_hist_repair -------------------- 84e8bfc3b974e9cf (1 row) 该结果表明datanode1节点用户历史表修复成功,修复造成的用户历史表hash增量为84e8bfc3b974e9cf。 连接CN执行全局区块表修复操作。 1 gaussdb=# SELECT pg_catalog.ledger_gchain_repair('ledgernsp', 'usertable'); 查询结果如下: ledger_gchain_repair ---------------------- a41714001181a294 (1 row) 该结果表明,当前集群全局区块表修复成功,且向当前CN节点插入一条修复数据,其hash值为a41714001181a294。
  • 恢复用户表和用户历史表名称 已通过enable_recyclebin参数和recyclebin_retention_time参数开启闪回DROP功能,恢复用户表和用户历史表名称。示例如下: DROP用户表,对用户表执行闪回DROP。使用ledger_hist_repair对用户表、用户历史表进行表名恢复。 -- 对用户表执行闪回drop,使用ledger_hist_repair对用户历史表进行表名恢复。 gaussdb=# CREATE TABLE ledgernsp.tab2(a int, b text); NOTICE: The 'DISTRIBUTE BY' clause is not specified. Using 'a' as the distribution column by default. HINT: Please use 'DISTRIBUTE BY' clause to specify suitable data distribution column. NOTICE: The 'DISTRIBUTE BY' clause is not specified. Using 'rec_num' as the distribution column by default. HINT: Please use 'DISTRIBUTE BY' clause to specify suitable data distribution column. CREATE TABLE gaussdb=# DROP TABLE ledgernsp.tab2; DROP TABLE gaussdb=# SELECT rcyrelid, rcyname, rcyoriginname FROM gs_recyclebin; rcyrelid | rcyname | rcyoriginname ----------+------------------------------+--------------------- 32838 | BIN$39B523388046$55C8400==$0 | tab2 32846 | BIN$39B52338804E$55C90E8==$0 | gs_hist_tab2_index 32843 | BIN$39B52338804B$55C96A0==$0 | ledgernsp_tab2_hist 32841 | BIN$39B523388049$55C9EE0==$0 | pg_toast_32838 (4 rows) -- 对用户表执行闪回drop。 gaussdb=# TIMECAPSULE TABLE ledgernsp.tab2 TO BEFORE DROP; TimeCapsule Table -- 使用ledger_hist_repair恢复用户历史表表名。 gaussdb=# SELECT ledger_hist_repair('ledgernsp', 'tab2'); ledger_hist_repair -------------------- 0000000000000000 (1 row) gaussdb=# \d+ ledgernsp.tab2; Table "ledgernsp.tab2" Column | Type | Modifiers | Storage | Stats target | Description -------------+---------+-----------+----------+--------------+------------- a | integer | | plain | | b | text | | extended | | hash_1d2d14 | hash16 | | plain | | Has OIDs: no Distribute By: HASH(a) Location Nodes: ALL DATANODES Options: orientation=row, compression=no, storage_type=USTORE, segment=off, toast.storage_type=USTORE, toast.toast_storage_type=enhanced_toast History table name: ledgernsp_tab2_hist -- 对用户表执行闪回drop,使用ledger_hist_repair对用户表进行表名恢复。 gaussdb=# CREATE TABLE ledgernsp.tab3(a int, b text); NOTICE: The 'DISTRIBUTE BY' clause is not specified. Using 'a' as the distribution column by default. HINT: Please use 'DISTRIBUTE BY' clause to specify suitable data distribution column. NOTICE: The 'DISTRIBUTE BY' clause is not specified. Using 'rec_num' as the distribution column by default. HINT: Please use 'DISTRIBUTE BY' clause to specify suitable data distribution column. CREATE TABLE gaussdb=# DROP TABLE ledgernsp.tab3; DROP TABLE gaussdb=# SELECT rcyrelid, rcyname, rcyoriginname FROM gs_recyclebin; rcyrelid | rcyname | rcyoriginname ----------+------------------------------+--------------------- 32952 | BIN$80B6233880B8$FECFF98==$0 | tab3 32960 | BIN$80B6233880C0$FED0C98==$0 | gs_hist_tab3_index 32957 | BIN$80B6233880BD$FED1250==$0 | ledgernsp_tab3_hist 32955 | BIN$80B6233880BB$FED1A00==$0 | pg_toast_32952 (4 rows) -- 对用户历史表执行闪回drop。 gaussdb=# TIMECAPSULE TABLE blockchain.ledgernsp_tab3_hist TO BEFORE DROP; TimeCapsule Table -- 拿到回收站中用户表对应的rcyname,使用ledger_hist_repair恢复用户表表名。 gaussdb=# SELECT ledger_hist_repair('ledgernsp', 'BIN$80B6233880B8$FECFF98==$0'); ledger_hist_repair -------------------- 0000000000000000 (1 row) gaussdb=# \d+ ledgernsp.tab3; Table "ledgernsp.tab3" Column | Type | Modifiers | Storage | Stats target | Description -------------+---------+-----------+----------+--------------+------------- a | integer | | plain | | b | text | | extended | | hash_7a0c87 | hash16 | | plain | | Has OIDs: no Distribute By: HASH(a) Location Nodes: ALL DATANODES Options: orientation=row, compression=no, storage_type=USTORE, segment=off, toast.storage_type=USTORE, toast.toast_storage_type=enhanced_toast History table name: ledgernsp_tab3_hist -- 删除表。 gaussdb=# DROP TABLE ledgernsp.tab2 PURGE; DROP TABLE gaussdb=# DROP TABLE ledgernsp.tab3 PURGE; DROP TABLE
  • 背景信息 当前的账本数据库机制为:全局区块表存储在CN端,各个CN数据独立。用户历史表存储在DN端,历史表记录的数据为所在DN防篡改表的数据变化。因此,在触发数据重分布时,可能导致防篡改表和用户历史表数据不一致,此时需要使用ledger_hist_repair(text, text)接口对指定DN节点的用户历史表进行修复,修复后当前DN节点调用历史表校验接口结果为true。在CN剔除、修复的场景下,可能导致全局区块表数据丢失或者与用户历史表不一致,此时需要使用ledger_gchain_repair(text, text)接口对整个集群范围内的全局区块表进行修复,修复后调用全局区块表校验接口结果为true。 修复用户历史表的接口为pg_catalog.ledger_hist_repair,操作为: SELECT pg_catalog.ledger_hist_repair(schema_name text,table_name text); 如果修复成功,函数返回修复过程中用户历史表hash的增量。 注:对用户表执行闪回DROP时,可使用该函数恢复用户表和用户历史表名称,请参见恢复用户表和用户历史表名称。 修复全局区块表的接口为pg_catalog.ledger_gchain_repair,操作为: SELECT pg_catalog.ledger_gchain_repair(schema_name text,table_name text); 如果修复成功,函数返回修复过程中全局区块表中指定表的hash总和。
  • 操作步骤 查询全局区块表记录。 1 gaussdb=# SELECT * FROM gs_global_chain; 查询结果如下: blocknum | dbname | username | starttime | relid | relnsp | relname | relhash | globalhash | txcommand ----------+----------+----------+-------------------------------+-------+-----------+-----------+------------------+----------------------------------+------------------ ------------------------------------------------------------ 0 | testdb | omm | 2021-04-14 07:00:46.32757+08 | 16393 | ledgernsp | usertable | a41714001181a294 | 6b5624e039e8aee36bff3e8295c75b40 | insert into ledge rnsp.usertable values(1, 'alex'), (2, 'bob'), (3, 'peter'); 1 | testdb | omm | 2021-04-14 07:01:19.767799+08 | 16393 | ledgernsp | usertable | b3a9ed0755131181 | 328b48c4370faed930937869783c23e0 | update ledgernsp. usertable set name = 'bob2' where id = 2; 2 | testdb | omm | 2021-04-14 07:01:29.896148+08 | 16393 | ledgernsp | usertable | 0ae4b4e4ed2fcab5 | aa8f0a236357cac4e5bc1648a739f2ef | delete from ledge rnsp.usertable where id = 3; 该结果表明,用户omm连续执行了三条DML命令,包括INSERT、UPDATE和DELETE操作。 查询历史表记录。 1 gaussdb=# SELECT * FROM blockchain.ledgernsp_usertable_hist; 查询结果如下: rec_num | hash_ins | hash_del | pre_hash ---------+------------------+------------------+---------------------------------- 0 | 1f2e543c580cb8c5 | | e1b664970d925d09caa295abd38d9b35 1 | 8fcd74a8a6a4b484 | | dad3ed8939a141bf3682043891776b67 2 | f51b4b1b12d0354b | | 53eb887fc7c4302402343c8914e43c69 3 | 437761affbb7c605 | 8fcd74a8a6a4b484 | c2868c5b49550801d0dbbbaa77a83a10 4 | | f51b4b1b12d0354b | 9c512619f6ffef38c098477933499fe3 (5 rows) 查询结果显示,用户omm对ledgernsp.usertable表插入了3条数据,更新了1条数据,随后删除了1行数据,最后剩余2行数据,hash值分别为1f2e543c580cb8c5和437761affbb7c605。 查询用户表数据及校验列。 1 gaussdb=# SELECT *, hash_69dd43 FROM ledgernsp.usertable; 查询结果如下: id | name | hash_69dd43 ----+------+------------------ 1 | alex | 1f2e543c580cb8c5 2 | bob2 | 437761affbb7c605 (2 rows) 查询结果显示,用户表中剩余2条数据,与2中的记录一致。
  • 使用规格 非SMP场景下的Partition-wise Join的使用规格: 只支持一级RANGE分区。 支持Hash Join、Nestloop Join、Merge Join。 只支持Inner Join。 需要设置query_dop的值为1。 由于非SMP场景下的Partition-wise Join为规则选择,所以Partition-wise Join计划可能造成性能下降,需要用户自行决定是否启用。 仅支持FQS计划。
  • 操作步骤 校验防篡改用户表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的记录保持一致,未发生篡改行为。
  • 背景信息 账本数据库校验功能目前提供两种校验接口,分别为: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。
  • Partition-wise Join Partition-wise Join是一种分区级并行的优化技术,是指在符合一定条件的情况下,将两张表之间的Join,分解为两张表中对应的两个分区之间的Join。通过并发执行、减少数据通信量等方式,提升分区表的Join查询的性能。 Partition-wise Join分为SMP场景和非SMP场景。 非SMP场景下的Partition-wise Join SMP场景下的Full Partition-wise Join 父主题: 分区表查询优化
  • 使用步骤 逻辑解码特性需提前设置GUC参数wal_level为logical,该参数需要重启生效。 gs_guc set -Z datanode -D $node_dir -c "wal_level = logical" 其中,$node_dir为数据库节点路径,用户可根据实际情况替换。 以具有REPLICATION权限的用户登录 GaussDB数据库 主节点,使用如下命令连接数据库。 gsql -U user1 -W password -d db1 -p 16000 -r 其中,user1为用户名,password为密码,db1为需要连接的数据库名称,16000为数据库端口号,用户可根据实际情况替换。 创建名称为slot1的逻辑复制槽。 1 2 3 4 5 gaussdb=# SELECT * FROM pg_create_logical_replication_slot('slot1', 'mppdb_decoding'); slotname | xlog_position ----------+--------------- slot1 | 0/3764C788 (1 row) 在数据库中创建Package。 1 2 3 4 5 6 gaussdb=# CREATE OR REPLACE PACKAGE ldp_pkg1 IS var1 int:=1; --公有变量 var2 int:=2; PROCEDURE testpro1(var3 int); --公有存储过程,可以被外部调用 END ldp_pkg1; / 读取复制槽slot1解码结果,可通过JDBC接口或者pg_logical_slot_peek_changes推进复制槽。 逻辑解码选项请参见逻辑解码选项和新增控制参数。 并行解码中,在JDBC接口中改变参数decode_style可以决定解码格式: 通过配置选项decode-style,指定解码格式。其取值为char型的字符'j'、't'或'b',分别代表json格式、text格式及二进制格式。 1 2 3 4 5 6 7 gaussdb=# SELECT data FROM pg_logical_slot_peek_changes('slot1', NULL, NULL, 'enable-ddl-decoding', 'true', 'enable-ddl-json-format', 'false') WHERE data not like 'BEGIN%' AND data not like 'COMMIT%' AND data not like '%dbe_pldeveloper.gs_source%'; data -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- {"TDDL":"CREATE OR REPLACE PACKAGE public.ldp_pkg1 AUTHID CURRENT_USER IS var1 int:=1; --公有变量\n var2 int:=2;\n PROCEDURE testpro1(var3 int); --公有存储过程,可以被外部调用\nEND ldp_pkg1; \n /"} (1 row) 删除逻辑复制槽slot1,删除package ldp_pkg1。 1 2 3 4 5 6 7 8 9 gaussdb=# SELECT * FROM pg_drop_replication_slot('slot1'); pg_drop_replication_slot -------------------------- (1 row) gaussdb=# DROP PACKAGE ldp_pkg1; NOTICE: drop cascades to function public.testpro1(integer) DROP PACKAGE
  • 解码格式 JSON格式 对于输入的DDL语句,SQL引擎解析器会通过语法、词法分析将其分解为解析树,解析树节点中包含了DDL的全部信息,并且执行器会根据解析树内容,执行系统元信息的修改。在执行器执行完成之后,便可以获取到DDL操作数据对象的search_path。本特性在执行器执行成功之后,对解析树信息以及执行器结果进行反解析,以还原出DDL原语句的全部信息。反解析的方式可以分解整个DDL语句,以方便输出JSON格式的DDL,用以适配异构数据库场景。 CREATE TABLE语句在经过词法、语法分析之后,得到对应的CreateStmt解析树节点,节点中包含了表信息、列信息、分布式信息(DistributeBy结构体)、分区信息(PartitionState结构)等。通过反解析后,可输出的JSON格式如下: {"JDDL":{"fmt":"CREATE %{persistence}s TABLE %{if_not_exists}s %{identity}D %{table_elements}s %{with_clause}s %{compression}s","identity":{"object_name":"test_create_table_a","schema_name":"public"},"compression":"NOCOMPRESS","persistence":"","with_clause":{"fmt":"WITH (%{with:, }s)","with":[{"fmt":"%{label}s = %{value}L","label":{"fmt":"%{label}I","label":"orientation"},"value":"row"},{"fmt":"%{label}s = %{value}L","label":{"fmt":"%{label}I","label":"compression"},"value":"no"}]},"if_not_exists":"","table_elements":{"fmt":"(%{elements:, }s)","elements":[{"fmt":"%{name}I %{column_type}T","name":"a","column_type":{"typmod":"","typarray":false,"type_name":"int4","schema_name":"pg_catalog"}}]}}} 可以看到,JSON格式中包含对象的search_path,其中的identity键标识schema为public,表名为test_create_table_a,其中%{persistence}s对应的字段如下,此SQL语句不含此字段所以为空。 [ [ GLOBAL | LOCAL ] [ TEMPORARY | TEMP ] | UN LOG GED ] %{if_not_exists}s对应SQL语句中的字段,不含此字段所以为空: [ IF NOT EXISTS ] %{identity}D对应SQL语句中的字段: table_name %{table_elements}s对应SQL语句中的字段: (column_name data_type) %{with_clause}s对应SQL语句中的字段: [ WITH ( {storage_parameter = value} [, ... ] ) ] %{compression}s对应SQL语句中的字段: [ COMPRESS | NOCOMPRESS ] decode-style指定格式 输出的格式由decode-style参数控制,如当decode-style='j'时,输出格式如下: {"TDDL":"CREATE TABLE public.test_create_table_a (a pg_catalog.int4) WITH (orientation = 'row', compression = 'no') NOCOMPRESS"} 其中语句中也包含Schema名称。
  • 接口设计 新增控制参数 新增逻辑解码控制参数,用于控制DDL的反解析流程以及输出形式。可通过JDBC接口或者pg_logical_slot_peek_changes开启。 enable-ddl-decoding:默认false,不开启DDL语句的逻辑解码;值为true时,开启DDL语句的逻辑解码。 enable-ddl-json-format:默认false,传送TEXT格式的DDL反解析结果;值为true时,传送JSON格式的DDL反解析结果。 新增GUC参数 enable_logical_replication_ddl:默认为ON,ON状态下,逻辑复制可支持DDL,否则,不支持DDL。只有当ON状态下,才会对DDL执行结果进行反解析,并生成DDL的WAL日志。否则,不反解析也不生成WAL日志。 enable_logical_replication_ddl的开关日志,以证明是否是用户修改了该参数导致逻辑解码不支持DDL。 新增日志 新增DDL日志xl_logical_ddl_message,其类型为RM_LOGICALDDLMSG_ID。其定义如下: 名称 类型 意义 db_id OID 数据库ID rel_id OID 表ID csn CommitSeqNo CS N快照 cid CommandId Command ID tag_type NodeTag DDL类型 message_size Size 日志内容长度 filter_message_size Size 日志中白名单过滤信息长度 message char * DDL内容
  • 功能描述 数据库在执行DML的时候,存储引擎会生成对应的DML日志,用于进行恢复,对这些DML日志进行解码,即可还原对应的DML语句,生成逻辑日志。而对于DDL语句,数据库并不记录DDL原语句的日志,而是记录DDL语句涉及的系统表的DML日志。DDL种类多样、语法复杂,逻辑复制要支持DDL语句,通过这些系统表的DML日志来解码原DDL语句是非常困难的。新增DDL日志记录原DDL信息,并在解码时通过DDL日志可以得到DDL原语句。 在DDL语句执行过程中,SQL引擎解析器会对原语句进行语法、词法解析,并生成解析树(不同的DDL语法会生成不同类型的解析树,解析树中包含DDL语句的全部信息)。随后,执行器通过这些信息执行对应操作,生成、修改对应元信息。 本节通过新增DDL日志的方式,来支持逻辑解码DDL,其内容由解析器结果(解析树)以及执行器结果生成,并在执行器执行完成后生成该日志。 从语法树反解析出DDL,DDL反解析能够将DDL命令转换为JSON格式的语句,并提供必要的信息在目标位置重建DDL命令。与原始DDL命令字符串相比,使用DDL反解析的好处包括: 解析出来的每个数据库对象都带有Schema,因此如果使用不同的search_path,也不会有歧义。 结构化的JSON和格式化的输出能支持异构数据库。如果用户使用的是不同的数据库版本,并且存在某些DDL语法差异,需要在应用之前解决这些差异。 反解析输出的结果是规范化后的形式,结果与用户输入等价,不保证完全相同,例如: 示例1:在函数体中没有单引号'时,函数体的分隔符$$会被解析为单引号'。 原始SQL语句: CREATE FUNCTION func(a INT) RETURNS INT AS $$ BEGIN a:= a+1; CREATE TABLE test(col1 INT); INSERT INTO test VALUES(1); DROP TABLE test; RETURN a; END; $$ LANGUAGE plpgsql; 反解析结果: CREATE FUNCTION public.func ( IN a pg_catalog.int4 ) RETURNS pg_catalog.int4 LANGUAGE plpgsql VOLATILE CALLED ON NULL INPUT SECURITY INVOKER COST 100 AS ' BEGIN a:= a+1; CREATE TABLE test(col1 INT); INSERT INTO test VALUES(1); DROP TABLE test; RETURN a; END; '; 示例3:“ALTER INDEX "Alter_Index_Index" REBUILD PARTITION "CA_ADDRESS_SK_index2"”会被反解析为“REINDEX INDEX public."Alter_Index_Index" PARTITION "CA_ADDRESS_SK_index2"”。 示例4:创建/修改范围分区表,START END语法格式均解码转化为LESS THAN语句: gaussdb=# CREATE TABLE test_create_table_partition2 (c1 INT, c2 INT) PARTITION BY RANGE (c2) ( PARTITION p1 START(1) END(1000) EVERY(200) , PARTITION p2 END(2000), PARTITION p3 START(2000) END(2500), PARTITION p4 START(2500), PARTITION p5 START(3000) END(5000) EVERY(1000) ); 会被反解析为: gaussdb=# CREATE TABLE test_create_table_partition2 (c1 INT, c2 INT) PARTITION BY RANGE (c2) ( PARTITION p1_0 VALUES LESS THAN ('1'), PARTITION p1_1 VALUES LESS THAN ('201'), PARTITION p1_2 VALUES LESS THAN ('401'), PARTITION p1_3 VALUES LESS THAN ('601'), PARTITION p1_4 VALUES LESS THAN ('801'), PARTITION p1_5 VALUES LESS THAN ('1000'), PARTITION p2 VALUES LESS THAN ('2000'), PARTITION p3 VALUES LESS THAN ('2500'), PARTITION p4 VALUES LESS THAN ('3000'), PARTITION p5_1 VALUES LESS THAN ('4000'), PARTITION p5_2 VALUES LESS THAN ('5000') );
  • 规格约束 逻辑解码支持DDL规格: 纯DDL逻辑解码性能标准环境下约为100MB/S,DDL/DML混合事务逻辑解码性能标准环境下约为100MB/S。 开启此功能后(设置wal_level=logical且enable_logical_replication_ddl=on),对DDL语句影响性能下降小于15%。 解码通用约束(串行和并行): 不支持解码本地临时对象的DDL操作。 不支持FOREIGN TABLE场景的DDL解码。 alter table add column的default值不支持stable类型和volatile类型的函数;create table和alter table的column的check表达式不支持stable类型和volatile类型的函数;alter table如果有多条子语句,只要其中一条子语句存在上述两种情况,则该条alter table整条语句不反解析。 gaussdb=# ALTER TABLE tbl_28 ADD COLUMN b1 TIMESTAMP DEFAULT NOW(); -- 's' NOT DEPARSE gaussdb=# ALTER TABLE tbl_28 ADD COLUMN b2 INT DEFAULT RANDOM(); -- 'v' NOT DEPARSE gaussdb=# ALTER TABLE tbl_28 ADD COLUMN b3 INT DEFAULT ABS(1); -- 'i' DEPARSE 不支持分布式CREATE MATERIALIZED VIEW的DDL解码。 不支持CREATE/ALTER/DROP VIEW、COMMENT ON VIEW的DDL解码。 不支持REINDEX DATABASE/SYSTEM的DDL解码。 不支持视图上触发器相关的DDL解码。 不支持CONCURRENTLY相关语句的DDL解码。 创建对象时语句中存在IF NOT EXISTS时,如果对象已存在,则不进行解码。删除对象时语句中存在IF EXISTS时,如果对象不存在,则不进行解码。 不对ALTER PACKAGE COMPILE语句进行解码,但会解码实例化内容中包含的DDL/DML语句。如果PACKAGE里没有DDL或DML部分的实例化内容,则alter package compile会被逻辑解码忽略。 仅支持本版本之前版本的商用DDL语法,以下SQL语句不支持逻辑解码。 创建行存表,设置ILM策略。 原始SQL语句: gaussdb=# CREATE TABLE IF NOT EXISTS tb3 (c1 int) with (storage_type=USTORE,ORIENTATION=ROW) ILM ADD POLICY ROW STORE COMPRESS ADVANCED ROW AFTER 7 day OF NO MODIFICATION; 反解析结果: gaussdb=# CREATE TABLE IF NOT EXISTS public.tb3 (c1 pg_catalog.int4) WITH (storage_type = 'ustore', orientation = 'row', compression = 'no') NOCOMPRESS; B兼容模式下创建或修改表时,给表或列添加注释。 原始SQL语句: gaussdb=# CREATE TABLE IF NOT EXISTS tb6 (c1 integer comment 'Mysql兼容注释语法') with (ORIENTATION=ROW, STORAGE_TYPE=USTORE); 反解析结果: gaussdb=# CREATE TABLE IF NOT EXISTS public.tb6 (c1 pg_catalog.int4) WITH (storage_type = 'ustore', orientation = 'row', compression = 'no') NOCOMPRESS; 逻辑解码不支持DDL(DCL)/DML混合事务,混合事务中DDL之后的DML解码不支持。 -- 均不反解析,DCL为不支持语句故不解析,DML处于DCL之后也不反解析 gaussdb=# BEGIN; gaussdb=# GAINT ALL PRIVILEGES to u01; gaussdb=# INSERT INTO test1(col1) values(1); gaussdb=# COMMIT; -- 只反解析第一句和第三句SQL语句 gaussdb=# BEGIN; gaussdb=# CREATE TABLE mix_tran_t4(id int); gaussdb=# INSERT INTO mix_tran_t4 VALUES(111); gaussdb=# CREATE TABLE mix_tran_t5(id int); gaussdb=# COMMIT; -- 只反解析第一句和第二句SQL语句 gaussdb=# BEGIN; gaussdb=# INSERT INTO mix_tran_t4 VALUES(111); gaussdb=# CREATE TABLE mix_tran_t6(id int); gaussdb=# INSERT INTO mix_tran_t4 VALUES(111); gaussdb=# COMMIT; -- 全反解析 gaussdb=# BEGIN; gaussdb=# INSERT INTO mix_tran_t4 VALUES(111); gaussdb=# CREATE TABLE mix_tran_t7(id int); gaussdb=# CREATE TABLE mix_tran_t8(id int); gaussdb=# COMMIT; -- 只反解析第一句和第三句SQL语句 gaussdb=# BEGIN; gaussdb=# CREATE TABLE mix_tran_t7(id int); gaussdb=# CREATE TYPE compfoo AS (f1 int, f2 text); gaussdb=# CREATE TABLE mix_tran_t8(id int); gaussdb=# COMMIT; -- 全反解析 gaussdb=# BEGIN; gaussdb=# INSERT INTO mix_tran_t4 VALUES(111); gaussdb=# INSERT INTO mix_tran_t4 VALUES(111); gaussdb=# INSERT INTO mix_tran_t4 VALUES(111); gaussdb=# COMMIT; -- 只反解析第一句SQL语句 gaussdb=# BEGIN; gaussdb=# INSERT INTO mix_tran_t4 VALUES(111); gaussdb=# CREATE TYPE compfoo AS (f1 int, f2 text); gaussdb=# INSERT INTO mix_tran_t4 VALUES(111); gaussdb=# COMMIT; -- 只反解析第一句和第三句SQL语句 gaussdb=# BEGIN; gaussdb=# INSERT INTO mix_tran_t4 VALUES(111); gaussdb=# CREATE TYPE compfoo AS (f1 int, f2 text); gaussdb=# CREATE TABLE mix_tran_t9(id int); gaussdb=# COMMIT; 逻辑解码语句CREATE TABLE AS SELECT、SELECT INTO和CREATE TABLE AS仅能解码出CREATE TABLE语句,暂不支持解码INSERT语句。 对于CTAS创建的表,仍会解码其ALTER和DROP语句。 示例: 原始SQL语句: CREATE TABLE IF NOT EXISTS tb35_2 (c1 int) with (storage_type=USTORE,ORIENTATION=ROW); INSERT INTO tb35_2 VALUES (6); CREATE TABLE tb35_1 with (storage_type=USTORE,ORIENTATION=ROW) AS SELECT * FROM tb35_2; 最后一句SQL语句反解析结果: CREATE TABLE public.tb35_1 (c1 pg_catalog.int4) WITH (storage_type = 'ustore', orientation = 'row', compression = 'no') NOCOMPRESS; 执行存储过程/函数/高级包时,若其本身包含DDL/DML混合事务或者其本身与同事务内其他语句组成DDL/DML混合事务,则按照混合事务原则执行解码。 逻辑解码不支持账本数据库功能,创建账本数据库的DDL语句解码结果中会包含hash列。 原始语句: CREATE SCHEMA blockchain_schema WITH BLOCKCHAIN; CREATE TABLE blockchain_schema.blockchain_table(mes int); 解码结果: CREATE SCHEMA blockchain_schema WITH BLOCKCHAIN; CREATE TABLE blockchain_schema.blockchain_table (mes pg_catalog.int4, hash_a1d895 pg_catalog.hash16); -- 此语句无法在目标端回放。 需要在目标端手动关闭blockchain_schema的防篡改属性后,才可以正常回放,此时目标端的blockchain_table等同于一张普通表,再次执行DML命令可以正常回放。 SQL命令: ALTER SCHEMA blockchain_schema WITHOUT BLOCKCHAIN; CREATE TABLE blockchain_schema.blockchain_table (mes pg_catalog.int4, hash_a1d895 pg_catalog.hash16); 串行逻辑解码支持DDL特有约束: sql_decoding插件不支持json格式的DDL。
  • 使用规格 SMP场景下的Full Partition-wise Join的使用规格: 支持一级HASH分区表和一级RANGE分区表。 Hash分区表的分区策略完全相同是指分区键类型相同、分区数相同。 Range分区表的分区策略完全相同是指分区键类型相同、分区数相同、分区键数量相同、每个分区的边界值相同。 仅支持Stream计划。 仅支持分区键和分布键完全一致的场景。 仅支持Join算子在单DN内完成计算,即Join算子的数据不跨节点。 支持Hash Join和Merge Join。 支持Seqscan、Indexscan、Indexonlyscan、Imcvscan。其中,对于Indexscan和Indexonlyscan,只支持分区Local索引,且索引类型为BTREE或UBTREE。 相关规格继承SMP规格,不支持SMP场景下的IUD操作。 需要开启SMP功能,且设置query_dop的值大于1。
  • 操作加密表 创建加密表。 创建表时,通过在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
  • 查看透明加密基本配置 查看透明加密功能是否已开启 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=...
  • 操作加密索引 创建加密表。 创建索引的基表,需确保基表也是加密表。 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_recyclebin参数和recyclebin_retention_time参数开启闪回DROP功能,恢复用户表和用户历史表名称。示例如下: DROP用户表,对用户表执行闪回DROP。使用ledger_hist_repair对用户表、用户历史表进行表名恢复。 -- 对用户表执行闪回drop,使用ledger_hist_repair对用户历史表进行表名恢复。 gaussdb=# CREATE TABLE ledgernsp.tab2(a int, b text); CREATE TABLE gaussdb=# DROP TABLE ledgernsp.tab2; DROP TABLE gaussdb=# SELECT rcyrelid, rcyname, rcyoriginname FROM gs_recyclebin; rcyrelid | rcyname | rcyoriginname ----------+------------------------------+--------------------- 16717 | BIN$38242338414D$42EB978==$0 | tab2 16725 | BIN$382423384155$42EC678==$0 | gs_hist_tab2_index 16722 | BIN$382423384152$42ECC30==$0 | ledgernsp_tab2_hist 16720 | BIN$382423384150$42ED3E0==$0 | pg_toast_16717 (4 rows) -- 对用户表执行闪回drop。 gaussdb=# TIMECAPSULE TABLE ledgernsp.tab2 TO BEFORE DROP; TimeCapsule Table -- 使用ledger_hist_repair恢复用户历史表表名。 gaussdb=# SELECT ledger_hist_repair('ledgernsp', 'tab2'); ledger_hist_repair -------------------- 0000000000000000 (1 row) gaussdb=# TIMECAPSULE TABLE ledgernsp.tab2 TO BEFORE DROP; TimeCapsule Table gaussdb=# SELECT ledger_hist_repair('ledgernsp', 'tab2'); ledger_hist_repair -------------------- 0000000000000000 (1 row) gaussdb=# \d+ ledgernsp.tab2; Table "ledgernsp.tab2" Column | Type | Modifiers | Storage | Stats target | Description -------------+---------+-----------+----------+--------------+------------- a | integer | | plain | | b | text | | extended | | hash_1d2d14 | hash16 | | plain | | Has OIDs: no Options: orientation=row, compression=no, storage_type=USTORE, segment=off, toast.storage_type=USTORE, toast.toast_storage_type=enhanced_toast History table name: ledgernsp_tab2_hist -- 对用户表执行闪回drop,使用ledger_hist_repair对用户表进行表名恢复。 gaussdb=# CREATE TABLE ledgernsp.tab3(a int, b text); CREATE TABLE gaussdb=# DROP TABLE ledgernsp.tab3; DROP TABLE gaussdb=# SELECT rcyrelid, rcyname, rcyoriginname FROM gs_recyclebin; rcyrelid | rcyname | rcyoriginname ----------+------------------------------+--------------------- 17574 | BIN$44A4233844A6$B18E7A0==$0 | tab3 17582 | BIN$44A4233844AE$B18F488==$0 | gs_hist_tab3_index 17579 | BIN$44A4233844AB$B18FA40==$0 | ledgernsp_tab3_hist 17577 | BIN$44A4233844A9$B190208==$0 | pg_toast_17574 (4 rows) -- 对用户历史表执行闪回drop。 gaussdb=# TIMECAPSULE TABLE blockchain.ledgernsp_tab3_hist TO BEFORE DROP; TimeCapsule Table -- 拿到回收站中用户表对应的rcyname,使用ledger_hist_repair恢复用户表表名。 gaussdb=# SELECT ledger_hist_repair('ledgernsp', 'BIN$44A4233844A6$B18E7A0==$0'); ledger_hist_repair -------------------- 0000000000000000 (1 row) gaussdb=# \d+ ledgernsp.tab3; Table "ledgernsp.tab3" Column | Type | Modifiers | Storage | Stats target | Description -------------+---------+-----------+----------+--------------+------------- a | integer | | plain | | b | text | | extended | | hash_7a0c87 | hash16 | | plain | | Has OIDs: no Options: orientation=row, compression=no, storage_type=USTORE, segment=off, toast.storage_type=USTORE, toast.toast_storage_type=enhanced_toast History table name: ledgernsp_tab3_hist -- 删除表。 gaussdb=# DROP TABLE ledgernsp.tab2 PURGE; DROP TABLE gaussdb=# DROP TABLE ledgernsp.tab3 PURGE; DROP TABLE
  • 恢复用户表数据和全局区块表数据 执行历史表修复操作。 1 gaussdb=# SELECT pg_catalog.ledger_hist_repair('ledgernsp', 'usertable'); 查询结果如下: ledger_hist_repair -------------------- 84e8bfc3b974e9cf (1 row) 该结果表明当前节点用户历史表修复成功,修复造成的用户历史表hash增量为84e8bfc3b974e9cf。 执行全局区块表修复操作。 1 gaussdb=# SELECT pg_catalog.ledger_gchain_repair('ledgernsp', 'usertable'); 查询结果如下: ledger_gchain_repair ---------------------- a41714001181a294 (1 row) 该结果表明,全局区块表修复成功,且插入一条修复数据,其hash值为a41714001181a294。
  • 背景信息 当在异常情况或表被损坏时,需要使用ledger_gchain_repair(text, text)接口对全局区块表进行修复,或使用ledger_hist_repair(text, text)接口对用户历史表进行修复,修复后调用全局区块表或用户历史表校验接口结果为true。 修复用户历史表的接口为pg_catalog.ledger_hist_repair,操作为: SELECT pg_catalog.ledger_hist_repair(schema_name text,table_name text); 如果修复成功,函数返回修复过程中用户历史表hash的增量。 注:对用户表执行闪回DROP时,可使用该函数恢复用户表和用户历史表名称,请参见恢复用户表和用户历史表名称。 修复全局区块表的接口为pg_catalog.ledger_gchain_repair,操作为: SELECT pg_catalog.ledger_gchain_repair(schema_name text,table_name text); 如果修复成功,函数返回修复过程中全局区块表中指定表的hash总和。
  • 接口设计 新增控制参数 新增逻辑解码控制参数,用于指定解码开始点。可通过JDBC接口或者逻辑复制函数(例如:pg_logical_slot_peek_changes、pg_logical_slot_get_changes、pg_logical_slot_peek_binary_changes、pg_logical_slot_get_binary_changes)开启。 restart-lsn:未使用该可选参数时,表示逻辑解码开始点使用逻辑复制槽原来的一致性点;有值时,表示逻辑解码开始点是restart-lsn后的一个一致性点。 新增GUC参数 logical_replication_dictionary_retention_time:默认值为365天,用于控制数据字典相关系统表回收时,数据保存时间。 enable_logical_replication_dictionary:默认为ON,ON状态下,逻辑复制支持创建多版本字典表类型的逻辑复制槽;OFF状态下,不支持创建多版本字典表类型的逻辑复制槽。 新增系统函数 gs_logical_dictionary_baseline():执行逻辑解码数据字典的存量数据基线化,执行成功返回耗时,执行失败返回失败原因。 规格说明:函数的执行时长与实例上的业务表数量正相关。实例存在1万张业务表的场景下,基线化函数执行耗时25秒左右;10万张业务表的场景下,基线化函数执行耗时120秒左右。函数执行期间不会阻塞其他SQL语句的操作。 可以通过SELECT status FROM gs_logical_dictionary;确认实例是否已经完成基线化,返回值及含义: 0:基线化完成状态未加载。 1:基线化未完成。 2:基线化进行中。 3:基线化已完成。 函数执行成功,查询结果预期是3,表示基线化已完成。并开启对数据字典相关系统表的同步写入,例如:pg_class更改时会同步更改gs_logical_class。 gs_logical_dictionary_disabled():关闭逻辑解码数据字典功能,停止对数据字典相关系统表的同步写入,执行成功返回OK,执行失败返回失败原因。 关闭数据字典功能之后,无法使用已有的数据字典模式复制槽继续解码,如需使用数据字典功能,须执行gs_logical_dictionary_baseline()函数,对逻辑数据字典重新进行基线化。
  • 规格约束 只支持对在线WAL日志的指定位点解码。用户需要根据不同业务每天产生的WAL日志数量,来调整GaussDB保留在线WAL日志文件数量的配置参数,以达到满足指定位点WAL日志需求的目的。 逻辑解码真正的开始点是一致性点,一致性点具体位置和当时的并发执行事务实际情况相关,例如长事务等。一致性点及之后开启的事务所产生的数据修改才会被解码出来,用户需要确保要解码的事务开始于一致性点之后,为了防止漏解,建议在选择指定的逻辑解码位点时,尽量将其前移一段距离。 安装带指定位点功能的版本时,初始化时会自动执行字典表的基线化,安装完成后管理员无需执行基线化函数即可使用指定位点功能;升级场景,从不支持指定位点版本升级到指定位点版本,需要管理员执行基线化系统函数后才能使用指定位点功能,且指定位点必须大于基线化完成时的lsn。 如果用户设置的数据字典保留时长小于指定区间的WAL日志产生时长,会造成由于字典表数据缺失而导致解码异常的情况。逻辑解码数据字典的保留时长通过GUC参数(logical_replication_dictionary_retention_time)来设置。 数据字典相关系统表元组满足如下回收条件才可被回收: 当前时间减去系统表元组数据的创建时间得到的值大于logical_replication_dictionary_retention_time。 系统表数据的csnmax不为0,且csnmax小于逻辑复制槽推进后的最小csn(即如下所示的slot_dictionary_type为dictionary table的元组中最小的dictionary_csn_min)。 gaussdb=# select * from pg_get_replication_slots(); slot_name | plugin | slot_type | datoid | active | xmin | catalog_xmin | restart_lsn | dummy_standby | confirmed_flush | confirmed_csn | dictionary_csn_min | slot_dictionary_type -----------+----------------+-----------+--------+--------+------+--------------+-------------+---------------+-----------------+---------------+--------------------+---------------------- slot_lsn | mppdb_decoding | logical | 41313 | f | | | 0/E34CDC0 | f | 0/E34CE40 | | 3011 | dictionary table (1 row)
共100000条