vendredi 3 septembre 2010

Actualisation d'une vue matérialisée avec l'option "parallel"

En tentant de mettre en place une tâche via Oracle Scheduler qui effectue le rafraichissement d'un groupe de vues matérialisées, j'obtenais une erreur qui sentait le "service request" à plein nez !

ORA-07445: exception encountered: core dump [_memcpy()+264] [SIGSEGV] [ADDR:0x0] [PC:0xFFFFFFFF7C500908] [Address not mapped to object] []

Ce genre d'erreur n'augure jamais bien. Après avoir fouillé et effectué un ensemble de tests, j'ai réussi à identifier la vue matérialisée qui causait l'erreur. Elle comportait des colonnes dont le type de données est SDO_GEOMETRY (Oracle Spatial) et la source de celle-ci se trouve sur une base de données distante. Voilà, des particularités intéressantes...

Après avoir googolisé le Net de bout en bout, je me suis souvenu que la manipulation des données spatiales sont souvent capricieuses. J'ai alors réalisé qu'en enlevant les colonnes de la vue, je pouvais actualiser (refresh) la vue matérialisée avec succès.

Avec un peu de recul, je me suis dit : "Utilisons une commande simple qui n'utilisera pas des fonctionnalités qui pourrait augmenter les chances de provoquer des erreurs". La commande CREATE MATERIALIZED VIEW utilisait le parallélisme.... Hmmm... Spatial et parallélisme... Une autre belle particularité ! Essayons NOPARALLEL, juste pour voir. Eh bien, devinez quoi? L'actualisation de la vue matérialisée a fonctionné.

Dans mon cas, le parallélisme n'est vraiment pas obligatoire donc, je peut m'en passer sans problème. Par contre, comme je le disait plus tôt, il y a sûrement place à créer un SR chez Oracle pour identifier la cause.

jeudi 5 août 2010

La boîte virtuelle d'Oracle

Suite à l'acquisition de la compagnie Sun, Oracle a mis la main sur l'outil permettant de créer et gérer des machines virtuelles (VM). Cet outil s'appelle Virtualbox et sa plus belle qualité est qu'il est gratuit.

J'ai eu la chance de m'amuser avec l'outil et jusqu'à présent, je dois vous dire que je l'apprécie énormément. J'ai pu créer quelques machines virtuelles fonctionnant sous Linux (Oracle Enterprise Linux 5) et actuellement, je tente d'installer un cluster Oracle 11gR2 composé de deux noeuds et un troisième noeud simulant une unité de stockage (SAN). Ce dernier me permettra de configurer des "raw devices" sous Oracle ASM.

Les machines virtuelles sont une belles façon d'expérimenter les produits ainsi que les nouveautés. En quelque sorte, ça devient de réels bacs à sables ou si vous préférez, des terrains de jeux.

Sur Internet, vous trouverez plusieurs informations à propos de Virtualbox tels que des articles (blog), des tutoriels pour procéder à divers installations de systèmes d'exploitation et de logiciels Oracle. Je vous suggère de visiter les adresses suivantes :

Le lien concernant Oracle Technology Network vous permet de télécharger une VM complète qui contient les éléments suivants :

  • Oracle Enterprise Linux 5
  • Oracle Database 11g Release 2 Enterprise Edition
  • Oracle TimesTen In-Memory Database Cache
  • Oracle XML DB
  • Oracle SQL Developer
  • Oracle SQL Developer Data Modeler
  • Oracle Application Express 4.0
  • Oracle JDeveloper
  • Hands-On-Labs (accessed via the Toolbar Menu in Firefox)
Alors, vous n'avez plus de raisons pour ne pas vous amuser ! ;)

mercredi 4 août 2010

Impact des contraintes étrangères sur la performance

Il y a quelques temps, Tom Kyte a effectué un essai pour vérifier l'impact d'une clé étrangère lors de l'insertion de plus de 37 000 rangées.

L'essai consiste à effectuer deux insertions dans deux tables dont l'une d'elle a une clé étrangère :

SQL> alter session set sql_trace=true;
Session altered.
SQL> declare
2 type array is table of varchar2(30) index by binary_integer;
3 l_data array;
4 begin
5 select * BULK COLLECT into l_data from cities;
6 for i in 1 .. 1000
7 loop
8 for j in 1 .. l_data.count
9 loop
10 insert into with_ri 11 values ('x', l_data(j) );
11 insert into without_ri values ('x', l_data(j) );
12 end loop;
13 end loop;
14 end;
15 /
PL/SQL procedure successfully completed.


