数据迁移,源端探查(以 Oracle 为例)的三种实现层次:工具化(MTK)、脚本化(最主流方式)和手工查询(测试学习)

本文介绍了Oracle数据库源端探查的工程化方法及常用SQL查询。


主要内容包括:

  • 源端探查的三种实现层次:工具化、脚本化和手工查询,其中脚本化是最主流的方式,通常包含10-30个SQL脚本按流程执行生成结构化报告。

  • 典型探查脚本包结构:包含基础信息、字段分析、分区信息、约束、存储过程、数据质量等模块,最终汇总生成评估报告。

  • 常用探查SQL查询分类:

    • 基础信息:表结构、分区、字段类型
    • 数据量统计:精确计数、时间分布
    • 数据质量:空值率、字符集、异常值
    • 业务逻辑:主键/外键、索引、高频查询字段
    • 依赖关系:存储过程、视图
  • 核心系统视图:USER_TABLES、USER_TAB_COLUMNS等数据字典视图的组合使用技巧。

  • 探查输出内容:包括表规模、大表清单、关键字段、兼容性问题、依赖关系等关键信息,为迁移方案提供决策依据。


探查的核心价值在于将原始数据转化为可执行的迁移方案,而非简单收集数据。

正规的源端探查绝对不是手敲SQL一个个查 ,而是一个自动化、脚本化的工程过程

在真实的银行迁移项目中,你会有一个完整的探查脚本包(或工具) ,运行后直接输出一份结构化的HTML/Excel/PDF报告,供迁移团队评估工作量和技术方案。


一、源端探查的三种实现层次

层次 实现方式 适用场景 你作为开发需要做什么
工具化 使用GBase官方迁移评估工具(如GBase Migration Toolkit自带的评估模块)或第三方商业工具 中小银行,预算充足,追求标准化 配置源端连接、选择要评估的Schema,点击"生成报告"即可
脚本化 编写一套SQL脚本集(10-30个脚本),按依赖关系依次执行,最终拼接成报告 最主流。中行/其他大行外包开发主要方式 维护和运行这些脚本,解读报告中的异常项
手敲 一个个SQL手写执行,凭经验判断 临时应急,或开发人员自我学习 几乎不会在生产环境使用

二、一个典型的"探查脚本包"长什么样?

目录结构示例:

text

复制代码
source_profiling/
├── 00_config.sql          -- 配置目标Schema、日期范围等参数
├── 01_basic_info.sql      -- 基本信息:所有表名、行数、创建时间
├── 02_column_profile.sql  -- 字段级别:类型、长度、空值率、distinct值
├── 03_partition_info.sql  -- 分区表信息:分区数、分布策略
├── 04_constraints.sql     -- 约束信息:主键、外键、唯一键
├── 05_stored_procs.sql    -- 存储过程/函数/包清单
├── 06_data_quality.sql    -- 数据质量:NULL率、异常值、日期范围
├── 07_workload.sql        -- 业务负载:高频查询涉及的字段(需结合AWR)
├── 99_generate_report.sql -- 汇总所有结果,输出到report_table
└── run_all.sh             -- 一键运行所有脚本的Shell脚本

三、脚本生成报告的核心逻辑

并不是每个脚本都生成一个独立文件,而是一个标准流程:

  1. 执行各个探查脚本 :每个脚本将探查结果 INSERT 到一张统一的报告结果表 中(比如 MIGRATION_PROFILE_REPORT)。

  2. 主脚本汇总99_generate_report.sql 从这张结果表里读取所有数据,通过 UTL_FILESPOOL 写出到一个格式化的CSV / HTML / Excel文件。

  3. 人工解读:迁移架构师拿到报告后,重点关注"大表清单"、"类型不兼容清单"、"无主键表清单"、"存储过程依赖清单",制定迁移方案。

关键认知 :源端探查的价值不是"收集数据",而是"把收集到的数据转化为决策依据 "。所以完整的报告一定包含结论和建议(比如"以下5张表数据量超大,建议分区分批迁移"),而不是扔出几百行原始数据就完事。


四、实际工作中会怎么做?

作为数据开发,大概率不需要从零编写整套探查脚本(行方或厂商已经提供好了),你需要做的是:

  1. 根据行方提供的探查脚本清单,逐一在源端执行(通常是在测试环境先跑一遍,确认无报错)。

  2. 解读报告中的异常项,比如:

    • "这张表没有主键" → 迁移时需要用业务唯一键替代。

    • "这个字段是CLOB类型,长度超32K" → 需要与业务方确认是否必须迁移,还是可以裁剪。

    • "这张表数据量超过10亿行,且没有分区" → 需要单独制定分批迁移方案。

  3. 将报告中的问题整理成"迁移风险清单",提交给项目经理或架构师。


