我在 Oracle 数据库中有一个 PL/SQL 过程,它使用游标处理“PAYMENTS”表中的数据,并对外部 api 执行 HTTP 请求以检索 xml 形式的相关数据。然后该过程解析 XML 并将数据保存到另一个表中。这是代码的简化版本:
CREATE OR REPLACE PROCEDURE ... IS
CURSOR TRANSACTIONS IS SELECT ... FROM PAYMENTS WHERE ...
C1 TRANSACTIONS%ROWTYPE;
URL VARCHAR2(...);
L_XMLTYPE ...
BEGIN
URL := 'http://...'
OPEN TRANSACTIONS;
LOOP -- COULD BE 10000 ROWS OR MANY MORE
FETCH TRANSACTIONS INTO C1;
EXIT WHEN C%NOTFOUND;
MY_SCHEMA.MY_PACKAGE.MAKE_HTTP_REQUEST_TO_API(URL, C1.ID, RESPONSE_XML);
-- PARSE RESPONSE XML
L_XMLTYPE := XMLTYPE(LV_RESPONSE_DATA);
SELECT
EXTRACTVALUE(L_XMLTYPE, ...) AS ...
...
INTO ...
FROM DUAL;
-- SAVE DATA FROM RESPONSE XML
INSERT ...
END LOOP;
CLOSE TRANSACTIONS;
END;
我想了解此过程的潜在性能影响以及任何其他相关注意事项。 如何测量它们?
因为该过程会发出 HTTP 请求并等待响应,然后再继续下一行。 可能会发生哪些具体问题?
注意:该 API 旨在返回每行数据且无法更改。
我找到了像wireshark这样的工具来测量网络问题,但我仍然不知道如何有效地使用它。我已经阅读了有关异步和同步 http 调用以及如何阻止主线程的信息。但我不确定它如何应用于 Oracle 上下文。
网络呼叫很容易被防火墙或网络阻止软件或路由问题阻止,并且永远不会返回。您想对此进行测试以查看 sqlnet 超时是否有效,但即使如此,也不能完全信任它。我见过很多在外部网络调用中丢失的孤立会话。这将导致无限期地挂起锁、撤消和其他资源。您可能需要一个单独的异步监视进程来检测这一点,并在进程卡住时终止该进程。
当 Oracle 等待 http 请求返回时,它将报告其事件为
TCP Socket (KGAS)
。您可以在 v$session
中看到当前正在等待的会话,或者在 ASH (v$active_session_history
) 中看到过去的会话。您可以采样 v$session
或使用 Oracle 在 ASH 中按等待事件分组的 1 秒采样,以查看您的过程有多少是在等待网络、CPU 以及数据库内的其他工作。
只要存在对 Oracle 数据库外部异构事物的依赖(例如网络调用),就不建议在这些外部调用之间保持事务打开。如果您成为孤儿,或者外部代理需要很长时间才能做出响应,您可能会无限期地阻止其他人。我建议在
COMMIT
之后在循环内添加一个 INSERT
。如果您需要事务控制,以便错误应该回滚all插入(我猜不太可能),那么安全的解决方法是使用临时表,随时提交,然后您可以执行单个INSERT SELECT
进入决赛桌。
还建议在外部调用之间尽可能少地进行本地工作,以便您可以尽快摆脱对远程源的依赖。 Oracle 数据库之间的数据库链接也是如此。网络中断的可能性会提高该部分代码的风险级别,因此您希望快速使用网络,然后再完成它。尝试将任何繁重的本地工作推迟到之后,这样就不再容易受到网络问题的影响。
考虑添加异常处理。如果 http 请求(或 XML 解析)失败并引发某种异常,您是否希望整个程序中止,或者您是否希望记录它并继续下一条记录并处理有效的内容?如果是后者,您需要使用异常处理程序将调用包装在匿名块中:
LOOP
BEGIN
// http call
// XML parse
// something else that could fail
COMMIT;
EXCEPTION
WHEN OTHERS THEN
NULL; -- here you may log the error and the record that caused it. the loop will continue without aborting
END;
END LOOP;
对于往返客户端和数据库链接的正常网络流量,您还可以在
v$sesstat
中获得会话统计信息,提供传输至/来自这两个源的字节。但我不相信通过 UTL_TCP
的 TCP 套接字及其更高级别的包(如 UTL_HTTP
、UTL_SMTP
等)如此仪器化。我的数据表明没有任何 v$sesstat
统计数据可以跟踪流量。当然,您可以在操作系统上放置一个监视 shell 脚本,并每分钟运行一次 netstat
,并在系统级别以这种方式收集 TCP 统计信息,但是您当然无法区分应用程序的工作和其他使用网络。您可以在 http 请求之前和之后使用 SYSTIMESTAMP
,同时获取每个响应的 LENGTH
,并创建您自己的指标来从过程内部监控吞吐量。