Není dobrým zvykem předávat hodnoty pro IN
podmínka jako zřetězení řetězců. Na prvním místě je samozřejmě bezpečnost a správnost, ale dalším bodem je výkon.
Pokaždé, když zavoláte databázový stroj příkazů, analyzuje jej, sestaví plán dotazů a poté provede akce specifikované v příkazu SQL.
Pokud pokaždé vytvoříte text dotazu od nuly a poté se pokaždé provedou všechny tři fáze.
Pokud ale použijete proměnné vazby, dotaz vždy vypadá stejně, takže databáze používá plán dotazů uložený v mezipaměti, což urychluje provádění dotazu. I vy můžete volat oci_parse()
pouze jednou a znovu použít $stmt
proměnná s jinou sadou dodaných parametrů.
Pro nejlepší výkon tedy musíte použít proměnnou bind a vyplnit ji polem pomocí oci_bind_array_by_name
.
Další věcí je, že načítání výsledků pomocí oci_fetch_all
může fungovat rychleji než čtení sady výsledků řádek po řádku, ale to závisí na logice zpracování výsledků.
Aktualizovat
Zdá se, že předávání parametrů pole funguje pouze v případě, že se chystáte spustit blok PL/SQL a nemůžete jej použít s příkazy SQL. Ale další možností je použít kolekce
předat seznam hodnot parametrů. Je možné splnit podmínky otázky i s poli, ale tento způsob je méně elegantní.
Kromě různých způsobů dotazování databáze existují také něco jako nastavení systému. V případě PHP jsou některé parametry v php.ini
soubor, který řídí interakci s Oracle. Jeden z nich ( oci8.statement_cache_size
) související s ukládáním dotazů do mezipaměti a výkonem.
Příklady
Všechny příklady používají stejné nastavení dat v Oracle.
Pro předávání dat volím předdefinovaný SYS.ODCIVarchar2List
typu, ale je také možné definovat vlastní typ se stejnými charakteristikami (demonstrováno v příkladu nastavení dat). Níže je uveden kód pro ukázku nastavení schématu dat a principu použití kolekcí v DML.
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;
/
Dotazy k předvedení sbírek:
--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))
)
/
Příklad 1 – volání z PHP pomocí kolekcí
<?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);
?>
Příklad 2 – Volání z PHP pomocí pole a balíčku
<?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);
?>
Příklad 3 – volání z PHP pomocí pole a anonymního 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);
?>