Skip to content

PostgreSQL 迁移功能验证

迁移功能验证的步骤

1. 准备阶段

1.1 制定验证计划

  • 确定验证范围和优先级
  • 制定验证测试用例
  • 准备验证工具和脚本
  • 确定验证人员和职责
  • 制定验证时间表

1.2 准备验证环境

bash
# 创建测试数据库
createdb migration_test_db

# 连接测试数据库
psql -h localhost -U username -d migration_test_db

1.3 准备验证数据

sql
-- 创建测试表
CREATE TABLE test_users (
    id serial PRIMARY KEY,
    username varchar(50) NOT NULL UNIQUE,
    email varchar(100) NOT NULL UNIQUE,
    created_at timestamp DEFAULT CURRENT_TIMESTAMP
);

-- 插入测试数据
INSERT INTO test_users (username, email) VALUES
('user1', 'user1@example.com'),
('user2', 'user2@example.com'),
('user3', 'user3@example.com');

2. 结构验证

2.1 表结构验证

sql
-- 比较源数据库和目标数据库的表结构
-- 源数据库
SELECT table_name, column_name, data_type, is_nullable, column_default
FROM information_schema.columns
WHERE table_schema = 'public'
ORDER BY table_name, ordinal_position;

-- 目标数据库执行相同查询,然后对比结果

2.2 索引和约束验证

sql
-- 源数据库查询索引信息
SELECT tablename, indexname, indexdef
FROM pg_indexes
WHERE schemaname = 'public'
ORDER BY tablename, indexname;

-- 源数据库查询约束信息
SELECT conname, conrelid::regclass AS table_name, contype, conkey,
       confrelid::regclass AS referenced_table
FROM pg_constraint
WHERE connamespace = 'public'
ORDER BY conrelid::regclass, conname;

-- 目标数据库执行相同查询,然后对比结果

2.3 视图、函数和存储过程验证

sql
-- 查询视图定义
SELECT viewname, definition
FROM pg_views
WHERE schemaname = 'public'
ORDER BY viewname;

-- 查询函数定义
SELECT proname, pg_get_functiondef(oid) AS definition
FROM pg_proc
WHERE pronamespace = 'public'
ORDER BY proname;

-- 目标数据库执行相同查询,然后对比结果

3. 数据验证

3.1 行数验证

sql
-- 源数据库统计各表行数
SELECT table_name, table_rows
FROM information_schema.tables
WHERE table_schema = 'public'
ORDER BY table_name;

-- 目标数据库执行相同查询,然后对比结果

3.2 数据抽样验证

sql
-- 随机抽样验证数据一致性
-- 源数据库
SELECT * FROM table_name ORDER BY random() LIMIT 100;

-- 目标数据库执行相同查询,然后对比结果

3.3 数据校验和验证

sql
-- 计算表数据的校验和
-- 源数据库
SELECT md5(CAST((array_agg(t.* order by id)) AS text)) AS table_checksum
FROM table_name t;

-- 目标数据库执行相同查询,然后对比结果

3.4 关键字段验证

sql
-- 验证关键字段的数据完整性
-- 源数据库
SELECT min(id), max(id), count(id), count(DISTINCT id)
FROM table_name;

-- 目标数据库执行相同查询,然后对比结果

4. 功能验证

4.1 存储过程和函数验证

sql
-- 测试存储过程和函数的执行结果
-- 源数据库
SELECT function_name(parameter1, parameter2);

-- 目标数据库执行相同函数,然后对比结果

4.2 触发器验证

sql
-- 测试触发器的执行
-- 源数据库
INSERT INTO table_name (column1, column2) VALUES (value1, value2);
SELECT * FROM table_name WHERE id = lastval();

-- 目标数据库执行相同操作,然后对比结果

4.3 视图验证

sql
-- 测试视图的查询结果
-- 源数据库
SELECT * FROM view_name WHERE condition;

-- 目标数据库执行相同查询,然后对比结果

5. 应用验证

5.1 应用连接验证

bash
# 测试应用程序连接
psql -h target_host -U app_user -d app_db -c "SELECT 1;

# 检查应用程序日志

5.2 业务功能测试

  • 执行应用程序的核心业务流程
  • 测试数据的增删改查操作
  • 测试报表生成和数据分析功能
  • 测试批处理作业和定时任务

5.3 并发访问测试

bash
# 使用pgbench进行并发测试
pgbench -h target_host -U username -d dbname -c 10 -j 2 -T 60

