简介:这份资源是一份关于Informatica调用存储过程的图文操作说明,主要面向数据集成开发人员、ETL工程师以及需要借助Informatica完成复杂数据加工的技术读者。文档从存储过程的基础概念讲起,围绕在Mapping中通过pre SQL调用存储过程的核心场景,梳理了从Mapping新建、目标表属性编辑,到写入调用脚本、使用变量传递入参直至保存运行的完整流程,同时总结了调用存储过程在提升集成速度、数据安全性与可靠性方面的优势,并给出数据迁移、数据同步、报表生成等典型应用场景。资源采用图文对照形式,关键配置位置和操作顺序均有标注,可帮助读者快速上手、减少摸索成本。资源为单个docx文档,压缩包大小约180KB,体积轻量便于下载阅读。已有975人学习下载,适合刚开始接触Informatica或希望系统了解存储过程调用方法的读者作为参考。
1. Informatica调用存储过程:先分清你是哪一种调用场景
在Informatica里调用存储过程,几乎是每个做数据仓库的人都会撞上的需求:比如跑批前要执行一个统计当前库下各表数据总量的存储过程,刷新统计表;比如目标表要先清后插,清数逻辑封装在Oracle或MySQL的存储过程里;又比如想在映射里按批次调用一段存储过程,拿到返回码再决定数据往哪边走。这些场景都叫“调用存储过程”,但入口和写法完全不同,很多人一上来就在Mapping里乱放存储过程转换,结果参数传不进去,性能也翻车。
其实Informatica调用存储过程有几种固定的成熟入口,分布在Session属性和Mapping两个层级。选型原则很简单:能在Session级一次完成的,就别放进Mapping逐行执行;必须取返回值的,再用定制存储过程转换。这篇文章适合正在做ETL开发、Informatica运维,或者在数据库侧写存储过程但被Informatica接不过来卡住的人。
下面按落地顺序讲:先选型,再讲参数传递和事务控制,最后是排查坑和验证手段。读完你至少能判断自己该用哪个入口,并把第一个能跑的调用搭出来。
2. 调用前先定方案:四种方式的能力边界与选型
2.1 先看一张选型表:Pre/Post SQL、存储过程转换、定制转换、Call SP
先把四种入口摆出来。它们不是同一种东西的四个名字,而是分布在两个层级:Session和Mapping。Session层面的Pre SQL/Post SQL,本质是在数据抽取前后执行一段SQL;Mapping层面的存储过程转换(Connected)和定制存储过程转换(Unconnected),则是把存储过程当成一个组件参与数据流;还有一种是调用存储过程转换(Call Stored Procedure),它可以批量执行一次,也可以按行执行,取决于你怎么接线。
| 入口 | 所在层级 | 是否需要独立数据库连接 | 参数支持 | 典型场景 | 性能注意点 |
|---|---|---|---|---|---|
| Session 的 Pre/Post SQL | Session 属性 | 复用 Session 连接对象 | 支持工作流变量,写死或传参 | 跑批前清数、跑批后统计 | 整个 Session 只执行一次,最轻量 |
| 存储过程转换(Connected) | Mapping | 需要单独配置数据库连接 | IN/OUT 端口都能绑 | 每行数据都需要调用存储过程并取返回结果 | 每行一次网络往返,行数多了很危险 |
| 定制存储过程转换(Unconnected) | Mapping | 可不单独配置,复用会话上下文 | IN 参数,单值返回 | 少量调用、表达式里当函数用 | 按调用次数执行,可控但不要放进循环大表 |
| 调用存储过程转换(Call SP) | Mapping | 需要或复用 | IN/OUT 都支持 | 批量调用一段存储过程,不关心逐行结果 | 可一次执行,配置比 Connected 简洁 |
为什么先看这张表?因为选型决定后面所有参数的写法。我一般先把上面的决策顺序背下来:能走 Pre/Post SQL 就不进 Mapping;必须进 Mapping 的,优先用 Unconnected,因为不用多拉一根数据库连接;只有当存储过程的 OUT 参数要接到下游字段上、或者确实要逐行处理时,才用 Connected。Call SP 在大部分场景里和 Connected 的选型重叠,区别在于它更适合“只调用不取数”的批量操作。
2.2 从 Session 里直接调:Pre/Post SQL 的最小可跑通写法
最常见的做法是在 Session 属性里配 Pre SQL 和 Post SQL,很多老团队的ETL流程里,存储过程调用全部集中在这里,Mapping 里根本不出现存储过程转换。好处是直观,坏处是这些SQL写在 Session 配置里,脱离版本管理,改动稍不注意就漏。
以 Oracle 为例,最小可跑通写法是这样:
-- Pre SQL 或 Post SQL 中调用 Oracle 存储过程 BEGIN proc_clean_staging('$$BIZ_DATE'); END;如果是 SQL Server,则写成:
EXEC dbo.proc_clean_staging @biz_date = '$$BIZ_DATE';逻辑说明:Oracle 的存储过程不是可执行表达式,在 SQL 编辑器里必须用BEGIN ... END;包一层,EXEC在 Oracle 的 JDBC/ODBC 驱动下不一定被正确解析;SQL Server 用EXEC没问题。如果存储过程没有参数,直接写BEGIN proc_name; END;即可,不要画蛇添足写成SELECT proc_name FROM dual,那是调函数,不是调过程。
参数说明:$$BIZ_DATE是工作流变量,在 Session 的配置文件里定义,运行时由 Informatica 解析成具体日期字符串。注意这里传进去的是字符串字面量,Oracle 存储过程的入参如果是VARCHAR2,千万别在数据库侧声明成DATE,隐式转换在数据量小的时候看不出来,数据量一上来就是灾难,这个坑放到后面排查章节详细说。
注意:Pre SQL 的执行时机在不同数据库驱动下略有差异,但整体都在 Source 读取之前。Post SQL 则在 Target 加载完成后执行,如果你用 Post SQL 操作目标表,要格外注意提交时机,第 4 章会讲。
2.3 放进 Mapping:Connected 存储过程转换和 Unconnected 定制转换怎么分工
当存储过程必须参与映射数据流时,就要在 Mapping 里加存储过程转换了。先说 Connected。打开 Mapping,在转换面板里找 Stored Procedure,双击配置,选择一个数据库连接对象,再选存储过程名。它的工作方式是:每来一行数据,调用一次存储过程,调用完成后把 OUT 参数输出到下游。这意味着它适合“小数据量但每行都要逻辑处理”的场景,不适合几十万行的主数据流。
配置 Connected 的步骤我一般这样走:
- 在 Mapping 里添加 Stored Procedure 转换,命名成
SP_业务名。 - 属性页选择数据库连接对象,连接上后点“选择存储过程”,库里已有的过程会被列出来。
- 打开参数页,IN 参数选择来源:端口、表达式或映射参数;OUT 参数绑定到输出端口。
- 把需要传入的字段从上游 Source/转换连到 IN 端口,把 OUT 端口接到目标表字段。
Unconnected 是另一条路。它不需要像 Connected 那样配置独立连接对象做端口绑定,在转换属性里把存储过程名和参数方向声明好,然后在表达式转换里当函数调用。比如:
-- 表达式转换里调用定制存储过程转换 :SP.proc_sync_daily($$BIZ_DATE)逻辑说明::SP.过程名(...)是 Informatica 表达式里调用 Unconnected 存储过程转换的固定语法,括号里传 IN 参数,表达式的值就是存储过程的返回值。这个返回值可以是单值,也可以继续参与下游路由判断。Unconnected 的好处是不依赖单独的数据库连接对象,代价是只能返回一个值,带不出复杂结果集。
选型时注意:如果只是跑批前刷一张统计表,完全用不上 Mapping 里的转换,Pre SQL 一行 BEGIN...END; 就搞定了。不要为了让流程“看起来规范”而把存储过程硬塞进 Mapping,那会引入无关的数据库连接和网络开销,这是新手最容易犯的过度设计。
3. 参数传递:让存储过程不再是黑匣子
3.1 IN 参数绑定:常量、端口、映射参数三种来源
存储过程转换配置页里的“参数”表是核心。IN 参数的来源有三种:
| 来源类型 | 配置方式 | 典型场景 |
|---|---|---|
| 常量 | 参数页直接填值 | 固定业务类型编码 |
| 端口 | 从上游连线,选中某个字段 | 把源表的批次号、日期字段传进去 |
| 映射参数 | 填$${Param} | 跑批日期、分区编号 |
在参数页里,选中某一行的 IN 参数,在来源列选择类型。选端口时,会自动生成一个输入端口,你需要回到转换的输入端口视图里,把上游字段连上去;选映射参数时,表达式里写$$PARAM_NAME即可,Workflow 运行时会从参数文件里取值。
这一步最容易忽略的是数据类型对齐。Oracle 的NUMBER在 Informatica 侧通常映射成 Decimal,如果你要传整数,就把精度设成整数位;要传VARCHAR2,确认长度够,否则会被截断。MySQL 的INT、BIGINT和DATETIME也同理,别指望数据库侧隐式转换能兜底,ETL 里最怕就是“看起来能跑”的隐式转换。
3.2 OUT 参数和返回值:把存储过程的输出接出来
很多存储过程不止要被执行,还要把统计结果或错误码带出来。以 Oracle 为例,最常见的模式是 OUT 参数返回数字和错误码。下面是一个可复现的“统计当前库下各表数据总量”的存储过程,正好适合做演示:
CREATE OR REPLACE PROCEDURE proc_count_tables ( p_owner IN VARCHAR2, p_total OUT NUMBER, p_errno OUT NUMBER ) IS BEGIN p_errno := 0; SELECT SUM(num_rows) INTO p_total FROM all_tables WHERE owner = p_owner; EXCEPTION WHEN OTHERS THEN p_errno := SQLCODE; p_total := 0; END proc_count_tables;这段代码里,p_owner是入参,p_total返回表数量,p_errno返回错误码。在 Informatica 的 Connected 存储过程转换里,把p_owner绑到一个输入端口,把p_total和p_errno绑到输出端口,再连到目标表的两个字段,就能把存储过程的执行结果落库。注意ALL_TABLES里的NUM_ROWS是统计信息里的行数,不是精确值,真实项目里如果要精确统计,会改成动态 SQL 逐表SELECT COUNT(*),这里不再展开。
把这段代码放到 Informatica 里配置时,有一个行为要记住:Connected 转换是每输入一行就调用一次存储过程,如果你的上游有 100 条记录,存储过程会被调用 100 次,OUT 参数返回 100 组值。所以这个模式只适合上游很小的情况;上游如果很大,就别走 Connected,而是把统计表先加载到临时表,由存储过程在数据库内部完成全部统计。
3.3 传复杂参数:日期、动态表名和结果集怎么绕过
复杂参数主要分三类。第一类是日期,Oracle 存储过程入参经常声明为DATE,但 Informatica 端口传过去的是字符串,最常见做法是把入参改成VARCHAR2,在过程内部用TO_DATE转换;反过来,如果入参是DATE,绑定时让 Informatica 做转换也没问题,但转换函数选错就报错,不如在数据库侧收窄。
第二类是动态表名。很多存储过程允许传入表名字符串,再拼动态 SQL 执行。例如:
EXECUTE IMMEDIATE 'TRUNCATE TABLE ' || p_table_name;注意这种写法有 SQL 注入风险,生产环境一定要做白名单校验,比如只允许p_table_name等于预设的几个业务表名。Informatica 传过来的只是一个字符串,它不会帮你判断安不安全,数据库侧要有防御。
第三类是结果集。Oracle 的存储过程如果通过 REF CURSOR 返回结果集,在 Informatica 里接起来非常别扭,能绕就绕。常见做法是存储过程内部把结果写入临时表或者日志表,结束后 Informatica 直接SELECT * FROM 临时表。MySQL、openGauss 的存储过程虽然也有游标,但结果集返回语义和 Oracle 不一样,Informatica 对这类“返回结果集”的调用支持有限,最稳妥的方案同样是落临时表。记住一个原则:Informatica 擅长的是读表,存储过程擅长的是算和写,别让 Informatica 去解析存储过程的游标。
4. 事务与并发:提交时机和数据一致性
4.1 谁在提交:Oracle、MySQL、openGauss 的事务差异
调用存储过程最玄学的地方就是提交时机。你明明在存储过程里写了 INSERT,会话也显示成功,但数据就是查不到,十有八九是提交时机出了问题。
Oracle 默认不自动提交,存储过程里的 DML 只有在执行 COMMIT 后才生效。Informatica 的 Session 默认按目标表加载完成后统一提交,如果存储过程里没有 COMMIT,那么它的未提交事务会一直挂到 Informatica 提交目标表时一起提交。这个行为看起来合理,但有一个例外:存储过程里如果执行了TRUNCATE,这是 DDL,会隐式提交当前事务,把前面所有未提交的 DML 一起提交掉。这种“意外提交”很难排查,因为从日志看一切正常。
MySQL 和 openGauss 的行为又不一样。MySQL 默认autocommit=1,存储过程里的单条 DML 语句执行完就可能已经提交;如果显式开了事务,则要等 COMMIT。openGauss 兼容 Oracle 风格,不自动提交。这意味着同样的存储过程代码,在不同数据库上挂着 Informatica 跑,结果可能完全不同。我一般会先确认数据库的自动提交开关和存储过程内部是否显式提交,再决定 Informatica 侧的事务控制。
| 数据库 | 默认提交行为 | 存储过程里 TRUNCATE 的影响 |
|---|---|---|
| Oracle | 不自动提交,等 COMMIT | DDL 隐式提交,可能连带提交前面的未提交事务 |
| MySQL(InnoDB) | autocommit=1,单条语句通常已提交 | TRUNCATE 属于 DDL,也会隐式提交 |
| openGauss | 兼容 Oracle,不自动提交 | 同 Oracle,DDL 隐式提交 |
4.2 用 User Defined 事务控制接管提交
Informatica 的 Session 属性里有一个事务控制选项,默认是 Target,意思是按目标表加载来定提交。当你的存储过程还写了其他业务表时,建议把事务控制改成 User Defined,把提交和回滚完全交给存储过程。
配置步骤:
- 打开 Session 属性,找到 Transactions 配置项。
- 把 Transaction Control 改为 User Defined。
- 在存储过程的正常路径写 COMMIT,在异常路径写 ROLLBACK,并把错误码通过 OUT 参数返回。
- 保证所有写操作(包括目标表)都在存储过程内完成,因为 Informatica 在 User Defined 模式下不再主动提交。
一个稳妥的事务模板:
BEGIN SAVEPOINT sp_start; DELETE FROM target WHERE biz_date = p_biz_date; INSERT INTO target SELECT ... FROM staging WHERE biz_date = p_biz_date; COMMIT; EXCEPTION WHEN OTHERS THEN ROLLBACK TO sp_start; p_err_code := SQLCODE; RAISE; END;逻辑说明:SAVEPOINT给过程设了一个回滚点,报错时回滚到该点,而不是把整个 Session 的既有事务全部回滚。最后RAISE把异常重新抛给 Informatica,让会话状态变成失败,避免“数据没写进去但会话成功”的尴尬。参数说明:p_err_code是 OUT 参数,Informatica 侧可以接到日志表,也可以不用;关键是异常必须向上抛,不能吞。
提示:User Defined 模式下,Informatica 不再主动提交目标表。如果存储过程只处理业务表、不写目标表,那目标表加载的提交行为不受影响。
4.3 并发调用:多分区执行 Pre/Post SQL 会重复执行
这是并发里最隐蔽的坑。Session 如果开了多分区(Partitioned),Pre SQL 和 Post SQL 会在每个分区都执行一遍。如果你的存储过程是“清空某张表再插入”,多分区会把它跑好几遍,轻则锁等待,重则主键冲突直接失败。
我一般用两个办法绕开。第一,把存储过程调用从 Session 里挪出来,单独建一个 Workflow 的 Command 任务或一个前置 Session,让它只执行一次;第二,把存储过程设计成幂等,用 MERGE 代替 DELETE+INSERT,同一个 Session 重复执行也不会产生重复数据。
MERGE 示例:
MERGE INTO target t USING source s ON (t.id = s.id) WHEN MATCHED THEN UPDATE SET t.val = s.val, t.update_time = SYSDATE WHEN NOT MATCHED THEN INSERT (id, val, update_time) VALUES (s.id, s.val, SYSDATE);逻辑说明:有匹配就更新,没匹配就插入,天然支持重跑。第一次跑进来 10 条,第二次同源数据再跑,还是 10 条,不会变 20 条。这个设计放在存储过程里,比让 Informatica 去做去重可靠得多。并发场景里还有一个注意点:如果存储过程内部用了临时表,多个分区同时执行会互相干扰,Oracle 的临时表是会话隔离的没问题,MySQL 的临时表也是会话隔离,但如果你用的是物理表当临时表,就必须先清后写,否则多分区并发直接把数据写串。
5. 避坑与排查:调用存储过程最容易翻车的 5 个地方
5.1 会话报“存储过程不存在”,库里明明有
现象:Workflow 在 Pre SQL 阶段失败,日志提示ORA-04043 object does not exist或者驱动报PROCEDURE NOT FOUND,但你去数据库客户端一查,存储过程就在那里。
原因:Session 连接对象连进去的用户和存储过程所在的 schema 不是同一个。比如存储过程建在ETL_OWNER下,但 Session 连接用的是ETL_APP,如果没有权限或没有同义词,就找不到。跨 schema 调用时还容易踩授权缺失的坑。
解决:先在数据库客户端用 Session 同一个账号执行一遍,确认能跑;然后给存储过程名加 schema 前缀,写成ETL_OWNER.proc_sync_daily(...);如果不想写前缀,给账号GRANT EXECUTE ON 存储过程并建同义词。这个排查步骤我可以直接告诉新手:别去改 Informatica 配置,先手工复制 Pre SQL 到数据库客户端跑,能跑通就是权限问题,跑不通就是 SQL 写法问题。
5.2 调用不报错,但数据一点没变
现象:Session 正常结束,日志没有异常,目标表该被清理的数据还在原封不动。
原因:存储过程里写了 DML 但没有 COMMIT;更隐蔽的是存储过程内部有异常处理器,把异常捕获后只写入 OUT 参数,没有向上抛,Informatica 根本不知道它失败了。
解决:先把存储过程的 OUT 错误码接出来检查;再在存储过程末尾加一个判断,IF p_err_code != 0 THEN RAISE_APPLICATION_ERROR(-20001, '...'),把错误抛出来。不要迷信“Session 成功 = 数据没问题”,这种安静失败是最贵的教训。我自己吃过一次亏,一个统计类存储过程连续两周数据对不上,最后发现是异常被WHEN OTHERS THEN NULL吞掉了,从那以后我要求所有存储过程的异常分支必须往外抛。
5.3 ORA-14551:无法在查询中执行 DML
现象:在 Source Qualifier 自定义 SQL 里调用存储过程,启动 Session 时直接报ORA-14551 cannot perform a DML operation inside a query。
原因:Source Qualifier 执行的是查询,Oracle 不允许在查询上下文中执行包含 DML 的存储过程。这个错误还常见于在 Pre SQL 里写了SELECT 存储过程(...) FROM dual,本质上也是查询上下文。
解决:把调用放到 Post SQL 里,或者改用存储过程转换。如果确实要在查询阶段刷新数据,可以考虑自治事务,写法是PRAGMA AUTONOMOUS_TRANSACTION,但自治事务会独立提交,和主事务的协调很别扭,我一般不建议。记住了:Pre SQL 适合做准备动作,但别让它和 Source 查询混在一起。
5.4 存储过程在数据库秒回,在 Informatica 里跑了十分钟
现象:同一个存储过程,数据库客户端里单独执行只要几秒,挂到 Informatica 上之后肉眼可见地慢,有时候直接超时。
原因:两种最常见。一是 IN 参数类型不匹配,Oracle 做了隐式转换,导致表上索引失效,全表扫描;二是用了 Connected 存储过程转换,上游数据几十万行,相当于每行都来回一次数据库调用,网络往返时间叠加起来就很吓人。
解决:参数类型在 Informatica 侧精确到和数据库字段一致,VARCHAR2长度、NUMBER精度都要对应;数据量大的场景别用 Connected,改用 Pre/Post SQL 一次性调用。如果慢的是存储过程本身,在数据库侧开 SQL 跟踪,看执行计划,这种“看起来是 Informatica 慢、其实是数据库慢”的问题,要先把锅甩回数据库侧查清楚。
5.5 存储过程没有操作日志,查错全靠猜
现象:Session 失败,日志只提示存储过程内部异常,但你不知道它执行到哪一步,是清数失败了还是插入失败了。
原因:存储过程内部没有任何留痕,数据库会话一结束,现场全没了。
解决:在存储过程关键步骤写审计日志表,每完成一段插一条记录:
INSERT INTO etl_step_log(job_name, step_name, status, run_time) VALUES ('PRC_SYNC_DAILY', 'STEP1_CLEAN', 'OK', SYSDATE); COMMIT;逻辑说明:job_name写存储过程名,step_name写当前步骤,status写 OK 或 FAIL,run_time写时间点。如果存储过程在 STEP2 失败,STEP1 的日志已经落库,查一下就知道问题出在哪一段。这个习惯比任何调试工具都管用,尤其是生产环境不能随便重跑的时候。
6. 收尾也可以当技巧用:如何确认存储过程真的被调用了
6.1 三步验证:会话日志、目标表计数、审计日志
调用完存储过程,不要只看 Workflow 状态。我一般做三件事:
第一,在 Informatica Workflow Monitor 里打开 Session 日志,搜索存储过程名和Pre SQL/Post SQL关键字,确认调用语句真实下发到了数据库。第二步,核对目标表的业务数据量,和手工执行存储过程的结果做对比。第三步,查存储过程里自己写的审计日志表,看每一步是否按顺序完成。
SELECT * FROM etl_step_log WHERE job_name = 'PRC_SYNC_DAILY' ORDER BY run_time DESC;这三步要配合着看。会话日志只能证明“SQL 发出去了”,审计日志能证明“存储过程跑完了”,目标表计数能证明“数据真的变了”。只查其中一个,很容易被“成功但没数据”骗过去。
6.2 一个值得长期保留的习惯:让存储过程幂等
做 ETL 的人都知道,跑批不可能只跑一次。开发环境调试一遍、测试环境验证一遍、生产环境重跑一遍,如果存储过程不是幂等的,越跑数据越多。
最简单有效的写法是按业务日期清理后再插入:
DELETE FROM target WHERE biz_date = p_biz_date; COMMIT; INSERT INTO target SELECT ... FROM staging WHERE biz_date = p_biz_date; COMMIT;这样做的好处是,不管 Session 重跑多少次,只要参数日期不变,目标表永远只保留这一天的数据。如果性能允许,用 MERGE 更好,连 DELETE 都省了。这个习惯我大概是在第三次被重复数据坑到之后才彻底建立的,现在每个挂到 Informatica 下的存储过程,第一行一定是清理动作,最后一行一定是 COMMIT。
6.3 上线前五件事
要把一个存储过程挂到 Informatica 上,我最后会在五件事上过一遍:连接对象的用户和 schema 与存储过程所在库一致;IN/OUT 参数的数据类型完全对齐;事务控制模式确认过是 User Defined 还是 Target;存储过程里有 COMMIT 和异常抛出;同一个 Session 连续跑两遍数据不翻倍。这五件做完,基本不会在调用环节出幺蛾子。
从选型到参数绑定,再到事务和排查,这套流程是我这几年做 Informatica 存储过程调用的核心路径。最想提醒的就是一句话:先在数据库客户端把存储过程单独跑熟,再考虑 Informatica 怎么接。存储过程本身有问题,换什么工具都白搭。希望帮到你。
本文还有配套的精品资源,点击获取