华为云用户手册

  • 场景10:小文件多IOPS高 某业务执行过程中,整个集群IOPS飙高,另外当出现集群故障后,长期Building不成功,IOPS飙高,相关表信息如下: SELECT relname,reloptions,partcount FROM pg_class c INNER JOIN ( SELECT parentid,count(*) AS partcount FROM pg_partition GROUP BY parentid ) s ON c.oid = s.parentid ORDER BY partcount DESC; 触发因素:某业务库大量列存多分区(3000+)的表,导致小文件巨多(单DN文件2000w+),访问效率低,故障恢复Building极慢,同时Building也消耗大量IOPS,反向影响业务性能。 解决办法: 整改列存分区间隔,减少分区个数来降低文件个数。 列存表修改为行存表,行存的存储特征决定其文件个数不会像列存般膨胀严重。
  • 场景8:大量数据带索引导入 某业务场景数据往DWS同步时,延迟严重,集群整体IO压力大。 后台查看等待视图有大量wait wal sync和WALWriteLock状态,均为xlog同步状态。 触发因素:大量数据带索引(一般超过3个)导入(insert/copy/merge into)会产生大量xlog,导致主备同步慢,备机长期Catchup,整体IO利用率飙高。历史案例参考:实例长期处于catchup问题分析。 解决方案: 严格控制每张表的索引个数,建议3个以内。 大量数据导入前先将索引删除,导入完成后再重新建索引。
  • 场景9:行存大表首次查询 某业务场景出现备DN持续catchup,IO压力大,观察某个SQL等待视图在wait wal sync。 排查业务发现某查询语句执行时间较长,执行kill命令后恢复。 触发因素:行存表大量数据入库后,首次查询触发page hint产生大量XLOG,触发主备同步慢及大量IO消耗。 解决措施: 对该类一次性访问大量新数据的场景,修改行存表为列存表。 可关闭wal_log_hints和enable_crc_check参数(不推荐该方式,因故障期间有数据丢失风险)。
  • 场景1:列存小CU膨胀 某业务SQL查询出390871条数据需43248ms,分析计划主要耗时在Cstore Scan。 Cstore Scan的详细信息中,每个DN扫描出2w左右的数据,但是扫描了有数据的CU(CUSome)155079个,没有数据的CU(CUNone)156375个,说明当前小CU、未命中数据的CU极多,即CU膨胀严重。 触发因素:对列存表(尤其是分区表)进行高频小批量导入会造成CU膨胀。 处理方法 列存表的数据入库方式修改为攒批入库,单分区单批次入库数据量需大于DN个数*6W。 如果因业务原因无法攒批入库,则需定期VACUUM FULL此类高频小批量导入的列存表。 当小CU膨胀很快时,频繁VACUUM FULL也会消耗大量IO,甚至加剧整个系统的IO瓶颈,此场景建议修改列存表为行存表(CU长期膨胀严重的情况下,列存的存储空间优势和顺序扫描性能优势将不复存在)。
  • 场景2:脏数据&数据清理 某业务SQL总执行时间2.519s,其中Scan占了2.516s,同时该表的扫描最终只扫描到0条符合条件数据,过滤了20480条数据,即总共扫描了20480+0条数据却消耗了2s+,扫描时间与扫描数据量严重不符,此现象可判断为由于脏数据多从而影响扫描和IO效率。 查看表脏页率为99%,VACUUM FULL后性能优化到100ms左右。 触发因素:表频繁执行UPDATE/DELETE导致脏数据过多,且长时间未VACUUM FULL清理。 处理方法 对频繁UPDATE/DELETE产生脏数据的表,定期VACUUM FULL,因大表的VACUUM FULL也会消耗大量IO,因此需要在业务低峰时执行,避免加剧业务高峰期IO压力。 当脏数据产生很快,频繁VACUUM FULL也会消耗大量IO,甚至加剧整个系统的IO瓶颈,这时需要考虑脏数据的产生是否合理。针对频繁DELETE的场景,可以考虑如下方案: 全量DELETE修改为TRUNCATE或者使用临时表替代。 定期DELETE某时间段数据,使用分区表并使用TRUNCATE或DROP分区替代。
  • 原因分析 创建OBS外表语句中的访问密钥AK和SK错误,会出现如下所示的错误信息: 1 ERROR: Fail to connect OBS in node:cn_5001 with error code: AccessDenied 账户OBS权限不足,对OBS桶没有读、写权限,会出现如下所示的错误信息: 1 dn_6001_6002: Datanode 'dn_6001_6002' fail to read OBS object bucket:'obs-bucket-name' key:'xxx/xxx/xxx.csv' with OBS error code:AccessDenied message: Access Denied 默认情况下,您不具备访问其他账号的OBS数据的权限,此外,IAM用户(相当于子用户)也不具备访问其所属账号的OBS数据的权限。
  • 处理方法 创建OBS外表语句中的访问密钥AK和SK错误 请获取正确的访问密钥AK和SK,写入创建OBS外表的SQL语句中。获取访问密钥的步骤如下: 登录GaussDB(DWS)管理控制台。 将鼠标移至右上角的用户名,单击“我的凭证”。 进入“我的凭证”后,在左侧导航树单击“访问密钥”。 在访问密钥页面,可以查看已有的访问密钥ID(即AK)。 如果要同时获取AK和SK,单击“新增访问密钥”创建并下载访问密钥。 账户OBS权限不足,对OBS桶没有读、写权限 您必须给指定的用户授予所需的OBS访问权限: 通过OBS外表导入数据到GaussDB(DWS)时,执行导入操作的用户必须具备数据源文件所在的OBS桶和对象的读取权限。 通过OBS外表导出数据时,执行导出操作的用户必须具备数据导出路径所在的OBS桶和对象的读取和写入权限。 有关配置OBS权限的具体操作,请参见《对象存储服务控制台指南》中的配置桶ACL和“配置对象ACL”章节。
  • 原因分析 GaussDB(DWS)支持Hash、REPLICATION和ROUNDROBIN(8.1.2集群及以上版本支持ROUNDROBIN)分布方式。如果创建了Hash分布的表,未指定分布键,则选择表的第一列作为分布键,这种情况就可能存在倾斜。倾斜造成以下负面影响: SQL的性能会非常差,因为数据只分布在部分DN,那么SQL运行的时候就只有部分DN参与计算,没有发挥分布式的优势。 会导致资源倾斜,尤其是磁盘。可能部分磁盘的空间已经接近极限,但是其他磁盘利用率很低。 可能出现部分节点CPU过高等问题。
  • 处理方法 数据库的兼容模式在CREATE DATABASE时由DBCOMPATIBILITY参数指定。 DBCOMPATIBILITY [ = ] compatibility_type 指定兼容的数据库的类型。 取值范围:ORA、TD、MySQL。分别表示兼容Oracle、Teradata和MySQL数据库。 若创建数据库时不指定该参数,默认为ORA。 为解决DATABASE的兼容性模式问题,需要将两个数据库的兼容模式修改为一致。GaussDB(DWS)不支持ALTER方式修改已有数据库的兼容模式DBCOMPATIBILITY,只能通过新建数据库的方式来指定兼容模式。 1 2 CREATE DATABASE td_db DBCOMPATIBILITY ='TD'; CREATE DATABASE GaussDB(DWS)不同兼容模式下Oracle、Teradata和MySQL语法行为会有一些差异,具体的差异内容可参考Oracle、Teradata和MySQL语法兼容性差异。
  • 原因分析 GaussDB(DWS)支持Oracle、Teradata和MySQL数据库兼容模式。 在TD/MySQL兼容模式下,空和NULL是不相等的,在ORA兼容模式下,空和NULL是相等的。因此上述场景可能是因为两个环境中数据库的兼容性模式设置不一致导致。 可通过查询PG_DATABASE系统表确认数据库的兼容模式: 1 SELECT datname, datcompatibility FROM pg_database;
  • 处理方法 可在GaussDB(DWS)管理控制台设置告警的触发条件,指定达到磁盘使用率、告警持续时间及告警频次。 集群磁盘使用率达到90%就会触发集群只读,需要预留时间来处理问题,避免使用率达到只读阈值。 登录GaussDB(DWS) 管理控制台。 在左侧导航栏,单击“告警管理”,切换至“告警”页签。 单击左上角的“查看告警规则”按钮,进入告警规则页面。 在指定告警规则名称所在行操作列,单击“修改”按钮进入修改告警规则页面。将触发条件修改为平均值大于90%,抑制条件修改为“每1天告警一次”。(此处仅做举例,实际情况以业务诉求为准。) 触发条件:定义对监控指标做阈值判断的计算规则。目前主要使用一段时间内的平均值来降低告警震荡的几率。 抑制条件:在指定的时间段内,抑制同类型告警的反复触发和消除。 图1 设置告警规则
  • 处理方法 方法一:分布键目前暂不支持更新,直接跳过该报错。 方法二:将分布列修改为一个不会更新的列(8.1.0版本后,支持调整分布列,以下为示例)。 查询当前表定义,返回结果显示该表分布列为c_last_name。 1 SELECT pg_get_tabledef('customer_t1'); 更新分布列中的数据时报错。 1 UPDATE customer_t1 SET c_last_name = 'Jimy' WHERE c_customer_sk = 6885; 将该表的分布列修改为不会更新的列,例如c_customer_sk。 1 ALTER TABLE customer_t1 DISTRIBUTE BY hash (c_customer_sk); 重新执行更新旧的分布列的数据。更新成功。 1 UPDATE customer_t1 SET c_last_name = 'Jimy' WHERE c_customer_sk = 6885;
  • 原因分析 日志中的“Lock wait timeout”说明锁等待超时。锁等待超时一般是因为有其他的SQL语句已经持有了锁,当前SQL语句需要等待持有锁的SQL语句执行完毕释放锁之后才能执行。当申请的锁等待时间超过GUC参数lockwait_timeout的设定值时,系统会报LOCK_WAIT_TIMEOUT的错误。 执行VACUUM FULL命令时出现报错的原因一般为执行命令超时,如果对整个数据库执行VACUUM FULL执行时间较长可能会超时。
  • 问题现象 DROP TABLE失败的两种现象: 在使用“SELECT * FROM DBA_TABLES;”语句(或者gsql客户端也可以使用\dt+命令)查看数据库中无相关表;CREATE TABLE时报该表已经存在的错误,使用DROP TABLE语句失败,报不存在该表的错误,导致无法再次创建表。 在使用“SELECT * FROM DBA_TABLES;”语句(或者gsql客户端也可以使用\dt+命令)查看数据库中有相关表;使用DROP TABLE时失败,报不存在该表的错误,导致无法再次创建表。
  • 处理方法 方法一:更改某个GaussDB(DWS)集群的数据库默认时区。 登录GaussDB(DWS)管理控制台。 在左侧导航栏中,单击“集群管理”。 在集群列表中找到所需要的集群,单击集群名称,进入集群“基本信息”页面。 单击“参数修改”页签,修改参数“timezone”,修改为您所在的时区,然后单击“保存”。 在“修改预览”窗口,确认修改无误后,单击“保存”。 用户可根据界面中参数“timezone”所在行的“是否重启”列,判断修改参数后无需进行重启操作。 修改“timezone”参数后无需重启集群操作 ,则修改后立即生效。 方法二:通过后台命令查询和更改数据库时区。 查询客户端时区和当前时间。其中客户端时区为UTC时区,now()函数返回当前时间。 1 2 3 4 5 6 7 8 9 10 11 SHOW time zone; TimeZone ---------- UTC (1 row) select now(); now ------------------------------- 2022-05-16 06:05:58.711454+00 (1 row) 创建数据表,其中timestamp、timestamptz是常用的时间类型。timestamp不保存时区,timestamptz保存时区。 1 2 3 4 5 6 7 8 9 CREATE TABLE timezone_test (id int, t1 timestamp, t2 timestamptz) DISTRIBUTE BY HASH (id); \d timezone_test Table "public.timezone_test" Column | Type | Modifiers --------+-----------------------------+----------- id | integer | t1 | timestamp without time zone | t2 | timestamp with time zone | 向timezone_test表插入当前时间并查询当前表。 1 2 3 4 5 6 7 8 9 10 11 12 INSERT INTO timezone_test values (1, now(), now() ); show time zone; TimeZone ---------- UTC (1 row) SELECT * FROM timezone_test; id | t1 | t2 ----+----------------------------+------------------------------- 1 | 2022-05-16 06:10:04.564599 | 2022-05-16 06:10:04.564599+00 (1 row) t1(timestamp类型)在保存数据时丢弃了时区信息,t2(timestamptz类型)保存了时区信息。 把客户端时区设置为东8区(UTC-8),再次查询timezone_test表。 1 2 3 4 5 6 7 8 9 10 11 12 SET time zone 'UTC-8'; SHOW time zone; TimeZone ---------- UTC-8 (1 row) SELECT now(); now ------------------------------- 2022-05-16 14:13:43.175416+08 (1 row) 继续插入当前时间到timezone_test表,并查询。此时t1新插入的值是用的东8区时间,t2根据客户端时区对查询结果进行转换。 1 2 3 4 5 6 7 INSERT INTO timezone_test values (2, now(), now() ); SELECT * FROM timezone_test; id | t1 | t2 ----+----------------------------+------------------------------- 1 | 2022-05-16 06:10:04.564599 | 2022-05-16 14:10:04.564599+08 2 | 2022-05-16 14:15:03.715265 | 2022-05-16 14:15:03.715265+08 (2 rows) timestamp类型只受数据在插入时的时区影响,查询结果不受客户端时区影响。 timestamptz类型在数据插入时记录了时区信息,查询时会根据客户端时区做转换,以客户端时区显示数据。
  • 问题现象 查看日志提示: [ERROR] Mpp task queryDataAnalyseById or updateDataAnalyseHistoryEndTimesAndResult fail, dataAnalyseId:17615 org.postgresql.util.PSQLException: ERROR: memory is temporarily unavailable sql:vacuum full dws_customer_360.t_user_resource;
  • 操作场景 在日常作业开发中,数据库事务管理中的锁一般指的是表级锁,GaussDB(DWS)中支持的锁模式有8种,按排他级别分别为1~8。每种锁模式都有与之相冲突的锁模式,由锁冲突表定义相关的信息,锁冲突表如表1所示。 举例:用户u1对某张表test执行INSERT事务时,此时持有RowExclusiveLock锁;此时用户u2也对test表进行VACUUM FULL事务,则该事务与INSERT事务产生锁冲突,处于锁等待状态。 常用的锁等待检测主要通过查询视图pgxc_lock_conflicts、pgxc_stat_activity、pgxc_thread_wait_status、pg_locks进行。其中pgxc_lock_conflicts视图在8.1.x版本后支持,根据集群版本号不同,检测方式不同。
  • 操作步骤 构造锁等待场景: 打开一个新的连接会话,使用普通用户u1连接GaussDB(DWS)数据库,在自己的同名SCHEMA u1下创建测试表u1.test。 1 CREATE TABLE test (id int, name varchar(50)); 开启事务1,进行INSERT操作。 1 2 START TRANSACTION; INSERT INTO test VALUES (1, 'lily'); 打开一个新的连接会话,使用系统管理员dbadmin连接GaussDB(DWS)数据库,执行VACUUM FULL操作,发现语句阻塞。 1 VACUUM FULL u1.test; 锁等待检测(8.1.x及以上版本) 打开一个新的连接会话,使用系统管理员dbadmin连接GaussDB(DWS)数据库,通过pgxc_lock_conflicts视图查看锁冲突情况。 如下图,回显中查看granted字段为“f”,表示VACUUM FULL语句正在等待其他锁。granted字段为“t”,表示INSERT语句是持有锁。nodename,表示锁产生在的位置,即CN或DN位置,例如cn_5001。 1 SELECT * FROM pgxc_lock_conflicts; 据语句内容确认是否中止持锁语句。如果终止,则执行以下语句。pid从1获取,cn_5001为上面查询到的nodename。 1 execute direct on (cn_5001) 'SELECT PG_TERMINATE_BACKEND(pid)'; 锁等待检测(8.0.x及以前版本) 在数据库中执行以下语句,获取VACUUM FULL操作对应的query_id。 1 SELECT * FROM pgxc_stat_activity WHERE query LIKE '%vacuum%'AND waiting = 't'; 根据获取的query_id,执行以下语句查看是否存在锁等待,并获取对应的tid。其中,{query_id}从1获取。 1 SELECT * FROM pgxc_thread_wait_status WHERE query_id = {query_id}; 回显中“wait_status”存在“acquire lock”表示存在锁等待。同时查看“node_name”显示在对应的CN或DN上存在锁等待,记录相应的CN或DN名称,例如cn_5001或dn_600x_600y。 执行以下语句,到等锁的对应CN或DN上通过查询pg_locks系统表查看VACUUM FULL操作在等待哪个锁。以下以cn_5001为例,如果在DN上等锁,则改为相应的DN名称。pid为2获取的tid。 回显中记录relation的值。 1 execute direct on (cn_5001) 'SELECT * FROM pg_locks WHERE pid = {tid} AND granted = ''f'''; 根据获取的relation,通过查询pg_locks系统表查看当前持有锁的pid。{relation}从3获取。 1 execute direct on (cn_5001) 'SELECT * FROM pg_locks WHERE relation = {relation} AND granted = ''t'''; 根据pid,执行以下语句,查到对应的SQL语句。{pid}从4获取。 1 execute direct on (cn_5001) 'SELECT query FROM pg_stat_activity WHERE pid={pid}'; 根据语句内容确认是中止持锁语句还是待持锁语句结束再重新执行VACUUM FULL。如果终止,则执行以下语句。pid从4获取。 中止结束后,再尝试重新执行VACUUM FULL。 1 execute direct on (cn_5001) 'SELECT PG_TERMINATE_BACKEND(pid)';
  • 处理方法 方法一:检查数据冲突,修改插入数据。例如,修改示例重复字段UA502为UA509。 1 2 INSERT INTO films VALUES ('UA509', 'Bananas', 105, '1971-07-13', 'Comedy', '82 minutes'); INSERT 0 1 方法二:删除表films主键约束。 1 2 3 4 ALTER TABLE films DROP CONSTRAINT films_pkey; ALTER TABLE INSERT INTO films VALUES ('UA502', 'Bananas', 105, '1971-07-13', 'Comedy', '82 minutes'); INSERT 0 1
  • 问题现象 向表中插入数据报错:duplicate key value violates unique constraint "%s"。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 CREATE TABLE films ( code char(5) PRIMARY KEY, title varchar(40) NOT NULL, did integer NOT NULL, date_prod date, kind varchar(10), len interval hour to minute ); NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "films_pkey" for table "films" CREATE TABLE INSERT INTO films VALUES ('UA502', 'Bananas', 105, DEFAULT, 'Comedy', '82 minutes'); INSERT INTO films VALUES ('UA502', 'Bananas', 105, '1971-07-13', 'Comedy', '82 minutes'); ERROR: dn_6003_6004: duplicate key value violates unique constraint "films_pkey" DETAIL: Key (code)=(UA502) already exists.
  • 处理方法 这两种行为由参数behavior_compat_options控制,当参数behavior_compat_options缺省的情况下,匹配到多行会报错,如果behavior_compat_options设置了merge_update_multi参数项,这种情况下不会报错,而是会随机匹配一行数据。 因此,当出现MERGE INTO的结果与预期不符时,需查看该参数是否被设置,同时排查是否匹配了多行数据,并修改业务逻辑。
  • 原因分析 增加分区时需同时满足以下条件: 新增分区名不能与已有分区名相同。 新增分区的边界值必须大于最后一个分区的上边界。 新增分区的边界值要和分区表的分区键的类型一致。 已有分区p1的边界为(-∞,20221010),而新增分区p0的上边界为20221009,落在分区p1内;已有分区p4的边界为[20221012,+∞),而新增分区p5的上界为20221013,落在分区p4内。新增分区p0、p5不满足使用ADD PARTITION增加分区的条件,因此执行新增分区语句报错。
  • 处理方法 使用ALTER TABLE SPLIT PARTITION分割已有分区,也能达到新增分区的目的。同样, SPLIT PARTITION的新分区名称也不能与已有分区相同。 使用split子句分割p4分区[20221012,+∞)为p4a分区范围为[20221012,20221013)和p4b分区范围为[20221013,+∞)。 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 ——SPLIT PARTITION分割前的分区 SELECT relname, boundaries FROM pg_partition p where p.parentid='studentinfo'::regclass ORDER BY 1; relname | boundaries -------------+------------------------- p1 | {"2022-10-10 00:00:00"} p2 | {"2022-10-11 00:00:00"} p3 | {"2022-10-12 00:00:00"} p4 | {NULL} studentinfo | (5 rows) ALTER TABLE studentinfo SPLIT PARTITION p1 AT('2022-10-09 00:00:00+08') INTO (PARTITION P1a,PARTITION P1b); ALTER TABLE studentinfo SPLIT PARTITION p4 AT('2022-10-13 00:00:00+08') INTO (PARTITION P4a,PARTITION P4b); ——执行SPLIT PARTITION分割后的分区 SELECT relname, boundaries FROM pg_partition p where p.parentid='studentinfo'::regclass ORDER BY 1; relname | boundaries -------------+------------------------- p1a | {"2022-10-09 00:00:00"} p1b | {"2022-10-10 00:00:00"} p2 | {"2022-10-11 00:00:00"} p3 | {"2022-10-12 00:00:00"} p4a | {"2022-10-13 00:00:00"} p4b | {NULL} studentinfo | (7 rows) 如果对分区名称有要求,可以在分割后再使用rename partition统一分区名。 ALTER TABLE studentinfo RENAME PARTITION p1a to p0;
  • 问题现象 创建范围分区表后增加新的分区,使用ALTER TABLE ADD PARTITION语句报错upper boundary of adding partition MUST overtop last existing partition。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 ——创建范围分区表studentinfo CREATE TABLE studentinfo (stuno smallint, sname varchar(20), score varchar(20), examate timestamp) PARTITION BY RANGE (examate) ( PARTITION p1 VALUES LESS THAN ('2022-10-10 00:00:00+08'), PARTITION p2 VALUES LESS THAN ('2022-10-11 00:00:00+08'), PARTITION p3 VALUES LESS THAN ('2022-10-12 00:00:00+08'), PARTITION p4 VALUES LESS THAN (maxvalue) ); ——添加边界值为2022-10-9 00:00:00+08的分区p0 ALTER TABLE studentinfo ADD PARTITION p0 values less than ('2022-10-9 00:00:00+08'); ERROR: the boundary of partition "p0" is less than previous partition's boundary ——添加边界值为2022-10-13 00:00:00+08的分区p5 ALTER TABLE studentinfo ADD PARTITION p5 values less than ('2022-10-13 00:00:00+08'); ERROR: the boundary of partition "p5" is equal to previous partition's boundary
  • 问题现象 数据库中新建一张表,某个表字段使用character类型,在Java中读取character类型的字段时返回类型是byte。 例如,创建示例表table01: 1 2 3 4 CREATE TABLE IF NOT EXISTS table01( msg_id character(36), msg character varying(50) ); 在Java中,读取character类型的字段代码如下: 1 ColumnMetaInfo(msg_id,1,Byte,true,false,1,true);
  • 问题现象 DWS中有两种情况需要关注表是否做过UPDATE及DELETE操作: 对表频繁执行UPDATE或者DELETE操作会产生大量的磁盘页面碎片,从而逐渐降低查询的效率,需要将磁盘页面碎片恢复并交还操作系统,即VACUUM FULL操作,这种场景下需要查找出哪些表执行过UPDATE; 判断一张表是否是维度表,是否可以从Hash表变更为复制表,可以查看这张表是否执行过UPDATE或DELETE,如果执行过UPDATE或DELETE操作,则不能修改为复制表。
  • 处理方法 通过以下命令查找哪些表执行过UPDATE及DELETE操作: 1 2 3 4 5 6 7 8 9 ANALYZE tablename; SELECT n.nspname , c.relname, pg_stat_get_tuples_deleted(x.pcrelid) as deleted, pg_stat_get_tuples_updated(x.pcrelid) as updated FROM pg_class c INNER JOIN pg_namespace n ON n.oid = c.relnamespace INNER JOIN pgxc_class x ON x.pcrelid = c.oid WHERE c.relkind = 'r' and c.relname='tablename' ;
  • 处理方法 删除该表索引信息。 1 DROP INDEX a_0317_index; 对该表索引进行重建。 1 CREATE INDEX a_0317_index on a_0317(a) local (partition p1_index, partition p2_inde); 查看表定义无报错。 1 2 3 4 5 6 7 8 9 10 11 12 13 \d+ a_0317 Table "public.a_0317" Column | Type | Modifiers | Storage | Stats target | Description --------+---------+-----------+---------+--------------+------------- a | integer | | plain | | Indexes: "a_0317_index" btree (a) LOCAL(PARTITION p1_index, PARTITION p2_inde) TABLESPACE pg_default Range partition by(a) Number of partition: 2 (View pg_partition to check each partition range.) Has OIDs: no Distribute By: HASH(a) Location Nodes: ALL DATANODES Options: orientation=row, compression=no
  • 问题复现 创建分区表a_0317,含p1,p2两个分区。 1 CREATE TABLE a_0317(a int) partition by range(a) (partition p1 values less than (4), partition p2 values less than (8)); 创建主表与分区索引。 1 CREATE INDEX a_0317_index on a_0317(a) local (partition p1_index, partition p2_inde); 查看分区表分区索引信息如下: 查看主表索引信息。 1 2 3 4 5 6 7 8 9 10 11 SELECT oid,* FROM pg_class where relname ='a_0317_index'; oid | relname | relnamespace | reltype | reloftype | relowner | relam | relfilenode | reltablespace | relpages | reltuples | relallvisible | reltoastrelid | reltoastidxid | reldeltarelid | reld eltaidx | relcudescrelid | relcudescidx | relhasindex | relisshared | relpersistence | relkind | relnatts | relchecks | relhasoids | relhaspkey | relhasrules | relhastriggers | relhassubclass | relcmprs | relhasclusterkey | relrowmovement | parttype | relfrozenxid | relacl | reloptions | relreplident | relfrozenxid64 --------+--------------+--------------+---------+-----------+----------+-------+-------------+---------------+----------+-----------+---------------+---------------+---------------+---------------+----- --------+----------------+--------------+-------------+-------------+----------------+---------+----------+-----------+------------+------------+-------------+----------------+----------------+--------- -+------------------+----------------+----------+--------------+--------+------------+--------------+---------------- 241487 | a_0317_index | 2200 | 0 | 0 | 16393 | 403 | 241487 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | f | f | p | i | 1 | 0 | f | f | f | f | f | 0 | f | f | p | 0 | | | n | 0 (1 row) 根据主表索引信息查看分区索引信息。 1 2 3 4 5 6 7 8 9 10 SELECT * FROM pg_partition where parentid= 241487; relname | parttype | parentid | rangenum | intervalnum | partstrategy | relfilenode | reltablespace | relpages | reltuples | relallvisible | reltoastrelid | reltoastidxid | indextblid | indisusable | reldeltarelid | reldeltaidx | relcudescrelid | relcudescidx | relfrozenxid | intspnum | partkey | intervaltablespace | interval | boundaries | transit | reloptions | relfrozenxid64 ----------+----------+----------+----------+-------------+--------------+-------------+---------------+----------+-----------+---------------+---------------+---------------+------------+-------------+- --------------+-------------+----------------+--------------+--------------+----------+---------+--------------------+----------+------------+---------+------------+---------------- p1_index | x | 241487 | 0 | 0 | n | 241488 | 0 | 0 | 0 | 0 | 0 | 0 | 241485 | t | 0 | 0 | 0 | 0 | 0 | | | | | | | | 0 p2_inde | x | 241487 | 0 | 0 | n | 241489 | 0 | 0 | 0 | 0 | 0 | 0 | 241486 | t | 0 | 0 | 0 | 0 | 0 | | | | | | | | 0 (2 rows) 连接CN开启读写事务,从pg_partition系统表删除p1分区的索引信息。 1 2 START TRANSACTION read write; DELETE from pg_partition where relname = 'p1_index'; 查看表定义报错与现场报错相同,问题复现: 1 2 \d+ a_0317 ERROR: The local index 700633 on the partition 700647 not exist.CONTEXT: referenced column: pg_get_indexdef
  • 解决办法 为防止出现分区间隙,需要将ADD PARTITION的START值前移。 以分区表partitiontest为例: 1 2 3 4 5 6 7 8 9 10 CREATE TABLE partitiontest ( c_int integer, c_time TIMESTAMP WITHOUT TIME ZONE ) PARTITION BY range (c_int) ( partition p1 start(100)end(108), partition p2 start(108)end(120) ); 执行如下两种语句会发生报错: 1 2 ALTER TABLE partitiontest ADD PARTITION p3 start(120)end(130), DROP PARTITION p2; ERROR: start value of partition "p3" NOT EQUAL up-boundary of last partition. 1 2 ALTER TABLE partitiontest DROP PARTITION p2,ADD PARTITION p3 start(120)end(130); ERROR: start value of partition "p3" NOT EQUAL up-boundary of last partition. 可以修改语句为: 1 ALTER TABLE partitiontest ADD PARTITION p3 start(108)end(130), DROP PARTITION p2; 1 ALTER TABLE partitiontest DROP PARTITION p2,ADD PARTITION p3 start(108)end(130);
共100000条