当前位置: 首页 > 知识库问答 >
问题:

Oracle:如何使用键列表高效地选择行

凤安然
2023-03-14

我有一个Oracle表,其中包含一个主键(我们称之为)和一个字段。在我的PHP应用程序中,我有一个键列表,我想从数据库中提取所有相应的值。我可以使用类似于以下PHP代码的东西来做到这一点:

$keyList = array('apple', 'orange', 'banana');

$conn = oci_pconnect(USERNAME, PASSWORD, URI);
$stmt = oci_parse($conn, 'SELECT * FROM myTable WHERE value IN ('
                         .explode(',', $keylist)
                         .')');
oci_execute($stmt);
while($row = oci_fetch_array($stmt, OCI_ASSOC)) {
    echo "{$row['KEY']}, {$row['VALUE']}\n"; // Print the values
}

这应该可以工作,但是$keyList最多可以有200个项目长(甚至更多)。这就提出了问题:

  • 这是最有效/稳健的方法吗
  • 还是最好使用某种预先准备好的语句从数据库中选择一个值,并对列表中的每个键执行一次

共有2个答案

萧英睿
2023-03-14

您的方法可能是最有效的方法,除非<code>keyList</code>首先来自Oracle(例如,如果它是另一个查询的结果,那么您希望合并这些查询)。

我绝对不会为列表中的每个键执行一次,因为这样的往返可能非常昂贵。至于一个200条长的列表,您必须进行实验,但我认为这不是问题。

还有一点非常重要:请务必清理 keyList 中的数据否则可能会向 SQL 注入公开您的应用。

施雅懿
2023-03-14

将< code>IN条件的值作为字符串串联传递不是一种好的做法。首先当然是安全性和正确性,但下一点是性能。< br >每次调用语句时,数据库引擎都会对其进行分析,生成查询计划,然后执行SQL语句中指定的操作。< br >如果每次都从头开始构建查询文本,那么每次都会执行所有三个阶段。< br >但是,如果您始终使用绑定变量,查询看起来是一样的,因此数据库使用缓存的查询计划来加快查询执行。甚至可以只调用< code>oci_parse()一次,并使用不同参数集重用< code>$stmt变量。< br >因此,为了获得最佳性能,您必须使用绑定变量,并使用< code > OCI _ bind _ array _ by _ name 用数组填充它。

另外,使用oci_fetch_all检索结果可能比逐行读取结果集执行得更快,但这取决于处理结果的逻辑。

更新

似乎传递数组参数仅在您要执行PL / SQL块并且不能将其与SQL语句一起使用时才有效。但另一种可能性是使用集合来传递参数值列表。即使使用数组,也可以满足问题的条件,但这种方式不太优雅。
除了查询数据库的不同方法外,还有系统设置之类的东西。在PHP的情况下,php中有一些参数.ini文件控制与Oracle的交互。其中之一(oci8.statement_cache_size)与查询缓存和性能有关。

例子

所有示例都使用Oracle中相同的数据设置。< br >为了传递数据,我选择了预定义的< code>SYS。ODCIVarchar2List类型,但是也可以定义具有相同特征的自定义类型(在数据设置示例中演示)。下面的代码演示了数据方案的设置以及在DML中使用集合的原则。

SQLFiddle

create table myTable(value varchar2(100), key varchar2(100))
/

insert into myTable(value, key)
select * from (
  select 'apple', 'apple_one' from dual union all
  select 'apple', 'apple_two' from dual union all
  select 'banana', 'banana_one' from dual union all
  select 'orange', 'orange_one' from dual union all
  select 'orange', 'orange_two' from dual union all
  select 'potato', 'potato_one' from dual
)
/

create or replace type TCustomList as table of varchar2(4000)
/

create or replace package TestPackage as

  type TKeyList is table of varchar2(1000) index by binary_integer;

  function test_select(pKeyList in out TKeyList) return sys_refcursor;

end;
/

