华为云用户手册

  • 审视计划跳变场景 优化器生成计划的方式是基于代价完成的(Cost Based Optimizer),其会根据代价模型和相关表的统计信息生成最优的执行计划。因此,相关表的统计信息变更或代价模型的参数修改都会影响最优计划的生成。此外,生产业务的许多操作均会导致计划缓存失效并重建,如更新统计信息的相关操作(VACUUM、ANALYZE、AUTOVACUUM、AUTOANALYZE)、重建索引等DDL操作、施加SQL Patch和其他导致缓存失效的场景。如果期间基于代价生成的最优计划与之前不同,就会发生计划跳变。故计划跳变在生产业务中是一种较为常见的现象。 一般而言,正向的计划跳变无需重点关注。需要重点关注因计划跳变导致性能下降、CPU冲高等一系列后果的场景。这通常伴随着数据库环境变量变更,如统计信息更新,表结构变更或数据库版本升级。 在 GaussDB 中,有如下几类场景可能导致计划跳变,需要业务审视并应用精准的调优手段(Hint等)。 Generic-Plan的重建:业务稳定运行时通常执行的是Generic-Plan,表示计划已经稳定不再需要优化器对SQL进行优化。而有些情况会导致Generic-Plan失效需要重新构建: 修改GUC参数:修改GUC参数会导致Generic-Plan的重建,而修改优化器相关参数如query_dop等会导致计划跳变。稳定业务非特殊需求应尽量避免修改优化器相关参数。 对查询中涉及的基表进行了DDL操作:对表的DDL操作会导致Generic-Plan的重建,而对索引进行增删改会影响计划选择。若对索引进行调优需要保证索引有效性且及时更新索引统计信息保证选择更优的计划。 对表进行IUD操作并手动或自动收集统计信息:统计信息的变化会导致Generic-Plan的重建。一般认为若统计信息收集及时,即使计划跳变通常不会引入性能劣化。业务中常见情况是对于查询中涉及的基表进行大量IUD而统计信息未及时更新,此时需要手动收集统计信息或审视自动收集统计信息的触发情况。 智能优化器:Generic-Plan在部分场景中并不能满足业务需求,例如数据倾斜的场景,对于不同的数据最优计划不同。而智能优化器会生成多个备选的Generic-Plan并实时根据查询反馈决策挑选其中最优的计划执行。智能优化器和业务执行的顺序有关,若智能优化器不能满足要求,建议对关键业务语句使用Hint或SQL Patch等手段进行针对性调优。 父主题: SQL调优指南
  • GS_SPM_PLAN_HISTORY GS_SPM_PLAN_HISTORY系统表是用于记录计划跳变历史的系统表,具备SYSADMIN权限的用户可以对该系统表进行读操作,但只有初始用户才可以对该系统表进行写的操作。 表1 GS_SPM_PLAN_HISTORY字段 名称 类型 描述 sql_hash bigint SPM中SQL的唯一标识。 plan_hash bigint plan id。 plan_hash_previous bigint 上一次使用的计划的plan id,若不存在上一次计划则为0。 userid oid 创建跳变历史的用户。 creation_time timestamp with time zone 创建跳变历史的时间。 父主题: SPM计划管理
  • 算子说明 表分区技术(Table-Partitioning)通过将非常大的表或者索引从逻辑上切分为更小、更易管理的逻辑单元(分区),能够减小用户对表查询、变更等语句操作的影响范围;能够让用户通过分区键(Partition Key)快速定位到数据所在的分区,从而避免在数据库中对大表的全量扫描,能够在不同的分区上并发进行DDL、DML操作。GaussDB支持三种分区策略 :范围分区、哈希分区、列表分区。范围分区基于二分binary-search实现,复杂度为O(logN);哈希分区和列表分区基于key-partOid哈希表实现,复杂度为O(1)。
  • PG_EXTENSION_DATA_SOURCE PG_EXTENSION_DATA_SOURCE系统表存储外部数据源对象的信息。一个外部数据源对象(Data Source)包含了外部数据库的一些密码编码等信息,主要配合Extension Connector使用,默认仅系统管理员可访问此表。由于规格变更,当前版本已经不再支持本特性,请不要使用。 表1 PG_EXTENSION_DATA_SOURCE字段 名称 类型 引用 描述 oid oid - 行标识符(隐含属性,必须明确选择)。 srcname name - 外部数据源对象的名称。 srcowner oid 12.2.11.1 PG_AUTHID.oid 外部数据源对象的所有者。 srctype text - 外部数据源对象的类型,缺省为空。 srcversion text - 外部数据源对象的版本,缺省为空。 srcacl aclitem[] - 访问权限。 srcoptions text[] - 外部数据源对象的指定选项,使用“keyword=value”格式的字符串。 父主题: 其他系统表
  • VACUUM系统函数 GS_STAT_PROGRESS_VACUUM(pid integer) 描述:根据vacuum线程pid查看vacuum的执行进度,支持autovacuum和手动vacuum。 参数:如GS_STAT_PROGRESS_VACUUM入参和返回值列表所示。 表1 GS_STAT_PROGRESS_VACUUM入参和返回值列表 参数 类型 描述 pid IN bigint VACUUM线程的线程pid。 dataname OUT text 正在清理的数据库名称。 relid OUT oid 正在清理表的OID。 relname OUT text 正在清理的表名称。 phase OUT text 当前VACUUM所处的阶段。 detail OUT text 清理进度详情,包含总页面数、已扫描页面数、已清理页面数、已清理索引数。 返回值类型:record 示例: gaussdb=# select * from GS_STAT_PROGRESS_VACUUM(139988726445824); pid | dataname | relid | relname | phase | detail -----------------+----------+-------+---------+---------------+--------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------- 139988726445824 | postgres | 98304 | t1 | scanning heap | vacuum command "vacuum freeze t1;" starts at 2025-02-07 13:48:51.189748-05, vacuumed 5/12 partitio ns, current part "a_lt_6"; heap: scanned 348/883 blocks, skipped 0 blocks; info: found 0 dead tuples, already run 0s, delay 0s. (1 row) 父主题: 系统管理函数
  • PG_STAT_USER_TABLES PG_STAT_USER_TABLES视图显示所有命名空间中用户自定义普通表和toast表的状态信息。通过该视图查看VACUUM在某张表上的执行情况,通常需要关注n_dead_tup和last_autovacuum字段。字段含义如下: 表1 PG_STAT_USER_TABLES字段 名称 类型 描述 relid oid 表的OID。 schemaname name 该表的模式名。 relname name 表名。 seq_scan bigint 该表发起的顺序扫描数。 seq_tup_read bigint 顺序扫描抓取的活跃行数。 idx_scan bigint 该表发起的索引扫描数。 idx_tup_fetch bigint 索引扫描抓取的活跃行数。 n_tup_ins bigint 插入行数。 n_tup_upd bigint 更新行数。 n_tup_del bigint 删除行数。 n_tup_hot_upd bigint HOT更新行数(即没有更新所需的单独索引)。 n_live_tup bigint 估计活跃行数。 n_dead_tup bigint 估计死行数。 last_vacuum timestamp with time zone 最后一次该表是手动清理的(不计算Vacuum Full)。 last_autovacuum timestamp with time zone 上次AUTOVACUUM守护进程清理的表。 last_analyze timestamp with time zone 上次手动分析这个表。 last_autoanalyze timestamp with time zone 上次被AUTOVACUUM守护进程分析的表。 vacuum_count bigint 这个表被手动清理的次数(不计算Vacuum Full)。 autovacuum_count bigint 这个表被AUTOVACUUM清理的次数。 analyze_count bigint 这个表被手动分析的次数。 autoanalyze_count bigint 这个表被AUTOVACUUM守护进程分析的次数。 last_data_changed timestamp with time zone 这个表数据最近修改时间。 执行示例如下: gaussdb=# \x Expanded display is on. gaussdb=# select * from pg_stat_user_tables where relname='t2'; -[ RECORD 1 ]-----+------------------------------ relid | 98316 schemaname | public relname | t2 seq_scan | 2 seq_tup_read | 20002 idx_scan | idx_tup_fetch | n_tup_ins | 10001 n_tup_upd | 10001 n_tup_del | 5001 n_tup_hot_upd | 0 n_live_tup | 5000 n_dead_tup | 15002 last_vacuum | 2025-02-09 10:16:47.317412-05 last_autovacuum | 2025-02-09 10:16:47.317412-05 last_analyze | 2025-02-09 10:16:37.491756-05 last_autoanalyze | 2025-02-09 10:16:37.491756-05 vacuum_count | 3 autovacuum_count | 3 analyze_count | 2 autoanalyze_count | 2 last_data_changed | 2025-02-09 10:16:34.660061-05 父主题: VACUUM
  • 算子说明 Rownum算子会生成伪列,它返回一个数字,表示从查询中获取结果的行编号。第一行的Rownum为1。可以使用Rownum关键字对查询结果的行编号进行条件过滤。通常出现在Rownum子句里。 使用Rownum有一定的约束条件: Rownum不可作为别名,以免SQL语句出现歧义。 创建索引时不可使用Rownum。 创建表时默认值不可为Rownum。 Where子句中不可使用Rownum的别名。 在插入数据时不可使用Rownum。 在无表查询中不可以使用Rownum。 Rownum不能用于Limit子句。 Rownum不能用于EXECUTE语句的参数。 Upsert语句不支持Rownum用做Update子句更新。
  • 运算符 Sort 对结果集进行排序。 Filter EXPLAIN输出显示WHERE子句当作一个"filter"条件附属于顺序扫描计划节点。这意味着规划节点为它扫描的每一行检查该条件,并且只输出符合条件的行。预计的输出行数降低了,因为有WHERE子句。不过,扫描仍将必须访问所有 10000 行,因此开销没有降低,实际上它还增加了一些(确切的说,通过10000 * cpu_operator_cost)以反映检查WHERE条件的额外CPU时间。 Limit LIMIT限定了执行结果的输出记录数。如果增加了LIMIT,那么不是所有的行都会被检索到。 Append 合并子操作的结果。 Aggregate 将查询行产生的结果进行组合。可以是GROUPBY、UNION、SELECT DISTINCT子句等函数的组合。 BitmapAnd 位图的AND操作,通过该操作组成匹配更复杂条件的位图。 BitmapOr 位图的OR操作,通过该操作组成匹配更复杂条件的位图。 Gather 将并行线程的数据汇总。 Group 对行进行分组,以进行GROUP BY操作。 GroupAggregate 聚合GROUP BY操作的预排序行。 Hash 对查询行进行散列操作,以供父查询使用。通常用于执行JOIN操作。 HashAggregate 使用哈希表聚合GROUP BY的结果行。 Merge Append 以保留排序顺序的方式对子查询结果进行组合,可用于组合表分区中已排序的行。 ProjectSet 对返回的结果集执行函数。 Recursive Union 对递归函数的所有步骤进行并集操作。 SetOp 集合运算,如INTERSECT或EXCEPT。 Unique 从有序的结果集中删除重复项。 HashSetOp 一种用于 INTERSECT 或 EXCEPT 等集合操作的策略,它使用 Append 来避免预排序的输入。 LockRows 锁定有问题的行以阻止其他查询写入,但允许读。 Materialize 将子查询的结果存储在内存里,以方便父查询快速访问获取。 Result 在不进行扫描的情况下返回一个值。 WindowAgg 窗口聚合函数,一般由OVER语句触发。 Merge 归并操作。 StartWith Operator 层次查询算子,用于执行递归查询操作。 Rownum 对查询结果的行编号进行条件过滤。通常出现在rownum子句里。 Index Cond 索引扫描条件。 Unpivot 转置算子。
  • 表连接方式 Nested Loop 嵌套循环,适用于被连接的数据子集较小的查询。在嵌套循环中,外表驱动内表,外表返回的每一行都要在内表中检索找到它匹配的行,因此整个查询返回的结果集不能太大(不能大于10000),要把返回子集较小的表作为外表,而且在内表的连接字段上建议要有索引。 (Sonic) Hash Join 哈希连接,适用于数据量大的表的连接方式。优化器使用两个表中较小的表,利用连接键在内存中建立hash表,然后扫描较大的表并探测散列,找到与散列匹配的行。Sonic和非Sonic的Hash Join的区别在于所使用hash表结构不同,不影响执行的结果集。 Merge Join 归并连接,通常情况下执行性能差于哈希连接。如果源数据已经被排序过,在执行归并连接时,并不需要再排序,此时归并连接的性能优于哈希连接。
  • 分区剪枝相关信息 Iterations 分区迭代算子对一级分区的迭代次数。如果显示PART则为动态剪枝场景。 例如:Iterations: 4表示迭代算子需要遍历4个一级分区。Iterations: PART表示遍历一级分区个数需要由分区键上的参数条件决定。 Selected Partitions 一级分区剪枝的结果,m..n表示m到n号分区被剪枝选中,多个不连续的分区由逗号连接。 例如:Selected Partitions: 2..4,7 表示2、3、4、7四个分区被选中。 Sub Iterations 分区迭代算子对二级分区的迭代次数。如果显示PART则为动态剪枝场景。 例如:Sub Iterations: 4表示迭代算子需要遍历4个二级分区。Iterations: PART表示遍历二级分区个数需要由分区键上的参数条件决定。 Selected Subpartitions 二级分区被剪枝的结果,由一级分区序号:二级分区序号的格式展示。 例如:Selected Subpartitions: 2:1 3:2 表示第二个一级分区的1号二级分区和第三个一级分区的2号二级分区被选中。Selected Subpartitions: ALL表示所有二级分区均被选中。
  • 表访问方式 Seq Scan 全表顺序扫描。 Index Scan 索引扫描,优化器决定使用两步的规划:最底层的规划节点访问一个索引,找出匹配索引条件的行的位置,然后上层规划节点真实地从表中抓取出那些行。独立地抓取数据行比顺序地读取它们的开销高很多,但是因为并非所有表的页面都被访问了,这么做实际上仍然比一次顺序扫描开销要少。使用两层规划的原因是,上层规划节点在读取索引标识出来的行位置之前,会先将它们按照物理位置排序,这样可以最小化独立抓取的开销。 如果在WHERE里面使用的好几个字段上都有索引,那么优化器可能会使用索引的AND或OR的组合。但是这么做要求访问两个索引,因此与只使用一个索引,而把另外一个条件只当作过滤器相比,这个方法未必是更优。 索引扫描可以分为以下几类,它们之间的差异在于索引的排序机制。 Bitmap Index Scan 使用位图索引抓取数据页。 Index Scan using index_name 使用简单索引搜索,该方式按照索引键的顺序在索引表中抓取数据。该方式最常用于在大数据量表中只抓取少量数据的情况,或者通过ORDER BY条件匹配索引顺序的查询,以减少排序时间。 Index-Only Scan 当需要的所有信息都包含在索引中时,仅索引扫描便可获取所有数据,不需要引用表。 Bitmap Heap Scan 从其他操作创建的位图中读取页面,过滤掉不符合条件的行。位图堆扫描可避免随机I/O,加快读取速度。 TID Scan 通过TupleID扫描表。 Index Ctid Scan 通过Ctid上的索引对表进行扫描。 CTE Scan CTE对子查询的操作进行评估并将查询结果临时存储,相当于一个临时表。CTE Scan算子对该临时表进行扫描。 Foreign Scan 从远程数据源读取数据。 Function Scan 获取函数返回的结果集,将它们作为从表中读取的行并返回。 Sample Scan 查询并返回采样数据。 Subquery Scan 读取子查询的结果。 Values Scan 作为VALUES命令的一部分读取常量。 WorkTable Scan 工作表扫描。在操作中间阶段读取,通常是使用WITH RECURSIVE声明的递归操作。
  • 总结 智能修正模式与严格校验模式可以结合使用,且智能修正模式具有优先级。在进行COPY导入时,若已明确指定对数据异常采用智能修正,那么该行数据的处理将不会触发严格校验模式。这意味着错误表不会记录相应数据,同时也不会扣除reject limit次数。建议用户根据自身实际情况,权衡是否自动修正列异常与字符异常后入库,还是直接舍弃。 对于严格校验模式的两个级别,推荐用户默认选择Level1。这是因为Level1所支持的错误类型较为常见,并且不会对导入性能产生任何影响。而Level2目前仅在集中式A兼容环境下支持,开启该特性会额外消耗导入性能和内存资源。具体信息请参见COPY支持约束冲突容错能力。因此,不建议用户默认使用Level2,仅在明确数据存在约束类型冲突时再开启。
  • INFORMATION_SCHEMA.TRIGGERS 显示所有定义在当前数据库中表和视图上的触发器,并且只显示当前用户拥有的触发器或当前用户在其上具有某种除了SELECT之外特权的触发器,如表1所示。 表1 INFORMATION_SCHEMA.TRIGGERS字段 名称 类型 描述 trigger_catalog information_schema.sql_identifier 包含该触发器的数据库名。 trigger_schema information_schema.sql_identifier 包含该触发器的模式名。 trigger_name information_schema.sql_identifier 触发器名称。 event_manipulation information_schema.character_data 触发该触发器的事件类型(INSERT、UPDATE、DELETE)。 event_object_catalog information_schema.sql_identifier 包含该触发器所在表的数据库名。 event_object_schema information_schema.sql_identifier 包含该触发器所在表的模式名。 event_object_table information_schema.sql_identifier 触发器所在表的名称。 action_order information_schema.cardinal_number 同一个表上具有相同event_manipulation、action_timing、action_orientation的触发器之间的触发顺序。 action_condition information_schema.character_data 触发器的WHEN条件,默认为空。 action_statement information_schema.character_data 触发器执行的语句。 action_orientation information_schema.character_data 标识触发器是对每个被处理的行触发一次还是为每个语句触发一次。 action_timing information_schema.character_data 触发器在什么时候触发(BEFORE、AFTER、INSTEAD OF)。 action_reference_old_table information_schema.sql_identifier 无实际意义,取值为空。 action_reference_new_table information_schema.sql_identifier 无实际意义,取值为空。 action_reference_old_row information_schema.sql_identifier 无实际意义,取值为空。 action_reference_new_row information_schema.sql_identifier 无实际意义,取值为空。 created information_schema.time_stamp 无实际意义,取值为空。 INFORMATION_SCHEMA.TRIGGERS视图只显示事件类型为INSERT、UPDATE、DELETE的触发器,不显示事件类型为TRUNCATE的触发器。 父主题: Information Schema
  • 示例 -- 创建包头包体。 CREATE OR REPLACE PACKAGE pkg_1 AS var1 int; var2 int; PROCEDURE proc1; END pkg_1; / CREATE PACKAGE CREATE OR REPLACE PACKAGE BODY pkg_1 AS PROCEDURE proc1 AS BEGIN var1 := var1 + var2; END; END pkg_1; / CREATE PACKAGE BODY -- 重新创建包头。 CREATE OR REPLACE PACKAGE pkg_1 AS var1 int; var2 int; var3 int; PROCEDURE proc1; END pkg_1; / CREATE PACKAGE -- 查询状态,包体定义未被删除。 SELECT * FROM gs_package WHERE pkgname='pkg_1'; pkgnamespace | pkgowner | pkgname | pkgspecsrc | pkgbodydeclsrc | pkgbodyinitsrc | pkgacl | pkgsecdef --------------+----------+---------+--------------------+----------------------+----------------+--------+----------- 2200 | 10 | pkg_1 | PACKAGE DECLARE +| PACKAGE DECLARE +| | | f | | | var1 int; +| procedure proc1 as +| | | | | | var2 int; +| begin +| | | | | | var3 int; +| var1 := var1 + var2;+| | | | | | procedure proc1; +| end; +| | | | | | end | end | | | (1 row) -- 包体对象被置为无效。 SELECT * FROM pg_object WHERE object_oid = (SELECT oid FROM gs_package WHERE pkgname='pkg_1'); object_oid | object_type | creator | ctime | mtime | createcsn | changecsn | valid ------------+-------------+---------+-------------------------------+-------------------------------+-----------+-----------+------- 171138 | B | 10 | 2024-12-31 16:50:29.923577+08 | 2025-01-17 15:56:42.271533+08 | | 183936 | f 171138 | S | 10 | 2024-12-24 16:09:29.527485+08 | 2025-01-17 15:56:42.271533+08 | | 183936 | t (2 rows) -- 删除已创建的对象。 DROP PACKAGE pkg_1; NOTICE: drop cascades to function public.proc1() DROP PACKAGE -- 包头包体定义被删除。 SELECT * FROM gs_package WHERE pkgname='pkg_1'; pkgnamespace | pkgowner | pkgname | pkgspecsrc | pkgbodydeclsrc | pkgbodyinitsrc | pkgacl | pkgsecdef --------------+----------+---------+------------+----------------+----------------+--------+----------- (0 rows) SELECT * FROM pg_object WHERE object_oid = (SELECT oid FROM gs_package WHERE pkgname='pkg_1'); object_oid | object_type | creator | ctime | mtime | createcsn | changecsn | valid ------------+-------------+---------+-------+-------+-----------+-----------+------- (0 rows)
  • 导出编码一致性处理原则 当客户端编码(client_encoding)与服务端编码(server_encoding)一致时: 执行原生数据导出; 保证数据完整性和原始性; 无需进行字符集转换。 当客户端编码(client_encoding)与服务端编码(server_encoding)不一致时: 采用客户端编码作为导出文件目标编码标准; 内核中对已有数据先基于服务端编码进行编码合法性校验,存在非法编码的数据会进行报错; 内核再将数据进行转码处理,对无法转码(源字符集存在码位,目标字符集不存在码位)的字符进行报错。
  • 非法编码处理方案 当用户的数据库中存在非法编码入库的数据,想要导出时不进行报错,推荐以下两种方案。 首选方案:保持客户端编码与服务端编码保持一致后,将数据以数据库服务端编码进行导出,不进行转码。 查询数据库服务端编码 gaussdb=# show server_encoding; 查询数据库客户端编码 gaussdb=# show client_encoding; 设置客户端编码与服务端编码一致 gaussdb=# set client_encoding = '{server_encoding}'; 执行COPY将数据以标准的 CS V格式导出到文件中 gaussdb=# COPY test_copy TO '/data/test_copy.csv' CSV; 次选方案:需要依赖数据库内核的转码能力,并对非法编码的字节通过占位符('?')进行替换,导出的数据内容会发生变化。 查询数据库服务端编码。 gaussdb=# show server_encoding; 设置数据库客户端编码为目标编码。 gaussdb=# set client_encoding = {target_encoding}; 依赖内核转码能力进行导出,将非法编码的字节进行替换。 gaussdb=# COPY test_copy TO '/data/test_copy.csv' CSV COMPATIBLE_ILLEGAL_CHARS;
  • 典型场景使用示例 针对独立零字符的基础处理逻辑相对简单,本文重点展示复合型异常场景的解决方案,即数据流中同时存在零字符(\0)与非法编码字符的容错处理过程: 构造UTF8的零字符与非法字符数据。 gaussdb=# create database db_utf8 encoding='UTF-8' LC_COLLATE='en_US.UTF-8' LC_CTYPE ='en_US.UTF-8' dbcompatibility = 'A'; CREATE DATABASE gaussdb=# \c db_utf8 Non-SSL connection (SSL connection is recommended when requiring high-security) You are now connected to database "db_utf8" as user "omm". db_utf8=# create table test_encodings(id int, content text); CREATE TABLE db_utf8=# insert into test_encodings values(1, dbe_raw.cast_to_varchar2(dbe_raw.concat(dbe_raw.cast_from_varchar2_to_raw('导入'), hextoraw('00'), dbe_raw.cast_from_varchar2_to_raw('导出')))); INSERT 0 1 db_utf8=# insert into test_encodings values(2, dbe_raw.cast_to_varchar2(dbe_raw.concat(hextoraw('2297'), dbe_raw.cast_from_varchar2_to_raw('导入导出')))); INSERT 0 1 db_utf8=# show client_encoding; client_encoding ----------------- UTF8 (1 row) --在id为1的行中,content包含零字符;在id为2的行中,content含有不属于UTF-8字符集的字符。 db_utf8=# select *, dbe_raw.cast_from_varchar2_to_raw(content) from test_encodings; id | content | cast_from_varchar2_to_raw ----+-----------+------------------------------ 1 | 导入 | E5AFBCE585A500E5AFBCE587BA 2 | "导入导出 | 2297E5AFBCE585A5E5AFBCE587BA (2 rows) 在导出文件时,若选择与服务端相同的字符集,无需进行转码操作,文件默认能够顺利导出。然而,当选择与服务端不同的字符集时,则需要进行转码处理。在转码过程中,一旦识别到UTF-8编码中的非法字符0x97,系统将报错。此时,只需开启compatible_illegal_chars参数,文件便可成功导出。 db_utf8=# copy test_encodings to '/home/xy/encodings.txt.utf8' encoding 'utf-8'; COPY 2 db_utf8=# copy test_encodings to '/home/xy/encodings.txt.gb18030' encoding 'gb18030'; ERROR: invalid byte sequence for encoding "UTF8": 0x97 db_utf8=# copy test_encodings to '/home/xy/encodings.txt.gb18030' encoding 'gb18030' compatible_illegal_chars; COPY 2 使用UTF-8编码打开文件/home/xy/encodings.txt.utf8,当前示例未针对A进行兼容处理,且未开启support_zero_character选项和compatible_illegal_chars参数。以下结果显示:第一行第二列的数据被截断;第二行第二列存在乱码,虽然在显示上未呈现明显异常,但通过hexdump命令可查看出乱码数据。用户可参考此示例进行复现操作,具体数据在此不再详述。 1 导入 2 "导入导出 使用gb18030编码打开文件/home/xy/encodings.txt.gb18030,以下结果表明:文件中第一行第二列的零字符被替换为空格;第二行第二列的非法字符被替换为“?”。 1 导入 导出 2 "?导入导出
  • 问题规避 如果发现AUTOVACUUM清理死行过慢,跟不上业务死行生成的速度,导致死行持续堆积,则需要人工介入处理,具体策略如下: 调整AUTOVACUUM参数:在系统I/O资源充足的情况下,可以通过减小autovacuum_vacuum_cost_delay来加快VACUUM的清理速度。该参数默认值为20ms,即扫描约20-50个页面时会触发一次强制睡眠,每次睡眠时间为20ms。建议将该参数调整为1ms,以极大地提高后台线程的清理效率。 手动执行VACUUM:如果调整参数后仍无法立即回收死行,可以通过视图获取死行较多的数据表,并对这些表进行手动VACUUM。手动VACUUM不使用I/O管控,会以最大效率清理死行,从而快速减少死行数量。
  • 算子说明 MergeAppend用于多个有序关系集合的追加,操作类似于Append,只是通过归并的方式对有序关系的集合进行加速运算。MergeAppend以保留排序顺序的方式对子查询结果进行组合,可用于组合表分区中已排序的行。因此,与普通Append不同,MergeAppend在执行操作之前需要确保输入的m_plan 是有序的。通常,在MergeAppend操作之前(即执行计划的子树中)会出现排序算子Sort。
  • 功能描述 GaussDB当前已有慢查询相关视图,并具备了SPM的基础能力。然而,当发生计划跳变时,无法对非慢查询的执行计划进行历史记录。因此,本特性在基于SPM的基础上,对历史执行计划进行记录,以提升SPM的易用性。由于SPM当前仅支持Generic-Plan,因此本功能所管理的计划类型限定在Generic-Plan。 当前计划跳变存在两种主要情况: 优化器对相同查询产生了不同的执行计划,并最终选用了新的计划。 每次执行时,优化器在历史已有的计划中切换。 这两种事件,均被称为跳变事件。 由于本特性涉及对计划跳变的快速感知和快速恢复两部分,以下将分别进行简明介绍。 快速感知 如果要实现全量的计划跳变历史记录,最直接的方法是记录每次执行计划与上一次的不同。这种方法会带来极大的性能开销。因此,出于性能和资源的考虑,本特性在以下两种场景进行跳变事件记录: 当优化器产生了SPM的baseline中不存在的新的计划。 当优化器产生了SPM的baseline中存在的,但超过一段时间未执行的老计划。 具体的执行流程,如图1所示。 图1 计划跳变支持快速感知流程图 此特性需要保证GUC参数spm_enable_plan_capture设置为STORE模式,且打开跳变历史记录开关spm_enable_plan_history_logging。 从图1可知,除了以下情况,均会对因产生新计划导致的跳变事件进行记录。 场景一:如果当前所捕获的基线个数已经超出上限 (spm_plan_capture_max_plannum),则查看当前计划是否是SPM所捕获过的查询的新计划。当前spm_enable_plan_history_logging打开并且历史记录数未超过上限,则进行额外的基线捕获,并进行历史记录。 场景二:如果当前所记录的跳变事件个数已经超出上限 (spm_plan_capture_max_plannum),则不进行历史记录。 为了确保在长期运行中能够记录更多的跳变历史,SPM会设置定时任务,在数据库启动起的每24小时触发一次历史记录清理,其校验准则是查看当前的历史记录数占最大上限的百分比,若超出此百分比,则会删除一些最旧的历史记录以保证记录数在此百分比要求之下,此百分比由spm_plan_history_reserved_percentage设置。 快速恢复 当发生计划跳变时,可以通过设置历史时间点的某条计划相应的baseline状态为ACC/FIXED,再结合计划选择功能spm_enable_plan_selection,即可实现回退至历史计划完成计划固化,也即完成快速回退。
  • 最佳实践 通常建议在业务低谷期打开spm_enable_plan_capture为STORE进行计划捕获,在批量执行业务完成后,打开历史记录开关spm_enable_plan_history_logging进行跳变历史记录。 在发生计划跳变时,可参考如下步骤操作。 获取unique_sql_id,比如通过statement_history查询。 gaussdb=# SELECT unique_query_id FROM DBE_PERF.statement_history; 根据unique_sql_id从PG_CATA LOG .GS_SPM_ID_HASH_JOIN中查出sql_hash。 gaussdb=# SELECT sql_hash FROM PG_CATALOG.gs_spm_id_hash_join WHERE unique_sql_id = $unique_query_id; 根据sql_hash和发生跳变的历史时间,利用系统函数(DBE_SQL_UTIL.GS_SPM_GET_PLAN_HISTORY)/视图(PG_CATALOG.GS_SPM_PLAN_HISTORY_DETAIL) /系统表(PG_CATALOG.GS_SPM_PLAN_HISTORY)中查出跳变历史。 gaussdb=# SELECT * FROM pg_catalog.gs_spm_plan_history WHERE sql_hash = $sql_hash; 锁定发生跳变的计划后,找出其plan_hash,并利用系统函数(DBE_SQL_UTIL.GS_SPM_ACCEPT_HISTORICAL_PLAN)接受指定时间的历史计划,或者直接使用系统函数(DBE_SQL_UTIL.GS_SPM_SET_PLAN_STATUS)来完成对应基线状态的设置,可设置为ACC/FIXED。 gaussdb=# SELECT dbe_sql_util.gs_spm_accept_historical_plan($sql_hash, $given_time, 'ACC'); 打开spm_enable_plan_selection完成计划快速回退。 gaussdb=# SET spm_enable_plan_selection = ON; 本特性仅支持Generic Plan。 与本特性相关的GUC参数有spm_enable_plan_history_logging,spm_enable_plan_history_logging_expired_time和spm_plan_history_reserved_percentage。 由于gs_spm_plan_history可写入记录数存在上限,因此新增GUC参数spm_plan_history_reserved_percentage用于指定gs_spm_plan_history可被占用的百分比。 快速感知和快速回退要求必须设置spm_enable_plan_capture = STORE 且 spm_enable_plan_history_logging = on。 该特性旨在解决当生成新计划时导致的计划跳变,对于智能优化器从现存的多个计划中进行最佳计划选择导致的计划变化,若未超出过期时间,则不属于新计划产生导致的计划跳变,不属于特性支持范围。
  • WDR Snapshot Schema WDR Snapshot在启动后(打开GUC参数enable_wdr_snapshot),会在用户表空间"pg_default",数据库"postgres"下的Snapshot Schema中创建对象,用于持久化WDR快照数据。默认初始化用户或monadmin用户可以访问和操作Snapshot Schema下的对象。 根据GUC参数wdr_snapshot_retention_days来自动管理快照的生命周期。 用户应该禁止对Snapshot Schema下的表进行增删改等操作,人为对这些表的修改或破坏可能会导致WDR各种异常情况甚至WDR不可用。 WDR Snapshot原信息 WDR Snapshot 数据表 父主题: Schema
  • 算子说明 在GaussDB中,Foreign Scan是一种用于访问外部数据源的扫描器。它可以将外部数据源中的数据作为关系型数据库中的表来处理,从而实现对外部数据源的查询和操作。在GaussDB中,Foreign Scan可以通过扩展API来实现。用户可以编写自己的扩展程序,以实现对外部数据源的访问和操作。同时,GaussDB还提供了一些常用的扩展程序,如FDW(Foreign Data Wrapper),可以用于访问其他关系型数据库中的数据。
  • 示例 数据准备。 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 gaussdb=# create database db1 encoding='UTF-8' LC_COLLATE='en_US.UTF-8' LC_CTYPE ='en_US.UTF-8' dbcompatibility = 'A'; CREATE DATABASE gaussdb=# \c db1 Non-SSL connection (SSL connection is recommended when requiring high-security) You are now connected to database "db1" as user "omm". db1=# CREATE TABLE test_copy(id int, name text); CREATE TABLE db1=# insert into test_copy values(1, 'aaa'); INSERT 0 1 db1=# insert into test_copy values(3, e'cc\tc'); INSERT 0 1 db1=# insert into test_copy(name) values('ddd'); INSERT 0 1 db1=# insert into test_copy values(5, e'ee\\e'); INSERT 0 1 db1=# insert into test_copy values(6, ','); INSERT 0 1 db1=# insert into test_copy values(7, '"'); INSERT 0 1 db1=# SELECT * FROM test_copy; id | name ----+----------- 1 | aaa 3 | cc c | ddd 5 | ee\e 6 | , 7 | " (6 rows) 数据导出。 1 2 3 4 db1=# set client_encoding = 'UTF-8'; SET db1=# COPY test_copy TO '/home/xy/test.bin' BINARY; COPY 6 数据导入。 db1=# truncate test_copy; TRUNCATE TABLE db1=# set client_encoding = 'UTF-8'; SET db1=# copy test_copy from '/home/xy/test.bin' BINARY; COPY 6
  • PG_AUTOVAC_STATUS 通过该函数查看某表是否达到了AUTOVACUUM阈值,通常需要关注返回结果中的doanalyze和dovacuum两个值。视图各字段定义如下: 表1 PG_AUTOVAC_STATUS字段 名称 类型 描述 nspname text 名称空间名称。 relname text 表、索引、视图等对象名称。 nodename text 节点名称。 doanalyze Boolean 是否执行analyze。 anltuples bigint analyze tuple数量。 anlthresh bigint analyze阈值。 dovacuum Boolean 是否执行vacuum。 vactuples bigint vacuum tuple数量。 vacthresh bigint vacuum阈值。 执行结果如下: gaussdb=# select * from pg_autovac_status('t2'::regclass); nspname | relname | nodename | doanalyze | anltuples | anlthresh | dovacuum | vactuples | vacthresh ---------+---------+----------+-----------+-----------+-----------+----------+-----------+----------- public | t2 | sgnode | f | 0 | 2050 | t | 15002 | 4050 (1 row) 父主题: VACUUM
  • 如何定位数据库死行等统计信息不准 可以使用ANALYZE命令来更新统计信息。如果在执行ANALYZE前后,死行数据差异较大,则表明统计信息不准确。需要注意的是,ANALYZE是通过采样进行统计的,因此存在一定的误差。当表中存在大量空页时,可能会影响统计信息收集的采样准确性。在这种情况下,可以利用上文提到的gs_parse_page_bypath工具增加采样率,以更准确地解析页面并计算死行。 父主题: 常见问题
  • 算子说明 嵌套循环连接(Nested Loop Join)是最简单的连接方法,也是所有关系数据库系统中都会实现的连接操作。这种方法的基本思想是“把两个表中的数据两两比较,看是否满足连接条件”。 在GaussDB中,Nested Loop Join的工作原理是,对于外部表(Outer Table)中的每一行,扫描内部表(Inner Table),查找符合连接条件的行。这类似于两个嵌套的循环,外部循环遍历外部表,内部循环遍历内部表,因此得名 。 Nested Loop Join的时间复杂度是O(n*m), 其中n和m分别代表两个表的行数,如果内部表可以用索引来扫描,那么时间复杂度可以降低到O(nlogm)。
  • 算子说明 层次查询算子,用于执行递归查询操作。层次查询的执行流程是: 由START WITH区域的条件选择初始的数据集,把初始的数据集设为工作集。 只要工作集不为空,会用工作集的数据作为输入,查询下一轮的数据,过滤条件由CONNECT BY区域指定。其中,PRIOR关键字表示当前记录。 把步骤2中筛选出来的数据集,设为工作集,返回第二步重复操作。 同时,数据库为每一条选出来的数据添加下述的伪列,方便用户了解数据在递归或者树状结构中的位置。可以根据CONNECT BY中的条件,建立对应的索引,来提高START WITH语句的性能。
  • GaussDB导出并导入到GaussDB场景 建议导出命令: 1 2 3 copy {data_source} to '/path/export.txt' eol e'\n' delimiter e'\t' encoding '{server_encoding}'; --data_source 可以是一个表名称,也可以是一个select语句 --server_encoding 可以通过show server_encoding获得 对应导入命令: 1 2 3 copy {data_destination} from '/path/export.txt' eol e'\n' delimiter e'\t' encoding '{file_encoding}'; --data_destination 只能是一个表名称 --file_encoding 为该二进制文件导出时指定的编码格式
  • GaussDB导出之后自行解析数据文件的场景 该场景下一般不希望导出的TEXT文件中有GaussDB独有的转义行为,此时需要按如下方式进行处理: 首先确认字段数据中是否存在行结束符或分隔符; 如果包含,需要使用EOL或delimiter参数改用其他字符。需要确保指定的新EOL或delimiter不会在字段数据中存在,建议从不可见字符(0x01 ~ 0x1F)中选取; 可以通过NULL选项指定对数据中的NULL值在导出时的表示方法。 最后添加without escaping参数,禁止转义输出。 建议导出命令: 1 2 3 copy {data_source} to '/path/export.txt' without escaping eol e'\x1E' delimiter e'\x1F' null '\N' encoding '{server_encoding}'; --data_source 可以是一个表名称,也可以是一个select语句 --server_encoding 可以通过show server_encoding获得
共100000条
提示

您即将访问非华为云网站,请注意账号财产安全