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

jobtbby3  于 2023-10-16  发布在  Oracle
关注(0)|答案(1)|浏览(93)

DBA让我在一个复杂的SQL语句中用绑定参数替换常量和变量值,以提高查询的性能。但是,我无法理解它如何提高查询的性能,因为它将执行完全相同的语句。
我还听到他说,绑定变量查询将得到改善与Oracle * 执行计划**,我是阅读this Oracle博客,可以请任何人帮助理解简单的话技术细节?谢谢

w1e3prcc

w1e3prcc1#

当您向Oracle提交SQL时,数据库必须留出共享内存来描述SQL,并通过一些复杂的优化器排列生成执行计划,然后存储其计划(它为满足您的请求而生成的内部程序)。这就是我们所说的“光标”。它会消耗内存并需要时间来生成。这发生在解析步骤,如果不显式执行,则在客户端执行SQL时隐式发生。如果你要在一个循环中进行一百万次迭代,使用相同的SQL,但每次都改变一些文字标识符,那么你会在这个解析活动上花费大量的时间,并且消耗大量的共享内存,因为每个SQL都与它之前的SQL不同,并且需要自己的游标。在高容量下,使用每次执行都会更改的文字的SQL可能会使数据库处于不健康的状态(它最终可能会在管理其共享池时遇到问题,这可能会导致其他用户的分配错误,甚至在严重时使数据库崩溃)。它还为用户增加了不必要的运行时间。如果程序必须对循环的每次迭代进行硬解析,那么它的运行速度比应有的要慢。所以你的DBA是正确的,这是我们总是引导开发人员远离的东西。
绑定变量允许重复使用相同的SQL语句(游标),即使引用的特定 predicate 值从一次执行到下一次执行会发生变化,也可以通过屏蔽每次变化的文字值来实现。然后SQL文本每次都是相同的,并且只需要一次(硬)解析。解析一次,执行多次。这消除了重复硬解析的昂贵开销以及在共享池中分配内存的压力,以及所需的所有引脚和锁存器,从而减少了争用和CPU开销。
如果您发现不可能实现绑定(不太可能),那么DBA可以选择创建一个登录触发器,该触发器拦截您的登录并发出alter session以设置“cursor_sharing=force“,这是解决此问题的一个老方法,尽管它可能会导致某些客户端接口出现问题,并且是最后的解决方案。这个设置会强制重写SQL,将每个文本替换为绑定,不管这样做是否有意义。这并不理想,但当代码无法更改时,这是一个有用的创可贴。最好的办法是更改代码,并在频繁更改的 predicate 值上使用客户端的适当绑定变量。
如何实现绑定取决于您的编程环境。在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;

在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

在使用OCI 8 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);

每个客户机编程环境和Oracle接口API都是唯一的,但几乎所有的都应该有绑定的概念。在所有情况下,SQL文本都包含一个占位符(通常使用:,但不总是)和一种将客户端变量绑定到该占位符的方法。如何实现取决于你的编程环境。

相关问题