# 比较源数据库和目标数据库的测试结果

迁移功能验证工具

1. 内置工具

1.1 pg_dump/pg_restore

bash
# 使用pg_dump生成源数据库的DDL
pg_dump -h source_host -U username -d dbname -s -f source_schema.sql

# 使用pg_dump生成目标数据库的DDL
pg_dump -h target_host -U username -d dbname -s -f target_schema.sql

# 比较两个DDL文件
diff source_schema.sql target_schema.sql

1.2 psql

bash
# 使用psql执行查询并输出结果
psql -h source_host -U username -d dbname -c "SELECT * FROM table_name" -t -A > source_data.csv
psql -h target_host -U username -d dbname -c "SELECT * FROM table_name" -t -A > target_data.csv

# 比较数据文件
diff source_data.csv target_data.csv

2. 第三方工具

2.1 pg_comparator

pg_comparator是一个开源工具,用于比较两个PostgreSQL数据库的结构和数据。

bash
# 安装pg_comparator
git clone https://github.com/dalibo/pg_comparator.git
cd pg_comparator
make && make install

# 使用pg_comparator比较数据库
pg_comparator -h source_host -U username -d source_db -H target_host -U username -D target_db

2.2 Liquibase/Flyway

Liquibase和Flyway是数据库版本管理工具,可以用于验证数据库结构的一致性。

bash
# 使用Liquibase生成数据库变更日志
liquibase --changeLogFile=dbchangelog.xml generateChangeLog

# 使用Liquibase验证数据库
liquibase --changeLogFile=dbchangelog.xml validate

2.3 DBUnit

DBUnit是一个用于数据库测试的Java框架,可以用于验证数据库数据的一致性。

java
// DBUnit测试示例
DatabaseConnection sourceConn = new DatabaseConnection(sourceDataSource.getConnection());
DatabaseConnection targetConn = new DatabaseConnection(targetDataSource.getConnection());

IDataSet sourceDataSet = sourceConn.createDataSet();
IDataSet targetDataSet = targetConn.createDataSet();

Assertion.assertEquals(sourceDataSet, targetDataSet);

迁移功能验证脚本示例

1. 表结构对比脚本

bash
#!/bin/bash

# 表结构对比脚本

source_host="source_host"
source_user="username"
source_db="dbname"
target_host="target_host"
target_user="username"
target_db="dbname"

# 生成源数据库表结构
echo "Generating source database schema..."
pg_dump -h $source_host -U $source_user -d $source_db -s -f source_schema.sql

# 生成目标数据库表结构
echo "Generating target database schema..."
pg_dump -h $target_host -U $target_user -d $target_db -s -f target_schema.sql

# 比较表结构
echo "Comparing schemas..."
diff source_schema.sql target_schema.sql > schema_diff.txt

if [ $? -eq 0 ]; then
    echo "Schemas are identical!"
else
    echo "Schema differences found. See schema_diff.txt for details."
fi

2. 数据行数验证脚本

bash
#!/bin/bash

# 数据行数验证脚本

source_host="source_host"
source_user="username"
source_db="dbname"
target_host="target_host"
target_user="username"
target_db="dbname"

# 查询源数据库表行数
echo "Querying source database table counts..."
psql -h $source_host -U $source_user -d $source_db -c "SELECT table_name, table_rows FROM information_schema.tables WHERE table_schema = 'public' ORDER BY table_name" -t -A > source_row_counts.txt

# 查询目标数据库表行数
echo "Querying target database table counts..."
psql -h $target_host -U $target_user -d $target_db -c "SELECT table_name, table_rows FROM information_schema.tables WHERE table_schema = 'public' ORDER BY table_name" -t -A > target_row_counts.txt

# 比较行数
echo "Comparing row counts..."
diff source_row_counts.txt target_row_counts.txt > row_count_diff.txt

if [ $? -eq 0 ]; then
    echo "Row counts are identical!"
else
    echo "Row count differences found. See row_count_diff.txt for details."
fi

迁移功能验证最佳实践

1. 验证前准备

  • 确保源数据库和目标数据库的网络连接稳定
  • 确保验证用户具有足够的权限
  • 准备完整的验证测试用例
  • 准备验证工具和脚本

2. 验证过程中的注意事项

  • 优先验证核心业务表和关键数据
  • 使用自动化工具和脚本提高验证效率
  • 记录验证过程和结果
  • 及时处理验证中发现的问题

