PL/SQL 中的 Oracle 数据库依赖关系

问题描述 投票:0回答:2

我需要找到函数/过程(在包体内定义)和它们使用的表之间的依赖关系。

我已经尝试过

all_dependencies
,但它仅适用于包级别,而不适用于内部函数/过程级别。 是否有可能使用例如找到此依赖项
all_source

预先感谢您的帮助。

sql oracle-database plsql
2个回答
2
投票

不可能找到程序(在包中)和表之间的依赖关系。

有多种工具可以检查依赖性。 正如您已经发现的,

*_DEPENDENCIES
仅跟踪每个包级别的对象依赖关系。 有一个简洁的工具 PL/Scope 可以跟踪包各部分之间的依赖关系。 但它确实不跟踪所有表引用。

理论上你可以使用

*_SOURCE
。 实际上,除非您的代码使用一组有限的功能,否则这是不可能的。 对于任何中等复杂的代码,请忘记使用字符串函数或正则表达式来解析代码。 不幸的是,似乎没有任何既可编程又能够准确解析复杂代码的 PL/SQL 解析器。

说“这是不可能的”并不是一个很好的答案。 但在这种情况下,它可能会节省你很多时间。 这是很容易陷入死胡同并浪费大量精力的任务之一。


0
投票

如果需要,您可以使用此过程

首先激活 PL/Scope 并重新编译您的 PL/SQL 包

-- activate PL/Scope
ALTER SESSION SET plscope_settings='identifiers:all';
-- this will feed the data in *_identifiers and *_statements views
ALTER PACKAGE MY_PACKAGE COMPILE;
-- deactivate PL/Scope
ALTER SESSION SET plscope_settings='identifiers:none';

然后您可以使用此查询:

-- CREATE OR REPLACE VIEW tables_usage_in_plsql AS
WITH stmt_upd_ins_del as (
select /*+MATERIALIZE*/ s.object_name, s.object_type, s.type, s.usage_id, s.line
  from user_statements s
 where s.object_type = 'PACKAGE BODY'
   and s.type in ('UPDATE','DELETE','INSERT')
 group by s.object_name, s.object_type, s.type, s.usage_id, s.line
)
select s.object_name, s.object_type, s.type as stmt_type, i.usage_context_id, s.line
        , count(1) as nb_objs_in_dml
        , min(i.name) keep(dense_rank first order by i.line, i.col) as dml_object
        , min(i.type) keep(dense_rank first order by i.line, i.col) as typ_obj_dml
        , min(i.usage_id) keep(dense_rank first order by i.line, i.col) as uid_obj_dml
  from user_identifiers i
 inner join stmt_upd_ins_del s
    on i.object_type = s.object_type and i.object_name = s.object_name and i.usage_context_id = s.usage_id
where i.object_type = 'PACKAGE BODY' -- NB: filtering again here to help the optimizer
  and i.object_name = 'MY_PACKAGE' -- remove this line if you want to process several packages
  and i.type in ('VIEW','TABLE')
group by s.object_name, s.object_type, s.type, i.usage_context_id, s.line
UNION ALL
select i.object_name, i.object_type, 'SELECT' as stmt_type, i.usage_context_id, i.line
        , count(1) over (partition by usage_context_id) as nb_objs_in_dml
        , i.name as dml_object, i.type as typ_obj_dml, usage_id as uid_obj_dml
 from user_identifiers i
where i.object_type = 'PACKAGE BODY'
  and i.object_name = 'MY_PACKAGE' -- remove this line if you want to process several packages
  and i.type in ('VIEW','TABLE');

我在查询中做了几个假设,否则事情会变得非常复杂:

  • 对于 UPDATE/DELETE/INSERT,我从 user_statements 视图开始,然后查找靠近语句起始行/列的第一个“标识符”,我假设它是更新/插入/删除的表(INSERT INTO ... / UPDATE ... / DELETE FROM ...)这样的语句可以有很多其他涉及的表。语句中的其他表假定为 SELECTed。
  • 如果某些表是通过 SQL 语句中的函数更新的,那么它不会出现在查询级别(但如果该函数在您的包中,则表将出现在此处)
  • 缺少MERGE语句,如果使用可以尝试添加。
  • 您需要重新编译(使用标识符:全部)您想要在 _identifiers/_statements 视图中看到的所有 PL/SQL 对象)
  • 我在这里只考虑 PL/SQL 包,但您也可以添加过程和函数来满足您的需要。

您还可以根据之前的查询创建一个视图,然后使用它来获取每个 PL/SQL 包的所有 DML 语句,例如:

select object_type, object_name, objet_dml, typ_obj_dml, count(1) as tot_usages
        ,sum(CASE WHEN type = 'INSERT' then 1 else 0 end) as nb_inserts
        ,sum(CASE WHEN type = 'UPDATE' then 1 else 0 end) as nb_updates
        ,sum(CASE WHEN type = 'DELETE' then 1 else 0 end) as nb_deletes
        ,sum(CASE WHEN type = 'SELECT' then 1 else 0 end) as nb_selects
 from tables_usage_in_plsql
 group by object_type, object_name, objet_dml, typ_obj_dml
 order by 1,2,3,4;

希望这有帮助

© www.soinside.com 2019 - 2024. All rights reserved.