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特有的同一数据库下索引不重名的问题。
  • 彻底检查所有依赖关系,确保外键、索引、序列、触发器等都正确同步
  • 禁用外键

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

相关推荐
~~李木子~~1 小时前
MySQL 迁移总结报告
数据库·mysql
有梦想的攻城狮2 小时前
通过Lettuce实现PB3格式对象在Redis中的存储与查询
数据库·redis·缓存·pb3
桦03 小时前
MySQL【函数】
数据库·mysql
⑩-3 小时前
Redis(1)
数据库·redis·缓存
2301_803554523 小时前
主从同步配置的步骤
数据库
无敌最俊朗@3 小时前
00-7天攻破sqlite数据库(总览sqlite)
数据库·sqlite
Access开发易登软件4 小时前
Access导出带图表的 HTML 报表:技术实现详解
数据库·后端·html·vba·导出·access
_Minato_4 小时前
数据库知识整理——SQL数据定义
数据库·sql·mysql·oracle·database·数据库开发·数据库架构
程序员卷卷狗4 小时前
MySQL 四种隔离级别:从脏读到幻读的全过程
数据库·mysql
l1t5 小时前
改写ITPUB newkid的求解数独DuckDB SQL为Clickhouse格式
数据库·sql·clickhouse·duckdb