create or replace package body TestPackage is

  function test_select(pKeyList in out TKeyList) return sys_refcursor
  is               
    vParam sys.ODCIVarchar2List := sys.ODCIVarchar2List();
    vCur sys_refcursor;  
    vIdx binary_integer;
  begin                

    vIdx := pKeyList.first;
    while(vIdx is not null) loop
      vParam.Extend;
      vParam(vParam.last) := pKeyList(vIdx);
      vIdx := pKeyList.next(vIdx);
    end loop;

    open vCur for 
      select * from myTable where value in (select column_value from table(vParam))    
    ;

    return vCur;
  end;

end;
/

演示集合的查询:

--select by value list
select * from myTable 
where value in (
        select column_value 
        from table(Sys.ODCIVarchar2List('banana','potato'))
      )
/

--same with custom type
select * from myTable 
where value in (
        select column_value 
        from table(TCustomList('banana','potato'))
      )
/

--same with demonstration of casting 
select * from myTable 
where value in (
        select column_value 
        from table(cast(TCustomList('banana','potato') as Sys.ODCIVarchar2List))
      )
/

示例1——使用集合从PHP调用

<?php
  $keyList = array('apple', 'potato');

  $conn = oci_pconnect("user_name", "user_password", "SERVER_TNS_NAME");

  $stmt = oci_parse($conn, "SELECT * FROM myTable where value in (select column_value from table(:key_list))");

  $coll = oci_new_collection($conn, 'ODCIVARCHAR2LIST','SYS');

  for ($i=0; $i < count($keyList); $i++) {
    $coll->append($keyList[$i]);
  }

  oci_bind_by_name($stmt, 'key_list', $coll, -1, OCI_B_NTY);

  oci_execute($stmt);

  while($row = oci_fetch_array($stmt, OCI_ASSOC)) {
      echo "{$row['KEY']}, {$row['VALUE']}\n"; // Print the values
  }
  echo "---\n";

  $coll->free();

  //-- Run statement another time with different parameters
  //-- without reparsing.

  $coll = oci_new_collection($conn, 'ODCIVARCHAR2LIST','SYS');
  $coll->append('banana');
  oci_bind_by_name($stmt, 'key_list', $coll, -1, OCI_B_NTY);

  oci_execute($stmt);

  while($row = oci_fetch_array($stmt, OCI_ASSOC)) {
      echo "{$row['KEY']}, {$row['VALUE']}\n"; // Print the values
  }
  echo "---\n";

  $coll->free();

  oci_free_statement($stmt);
  oci_close($conn);
?>

示例2-使用数组和包从PHP调用

<?php
  $keyList = array('apple', 'potato');

  $conn = oci_pconnect("user_name", "user_password", "SERVER_TNS_NAME");

  $stmt = oci_parse($conn, "begin :cur := TestPackage.test_select(:key_list); end;");

  $curs = oci_new_cursor($conn);

  oci_bind_array_by_name($stmt, "key_list", $keyList, 2, 100, SQLT_CHR);
  oci_bind_by_name($stmt, "cur", $curs, -1, OCI_B_CURSOR);

  oci_execute($stmt);
  oci_execute($curs);

  while($row = oci_fetch_array($curs, OCI_ASSOC)) {
      echo "{$row['KEY']}, {$row['VALUE']}\n"; // Print the values
  }
  echo "---\n";


  //-- Run statement another time with different parameters
  //-- without reparsing.

  $keyList = array('banana');

  oci_bind_array_by_name($stmt, "key_list", $keyList, 2, 100, SQLT_CHR);

  oci_execute($stmt);
  oci_execute($curs);

  while($row = oci_fetch_array($curs, OCI_ASSOC)) {
      echo "{$row['KEY']}, {$row['VALUE']}\n"; // Print the values
  }
  echo "---\n";

  oci_free_statement($stmt);
  oci_close($conn);
?>

示例3——使用数组和匿名块从PHP调用