Le rapport basé sur le fichier de trace généré par l'utilitaire " TKPROF " est le suivant :

INSERT into with_ri values ('x',:b1 )

call count cpu elpsed disk query current rows
------- ------ ---- ------ ---- ----- ------- -----
Parse 1 0.00 0.02 0 2 0 0
Execute 37000 9.49 13.51 0 566 78873 37000
Fetch 0 0.00 0.00 0 0 0 0
------- ------ ---- ------ ---- ----- ------- -----
total 37001 9.50 13.53 0 568 78873 37000

*****************************************************
INSERT into without_ri values ('x', :b1 )

call count cpu elpsed disk query current rows
------- ------ ---- ------ ---- ----- ------- -----
Parse 1 0.00 0.03 0 0 0 0
Execute 37000 8.07 12.25 0 567 41882 37000
Fetch 0 0.00 0.00 0 0 0 0
------- ------ ---- ------ ---- ----- ------- -----
total 37001 8.07 12.29 0 567 41882 37000


L'essai a démontré que lors de l'insertion de 37 000 enregistrements dans la table avec la contrainte référentielle, 0.000256 secondes CPU par enregistrements fut utilisé (9.50/37000). Tandis que la table n'ayant pas de contrainte référentielle, 0.000218 secondes CPU par enregistrement fut utilisé.

Donc, la différence est de 0.00004 secondes CPU. Rien de bien dérangeant. À ce coût, il est préférable de préserver l'intégrité des données.

