通过JDBC部署大型PLSQL包的速度非常慢

通过JDBC部署大型PLSQL包的速度非常慢,jdbc,plsql,Jdbc,Plsql,我必须通过JDBC部署非常大的PLSQL包,并经历非常长的部署时间。我知道使用包含多达25000行代码的包不是一个好主意,但我现在没有选择。通过JDBC部署这样一个包大约需要2.5个小时 我通过将文件读取器包装在BufferedReader中从文件系统读取包。我逐行解析它,检查是否有分隔符,并将每一行附加到StringBuilder,直到语句完成。然后我使用StringBuilders toString()并将结果字符串交给我的语句execute() 谢谢你的建议 我认为您的长包部署时间与Jav

我必须通过JDBC部署非常大的PLSQL包,并经历非常长的部署时间。我知道使用包含多达25000行代码的包不是一个好主意,但我现在没有选择。通过JDBC部署这样一个包大约需要2.5个小时

我通过将文件读取器包装在BufferedReader中从文件系统读取包。我逐行解析它,检查是否有分隔符,并将每一行附加到StringBuilder,直到语句完成。然后我使用StringBuilders toString()并将结果字符串交给我的语句execute()


谢谢你的建议

我认为您的长包部署时间与Java、JDBC加载过程无关,而是与Oracle数据库包管理有关

当您执行
CREATE PACKAGE BODY FOO…
时,RDBMS软件首先检查以确保系统中没有其他用户使用该包(通过数据库锁)。如果是,则进程将挂起,直到所有其他用户都使用完包。然后它将您的包提交到数据库中。测试这一点的方法之一是重命名包(在原始源文件中)并尝试加载它。如果不需要2.5小时,这可能是一个促成因素


运行语句时,RDMBS所做的另一件事是编译包,其中涉及验证代码中的所有引用(例如表、视图、其他包)并生成编码版本。对于大型软件包,编译时间可能非常重要。测试这一点的方法是运行语句
ALTER-PACKAGE-FOO-COMPILE和时间

Oracle PL/SQL包包括:

  • 包头-类似于C.h文件的规范
  • 包体-相当于.c文件
上载包头将使所有使用该包中的函数/过程/记录/常量/对象/类型的PL/SQL包无效-通常是引用或使用该包中某些内容的任何东西

指定PACKAGE以重新编译包规范和包体(如果存在),而不管它们是否无效。这是默认设置重新编译包规范和正文会导致规范和正文所述的从属对象失效和重新编译。

数据库还使依赖emp_管理的所有对象无效。如果随后引用其中一个对象而没有先显式地重新编译它,则数据库会在运行时隐式地重新编译它

资料来源:

上载包体对数据库状态的影响较小。依赖于上传单元的包不会失效

重新编译包体不会使依赖于包规范的对象无效

重新编译包正文时,如果其中任何对象无效,数据库将首先重新编译正文所依赖的对象。如果数据库成功地重新编译了主体,则主体将变为有效

资料来源:

编译时间过长的原因可能是由数据库执行的级联重新编译造成的。这通常是将包头和包体保存在单个文件中,然后按顺序上载每个包的头和包体的结果,如以下示例所示:

  • @pkg_a.sql-依赖项无效,并尝试重新编译
  • @pkg_b.sql-同上
  • @pkg_c.sql-同上
在这种情况下,数据库可能多次尝试重新编译某些包,但都没有成功,因为还没有上载其他依赖项。这浪费了依赖项解析和编译的时间

通过将包拆分为.pks(仅包含标头)和.pkb(仅包含正文),可以极大地改进此场景。首先上载头文件,然后上载正文

  • @pkg_a.pks-依赖项无效但未重新编译
  • @pkg_b.pks-同上
  • @pkg_c.pks-同上
  • @pkg_a.pkb-pkg_a已成功重新编译,因为所有标头都是最新的
  • @pkg_b.pkb-同上
  • @pkg_c.pkb-同上
这是可能的,因为只要求依赖项中的包头对编译依赖包有效在此场景中,每个包体的重新编译只发生一次

将包拆分为头文件和正文文件还可以避免上载未更改的头文件。这通常是因为大多数更改都是对库的主体(实际代码)进行的。跳过不必要的包头上传将导致更少的包无效,从而减少验证整个数据库的工作量


这种方法可以帮助您大大减少将更改上载到数据库所需的时间。

最明显的评论是:“为什么$%^会这样做?”!我永远不会这么做,但是我客户db开发团队的人。我对此不满意。。。相信我。那么大的包肯定是真正的犯罪。我猜JDBC不是瓶颈;-)@Hanno,我指的是通过JDBC调用“逐行”部署包的实践,而不是构建25000行包的实践(这可能有问题,但不是1%有问题!),我认为通过JDBC部署包不是问题所在。这意味着语句的执行将一直挂起,直到使用包的每个人都因为数据库锁定而停止为止。如果运行“createpackagebodyfoo…;”,则在所有使用包的人都完成之前,此语句不会完成。