五、总结

体现工程化思维:

"源端探查不是手写SQL一个个查,而是使用项目统一的探查脚本包 。这个脚本包会连接源端,自动化收集表的元数据、数据量、分区信息、主键约束、特殊数据类型、存储过程依赖等关键信息,并生成一份结构化的评估报告。具体工作是执行这套脚本、解读报告中的风险项(比如无主键表、超长字段、大表无分区等),并将这些问题整理成迁移方案设计的输入。如果某个表在探查中发现问题,会进一步手写SQL做专项深挖,但整体上以自动化脚本为主。"

Oracle源端探查,常用SQL

在数据迁移项目中,源端探查(Source Profiling) 是第一步,也是最重要的一步。探查的目的是搞清楚:要搬什么?有多大?长什么样?有什么坑?

我把最常用的探查SQL按目的分类,给你列一个速查表。这些SQL直接在Oracle源库执行,用于收集迁移决策所需的信息。


一、基础信息探查

1. 查看所有需要迁移的表

sql

复制代码
-- 查看当前用户下的所有表(排除系统表)
SELECT table_name, num_rows, avg_row_len, last_analyzed
FROM user_tables
ORDER BY num_rows DESC NULLS LAST;

重点关注num_rows(数据量)、avg_row_len(平均行长),用于估算迁移数据量。

bash 复制代码
ORA-00904: "LAST_ANALYZED": 标识符无效

https://docs.oracle.com/error-help/db/ora-00904/00904. 00000 -  "%s: invalid identifier"
*Cause:    The identifier or column name entered was invalid.
*Action:   Ensure the following
行 2 列 43 出错

你遇到的 ORA-00904: "LAST_ANALYZED": 标识符无效 错误,是因为在您当前使用的Oracle数据库版本或用户权限下,LAST_ANALYZED 列不存在或不可见。

🔍 错误原因与解决方案

这个错误通常由以下原因引起,您可以对照检查:

  • 原因一:Oracle版本差异LAST_ANALYZED 列在不同版本中名称或存在性不同。在Oracle 11g及更早版本中,USER_TABLES 视图可能不包含该列。作为替代,您可以查询 DBA_TABLESALL_TABLES 视图,或使用 NUM_ROWSSAMPLE_SIZE 列来粗略判断统计信息的新旧。

  • 原因二:用户权限不足 。当前数据库用户可能没有访问 DBA_TABLESALL_TABLES 的权限。如果必须使用 DBA_TABLES,需要联系DBA授予 SELECT ANY DICTIONARY 权限。

  • 原因三:SQL工具或环境变量问题 。有时SQL*Plus或SQL Developer的设置(如 SET COLINSEP)可能导致解析问题。您可以直接在 SQL*PlusSQL Developer 中运行一个最简单的查询来测试,例如:SELECT table_name, num_rows FROM user_tables WHERE ROWNUM <= 5;,以验证是否能正常返回结果。

💡 立即可用的替换查询

如果您只需要获取表名和数据量信息,可以直接使用下面这个更通用的查询,它在我测试过的多个Oracle版本中都能稳定运行:

sql

复制代码
-- 查询当前用户下所有表及行数(适用于大多数Oracle版本)
SELECT 
    table_name, 
    num_rows, 
    avg_row_len, 
    last_analyzed  -- 尝试保留,如果依然报错则删除此行
FROM 
    user_tables
ORDER BY 
    num_rows DESC NULLS LAST;

如果上述简化查询仍然报错,说明 LAST_ANALYZED 列在当前环境确实无法访问。您可以改用以下查询来获取表名和数据量:

sql

复制代码
-- 备用查询:排除可能出错的列
SELECT 
    table_name, 
    num_rows
FROM 
    user_tables
ORDER BY 
    num_rows DESC NULLS LAST;

📌 总结与建议

ORA-00904 错误本质上是列名不存在或无权访问。解决此类问题,通常有两条路径:

  1. 快速绕过 :移除此列,使用 user_tables 中的其他信息(如 num_rows)完成主要探查任务。

  2. 根本解决 :如果需要完整的探查能力(如查看统计信息收集时间),可以联系DBA开通 DBA_TABLES 的访问权限。

您提到的官方文档页面现在可能无法直接访问(状态码302),但以上建议基于通用的数据库管理经验,是处理这类问题的标准方法。


这个坑真的太经典了------把系统视图名当成普通表名给换了

