!
!
!
!
!
!
!
!

White Paper
Les curseurs
Toute instruction SQL est traitée par ORACLE en tant que curseur. Un curseur est un objet qui permet à ORACLE de résoudre quelques problèmes d’interprétation, d’exécution, de partage et de performance. Le curseur consiste en un ensemble de zones mémoire dont la SGA, plus précisément le shared pool.
Quand une session doit exécuter un curseur qui est déjà partagé dans le shared pool, elle doit acquérir un lien (pin) vers le handle de ce curseur. L’établissement de ce lien recharge implicitement ce curseur dans le cas de son vieillissement dans le cache, traduit par la colonne LOADS de la vue v$sqlarea. Ce vieillissement se produit notamment quand d’autres curseurs nécessitent de l’espace libre dans le cache et celui-ci a une taille inappropriée pour l’applicatif, ou lors de la présence du bug 1318267.
Le phénomène de chargement est gourmand en ressources (c’est pour éviter la consommation de ces ressources employés que le cache est utilisé). Idéalement, pour une instruction SQL, un seul chargement (initial est nécessaire) même dans le cas des millions d’exécutions.
Le traitement SQL
Comment interpréter les statistiques concernant le shared pool ?

Les trois phases de traitement SQL

Nous allons étudier en détail la façon dont le process SERVER exécute un ordre SQL transmis par le process utilisateur. Le process SERVER divise l'exécution d'un ordre SQL en trois phases : Analyse ou Parsing, Execute, Fetch.

Parsing et optimisation

Durant cette phase, ORACLE transforme la chaîne de caractères que vous croyez être ‘un ordre SQL’ en une requête intelligible par son noyau. Quelques étapes sont franchies lors du parsing :
  • Vérification de la syntaxe de l'ordre SQL.
  • Recherche dans le dictionnaire de données des informations :
    L’existence et les structures des objets référencés.
    Les droits de l'utilisateur sur les objets référencés.
    Les différents chemins d'accès (indirectement).
  • Traduction des noms employés (synonymes).
  • Mise dans le library cache de la requête SQL.
L’ensemble de ces étapes est connu dans la littérature ORACLE sous le nom de hard parse. Cette étape est extrêmement gourmande en ressources. Il est important de noter qu’à ce stade, le curseur (l’ordre SQL) est réellement stocké dans la shared pool, mais il n’est pas partagé, il est partageable. Il deviendra partagé lors de l’utilisation du curseur par une autre session lorsqu’un ordre identique devra s’exécuter.
A l'aide des informations ainsi collectées, ORACLE élabore un plan d'exécution. Ce plan d'exécution est ensuite stocké dans la SHARED POOL. Il sera partagé par tous les utilisateurs qui effectueront le MÊME ordre SQL. Le mécanisme de partage tire profit d’un algorithme de hachage qui est appliqué à l’intégralité du texte de l'ordre SQL :
  • La valeur calculée est comparée aux valeurs des autres ordres SQL déjà présents dans la SHARED POOL.
  • Si les valeurs de hachage sont identiques, les textes des curseurs qui partagent la même chaîne de valeurs sont comparés avec le texte actuel.
  • Si aucun texte n’est identique, il constituera un père pour tous les futurs ordres SQL identiques. Un enregistrement enfant est également constitué.
  • Si le texte est identique, il constituera une occurrence supplémentaire dans la liste des ‘enfants’ qui ont un père commun. Dans ce cas, des vérifications supplémentaires sont effectuées concernant les variables, l’authentification de l’utilisateur, la résolution des synonymes, etc.
Les étapes 1, 2 et 4 sont connues sous le nom de soft parse. L’idéal serait de faire le minimum de hard parse et le maximum de soft parse. Pourquoi cette organisation ? Il est fort probable que des requêtes avec des textes identiques se réfèrent à différents types d’objets, ont des bind variables de types différents, qu’elles soient lancées par des utilisateurs avec des privilèges différents, etc. Dans toutes les situations, l’enregistrement père contiendra le texte SQL et le type d’optimisation (RULE/CHOSE) et les enregistrements enfants contiendront le plan d’exécution, et les bind variables. Le soft parse tirera profit des informations déjà présentes dans les zones privées des curseurs.
En conclusion, pour partager un curseur, les ordres qui interrogent les mêmes données doivent être IDENTIQUES ! C’est pour ceci qu’idéalement les ordres souvent passés devraient passer par des procédures stockées : une procédure stockée présentera toujours le même texte au noyau, donc elle aura toujours le même résultat à la fin de la fonction de hachage. D’un autre point de vue, les procédures stockées offrent l’avantage d’être enregistrées avec le plan d’exécution, ceci réduit énormément l’étape de parsing.
Globalement, le parsing est une étape gourmande en ressources et actions. En conséquence, une des actions importantes de l’optimisation de la base de données est l’optimisation des ordres SQL. Un des buts souhaités est de minimiser le parse et load des requêtes. Pendant cette phase, un lock de type KGL est posé sur les objets participants à la requête : aucune structure référencée ne peut être modifiée pendant l’opération.