3. 验证后的处理

  • 生成验证报告,包含验证结果和问题分析
  • 修复验证中发现的问题
  • 重新验证修复后的问题
  • 获得业务部门的验证确认
  • 记录验证过程和结果,形成知识库

常见问题与解决方案

1. 表结构不一致

问题:迁移后表结构与源数据库不一致

解决方案

  • 检查迁移工具的配置和参数
  • 检查源数据库和目标数据库的版本差异
  • 手动对比DDL语句,找出差异
  • 根据差异修改目标数据库的表结构

2. 数据不一致

问题:迁移后数据与源数据库不一致

解决方案

  • 检查迁移工具的数据类型映射
  • 检查迁移过程中的日志,查找错误
  • 使用数据对比工具找出具体差异
  • 重新迁移不一致的数据

3. 功能对象执行失败

问题:存储过程、函数或触发器执行失败

解决方案

  • 检查功能对象的语法和依赖关系
  • 检查源数据库和目标数据库的版本差异
  • 手动修改功能对象的代码,适应目标数据库
  • 重新测试功能对象

4. 应用程序连接失败

问题:应用程序无法连接到新数据库

解决方案

  • 检查数据库连接字符串配置
  • 检查数据库的监听地址和端口
  • 检查数据库用户的权限
  • 检查防火墙设置

5. 性能下降

问题:迁移后数据库性能下降

解决方案

  • 重新收集统计信息
  • 重建索引
  • 调整数据库参数
  • 优化查询语句

常见问题(FAQ)

Q1:如何选择迁移功能验证的范围?

A1:

  • 优先验证核心业务表和关键数据
  • 验证使用频率高的功能对象
  • 验证复杂的业务流程
  • 根据业务重要性确定验证优先级

Q2:迁移功能验证需要多长时间?

A2:

  • 验证时间取决于数据量和验证范围
  • 小型数据库可能需要几小时
  • 大型数据库可能需要几天
  • 建议在业务低峰期进行验证

Q3:如何自动化迁移功能验证?

A3:

  • 使用自动化测试工具
  • 编写验证脚本
  • 集成到CI/CD流程
  • 使用容器化环境进行验证

Q4:迁移功能验证需要哪些人员参与?

A4:

  • DBA:负责数据库层面的验证
  • 开发人员:负责功能对象和应用程序的验证
  • 业务人员:负责业务流程的验证
  • 测试人员:负责编写和执行测试用例

Q5:如何处理迁移功能验证中发现的问题?

A5:

  • 记录问题的详细信息
  • 分析问题的根本原因
  • 制定修复方案
  • 实施修复
  • 重新验证
  • 记录修复过程和结果

Q6:迁移功能验证完成后需要做什么?

A6:

  • 生成验证报告
  • 获得相关部门的确认
  • 记录验证过程和结果
  • 进行最后的准备,准备切换到新数据库
  • 制定回滚计划,以防切换失败

迁移功能验证案例

1. 大型电商系统迁移验证案例

背景:某大型电商系统从Oracle迁移到PostgreSQL,数据量超过1TB

验证过程

  1. 结构验证:使用pg_comparator工具对比表结构,发现5个表的字段类型不一致,手动修复

  2. 数据验证

    • 行数验证:所有表行数一致
    • 数据抽样验证:随机抽取1000条数据,对比结果一致
    • 校验和验证:核心表的校验和一致
  3. 功能验证

    • 测试100个核心存储过程,其中3个需要修改语法
    • 测试50个触发器,全部通过
  4. 应用验证

    • 执行核心业务流程测试,包括用户注册、商品浏览、下单支付等
    • 压力测试:模拟1000并发用户,性能达到预期

结果:迁移功能验证通过,系统成功切换到PostgreSQL数据库

2. 企业ERP系统迁移验证案例

背景:某企业ERP系统从SQL Server迁移到PostgreSQL,包含500多个表

验证过程

  1. 结构验证:发现20个表的索引定义不一致,重新创建索引

  2. 数据验证

    • 行数验证:发现3个表的行数不一致,重新迁移
    • 数据抽样验证:发现日期类型的数据格式不一致,调整数据类型映射
  3. 功能验证

    • 测试存储过程时发现语法差异,修改15个存储过程
    • 测试视图时发现函数调用差异,修改8个视图
  4. 应用验证

    • 执行ERP系统的核心模块测试
    • 发现报表生成功能异常,修复相关查询

结果:经过2周的验证和修复,系统成功迁移到PostgreSQL,功能正常运行