数据库表名cases
使用哈希比较行的步骤
- 在两个数据库中为每一行生成哈希值
可以使用 Oracle 的 DBMS_CRYPTO.HASH 函数为每一行生成哈希值。该函数会为整行数据生成一个唯一的哈希值,然后可以在两个数据库之间进行比较。
Oracle 12c 的查询:
下面展示一些 内联代码片
。
SELECT
SYS.DBMS_CRYPTO.HASH(
UTL_RAW.CAST_TO_RAW(
COL1 || '|' || COL2 || '|' || COL3 || '|' ... -- 包含所有列
),
3 -- SHA-1 算法
) AS row_hash
FROM cases;
Oracle 19c 的查询:
SELECT
SYS.DBMS_CRYPTO.HASH(
UTL_RAW.CAST_TO_RAW(
COL1 || '|' || COL2 || '|' || COL3 || '|' ... -- 包含所有列
),
3 -- SHA-1 算法
) AS row_hash
FROM cases;
说明:
- 将 COL1, COL2, COL3 等替换为 cases 表中的实际列名。
- || ‘|’ || 用于将列值与分隔符(这里是 |)连接,以确保唯一性。
- DBMS_CRYPTO.HASH 函数使用 SHA-1 算法(通过 3 指定)生成哈希值。
- 导出哈希值
在 Oracle 12c 和 Oracle 19c 中运行上述查询,并将结果导出到文件或工具中进行比较。例如:
-
将结果导出到 CSV 文件。
-
使用 Excel、Python 或 diff 工具比较哈希值。
- 比较哈希值
-
如果所有行的哈希值匹配,则两个数据库中的数据是相同的。
-
如果存在不匹配的哈希值,通过比较原始数据找出差异行。
处理大数据(超过 100 行)
如果表中有大量行,可以通过以下方式优化比较过程:
a. 使用数据库链接直接比较
无需手动导出和比较,可以通过数据库链接直接比较哈希值。
在 Oracle 19c 中创建到 Oracle 12c 的数据库链接:
CREATE DATABASE LINK oracle12c_link
CONNECT TO username IDENTIFIED BY password
USING 'oracle12c_tns_entry';
运行查询比较哈希值:
WITH oracle12c_hashes AS (
SELECT
SYS.DBMS_CRYPTO.HASH(
UTL_RAW.CAST_TO_RAW(
COL1 || '|' || COL2 || '|' || COL3 || '|' ... -- 包含所有列
),
3 -- SHA-1 算法
) AS row_hash
FROM cases@oracle12c_link
),
oracle19c_hashes AS (
SELECT
SYS.DBMS_CRYPTO.HASH(
UTL_RAW.CAST_TO_RAW(
COL1 || '|' || COL2 || '|' || COL3 || '|' ... -- 包含所有列
),
3 -- SHA-1 算法
) AS row_hash
FROM cases
)
SELECT 'Oracle12c' AS source_db, row_hash
FROM oracle12c_hashes
MINUS
SELECT 'Oracle19c' AS source_db, row_hash
FROM oracle19c_hashes;
上面的查询将显示在 Oracle 12c 中存在但在 Oracle 19c 中不存在的行。
下面,反转查询以查找在 Oracle 19c 中存在但在 Oracle 12c 中不存在的行:
WITH oracle12c_hashes AS (
SELECT
SYS.DBMS_CRYPTO.HASH(
UTL_RAW.CAST_TO_RAW(
COL1 || '|' || COL2 || '|' || COL3 || '|' ... -- 包含所有列
),
3 -- SHA-1 算法
) AS row_hash
FROM cases@oracle12c_link
),
oracle19c_hashes AS (
SELECT
SYS.DBMS_CRYPTO.HASH(
UTL_RAW.CAST_TO_RAW(
COL1 || '|' || COL2 || '|' || COL3 || '|' ... -- 包含所有列
),
3 -- SHA-1 算法
) AS row_hash
FROM cases
)
SELECT 'Oracle19c' AS source_db, row_hash
FROM oracle19c_hashes
MINUS
SELECT 'Oracle12c' AS source_db, row_hash
FROM oracle12c_hashes;
b. 使用脚本自动化比较
import cx_Oracle
# 连接到 Oracle 12c
conn_12c = cx_Oracle.connect('username/password@oracle12c_tns_entry')
cursor_12c = conn_12c.cursor()
# 连接到 Oracle 19c
conn_19c = cx_Oracle.connect('username/password@oracle19c_tns_entry')
cursor_19c = conn_19c.cursor()
# 从 Oracle 12c 获取哈希值
cursor_12c.execute("""
SELECT SYS.DBMS_CRYPTO.HASH(
UTL_RAW.CAST_TO_RAW(
COL1 || '|' || COL2 || '|' || COL3 || '|' ... -- 包含所有列
),
3
) AS row_hash
FROM cases
""")
hashes_12c = set(row[0] for row in cursor_12c.fetchall())
# 从 Oracle 19c 获取哈希值
cursor_19c.execute("""
SELECT SYS.DBMS_CRYPTO.HASH(
UTL_RAW.CAST_TO_RAW(
COL1 || '|' || COL2 || '|' || COL3 || '|' ... -- 包含所有列
),
3
) AS row_hash
FROM cases
""")
hashes_19c = set(row[0] for row in cursor_19c.fetchall())
# 比较哈希值
if hashes_12c == hashes_19c:
print("两个表的数据完全相同。")
else:
print("发现差异:")
print("在 Oracle 12c 中但不在 Oracle 19c 中的行:", hashes_12c - hashes_19c)
print("在 Oracle 19c 中但不在 Oracle 12c 中的行:", hashes_19c - hashes_12c)
# 关闭连接
cursor_12c.close()
cursor_19c.close()
conn_12c.close()
conn_19c.close()
- 验证结果
- 如果未发现差异,则两个表的数据完全相同。
- 如果发现差异,通过在两个数据库中查询原始数据来调查具体行。