Le bind peeking (10g et antérieure)

A partir de l'article concernant les binds variables, il a été mis en évidence l'importance des bind variables pour les requêtes régulièrement utilisées (OLTP) ; cependant, un phénomène peut parfois apparaître et fausser complètement les plans d'exécution de la journée ; il s'agit du bind peeking. Ceci se traduit par l'utilisation d'un mauvais plan d'exécution car élaboré par des variables non représentatives.
En effet, lors de l'utilisation de bind variables, Oracle établit le plan au premier appel ; en utilisant donc les valeurs passées à ce moment là ; si les valeurs ne sont pas représentatives des futures valeurs, le plan sera alors inadapté.

Voici un exemple permettant de mieux comprendre :

Création d'une table pour le test :
create table bind_peeking (num number, type char(1));

Remplissage de table de manière hétérogène (une valeur sur 800 aura pour type 'R', les autres auront pour type 'F') :
begin
for i in 1 .. 10000 loop
insert into bind_peeking values (i, decode(mod(i,800),12, 'R', 'F'));
end loop;
end;
/

commit;


Création de l'index sur la colonne hétérogène :
SQL> create index i_bp_type on bind_peeking (type);

Index created.


Collecte des statistiques de la table et des index associés avec prise d'histogrammes :
BEGIN
DBMS_STATS.GATHER_TABLE_STATS (OWNNAME => 'HR',
tabname => 'BIND_PEEKING',
method_opt => 'FOR ALL INDEXED COLUMNS SIZE 10'
);
end;
/
PL/SQL procedure successfully completed.


Affichage du nombre de tuples selon la valeur de type :
SQL> select type, count(*) from bind_peeking group by type;


T COUNT(*)
- ----------
R 13
F 9987


Plan d'exécution
associés aux requêtes de sélection :

SQL> set autot trace exp
SQL> select num from bind_peeking where type = 'R';

Execution Plan
----------------------------------------------------------
Plan hash value: 79608651

--------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)
--------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 13 | 65 | 2 (0)
| 1 | TABLE ACCESS BY INDEX ROWID| BIND_PEEKING | 13 | 65 | 2 (0)
|* 2 | INDEX RANGE SCAN | I_BP_TYPE | 13 | | 1 (0)
--------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

2 - access("TYPE"='R')

SQL> select num from bind_peeking where type = 'F';

Execution Plan
----------------------------------------------------------
Plan hash value: 647370048

--------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time
--------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 9987 | 49935 | 8 (13)| 00:00:01
|* 1 | TABLE ACCESS FULL| BIND_PEEKING | 9987 | 49935 | 8 (13)| 00:00:01
--------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

1 - filter("TYPE"='F')


On constate ainsi que le plan diffère selon le prédicat de la clause WHERE.

Dans le cas de requêtes utilisant une bind variable sur ce prédicat, il est possible de constater, selon la première valeur utilisée, la prise en compte de l'un ou l'autre des plans d'exécution jusqu'au vidage de cache ou débordement de la LRU.

C'est pour cette raison que les bind variables peuvent être nuisibles, notamment dans le cadre de traitement batch (où le temps de construction du plan d'exécution est généralement négligeable au regard de la requête elle-même.




Vous n'avez pas trouver réponse à votre question ? Préciser votre recherche :

Catégories