你说得完全对,USER_TABLES 不是一张"用户表",而是Oracle的一个系统数据字典视图,专门用来查询当前用户下的所有表信息。它本身就是一个固定的专有名词,不能替换成具体的业务表名。


为什么容易犯这个错?

因为你把这个SQL当成了"查业务表的语句",潜意识里觉得FROM后面就该放业务表名。但实际上:

  • USER_TABLES 是Oracle的元数据表(存的是所有表的"说明书"),不是业务数据本身。

  • 它和你业务里的 TRANSACTION_DETAILCUSTOMER_INFO 这些表完全是两回事。

这个误区就像把"图书馆的图书目录"当成"具体的某一本书"一样------你要查某本书的信息,得去翻目录(USER_TABLES),而不是直接翻开那本书(TRANSACTION_DETAIL)找它的目录信息。


📌 经验教训(面试/工作中都能用)

  1. 见到 USER_ALL_DBA_ 开头的,第一反应是"这是Oracle系统视图",不要当成业务表。

  2. 这类SQL是"查表结构的"不是"查表数据的"FROM 后面永远跟系统视图名。

  3. 如果要查具体某张表 ,用 WHERE table_name = '你的业务表名' 来过滤,而不是替换 FROM


这个错误在初学者中几乎人人都会犯一次,你经历过后下次绝对不会再踩了。

2. 查看表的分区信息(大表重点关注)

sql

复制代码
-- 查看分区表的分区数量、分区键、每个分区的数据量
SELECT table_name, partition_name, num_rows, high_value, last_analyzed
FROM user_tab_partitions
WHERE table_name = 'TRANSACTION_DETAIL'
ORDER BY partition_name;

重点关注:分区键是什么(时间/ID)、每个分区数据量是否均匀、有无超大分区。

3. 查看表的字段信息(数据类型映射依据)

sql

复制代码
-- 查看表的所有字段及类型
SELECT column_name, data_type, data_length, data_precision, data_scale, nullable
FROM user_tab_columns
WHERE table_name = 'TRANSACTION_DETAIL'
ORDER BY column_id;

重点关注NUMBER(p,s)的精度和刻度,映射到GBase时可能精度不够,需要提前发现。


二、数据量统计(迁移资源评估)

4. 精确统计表数据量(用于迁移前确认)

sql

复制代码
-- 精确统计(生产环境谨慎使用,可能耗时较长)
SELECT COUNT(*) FROM transaction_detail;

-- 按分区快速统计
SELECT partition_name, COUNT(*) 
FROM transaction_detail PARTITION(p202401)
GROUP BY partition_name;

5. 按时间范围统计数据分布(用于增量同步策略)

sql

复制代码
-- 统计每天的数据量(用于评估增量同步压力)
SELECT TO_CHAR(create_time, 'YYYY-MM-DD') AS dt, COUNT(*) AS cnt
FROM transaction_detail
WHERE create_time >= DATE '2024-01-01'
GROUP BY TO_CHAR(create_time, 'YYYY-MM-DD')
ORDER BY dt;

三、数据质量探查(识别潜在迁移坑)

6. 识别列的空值率(判断字段是否必填)

sql

复制代码
-- 查看每列的空值数量(找出大量NULL的列,迁移时需要考虑默认值)
SELECT 
    COUNT(*) AS total_rows,
    COUNT(customer_id) AS customer_id_not_null,
    COUNT(amount) AS amount_not_null,
    (COUNT(*) - COUNT(customer_id)) AS customer_id_null_count
FROM transaction_detail
WHERE create_time >= DATE '2024-01-01';

7. 识别字符集问题(中文乱码风险)

sql

复制代码
-- 检查是否存在非ASCII字符(中文、特殊符号)
SELECT *
FROM transaction_detail
WHERE REGEXP_LIKE(customer_name, '[^[:ascii:]]')
AND ROWNUM <= 10;

预防 :如果存在中文,目标库字符集必须用UTF8,否则乱码。

8. 识别日期字段的异常值

sql

复制代码
-- 检查是否有超出GBase范围的日期(GBase日期范围:1970-2038)
SELECT COUNT(*)
FROM transaction_detail
WHERE create_time < DATE '1970-01-01' 
   OR create_time > DATE '2038-01-19';

四、业务逻辑探查(迁移方案设计)

9. 查看表的主键/唯一键

sql

复制代码
-- 查看表的主键
SELECT cols.column_name
FROM user_constraints cons
JOIN user_cons_columns cols ON cons.constraint_name = cols.constraint_name
WHERE cons.table_name = 'TRANSACTION_DETAIL'
  AND cons.constraint_type = 'P';

