Oracle
 sql >> Baza danych >  >> RDS >> Oracle

Oracle:Jak efektywnie wybierać wiersze za pomocą listy kluczy

Nie jest dobrą praktyką przekazywanie wartości dla IN warunek jako konkatenacja ciągów. Po pierwsze oczywiście bezpieczeństwo i poprawność, ale następnym punktem jest wydajność.
Za każdym razem, gdy wywołujesz silnik bazy danych instrukcji, analizuje go, buduje plan zapytania, a następnie wykonuje działania określone w instrukcji SQL.
Jeśli za każdym razem budujesz tekst zapytania od zera, a następnie za każdym razem wykonywane są wszystkie trzy etapy.
Ale jeśli używasz zmiennych wiążących za każdym razem, zapytanie wygląda tak samo, więc baza danych używa buforowanego planu zapytań, co przyspiesza wykonanie zapytania. Nawet możesz wywołać oci_parse() tylko raz i ponownie użyj $stmt zmienna z innym zestawem dostarczonych parametrów.
Więc, aby uzyskać najlepszą wydajność, musisz użyć zmiennej bind i wypełnić ją tablicą za pomocą oci_bind_array_by_name .

Dodatkową rzeczą jest to, że pobieranie wyników za pomocą oci_fetch_all może działać szybciej niż odczytywanie zestawu wyników wiersz po wierszu, ale zależy to od logiki przetwarzania wyników.

Aktualizacja

Wygląda na to, że przekazywanie parametrów tablicowych działa tylko wtedy, gdy zamierzasz wykonać blok PL/SQL i nie możesz go używać z instrukcjami SQL. Ale inną możliwością jest użycie kolekcji aby przekazać listę wartości parametrów. Możliwe jest spełnienie warunków pytania nawet za pomocą tablic, ale ten sposób jest mniej elegancki.
Oprócz różnych sposobów odpytywania bazy danych są takie rzeczy jak ustawienia systemowe. W przypadku PHP w php.ini znajdują się pewne parametry plik kontrolujący interakcję z Oracle. Jeden z nich ( oci8.statement_cache_size ) związane z buforowaniem zapytań i wydajnością.

Przykłady

Wszystkie przykłady używają tej samej konfiguracji danych w Oracle.
Aby przekazać dane, wybieram predefiniowany SYS.ODCIVarchar2List typ, ale możliwe jest również zdefiniowanie niestandardowego typu o tych samych cechach (zademonstrowane w przykładzie konfiguracji danych). Poniżej znajduje się kod demonstrujący konfigurację schematu danych i zasada korzystania z kolekcji w 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;
/

Zapytania demonstrujące kolekcje:

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

Przykład 1 – wywołanie z PHP przy użyciu kolekcji

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

Przykład 2 – Wywołanie z PHP przy użyciu tablicy i pakietu

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

Przykład 3 - wywołanie z PHP przy użyciu tablicy i anonimowego bloku

<?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. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Wyodrębnij n-ty podciąg

  2. konwersja oracle do_daty pokazująca literał nie pasuje do formatu ciągu

  3. Jak automatycznie wygenerować tożsamość dla bazy danych Oracle za pomocą frameworka Entity?

  4. Dlaczego nie mogę wprowadzić tej daty do tabeli za pomocą sql?

  5. Jak podłączyć bazę danych Oracle z PHP