Tuning SGA avec les vues dynamiques

Tuning

Depuis quelques version d’Oracle, la gestion de la mémoire a été simplifiée, comprenez que le nombre de paramètres minimal liés à sa gestion a été considérablement réduit. En clair, il suffirait de positionner le volume global de mémoire à allouer à l’instance par le truchement du paramètre memory_target et par le biais de réallocations dynamiques oracle serait capable de se débrouiller. On constate bien vite que c’est faux notamment pour le tuning sga.

Comme d’habitue lors de ce genre de cas, si on laisse l’initiative à Oracle, au bout d’un moment la mémoire finit par fragmenter et malgré une taille globale suffisante on rencontre de vilaines erreurs ORA-4031. Et plus généralement ce mode d’allocation (via memory_target donc) n’est pas compatible avec l’utilisation de huge pages. Il est donc recommandé de tuner les différentes sous-sections de mémoire, la pga au travers de pga_aggregate_target et la sga au travers de sga_target. Ces deux paramètres seuls ne suffisent cependant encore pas et il faut positionner des valeurs pour les divers pools et caches de la SGA qui seront considérées comme des minimums.

(suite…)

Scripts SQL

Branchements et boucles en pur SQL

SQL est pratique mais il est compliqué de produire un script SQL qui s’adapte à toutes les versions de la base oracle ou qui réagit en fonction de certains résultats de requêtes. Cet article pour donner des astuces de scripting afin de gérer des branchements et boucles en pur SQL et de pouvoir créer des scripts adaptifs.
(suite…)

Purger les problèmes dans ADRCI

Le souci

J’utilise la commande purge d’adrci mais mes problèmes restent présents

La commande

adrci> delete from PROBLEM

L’autre souci

L’autre souci c’est que ça purge tous les problèmes et que j’aimerais bien garder ceux qui sont “récents”.

C’est pas interdit de demander de l’aide …

adrci> help delete

  Usage: DELETE FROM <relation> [WHERE <predicate_string>]
       Arguments:
         <relation_name>: Name of the relation to delete from.

      [WHERE <predicate_string>]: The predicate string must be double-quoted.

      Examples:
       delete from incident where 'incident_id > 1'
adrci> show problems

ADR Home = /opt/oracle/diag/rdbms/dbun/DBNAME:
*************************************************************************
PROBLEM_ID           PROBLEM_KEY                                                 LAST_INCIDENT        LASTINC_TIME
-------------------- ----------------------------------------------------------- -------------------- ----------------------------------------
1                    ORA 600 [psdnopGetACL-4]                                    81105                2016-03-27 03:53:10.648000 +02:00
2                    ORA 600 [ktcccod-1]                                         3960130              2016-04-22 06:25:53.408000 +02:00
3                    ORA 600 [kdBlkCheckError]                                   8600040              2016-05-24 11:14:17.489000 +02:00

Allons-y essayons

adrci> delete from PROBLEM where lastinc_time < to_date('2016-03-27 04:00:00', 'YYY-MM-DD HH24:MI:SS' )
DIA-48260: Function to_date not found

Mince, c’est pas du vrais SQL Oracle avec les fonctions qui vont bien !

adrci> delete from PROBLEM where lastinc_time < sysdate-60
DIA-48230: Expression arguments must match types
DIA-48249: Type mismatch - lhs = 7, rhs = 6, result = 8, op = 0

Mince, ça ne sait pas transtyper !

adrci> delete from PROBLEM where lastinc_time < systimestamp - 60

1 Row Deleted

adrci> show problems

ADR Home = /opt/oracle/diag/rdbms/dbun/DBNAME:
*************************************************************************
PROBLEM_ID           PROBLEM_KEY                                                 LAST_INCIDENT        LASTINC_TIME
-------------------- ----------------------------------------------------------- -------------------- ----------------------------------------
2                    ORA 600 [ktcccod-1]                                         3960130              2016-04-22 06:25:53.408000 +02:00
3                    ORA 600 [kdBlkCheckError]                                   8600040              2016-05-24 11:14:17.489000 +02:00
2 rows fetched

C’était pourtant pas si compliqué

Tuer une tâche datapump qui n’a plus son fichier dump sur disque

Le souci

