Aucun message portant le libellé SHARED_POOL. Afficher tous les messages
Aucun message portant le libellé SHARED_POOL. Afficher tous les messages

vendredi 10 septembre 2010

Recompilation de packages PL/SQL sous Oracle RAC 11gR2

Suite à la mise en place d'une nouvelle version d'un package PL/SQL, certaines applications obtenaient l'erreur suivante :

ERROR at line 1:
ORA-04068: existing state of packages has been discarded
ORA-04065: not executed, altered or dropped stored procedure "ABC.PKG_CALC_PAMNT"
ORA-06508: PL/SQL: could not find program unit being called: "ABC.PKG_CALC_PAMNT"
ORA-06512: at "ABC.PKG_FACTRN", line 4


Habituellement, cette erreur disparait dès le prochain accès au package. C'est le cas pour la session active sauf que, lorsqu'il y avait une nouvelle connexion avec le même compte Oracle, l'erreur réapparaissait.

Étrangement, cette erreur ne se produisait pas pour certaines applications... pourquoi? Et bien, c'est surement parce que nous utilisons les services Oracle pour la répartition de la charge sur les différents noeuds hébergeant les instances du Cluster RAC 11gR2. Compte tenu que cette erreur était, disons-le, absurde, j'ai commencé à douter de la "fraîcheur" des caches en mémoire. Après quelques essais, je me suis rendu compte que le problème survenait sur une instance et non sur les autres. J'ai alors décidé de forcer une réinitialisation du "shared pool" pour que la nouvelle définition de l'objet y soit stockée. Pour ce faire, j'ai exécuté la commande : "Alter system flush shared_pool;" et, effectivement, l'erreur n'a par réapparu.

mardi 15 juin 2010

Enlever un énoncé SQL de la cache (SHARED POOL)

Voici un script que j'utilise pour supprimer une requête (énoncé SQL) de la cache partagée nommé "shared pool". Ce script est fort utile lorsque vous effectuez du "tuning" de requête.

REM *******************************************************************
REM * Script: FlushSQL.sql
REM * Titre : Chercher et générer la commande pour enlever un énoncé
REM * SQL du SHARED POOL
REM * Auteur: Eric Cloutier
REM * Date modif. : 15-06-2010
REM * Parametres :
REM * Aucun
REM *******************************************************************
set pagesize 9999 feed off linesize 200 trimspoo on verify off
--
-- Sous 10g (10.2.0.4) :
-- Alter session set events '5614566 trace name context forever';
--
spool FlushSQL.log

Accept sql_text prompt 'Inscrire une partie de la requête (LIKE est utilisé alors inscrire %): '

col cmd_sql format a80
col username format a20
col executions format 999999
col sql_text format a30 wrap

