sql >> Database >  >> RDS >> Oracle

Oracle:hoe efficiënt rijen selecteren met behulp van een sleutellijst

Het is geen goede gewoonte om waarden door te geven voor IN voorwaarde als tekenreeksaaneenschakeling. Allereerst natuurlijk veiligheid en correctheid, maar het volgende punt zijn de prestaties.
Elke keer dat u de instructiedatabase-engine aanroept, wordt deze geparseerd, een queryplan gemaakt en daarna acties uitgevoerd die zijn gespecificeerd in de SQL-instructie.
Als je bouwt elke keer een querytekst op en vervolgens worden alle drie de fasen elke keer uitgevoerd.
Maar als je bindvariabelen gebruikt, ziet de query er altijd hetzelfde uit, dus de database gebruikt een queryplan in de cache, wat de uitvoering van de query versnelt. Zelfs jij kunt oci_parse() . aanroepen slechts één keer en hergebruik $stmt variabele met verschillende set parameters.
Dus, voor de beste prestaties moet je de bindvariabele gebruiken en deze vullen met array met behulp van oci_bind_array_by_name .

Bijkomend is dat het ophalen van resultaten met behulp van oci_fetch_all kan sneller presteren dan het lezen van de resultatenreeks per rij, maar dit hangt af van de logica van de verwerking van resultaten.

Bijwerken

Het lijkt erop dat het doorgeven van arrayparameters alleen werkt als je het PL/SQL-blok gaat uitvoeren en het niet kunt gebruiken met SQL-instructies. Maar een andere mogelijkheid is om collections te gebruiken om de lijst met parameterwaarden door te geven. Het is mogelijk om zelfs met arrays aan de vraagvoorwaarden te voldoen, maar deze manier is minder elegant.
Naast andere manieren om een ​​database te doorzoeken, zijn er ook systeeminstellingen. In het geval van PHP zijn er enkele parameters in php.ini bestand dat de interactie met Oracle regelt. Een van hen (oci8.statement_cache_size ) gerelateerd aan een querycaching en prestaties.

Voorbeelden

Alle voorbeelden gebruiken dezelfde gegevensconfiguratie in Oracle.
Om gegevens door te geven kies ik voorgedefinieerde SYS.ODCIVarchar2List type, maar het is ook mogelijk om een ​​aangepast type met dezelfde kenmerken te definiëren (aangetoond in het voorbeeld van de gegevensinstelling). Hieronder vindt u code om de instelling van het gegevensschema en het principe van het gebruik van verzamelingen in DML te demonstreren.

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;
/

Query's om collecties te demonstreren:

--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))
      )
/

Voorbeeld 1 - aanroepen vanuit PHP met behulp van verzamelingen

<?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);
?>

Voorbeeld 2 - Aanroepen vanuit PHP met array en pakket

<?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);
?>

Voorbeeld 3 - aanroepen vanuit PHP met array en anoniem blok

<?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);
?>


  1. Laravel - Querymodel als waarden een bepaalde tekenreeks bevatten (overgenomen uit zoekinvoer)

  2. Cyrillische letters slaan niet goed op met Glassfish en Mysql

  3. Toon databases van MySql-server

  4. Converteer JSON-array in MySQL naar rijen