Не е добра практика да подавате стойности за IN
състояние като конкатенация на низове. Първите неща, разбира се, сигурността и коректността, но следващата точка е производителността.
Всеки път, когато извикате оператора, машината на базата данни го анализира, изгражда план за заявка и след това изпълнява действия, посочени в SQL израза.
Ако изграждате текст на заявката от нулата всеки път, след което и трите етапа се изпълняват всеки път.
Но ако използвате променливи за свързване през цялото време, заявката изглежда еднаква, така че базата данни използва кеширан план на заявка, което ускорява изпълнението на заявката. Дори вие можете да извикате oci_parse()
само веднъж и използвайте повторно $stmt
променлива с различен набор от предоставени параметри.
Така че за най-добра производителност трябва да използвате свързваща променлива и да я попълните с масив, като използвате oci_bind_array_by_name
.
Допълнително нещо е, че извличането на резултати чрез oci_fetch_allкод>
може да работи по-бързо от четенето на набор от резултати ред по ред, но зависи от логиката на обработка на резултатите.
Актуализация
Изглежда, че предаването на параметри на масив работи само ако ще изпълните PL/SQL блок и не можете да го използвате с SQL изрази. Но друга възможност е да използвате колекции
за предаване на списък със стойности на параметри. Възможно е да се задоволят условията на въпроса дори с масиви, но този начин е по-малко елегантен.
Освен различни начини за запитване към база данни има нещо като системни настройки. В случай на PHP има някои параметри в php.ini
файл, който контролира взаимодействието с Oracle. Един от тях ( oci8.statement_cache_size
), свързани с кеширане на заявки и производителност.
Примери
Всички примери използват една и съща настройка на данни в Oracle.
За предаване на данни избирам предварително дефиниран SYS.ODCIVarchar2List
тип, но също така е възможно да се дефинира персонализиран тип със същите характеристики (демонстрирано в примера за настройка на данни). По-долу е даден код за демонстрация на настройка на схема за данни и принцип на използване на колекции в 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;
/
Заявки за демонстриране на колекции:
--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);
?>