select 'exec sys.dbms_shared_pool.purge('''||address||','||hash_value||''',''C'',1);' cmd_sql,
sql_id, child_number, executions, u.username, sql_text
from v$sql s, dba_users u
where upper(sql_text) like upper(nvl('&sql_text',sql_text))
and sql_text not like '%from v$sql where sql_text like nvl(%'
and u.user_id = s.parsing_user_id
/

spool off
set feed on linesize 5000
Prompt
Prompt -- Résultat dans le fichier : FlushSQL.log
Prompt

Cette fonctionnalité peut être utilisé en 10g (10.2.0.4) cependant, vous devez initialiser un "event" soit à la session ou au niveau de la base de données que qu'elle fonctionne.

Un merci particulier à Kerry Osborne pour son blog.

mercredi 24 mars 2010

Comportement des statistiques systèmes en mode RAC

Lors de la collecte des statistiques systèmes d'un environnement RAC, on peut déclencher la collecte à partir de n'importe quelle instance. Tout s'effectue correctement... À vrai dire, pas exactement car les autres instances attachées au cluster ne prennent pas en compte les nouvelles valeurs.

Je me suis aperçu de ce problème quand une requête est devenue gourmande. Le plan d'exécution de la requête était complètement différent sur 2 instances. En me connectant sur l'une des instances du cluster, j'ai vérifié les valeurs des statistiques (select * from sys.aux_stats$). C'est à ce moment que j'ai remarqué qu'elles avaient été régénérées récemment et l'un de mes collègues me l'a confirmé. J'ai aussi eu la confirmation que la lenteur avait été observée depuis la date de la régénération des statistiques. Donc, je pouvais déduire que la collecte de statistiques systèmes était l'élément déclencheur.

Que se soit sur l'une ou l'autre des instances du cluster, les mêmes statistiques sont supposées être utilisées dont je suspecte que le problème soit au niveau de la mémoire ou d'une certaine cache. J'ai tenté une simple purge du "shared pool" et celle des données mais sans succès. Comme à l'habitude, j'ai fait une petite recherche sur Metalink et effectivement, il y a un problème de répertorier sur la base de données 10.2.0.3. (ID 7645777.8) concernant un plan d'exécution différent sur des instances RAC. La solution : Recycle the instances... Qu'est-ce que cela veut dire exactement ?!? J'imagine que c'est l'équivalent d'un redémarrage d'instance et, si c'est le cas, et bien, je ne peux pas me le permettre. Vu que ce bug concerne les statistiques systèmes alors, j'ai décidé de pousser la vérification en influençant l'optimisateur pour qu'il n'utilise pas les statistiques liées au CPU. Pour ce faire, j'ai utilisé le hint "NO_CPU_COSTING". Les résultats furent concluants, j'ai obtenu le même plan d'exécution que sur l'instance où la requête est optimale.

Tant qu'à pousser, j'ai décidé d'effectuer une trace de l'optimisateur sur l'exécution de la requête sur chacune des instances avec la commande :

ALTER SESSION SET EVENTS '10053 trace name context forever, level 1'

Les 2 fichiers de trace ont démontrés que les statistiques systèmes sont différentes donc ça confirme que l'optimisateur n'utilise pas les mêmes valeurs d'une instance à l'autre... Inquiétant ?

Après réflexion, je me suis dit, pourquoi ne pas répéter ou presque les mêmes étapes de collecte de statistiques systèmes mais cette fois-ci, en étant connecté sur l'instance n'ayant pas le même comportement ou si vous préférez, le même plan d'exécution. Alors, j'ai effectué ceci :

-- Établir une connexion sur l'instance qui n'utilise pas les nouvelles valeurs
connect sys@inst1 as sysdba

-- Prendre une copie des statistiques actuelles
Drop table stats_bkp;
EXECUTE DBMS_STATS.CREATE_STAT_TABLE ('SYS','stats_bkp','SYSAUX');
EXECUTE DBMS_STATS.EXPORT_SYSTEM_STATS (stattab => 'stats_bkp', statid => 'stats_bkp', statown => 'SYS');
select * from sys.stats_bkp;

-- Charger les valeurs
execute DBMS_STATS.DELETE_SYSTEM_STATS;
EXECUTE DBMS_STATS.IMPORT_SYSTEM_STATS (stattab => 'stats_bkp', statid => 'stats_bkp', statown => 'SYS');
select * from sys.aux_stats$;


-- Initialiser les espaces mémoires
Alter system flush shared_pool;
Alter system flush buffer_cache;


Et bien oui, ça fonctionne! La requête a maintenant le même plan d'exécution que sur l'autre instance. Stop! Le problème s'est déplacé sur l'autre instance... oups! Ok, alors, je vais refaire la même chose, mais cette fois-ci sur l'instance où le problème s'est déplacé. Suite à l'exécution des commandes précédentes, le plan d'exécution est redevenu celui d'auparavant et, sans impacter le plan d'exécution sur l'autre instance.

Je crois qu'un redémarrage de l'instance aurait pu régler le problème sauf que lorsque nous sommes sur un environnement de production, cela n'est pas toujours une solution et ce, même si c'est un environnement RAC à moins que vous preniez le temps de déplacer tous les services vers une autre instance puis que vous patientez jusqu'à ce que toutes les sessions se soient reconnectés vers la nouvelle instance.

lundi 17 août 2009

Jouons à cache-cache

À l'occasion, il peut être très payant de conserver en mémoire certains objets qui sont accédés fréquemment.

Objets PL/SQL
Les objets sont conservés dans l'espace mémoire partagé (shared pool) en utilisant le package « dbms_shared_pool ». Ce dernier doit être installé à partir du script « dbmspool.sql ».

Voici comment mettre en mémoire un objet :

execute dbms_shared_pool.keep('propriétaire.nom_objet');

Pour lister tous les objets qui sont conservés dans l'espace mémoire partagé :

select owner,name,type,sharable_mem from v$db_object_cache where kept='YES';

Pour identifier les objets qui pourrait être conservés en mémoire :

select substr(owner,1,10)'.'substr(name,1,35) "ObjectName",
type, sharable_mem,loads, executions, kept
from v$db_object_cache
where type in ('TRIGGER','PROCEDURE','PACKAGE BODY','PACKAGE')
and executions > 0
order by executions desc,loads desc,sharable_mem desc;

Certains objets appartenant à SYS pourraient être des candidats très intéressants, dépendamment de leur utilisation.

Tables et Indexes

Initialiser le cache « KEEP »

Alter system set db_keep_cache_size = 208M scope=spfile;
-- Peut être très intéressant pour les grosses tables qui sont chargées à 'occasion. Les données misent en cache n'affecteront pas les caches habituelles.
-- alter system set db_recycle_cache_size = 50M;
shutdown immediate
startup

Générer la commande mettant les tables candidates en cache « KEEP »

select 'Alter table 'owner'.'table_name
' storage (buffer_pool keep);', num_rows
from dba_tables
where owner in ('SCHEMA_1','SCHEMA_2')
and table_name in ('TABLE_1','TABLE_2')
order by num_rows
/

Générer la commande mettant les indexes candidates en cache « KEEP »

select 'Alter index 'owner'.'index_name
' storage (buffer_pool keep);', num_rows
from dba_indexes
where owner in ('SCHEMA_1','SCHEMA_2') and table_name in
('TABLE_1','TABLE_2')
order by num_rows
/

Charger les données dans le pool « KEEP »

select 'Select /*+ FULL(TABL) */ * from '
owner'.'table_name' TABL;'
from dba_tables
where owner in ('SCHEMA_1','SCHEMA_2')
and table_name in ('TABLE_1','TABLE_2')
order by num_rows
/