SQL 语句中的绑定变量如何提高查询性能 - Oracle?

Arp*_*ain -2 sql oracle

DBA要求我在复杂的SQL语句中用绑定参数替换const和变量值,以提高查询的性能。但是,我无法理解它将如何提高查询的性能,因为它将执行完全相同的语句。

我还听到他说绑定变量查询将通过 Oracle执行计划得到改进,我正在阅读这篇Oracle 博客,有人可以帮助用简单的语言理解技术细节吗?谢谢。

Pau*_*l W 6

当您向 Oracle 提交 SQL 时,数据库必须留出共享内存来描述 SQL 并通过一些复杂的优化器排列生成执行计划,然后存储其计划(它为满足您的请求而生成的内部程序)。这就是我们所说的“光标”。它消耗内存并且需要时间来生成。这发生在解析步骤,如果没有显式完成,则在客户端执行 SQL 时隐式发生。如果您要在循环中执行一百万次迭代,使用相同的 SQL 但每次都会更改一些文字标识符,则您会在此解析活动上花费过多的时间,并且会消耗大量共享内存,因为每个 SQL 都是从字面上看,它与之前的不同,并且需要自己的光标。在高容量时,使用随每次执行而变化的文字的 SQL 可能会使数据库陷入不健康的情况(它最终可能会在管理其共享池时遇到问题,这可能会导致其他用户出现分配错误,严重时甚至会导致数据库崩溃)。它还为用户增加了不必要的运行时间。如果程序必须对循环的每次迭代进行硬解析,则程序的运行速度会比应有的速度慢。所以您的 DBA 是正确的,这是我们总是引导开发人员远离的事情。

绑定变量允许重复使用相同的 SQL 语句(游标),即使引用的特定谓词值通过屏蔽每次更改的文字值从一次执行到下一次执行发生变化也是如此。那么 SQL 文本每次都是相同的,并且只需要一次(硬)解析。解析一次,经常执行。这消除了重复硬解析的昂贵开销以及在共享池中分配内存以及所需的所有引脚和锁存器的压力,从而减少了争用和 CPU 开销。

如果您发现无法实现绑定(不太可能),您的 DBA 可以选择创建一个登录触发器来拦截您的登录并发出设置alter sessioncursor_sharing=force”,这是解决此问题的旧解决方法,尽管它可能会导致某些客户端出现问题接口,是最后的手段。此设置会强制重写 SQL,将每个文字替换为绑定,无论这样做是否有意义。这并不理想,但当无法更改代码时,它是一个有用的创可贴。最好的办法是更改代码并在客户端对频繁更改的谓词值使用适当的绑定变量。

如何实现绑定取决于您的编程环境。在 PL/SQL 中,只需使用 PL/SQL 变量即可完成:

DECLARE
  var_customer_id number;
  rec_customer customer%ROWTYPE;
BEGIN
  var_customer_id := 1234567;

  SELECT *
    INTO rec_customer
    FROM customer
   WHERE customer_id = var_customer_id; -- this cursor can be reused by different customer ID values
END;
Run Code Online (Sandbox Code Playgroud)

在 SQL Plus 中,您使用以下var声明:

var customer_id number

exec :customer_id := 1234567;

SELECT *
  FROM customer
 WHERE customer_id = :customer_id; -- this cursor can be reused by different customer ids
Run Code Online (Sandbox Code Playgroud)

在使用 OCI8 instantclient 的 PHP 中,它可能看起来像这样:

   $s = oci_parse($c,"begin
                      :servicecall := myfunction(in_customer_id => :customerid);
                     end;");

  oci_bind_by_name($s,":servicecall",$servicecall,32767);
  oci_bind_by_name($s,":customerid",$customerid,-1, SQLT_INT);

  $r = oci_execute($s);
Run Code Online (Sandbox Code Playgroud)

等等。每个客户端编程环境和Oracle接口API都是唯一的,但几乎都应该有绑定的概念。在所有情况下,文字 SQL 文本都包含占位符(通常带有:,但并非总是如此)以及将客户端变量绑定到该占位符的方法。如何执行取决于您的编程环境。