Je vous invite à visiter le blog de Tom Kytes (http://tkyte.blogspot.com)

mardi 3 août 2010

Identifier les causes des verrous par l'historique

Depuis quelques temps grâce à Oracle Enterprise Manager, nous avons remarqué des verrous empêchaient ou plutôt retardaient certains traitements de se compléter dans un temps normal.

Pour identifier les sessions et/ou les requêtes en cause, j'ai utilisé la requête ci-dessous. Enterprise Manager me fournissait déjà les "session id" donc, assez simple d'extraire les infos et de plus, je savais à quel moment les verrous se sont produits :

col sql_text format a60 wrap
col event format a30 wrap
select count(*), s.sql_text, h.event
from GV$active_session_history h, gv$sql s
where h.sql_id = s.sql_id
and h.blocking_session in (1474,1260,200,592,1165,1351,584,18,780,1164,595)
and h.sample_time between to_date('2010-08-03 03:00:00','YYYY-MM-DD HH24:MI:SS')
and to_date('2010-08-03 12:00:00','YYYY-MM-DD HH24:MI:SS')
group by s.sql_text, h.event
order by 1 DESC;


Dans mon cas, j'ai remarqué beaucoup d'attente lié à une requête qui impliquait l'événement "enq: TX - row lock contention".

Ps. J'ai utilisé la vue GV$... parce que mon cas s'était produit sur un environnement Oracle RAC 11gR2.

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 5 mai 2010

ORA-01078 au démarrage d'une instance Oracle 11g sous ASM

J'ai rencontré cette erreur lors d'un redémarrage de la base de données suite à des modifications de paramètres de bases de données qui sont stockés dans un SPFILE.

La base de données est de la version Oracle 11gR2 et elle est liée à un Grid Infrastructure qui utilise Oracle ASM et Oracle Restart.

Voici les étapes que j'ai suivi pour résoudre le problème :

--
oracle@romeo:/tmp> srvctl stop database -d F100
oracle@romeo:/tmp> srvctl start database -d F100
PRCR-1079 : Failed to start resource ora.f100.db
ORA-01078: failure in processing system parameters
CRS-2674: Start of 'ora.f100.db' on 'romeo' failed


--
-- Tentative de démarrage avec SQL*Plus
--
oracle@romeo:/tmp> sqlplus / as sysdba

SQL*Plus: Release 11.2.0.1.0 Production on Mer. Mai 5 12:07:49 2010

Copyright (c) 1982, 2009, Oracle. All rights reserved.

Connected to an idle instance.

SQL> startup nomount;
ORA-01078: failure in processing system parameters
ORA-00844: Parameter not taking MEMORY_TARGET into account
ORA-00851: SGA_MAX_SIZE 1577058304 cannot be set to more than MEMORY_TARGET 1358954496.

--
-- Tentative de correction de la valeur du paramètre en erreur
--
SQL> alter system set SGA_MAX_SIZE=100 scope=spfile;
alter system set SGA_MAX_SIZE=100 scope=spfile
*
ERROR at line 1:
ORA-01034: ORACLE not available
ID de processus : 0
ID de session : 0, Numéro de série : 0

--
-- Essai de création du pfile à l'image du spfile
--
SQL> create pfile='/tmp/pfileEC.ora' from spfile;
create pfile='/tmp/pfileEC.ora' from spfile
*
ERROR at line 1:
ORA-01565: error in identifying file '?/dbs/spfile@.ora'
ORA-27037: unable to obtain file status
SVR4 Error: 2: No such file or directory
Additional information: 3

--
-- Afficher l'emplacement exact du SPFILE
--
SQL> ! cat $ORACLE_HOME/dbs/initF100.ora
SPFILE='+SYSDG01/F100/spfileF100.ora'

--
-- Création du pfile à l'image du spfile
--
SQL> create pfile='/tmp/pfileEC.ora' from spfile='+SYSDG01/F100/spfileF100.ora';

File created.

SQL> exit

--
-- Éditer le pfile pour enlever la ligne SGA_MAX_SIZE
--
oracle@romeo:/tmp> vi pfileEC.ora

--
-- Redémarrer la base de données avec le PFILE pour s'assurer
-- aucune autre erreur

--
oracle@romeo:/tmp> sqlplus / as sysdba


SQL*Plus: Release 11.2.0.1.0 Production on Mer. Mai 5 12:12:40 2010

Copyright (c) 1982, 2009, Oracle. All rights reserved.


Connected to an idle instance.

SQL> startup pfile='/tmp/pfileEC.ora'

ORACLE instance started.

Total System Global Area 1871208448 bytes
Fixed Size 2149152 bytes
Variable Size 1325405408 bytes
Database Buffers 536870912 bytes
Redo Buffers 6782976 bytes
Database mounted.
Database opened.

--
-- Création du spfile à l'image du pfile
--
SQL> Create spfile='+SYSDG01/F100/spfileF100.ora' from pfile='/tmp/pfileEC.ora';

File created.

--
-- Arrêt de la base de données
--
SQL> shutdown immediate
Database closed.
Database dismounted.
ORACLE instance shut down.
SQL> exit

--
-- Redémarrer la base de données à partir du Grid Infrastructure
--
oracle@romeo:/tmp> srvctl start database -d F100

Calculer le MEMORY_TARGET sous 11g

À partir des valeurs actuelles du SGA et du PGA, vous pouvez facilement déterminer les valeurs des nouveaux paramètres relatifs à la gestion automatique de la mémoire. Pour simplifier le calcul, je me suis bâtit une requête qui me propose les valeurs de base. La voici :

Select '-- Memory Target = '
||round(to_char((qry_sga_target.value+
greatest(qry_pga_target.value,
qry_pga_alloc.value)))/1024/1024)||' MB'||chr(10)||

'Alter system set memory_target='
||
to_char((qry_sga_target.value+
greatest(qry_pga_target.value,
qry_pga_alloc.value)))||' scope=spfile;'||chr(10)||

'-- Memory Max Target = '
||round(to_char((qry_sga_max.value+
greatest(qry_pga_target.value,
qry_pga_alloc.value)))/1024/1024)||' MB'||chr(10)||

'Alter system set memory_max_target='
||
to_char((qry_sga_max.value+
greatest(qry_pga_target.value,
qry_pga_alloc.value)))||' scope=spfile;'||chr(10)||

'Alter system reset sga_target scope=spfile;'||chr(10)||
'Alter system reset pga_aggregate_target scope=spfile;'||chr(10)||
'-- SGA_MAX_SIZE ne doit pas etre superieur a MEMORY_TARGET'||chr(10)||
'Alter system set sga_max_size='
||to_char((qry_sga_target.value+
greatest(qry_pga_target.value,
qry_pga_alloc.value)))||' scope=spfile;' CMD_SQL

from (select value from v$parameter
where name='sga_target') qry_sga_target,

(select value from v$parameter
where name='pga_aggregate_target') qry_pga_target,

(select value from v$pgastat
where name='maximum PGA allocated') qry_pga_alloc,

(select value from v$parameter
where name='sga_max_size') qry_sga_max
;


Il ne vous reste qu'à estimer le MEMORY_MAX_TARGET.