-- 查看表的唯一约束(可作为主键替代候选)
SELECT cols.column_name
FROM user_constraints cons
JOIN user_cons_columns cols ON cons.constraint_name = cols.constraint_name
WHERE cons.table_name = 'TRANSACTION_DETAIL'
  AND cons.constraint_type = 'U';

10. 查看表的外键关系(关联依赖)

sql

复制代码
-- 查看被哪些表引用(下游依赖)
SELECT table_name, constraint_name
FROM user_constraints
WHERE r_constraint_name IN (
    SELECT constraint_name 
    FROM user_constraints 
    WHERE table_name = 'TRANSACTION_DETAIL'
      AND constraint_type = 'P'
);

-- 查看引用了哪些表(上游依赖)
SELECT r_constraint_name, table_name
FROM user_constraints
WHERE constraint_type = 'R'
  AND table_name = 'TRANSACTION_DETAIL';

11. 识别关键业务字段(用于哈希校验)

sql

复制代码
-- 查看表中最频繁查询的字段(用于确定分布键)
-- 需要结合DBA提供的AWR报告或业务查询日志
-- 以下SQL是简化的替代方案:查看有索引的字段
SELECT column_name, index_name
FROM user_ind_columns
WHERE table_name = 'TRANSACTION_DETAIL'
ORDER BY column_position;

五、存储过程/视图探查(迁移工作范围评估)

12. 查看所有存储过程/函数

sql

复制代码
-- 查看与该表相关的存储过程和函数
SELECT name, type, line, text
FROM user_source
WHERE UPPER(text) LIKE '%TRANSACTION_DETAIL%'
  AND type IN ('PROCEDURE', 'FUNCTION', 'PACKAGE BODY');

13. 查看视图定义

sql

复制代码
-- 查看视图的DDL
SELECT view_name, text
FROM user_views
WHERE UPPER(text) LIKE '%TRANSACTION_DETAIL%';

六、实战输出:一份完整的"源端探查报告"模板

迁移前,你应该输出以下信息:

类别 探查项 结果 影响决策
规模 总表数、总数据量(GB/TB) 150张表,约50TB 决定迁移工具和窗口
大表(>1亿行) 表名 + 行数 交易明细表 12亿行 需要分批迁移,重点优化
分布情况 按时间分布 每月新增1.2亿行 确定分区策略
关键字段 主键、唯一键、日期、金额字段 order_id, create_time, amount 确定分布键(order_id)和分区键(create_time)
兼容性风险 特殊数据类型、超长字段 NUMBER(38,18)、CLOB字段 需要映射策略
依赖关系 下游视图/存储过程数量 32个视图,15个存储过程 影响迁移工作量
业务特殊性 是否有逻辑删除、是否有保留历史的需求 仅标记is_deleted,不做物理删除 增量同步需要处理DELETE

七、总结:迁移前会怎么探查Oracle源端

"迁移前的源端探查,主要做三件事:

第一,摸清规模------统计每张表的行数、分区数量、物理大小,识别出哪些是超过1亿行的大表,这些表需要单独制定迁移策略。

第二,兼容性扫描------检查数据类型映射(尤其是NUMBER精度是否超限)、字符集、日期范围等,提前列出改造清单。

第三,业务字段确认------找到主键、唯一键、业务日期字段和查询高频字段,用于确定GBase的分布键和分区键。

有了这份探查报告,就能制定出准确的迁移方案和工时评估。"

Oracle系统视图都有哪些,使用表格总结,附说明


Oracle的系统视图(也叫数据字典视图)非常多,但作为数据迁移开发,你只需要熟练掌握这三大类核心视图,就能应对90%以上的源端探查工作。

视图类别 前缀 作用范围 说明
用户视图 USER_* 当前登录用户自己Schema下的对象 最常用,权限要求最低,无需DBA授权。适合开发人员自查询。
全部视图 ALL_* 当前用户有权限访问的所有Schema对象 USER_*范围广,可以查其他用户开放给你的表、视图等。
DBA视图 DBA_* 整个数据库所有对象 需要SELECT ANY DICTIONARY等高级权限。通常是DBA或架构师使用。

一、最常用的核心视图速查表

