Ce n'est pas une bonne pratique de transmettre des valeurs pour IN
condition sous forme de concaténation de chaînes. Tout d'abord, bien sûr, la sécurité et l'exactitude, mais le point suivant est la performance.
Chaque fois que vous appelez le moteur de base de données d'instructions, il l'analyse, construit un plan de requête et exécute ensuite les actions spécifiées dans l'instruction SQL.
Si vous construisez le texte de la requête à partir de zéro à chaque fois, puis les trois étapes sont exécutées à chaque fois.
Mais si vous utilisez des variables de liaison à chaque fois, la requête a le même aspect, de sorte que la base de données utilise un plan de requête en cache, ce qui accélère l'exécution de la requête. Même vous pouvez appeler oci_parse()
une seule fois et réutiliser $stmt
variable avec un ensemble différent de paramètres fournis.
Ainsi, pour de meilleures performances, vous devez utiliser une variable de liaison et la remplir avec un tableau en utilisant oci_bind_array_by_name
.
Une chose supplémentaire est que la récupération des résultats en utilisant oci_fetch_all
peut être plus rapide que la lecture du jeu de résultats ligne par ligne, mais cela dépend de la logique de traitement des résultats.
Mettre à jour
Il semble que la transmission de paramètres de tableau ne fonctionne que si vous allez exécuter un bloc PL/SQL et que vous ne pouvez pas l'utiliser avec des instructions SQL. Mais une autre possibilité est d'utiliser des collections
pour transmettre la liste des valeurs des paramètres. Il est possible de satisfaire les conditions de la question même avec des tableaux, mais cette méthode est moins élégante.
En plus des différentes manières d'interroger une base de données, il existe des paramètres tels que les paramètres système. Dans le cas de PHP, il y a des paramètres dans php.ini
fichier qui contrôle l'interaction avec Oracle. L'un d'eux (oci8.statement_cache_size
) liés à la mise en cache et aux performances d'une requête.
Exemples
Tous les exemples utilisent la même configuration de données dans Oracle.
Pour transmettre des données, je choisis SYS.ODCIVarchar2List
prédéfini type, mais il est également possible de définir un type personnalisé avec les mêmes caractéristiques (illustré dans l'exemple de configuration des données). Vous trouverez ci-dessous du code pour démontrer la configuration du schéma de données et le principe d'utilisation des collections dans 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;
/
Requêtes pour démontrer les collections :
--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))
)
/
Exemple 1 - appel depuis PHP à l'aide de collections
<?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);
?>
Exemple 2 - Appel depuis PHP à l'aide d'un tableau et d'un package
<?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);
?>
Exemple 3 - appel depuis PHP à l'aide d'un tableau et d'un bloc anonyme
<?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);
?>