<?php
  $keyList = array('apple', 'potato');

  $conn = oci_pconnect("user_name", "user_password", "SERVER_TNS_NAME");

  $stmt = oci_parse($conn, "
    declare
      type TKeyList is table of varchar2(4000) index by binary_integer;

      pKeyList TKeyList := :key_list;
      vParam   sys.ODCIVarchar2List := sys.ODCIVarchar2List();
      vIdx     binary_integer;
    begin

      -- Copy PL/SQL array to a type which allowed in SQL context
      vIdx := pKeyList.first;
      while(vIdx is not null) loop
        vParam.Extend;
        vParam(vParam.last) := pKeyList(vIdx);
        vIdx := pKeyList.next(vIdx);
      end loop;

      open :cur for select * from myTable where value in (select column_value from table(vParam));
    end;
  ");

  $curs = oci_new_cursor($conn);

  oci_bind_array_by_name($stmt, "key_list", $keyList, 2, 100, SQLT_CHR);
  oci_bind_by_name($stmt, "cur", $curs, -1, OCI_B_CURSOR);

  oci_execute($stmt);
  oci_execute($curs);

  while($row = oci_fetch_array($curs, OCI_ASSOC)) {
      echo "{$row['KEY']}, {$row['VALUE']}\n"; // Print the values
  }
  echo "---\n";


  //-- Run statement another time with different parameters
  //-- without reparsing.

  $keyList = array('banana');

  oci_bind_array_by_name($stmt, "key_list", $keyList, 2, 100, SQLT_CHR);

  oci_execute($stmt);
  oci_execute($curs);

  while($row = oci_fetch_array($curs, OCI_ASSOC)) {
      echo "{$row['KEY']}, {$row['VALUE']}\n"; // Print the values
  }
  echo "---\n";

  oci_free_statement($stmt);
  oci_close($conn);
?>
 类似资料:
  • 问题内容: 我正在尝试使用Java和基于WebDriver的语法从硒的选择列表中选择一个元素。 我有选择列表 我怎么做? 问题答案: 如果速度较慢,请考虑类似

  • 问题内容: 我正在创建许多脚本,有时要检查表是否根据需要进行更新,我即时编写了一些SELECT语句。 在SQL SERVER中,您可以编写如下内容: 出于可见性原因,这很有用,但是在ORACLE中似乎不起作用,我不知道如何实现,除了手动写下所有列名。 您如何在oracle中做到这一点? 我知道我们不应该在生产脚本等中包含这样的查询。在开发中运行脚本时,我只是想即时使用它。在不同的点上,我更感兴趣的

  • 问题内容: 我想使用Hibernate选择单列而不是整个对象。到目前为止,我有这个: 我的问题是上述代码将整个People表返回为一个对象,而不仅仅是“ firstname”。我不确定如何指定仅返回“名字”而不是整个对象。 问题答案: 您可以像这样设置投影: 有了这个,您只能得到名字的回报。 我在同一情况下在堆栈上找到了另一个链接。希望这也将对您有所帮助。

  • 是否有可能设置IntelliJ IDEA,使我可以使用光标键进行列选择,类似于我在Notepad++、Visual Studio或FlashDeveloper中的操作。 例如,当我键入代码时,我几乎总是只通过使用键盘来完成导航。在前面提到的IDE中,我可以通过按住shift+alt,然后敲击将光标扩展到上面的行来快速选择代码块。然后,我可以按住Shift+Alt+Ctrl并点击或以快速跳过单词并选

  • 问题内容: 我想选择,,从多个选择其中有10个选项。我只想选择这三个选项。 HTML代码: selenium键代码: 我尝试使用此代码。使用此代码,我可以选择第一个选项,即“ P0_ENGLISH”。但是,选择第一个选项后,我得到一个错误: 问题答案: 要从 Multi Select 元素中选择多个 选项 ,可以使用 ActionChains 模拟 Control单击* ,如下所示: *

  • 问题内容: 有人知道为什么这对两个表别名“ x”都有效吗? 我知道ID为5的JOIN没有任何意义… 感谢您的教训! 问题答案: 下面的前两个查询是等效的。在连接的子句中,表别名仅指使用该别名的最后一个表,因此仅表受到限制。 在和表达式中,别名引用两个表-因此,列名是唯一的,则可以成功引用它们,但是,在列名相同的情况下,oracle会引发异常(如果删除了注释,则在查询3中会发生这种情况)。 我找不到