PostgreSQL表备份并重命名出现索引、外键仍指向旧表,恢复后仍失败的问题

文章目录

问题描述

遇到一个问题,在使用pgsql的时候,将其中几张表复制备份,原表导入增量数据,后面将复制的表和原表调换名称使用,结果引用过原表的其他表,外键仍然指向原表(但名称已发生变化),而且复制的表索引名称也与原表不同,导致使用这个数据库的系统报错,找不到外键、索引等,引发接口响应异常。随后将复制表和原表的索引、外键也还原,但依旧无法正常调用接口。

原因分析

  • 外键约束名称未改变:虽然重命名了表,但外键约束的名称仍然保持原样
  • 系统目录表未更新:PostgreSQL的pg_constraint、pg_index等系统表仍然记录着旧的依赖关系
  • 索引名称冲突:PostgreSQL会自动为重命名表上的索引添加后缀,导致名称不一致
  • 系统缓存未更新:PostgreSQL可能缓存了旧的依赖关系
  • 序列号不同步:如果表有自增字段,序列可能没有正确切换
  • 触发器状态:可能有些触发器仍然处于禁用状态

解决方法

  • 方案1:使用完整的表交换流程

    sql 复制代码
    -- 1. 禁用外键约束
    ALTER TABLE 子表1 DISABLE TRIGGER ALL;
    ALTER TABLE 子表2 DISABLE TRIGGER ALL;
    
    -- 2. 重命名表(使用事务保证原子性)
    BEGIN;
    ALTER TABLE 原表 RENAME TO 原表_backup;
    ALTER TABLE 备份表 RENAME TO 原表;
    COMMIT;
    
    -- 3. 重新创建外键约束
    ALTER TABLE 子表1 
    DROP CONSTRAINT 原外键约束名,
    ADD CONSTRAINT 新外键约束名 FOREIGN KEY (字段) REFERENCES 原表(字段);
    
    -- 4. 启用外键约束
    ALTER TABLE 子表1 ENABLE TRIGGER ALL;
  • 方案2:使用模式切换(推荐)

    sql 复制代码
    -- 1. 将备份表放在不同模式中
    CREATE SCHEMA IF NOT EXISTS backup_schema;
    ALTER TABLE 备份表 SET SCHEMA backup_schema;
    
    -- 2. 切换搜索路径或使用完整限定名
    SET search_path TO backup_schema, public;
    
    -- 3. 应用程序中使用模式限定表名
    SELECT * FROM backup_schema.表名;
  • 方案3:使用视图进行抽象

    sql 复制代码
    -- 创建视图指向当前活跃的表
    CREATE OR REPLACE VIEW 当前表 AS SELECT * FROM 原表;
    
    -- 需要切换时
    CREATE OR REPLACE VIEW 当前表 AS SELECT * FROM 备份表;
  • 彻底检查脚本

    sql 复制代码
    -- 检查外键约束
    SELECT 
    	tc.table_name, 
    	tc.constraint_name, 
    	ccu.table_name AS referenced_table_name
    FROM information_schema.table_constraints AS tc 
    JOIN information_schema.constraint_column_usage AS ccu
    ON tc.constraint_name = ccu.constraint_name
    WHERE tc.constraint_type = 'FOREIGN KEY';
    -- 检查索引
    SELECT 
    		indexname, 
    		tablename 
    FROM pg_indexes 
    WHERE tablename IN ('原表', '备份表');
    -- 检查依赖关系
    SELECT 
    	classid::regclass,
    	objid::regclass,
    	refclassid::regclass,
    	refobjid::regclass
    FROM pg_depend 
    WHERE objid IN (
    	SELECT oid FROM pg_class 
    	WHERE relname IN ('原表', '备份表')
    );

总结

  • 虽然最终通过dump恢复了数据,但在执行类似复制表一定要注意外键约束,还有pgsql特有的同一数据库下索引不重名的问题。
  • 彻底检查所有依赖关系,确保外键、索引、序列、触发器等都正确同步
  • 禁用外键

以上为个人学习分享,如有问题,欢迎指出:)

相关推荐
大模型玩家七七21 分钟前
梯度累积真的省显存吗?它换走的是什么成本
java·javascript·数据库·人工智能·深度学习
曾经的三心草23 分钟前
redis-9-哨兵
数据库·redis·bootstrap
明哥说编程28 分钟前
Dataverse自定义表查询优化:D365集成大数据量提速实战【索引配置】
数据库·查询优化·dataverse·dataverse自定义表·索引配置·d365集成·大数据量提速
xiaowu08038 分钟前
C# 拆解 “显式接口实现 + 子类强类型扩展” 的设计思想
数据库·oracle
讯方洋哥1 小时前
HarmonyOS App开发——关系型数据库应用App开发
数据库·harmonyos
惊讶的猫1 小时前
Redis持久化介绍
数据库·redis·缓存
Apple_羊先森2 小时前
ORACLE数据库巡检SQL脚本--19、磁盘读次数最高的前5条SQL语句
数据库·sql·oracle
全栈前端老曹2 小时前
【MongoDB】Node.js 集成 —— Mongoose ORM、Schema 设计、Model 操作
前端·javascript·数据库·mongodb·node.js·nosql·全栈
神梦流3 小时前
ops-math 算子库的扩展能力:高精度与复数运算的硬件映射策略
服务器·数据库
让学习成为一种生活方式3 小时前
trf v4.09.1 安装与使用--生信工具42-version2
数据库