Mon export datapump s’est planté, j’ai effacé mon fichier de dump et donc plus moyen de faire l’attachement qui me permettrait de tuer la tâche en faisant kill_job. Pire encore, quand je tente le coup, datapump me donne un message d’erreur qui n’a pas gtrand chose à vois avec la problème réel.

[oracle@serveur ~]$ impdp toto/lolo attach=SYS_IMPORT_TRANSPORTABLE_01

Import: Release 11.2.0.4.0 - Production on Thu Apr 7 09:45:57 2016

Copyright (c) 1982, 2011, Oracle and/or its affiliates.  All rights reserved.

Connected to: Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Production
With the Partitioning option
ORA-31626: job does not exist
ORA-06512: at &amp;quot;SYS.DBMS_SYS_ERROR&amp;quot;, line 79
ORA-06512: at &amp;quot;SYS.KUPV$FT&amp;quot;, line 405
ORA-31638: cannot attach to job SYS_IMPORT_TRANSPORTABLE_01 for user TOTO
ORA-31632: master table &amp;quot;TOTO.SYS_IMPORT_TRANSPORTABLE_01&amp;quot; not found, invalid, or inaccessible
ORA-00942: table or view does not exist

(suite…)

Vérifier le paramétrage CBO spécifique à une instance

Normalement on sait comment se comporte l’optimiseur Oracle, mais quand on a des surprises, c’est parfois tout simplement lié au paramétrage CBO, donc avant de sauter aux conclusions un petit check-up n’est pas du luxe.

Deux requêtes pour ça, les premières, basées sur v$sys_optimizer_env, pour vérifier le paramétrage, la dernière, basée sur v$system_fix_control pour voir si on a modifié le patchset :

select NAME
     , VALUE
     , DEFAULT_VALUE 
from v$sys_optimizer_env 
where VALUE &lt;&gt; DEFAULT_VALUE ;

Résultat (pour exemple de pourquoi ce con m’a mis optimizer_index_caching à 100 ? )

NAME                                     VALUE                     DEFAULT_VALUE
---------------------------------------- ------------------------- -------------------------
_pga_max_size                            4194200 KB                2048000 KB
optimizer_index_cost_adj                 10                        100
optimizer_index_caching                  100                       0

Si on a la possibilité d’effectuer la requête en tant que SYS, on peut aller un peu plus loin avec la ‘fixed table’ x$qkscesys :

select pname_qkscesyrow NAME
     , PVALUE_QKSCESYROW VALUE
     , DEFPVALUE_QKSCESYROW default_value
from x$qkscesys 
where PVALUE_QKSCESYROW != DEFPVALUE_QKSCESYROW
union 
select name
     , value
     , default_value 
from v$sys_optimizer_env
where VALUE &lt;&gt; DEFAULT_VALUE ;

Il est à noter que l’on peut aussi travailler au niveau des sessions avec x$qksceses et v$ses_optimizer_env, attention cependant, ces vues renseignent les SID (Session ID) mais pas les valeurs par défaut.

select VALUE
     , DESCRIPTION
     , OPTIMIZER_FEATURE_ENABLE
from V$SYSTEM_FIX_CONTROL
where IS_DEFAULT=0 ;

C’était pourtant pas si compliqué.

Identifier sa session

En PL/SQL

exec sys.dbms_session.set_identifier          ('identifiant de session')
exec sys.dbms_application_info.set_client_info('info client')
exec sys.dbms_application_info.set_module     ('module', 'action')

Eventuellement, si l’on veut ne changer que l’action

exec sys.dbms_application_info.set_action('action')

En PHP

<?php 
 oci_set_client_identifier($db , 'identifiant de session'); 
 oci_set_client_info      ($db , 'info client'); 
 oci_set_module_name      ($db , 'module'); 
 oci_set_action           ($db , 'action'); 
?>

Retrouver ces informations

select sys_context('USERENV', 'CLIENT_IDENTIFIER') as "client identifier"
     , sys_context('USERENV', 'CLIENT_INFO') as "client info"
     , sys_context('USERENV', 'MODULE') as module
     , sys_context('USERENV', 'ACTION') as action
from sys.dual ;

Avec un peu de mise en forme

SQL> col "client identifier" for a25
SQL> col "client info" for a17
SQL> col module for a17
SQL> col action for a17

SQL> /

client identifier         client info       MODULE            ACTION
------------------------- ----------------- ----------------- -----------------
identifiant de session    info client       module            action

