我相信我了解受保护和不受保护的存储过程背后的原因。
Fenced 在数据库“外部”运行(在我们的例子中是 DB2),以防止出现指针等问题时数据库引擎可能发生的损坏。
Unfenced 在数据库“内部”运行,这意味着性能更好。
根据我的研究,SQL PL 基本上总是不受保护的,因为它是 SQL,因此不能像编程语言那样访问内存。
C/C++ 和 Java 过程可以运行受保护或不受保护。但是由于它们可能会访问内存,因此应该考虑将它们隔离运行,除非可以确定代码的质量不会崩溃并且需要性能。
首先,我对上述内容的理解是否正确?
接下来,从所有存储过程(甚至定义为 SQL PL 的存储过程)开始作为防护通常是一个最佳实践吗?
存储过程的任何其他最佳实践,尤其是与防护和/或安全相关的?
编辑:进一步的研究表明 SQL PL 程序不能运行。因为它们不包含任何可能损害数据库引擎的代码,例如指针或文件 I/O,所以 DB2 知道它们是安全的并在引擎内部运行它们(即不受保护)。话虽如此,我仍在寻找有关所有其他存储过程的最佳实践。
更准确地说,
NOT FENCED
例程与数据库管理器本身在相同的进程空间中运行。该引擎是用 C 语言编写的,因此调用未受保护的例程就像从main()
. 这就是所有内存损坏和性能方面的来源:一个不受保护的例程可以访问所有相同的资源——内存、文件等——就像数据库管理器进程本身一样。对于
FENCED
例程,数据库管理器启动一个单独的进程 (db2fmp
),该进程依次执行例程代码。因此,操作系统保护可防止受防护的例程访问属于数据库管理器的任何内存区域或资源。严格来说, SQL 例程不能被隔离,因为它们不“运行”,但它们甚至比不被隔离更好——它们是 DB2 运行时引擎本身执行的字节码,因此没有单独的线程或进程。
C 和 C++ 例程可以被隔离,在这种情况下它们在单独的进程中执行,或者不被隔离,在这种情况下它们被加载到数据库管理器进程空间中并作为函数调用。
Java 例程只能通过它们需要一个单独的进程(Java 虚拟机)来执行这一事实来隔离。如果您将它们声明为 NOT FENCED,则该选项会被忽略。
说了这么多,您在受保护和不受保护之间的唯一选择是使用 C/C++ 例程。通常,为了安全起见,您会运行受保护的模式,仅当您非常确定它们不会损害数据库管理器并且它们需要更高的性能1时才更改为非受保护模式。
1 - 受保护的例程和未受保护的例程之间的性能差异来自与分配受保护的进程相关的开销,以及与数据库管理器和未受保护的例程之间的进程间通信相关的开销。即使这样,也不会在每次调用受保护例程时都创建受保护进程;将创建一个池并将其重用于此类调用。所有这一切意味着,只有在非常频繁地调用该例程(例如每秒数十次或更多)时,您才可能看到将例程声明为受保护的好处。
据我所知,你基本上是对的。关键是 PL SQL 函数不能进行内存分配,因此在内存管理方面确实没有办法特别对待它们。本质上,PL/SQL 与 db 引擎密切相关,但内存管理是 db 引擎的职责,而不是存储过程。
一般来说,我的建议是针对用于高性能系统的具有非常好的跟踪记录的广泛测试和/或审查的代码,无防护是最有意义的。然而,数据库很重要,像缓冲区溢出这样的事情可能会导致数据损坏,并且可能会在一段时间内未被检测到。我的建议是运行所有的 C/C++/Java 存储过程,除非您确定需要其他方式。
当然,UDF 也是如此。