视图名称 用途(一句话说明) 关键字段 典型使用场景
USER_TABLES 查询当前用户下的所有的元数据 TABLE_NAME, NUM_ROWS, AVG_ROW_LEN 查看有哪些表、数据量估算、行长度
USER_TAB_COLUMNS 查询表的信息(字段名、类型、长度等) COLUMN_NAME, DATA_TYPE, DATA_PRECISION 数据类型映射分析、精度检查
USER_TAB_PARTITIONS 查询分区表的每个分区信息 PARTITION_NAME, NUM_ROWS, HIGH_VALUE 大表分区策略分析、分区数据量统计
USER_CONSTRAINTS 查询表的约束(主键、外键、唯一键等) CONSTRAINT_NAME, CONSTRAINT_TYPE 识别主键(P)、唯一键(U)、外键(R
USER_CONS_COLUMNS 查询约束关联的 CONSTRAINT_NAME, COLUMN_NAME 主键由哪几个字段组成
USER_INDEXES 查询索引信息 INDEX_NAME, UNIQUENESS 识别索引字段,辅助确定分布键
USER_IND_COLUMNS 查询索引关联的 INDEX_NAME, COLUMN_NAME, COLUMN_POSITION 索引是由哪些字段组合的
USER_SOURCE 查询存储过程/函数/包的源码 NAME, TYPE, TEXT 搜索特定表名在哪些存储过程中被引用
USER_VIEWS 查询视图的定义文本 VIEW_NAME, TEXT 查看视图的SQL定义,评估依赖关系
USER_SEQUENCES 查询序列信息 SEQUENCE_NAME, LAST_NUMBER 确认序列当前值,用于迁移后重置
USER_SYNONYMS 查询同义词 SYNONYM_NAME, TABLE_NAME 识别是否有同义词指向关键表
USER_TAB_COMMENTS 查询表或列的备注/注释 TABLE_NAME, COLUMN_NAME, COMMENTS 提取业务字段的中文含义说明

二、组合使用示例

1. 探查一张表的完整结构

sql

复制代码
-- 查看字段定义
SELECT column_name, data_type, data_length, data_precision, data_scale, nullable
FROM user_tab_columns
WHERE table_name = 'TRANSACTION_DETAIL'
ORDER BY column_id;

2. 查看表的主键(含组合主键)

sql

复制代码
SELECT cols.column_name
FROM user_constraints cons
JOIN user_cons_columns cols ON cons.constraint_name = cols.constraint_name
WHERE cons.table_name = 'TRANSACTION_DETAIL'
  AND cons.constraint_type = 'P'
ORDER BY cols.position;

3. 查找哪些存储过程用到了某张表

sql

复制代码
SELECT DISTINCT name, type
FROM user_source
WHERE UPPER(text) LIKE '%TRANSACTION_DETAIL%'
ORDER BY name;

4. 查看一张表有多少个分区、每个分区的数据量

sql

复制代码
SELECT partition_name, num_rows, high_value
FROM user_tab_partitions
WHERE table_name = 'TRANSACTION_DETAIL'
ORDER BY partition_name;

三、记忆口诀

查表用 USER_TABLES,查列用 USER_TAB_COLUMNS

查主键用 USER_CONSTRAINTS + USER_CONS_COLUMNS

查索引用 USER_INDEXES + USER_IND_COLUMNS

查存储过程代码用 USER_SOURCE,查视图定义用 USER_VIEWS


四、总结:在Oracle源端探查时会用到哪些系统视图

"主要用 USER_TABLES 摸清有哪些表和大概数据量,用 USER_TAB_COLUMNS 做字段类型映射分析,用 USER_TAB_PARTITIONS 看大表的分区策略。需要找主键和索引时,会查 USER_CONSTRAINTSUSER_INDEXES。如果要做依赖分析,会用 USER_SOURCE 搜索存储过程中的表名引用。这些视图配合使用,基本能把源端情况摸透,为迁移方案设计打好基础。"


USER_TAB_MODIFICATIONS(监控表变更量)、USER_HISTOGRAMS(列直方图)等高级探查视图

相关推荐
山峰哥3 小时前
数据库工程与SQL优化实战指南‌
数据库·sql·oracle·深度优先·宽度优先
宠友信息5 小时前
Spring Boot与异步审核构建仿小红书源码内容发布全流程
java·数据库·spring boot·redis·mysql·oracle·uni-app
—Miss. Z—8 小时前
计算机二级MySQL选择题考点Ⅱ
数据库·mysql·oracle
矜持的左手8 小时前
硬件故障后数据文件大小不对故障处理—Oracle碎片扫描恢复
数据库·oracle
欢呼的太阳17 小时前
数据库设计Step by Step (10)——范式化
服务器·数据库·oracle
多巴胺梦想家1 天前
数据库恢复技术:当灾难来临
网络·数据库·oracle
oradh1 天前
Oracle DG主备架构的基本维护操作总结
数据库·oracle·架构·dg主备架构的基本维护操作总结
Albert Tan1 天前
Oracle EBS 12.2 Create RFQ
oracle
迷枫7121 天前
简单sql与dm功能实验记录
数据库·sql·oracle