C’était pourtant pas si compliqué

PS: On peut aussi le faire en java ou en .Net si tant est qu’on utilise encore des trucs aussi dépassés ou encore en C via la bibliothèque OCI1 si l’on est résolument moderne. Tout cela est détaillé dans l’excellent Troubleshooting Oracle Performance de Christian Antognini paru chez APress au chapitre 2 pages 45 à 48. Et de manière plus cryptique et éparpillée dans la documentation de l’éditeur.


1. OCI pour Oracle Call Interface, livré par Oracle avec tous les “clients”

Lister les structures mémoire

La structure mémoire (X$…) qui garde la trace des structures mémoires est x$kqfta pour les lister c’est la requête suivante :

select KQFTANAM from x$kqfta

ou, plus simple encore :

select name from v$fixed_table

C’est tout de même plus simple que de passer par un code perl qui ne va pas forcément s’avérer complet

Toujours intéressant à lire sur le sujet : http://www.orafaq.com/wiki/X$_Table ou encore http://yong321.freeshell.org/computer/x$table.html

Trouver le DDL d’une vue dynamique (V$… ou GV$…)

On utilise v$fixed_view_definition

SELECT * 
FROM v$fixed_view_definition 
where view_name = upper('v$fixed_view_definition')

On obtient :

V$FIXED_VIEW_DEFINITION
SELECT * FROM gv$fixed_view_definition where inst_id = USERENV('Instance')

Et donc, comme on a autre chose que du fromage blanc entre les oreille on passe la requête suivante :

SELECT * 
FROM v$fixed_view_definition 
where view_name = upper('gv$fixed_view_definition')

Pour finalement obtenir :

GV$FIXED_VIEW_DEFINITION
select i.inst_id,kqfvinam,kqftpsel from x$kqfvi i, x$kqfvt t where i.indx = t.indx

C’était pourtant pas si compliqué

(Dés)activer les taches automatiques

Sous Oracle on ne sait jamais si les tâches automatisées (autotasks en langue de Redwood Shores) sont actives ou non, lesquelles sont-elles et comment les activer ou les désactiver.

Lister les tâches automatiques actives

SELECT client_name, status
FROM dba_autotask_client
/
CLIENT_NAME                         STATUS
----------------------------------- ----------
auto optimizer stats collection     ENABLED
auto space advisor                  ENABLED
sql tuning advisor                  ENABLED

En désactiver une (en l’occurrence l’auto space advisor)

BEGIN
  dbms_auto_task_admin.disable('auto space advisor'
                              , NULL
                              , NULL);
END;
/

PL/SQL procedure successfully completed.

Pour vérifier

SELECT client_name, status
FROM dba_autotask_client
/
CLIENT_NAME                         STATUS
----------------------------------- ----------
auto optimizer stats collection     ENABLED
auto space advisor                  DISABLED
sql tuning advisor                  ENABLED

En activer une (en l’occurrence l’auto space advisor)

BEGIN
  dbms_auto_task_admin.enable( 'auto space advisor'
                              , NULL
                              , NULL);
END;
/

PL/SQL procedure successfully completed.

Vérifier

SELECT client_name, status
FROM dba_autotask_client
/
CLIENT_NAME                         STATUS
----------------------------------- ----------
auto optimizer stats collection     ENABLED
auto space advisor                  ENABLED
sql tuning advisor                  ENABLED

C’était pourtant pas si compliqué.

Générer un horodatage régulier

Problématique : on veut générer une suite de dates (surtout les heures, minutes et secondes) depuis en SQL pur

-- nombre de secondes
var nbsec number

-- nombre de valeurs souhaitées 
var nbVals number

-- On veut les 15 premiers multiples de 19 secondes
exec :nbsec := 19
exec :nbVals := 15 

-- La requête
select  to_char( trunc(sysdate-1) 
               + ( rownum/ ( 60 *60 *24 ) ) * :nbsec  
               , 'HH24:MI:SS' ) dt 
from dual
connect by rownum <= :nbVals ; 

Résultat

DT
--------
00:00:19
00:00:38
00:00:57
00:01:16
00:01:35
00:01:54
00:02:13
00:02:32
00:02:51
00:03:10
00:03:29
00:03:48
00:04:07
00:04:26
00:04:45

15 lignes sélectionnées.

C’était pourtant pas si compliqué.