Hit ratio du parse

Des informations concernant les diverses étapes de l’analyse sont disponibles dans quelques vues :
V$LIBRARYCACHE, V$SQLAREA, V$SQL.
Comme spécifié dans les paragraphes précédents, le rapport hard parses/soft parses devrait avoisiner 0. La requête suivante calcule le parse hit ratio, indicateur convenable des performances du library cache, reflet de la ‘bonne écriture des ordres SQL’ :
Select 100*gethits/gets from V$LIBRARYCACHE where namespace = ‘SQL AREA’;
Le résultat de cette requête devrait avoisiner 100 pour-cent (résultat impossible, au moins un hard parse est à faire pour chaque curseur).
Quelques paramètres de la vue V$SQLAREA sont essentiels pour déterminer les divers problèmes d’analyse :
LOADS
Nombre d’interprétations de l’ordre SQL. Un minimum de loads (valeur à un) est souhaitable.
VERSION_COUNT
Un même ordre SQL (en-tête du curseur) peut avoir plusieurs enfants (corps du curseur), en fonction de la résolution différente des synonymes, variables bind, etc.

Execute

Durant la phase d'exécution de l'ordre SQL, le process SERVER :
  • Applique le plan d'exécution aux données lues (qui se trouvent donc dans les buffers de données, en SGA).
  • Effectue des lectures physiques depuis les fichiers de données ou des lectures/écritures en mémoire.

Fetch

Pendant la phase de 'Fetch', les enregistrements sont transférés depuis les buffers de données vers le process utilisateur. Comment ? Avant la 8i, le curseur (explicite ou implicite) ramène les données ligne par ligne. Depuis la 8i, le curseur peut ramener des paquets de lignes lors du fetch.

LOADS INVALIDATIONS EXECUTIONS SQL_TEXT                                            
----- ------------- ---------- --------------------------------------------------  
93453            13      22228 insert into (coupé par TAFORA)                  
Après
----- ------------- ---------- --------------------------------------------------  
LOADS INVALIDATIONS EXECUTIONS SQL_TEXT                                            
1                 0      22550 insert into (coupé par TAFORA)                  
A voir directement sure le site TAFORA (www.tafora.fr):
  • Comment obliger Oracle de ne pas permettre le vieillissement des instructions SQL dans le shared pool ?
  • Comment reconnaître les instructions rebelles pour les fixer dans le shared pool ?
Mieux ranger le code
Deux notions Oracle permettent de mieux ranger les instructions SQL dans le shared pool :
  • Le paramètre shared_pool_reserved_size associé à shared_pool_reserved_min_alloc. Le paramètre shared_pool_reserved_size (zone qui fait partie de shared pool) sera utilisé pour stocker les gros objets (la limite ‘gros’ est établie par shared_pool_reserved_min_alloc) dans la zone réservée. Cette zone permet de ne pas mettre dans le reste du shared pool des objets qui risqueraient de la fragmenter gravement.
  • piner ;-) au démarrage de l'instance les objets souhaités avec dbms_shared_pool.keep: Les plus gros d'abord, taille calculée avec
SQL> col name FOR a30
SQL> col TYPE FOR a15
SQL> select name, type, SHARABLE_MEM
  2     from  v$db_object_cache
  3     where type in ('PACKAGE BODY', 'PROCEDURE', 'FUNCTION')
  4     AND SHARABLE_MEM > 20000 /* ce qui dépasse 2k */
  5     order by SHARABLE_MEM desc;
NAME                           TYPE            SHARABLE_MEM
------------------------------ --------------- ------------
DRIDDL                         PACKAGE BODY           73829
STATSPACK                      PACKAGE BODY           50010
CTX_DDL                        PACKAGE BODY           47514
DRIUTL                         PACKAGE BODY           45293
DRIPARSE                       PACKAGE BODY           42459
. . . etc

Copyright © 1998-2002 Radu Caulea, TAFORA MAJ 06/11/2006 !
Commentaires et suggestions radu[CHEZ]tafora.fr