lunes, 26 de agosto de 2013

Oracle + JDBC + SSL + TDE

Este articulo tiene como finalidad mostrat los pasos necesarios para usar el secure socket layer para asegurar la data que se mueve entre el cliente y la base de datos.

#1 - Crear un directorio para el wallet especifico para el SSL

Oracle recomienda usar wallet separados en caso de que se este usando el SSL mas el TDE.

mkdir /u01/app/oracle/product/11.2.0.3/dbhome/network/wallet_ssl

En caso de ambientes RAC es necesario recrear el directorio en cada nodo en caso de que no se cuente con un sistema para compartir el archivo. (como OCFS2 por ejemplo)

#2 - Editar los archivos listener.ora y sqlnet.ora para a#adirle los parametros WALLET_LOCATION and SSL_CLIENT_AUTHENTICATION y SSL_CIPHER_SUITES

WALLET_LOCATION =
  (SOURCE =
    (METHOD = FILE)
    (METHOD_DATA =
      (DIRECTORY = /u01/app/oracle/product/11.2.0.3/dbhome/network/wallet_ssl)
    )
  )

SSL_CLIENT_AUTHENTICATION = FALSE

SSL_CIPHER_SUITES = (SSL_DH_anon_WITH_3DES_EDE_CBC_SHA,SSL_DH_anon_WITH_RC4_128_MD5,SSL_DH_anon_WITH_DES_CBC_SHA,SSL_RSA_EXPORT_WITH_RC4_40_MD5,SSL_RSA_EXPORT_WITH_DES40_CBC_SHA,SSL_RSA_WITH_3DES_EDE_CBC_SHA,SSL_RSA_WITH_RC4_128_SHA,SSL_RSA_WITH_RC4_128_MD5,SSL_RSA_WITH_DES_CBC_SHA)

El valor por defecto del parametro SSL_CLIENT_AUTHENTICATION es TRUE. Este valor esta en FALSE por que queremos que sea el motor quien haga la autenticacion del usuario.

El valor potr defecto del parametro SSL_CIPHER_SUITES is SSL_RSA_WITH_RC4_128_MD5. Este parametro contiene una lista de cipher suites ya que la idea es permitir conexiones de clientes
con autenticacion y de manera anonima.

#3 - Editar el archivo sqlnet.ora a#adirle el parametro ENCRYPTION_WALLET_LOCATION and SSL_VERSION

ENCRYPTION_WALLET_LOCATION =
  (SOURCE =
    (METHOD = FILE)
    (METHOD_DATA =
      (DIRECTORY = /u01/app/oracle/admin/$ORACLE_UNQNAME/wallet/tde)
    )
  )

La variable de ambiente $ORACLE_UNQNAME es usada para indicarle al TDE que base de datos va a usar esta caracteristica y aque wallet tiene que acceder.

#4 - Creacion del wallet para el SSL

NOTA IMPORTANTE: todos estos comando se ejecutan del lado del servidor.

Para este punto hay un par de consideraciones:

#4.1 - Que el certificado pueda ser auto firmado (self_signed).

Server
======
cd /u01/app/oracle/product/11.2.0.3/dbhome/network/wallet_ssl

- orapki wallet create -wallet . -auto_login -pwd Welcome1

- orapki wallet remove -trusted_cert_all -wallet . -pwd Welcome1

orapki wallet add -wallet . -dn "" -keysize 1024 -self_signed -validity 365 -pwd Welcome1

For the creation of the certificate name we have this options:

CN - Common Name of the certificate owner
OU - Organizational Unit of the certificate owner
O - Organization to which the certificate owner belongs
L - Locality name of the certificate owner
S - State or province of the certificate owner
C - Country of the certificate owne

example: CN=juanudo,OU=databse,O=UDO,L=StPaul,ST=MN,C=US

- orapki wallet add -wallet . -dn "CN=juanudo,OU=databse,O=UDO,L=StPaul,ST=MN,C=US" -keysize 4096 -self_signedvalidity 365 -pwd Welcome1

- orapki wallet export -wallet . -dn "CN=juanudo,OU=databse,O=UDO,L=StPaul,ST=MN,C=US" -cert dbserver_ca.cert

- orapki wallet display -wallet . -summary -pwd Welcome1

example:
Oracle PKI Tool : Version 11.2.0.3.0 - Production
Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved.

Requested Certificates:
User Certificates:
Subject:        CN=juanudo,OU=databse,O=UDO,L=StPaul,ST=MN,C=US
Trusted Certificates:
Subject:        CN=juanudo,OU=databse,O=UDO,L=StPaul,ST=MN,C=US  Importante

#4.2 - Que el certificado NO pueda ser auto firmado. En este caso es necesario crear un CSR (Certificate Service Request) para que sea firmado por un tercero.

Server
======

cd /u01/app/oracle/product/11.2.0.3/dbhome/network/wallet_ssl

- orapki wallet create -wallet . -auto_login -pwd Welcome1

- orapki wallet remove -trusted_cert_all -wallet . -pwd Welcome1

orapki wallet add -wallet . -dn "" -keysize 1024 -validity 365 -pwd Welcome1

For the creation of the certificate name we have this options:

CN - Common Name of the certificate owner
OU - Organizational Unit of the certificate owner
O - Organization to which the certificate owner belongs
L - Locality name of the certificate owner
S - State or province of the certificate owner
C - Country of the certificate owne

example: CN=juanudo,OU=databse,O=UDO,L=StPaul,ST=MN,C=US

- orapki wallet add -wallet . -dn "CN=juanudo,OU=databse,O=UDO,L=StPaul,ST=MN,C=US" -keysize 4096 -validity 365 -pwd Welcome1

- orapki wallet export -wallet . -dn "CN=juanudo,OU=databse,O=UDO,L=StPaul,ST=MN,C=US" -request dbserver_ca.creq -pwd Welcome1   

Una vez creado el CA lo importamos a nuestro wallet

- orapki wallet add -wallet . -trusted_cert -cert dbserver_ca.cert -pwd Welcome1

- orapki wallet add -wallet . -user_cert -cert dbserver_ca.cert -pwd Welcome1

 A manera de ejericio se puede ver en este otro de mis articulos como firmar un certificado con OpemSSL

- orapki wallet display -wallet . -summary -pwd Welcome1

example:
Oracle PKI Tool : Version 11.2.0.3.0 - Production
Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved.

Requested Certificates:
User Certificates:
Subject:        CN=juanudo,OU=databse,O=UDO,L=StPaul,ST=MN,C=US
Trusted Certificates:
Subject:        CN=CODO,O=CODO,L=Salford,ST=Greater Manchester,C=GB Importante

Este caso se observa en el wallet la (o las firmas) de la autoridad (CA).

 #5 - Creacion del wallet para el TDE

export $ORACLE_UNQNAME=dbtest

cd /u01/app/oracle/admin/$ORACLE_UNQNAME/wallet/tde

sqlplus / as sysdba

SQL> ALTER SYSTEM SET ENCRYPTION KEY AUTHENTICATED BY "Passwor1";

Esto crea el archivo ewallet.p12, nuestro wallet para el TDE.

Creacion del auto login para el wallet (cwallet.sso)

- orapki  wallet create -wallet . -auto_login -pwd Passwor1

#6 - Preparacion del cliente.

NOTA IMPORTANTE: todos estos comando se ejecutan del lado del cliente.

Nuevamente, para este punto hay un par de consideraciones:

#6.1 - Que el cliente tenga instalado el software de Oracle.

Si el cliente que va a usar la BD tiene el software de Oracle solo hay que crear el wallet y intercambiar los certificados:

Client
======
- orapki wallet create -wallet . -auto_login -pwd Welcome2

- orapki wallet add -wallet . -dn "CN=cliente,OU=databse,O=UDO,L=StPaul,ST=MN,C=US" -keysize 512 -self_signed -validity 365 -pwd Welcome2

- orapki wallet export -wallet . -dn "CN=cliente,OU=databse,O=DHS,L=StPaul,ST=MN,C=US" -cert client_ca.cert

- orapki wallet add -wallet . -trusted_cert -cert dbserver_ca.cert -pwd Welcome2

  Del lado del servidor se debe importar el certificado del cliente a find e que se pueda establecer la relacion de confianza.
 
  Server
======
- orapki wallet add -wallet . -trusted_cert -cert client_ca.cert -pwd Welcome1

#6.2 - Que el cliente tenga NO instalado el software de Oracle y la instalacion no se pueda realizar.

Para este caso se utiliza un contenedor diferente al wallet de Oracle, se una el Java KeyStore (JKS).

Server
======
- keytool -genkey -alias server -dname "CN=juanudo,OU=databse,O=UDO,L=StPaul,ST=MN,C=US" -storetype JKS -keystore server.jks -keyalg RSA  -storepass Welcome1

- keytool -export -file server_ca.cert -keystore server.jks -storepass Welcome1 -alias server

- keytool -list -keystore server.jks -storepass 'Welcome1' -v

Client
======
- keytool -genkey -alias client -dname "CN=cliente,OU=databse,O=DHS,L=StPaul,ST=MN,C=US" -storetype JKS -keystore client.jks -keyalg RSA  -storepass Welcome2

- keytool -export -file client_ca.cert -keystore client.jks -storepass Welcome2 -alias client

- keytool -list -keystore server.jks -storepass 'Welcome2' -v

Se intercambian los certificados y se importan respectivamente:
       
        - keytool -import -file client_ca.cert -keystore server.jks -storepass Welcome1 -alias client    

        - keytool -import -file server_ca.cert -keystore client.jks -storepass Welcome2 -alias server  
     
 #7 - Conexion via SQL*NET y prueba de configuraciones SSL y TDE.

 A#adimos al tnsnames.ora nuestra cadena de conexiones TCPS.

 dbtest =
   (DESCRIPTION =
     (ADDRESS = (PROTOCOL = TCPS)(HOST = localhost)(PORT = 2484))
     (CONNECT_DATA =
       (SERVICE_NAME = dbtest)
     )
  )

tnsping dbtest

TNS Ping Utility for Linux: Version 11.2.0.3.0 - Production on 26-AUG-2013 14:37:50

Copyright (c) 1997, 2011, Oracle.  All rights reserved.

Used parameter files:
/u01/app/oracle/product/11.2.0.3/dbhome/network/admin/sqlnet.ora


Used TNSNAMES adapter to resolve the alias
Attempting to contact (DESCRIPTION = (ADDRESS = (PROTOCOL = TCPS)(HOST = localhost)(PORT = 2484)) (CONNECT_DATA = (SERVICE_NAME = dbtest)))
OK (30 msec)

sqlplus system@dbtest

SQL*Plus: Release 11.2.0.3.0 Production on Mon Aug 26 14:39:36 2013

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

Enter password:

Connected to:
Oracle Database 11g Enterprise Edition Release 11.2.0.3.0 - 64bit Production
With the Partitioning, Real Application Clusters, Automatic Storage Management, Oracle Label Security,
OLAP, Data Mining, Oracle Database Vault and Real Application Testing options

SQL> exit
Disconnected from Oracle Database 11g Enterprise Edition Release 11.2.0.3.0 - 64bit Production
With the Partitioning, Real Application Clusters, Automatic Storage Management, Oracle Label Security,
OLAP, Data Mining, Oracle Database Vault and Real Application Testing options

Con esto garantizamos que la configracion para el uso del SSL quedo correctamente configurada y que podemos conectarnos via SQL*NET.

Para probar la configuracion del TDE solo debemos create un tablespce que use algun tipo de algoritmo:

sqlplus "/as sysdba"

SQL*Plus: Release 11.2.0.3.0 Production on Mon Aug 26 14:47:24 2013

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


Connected to:
Oracle Database 11g Enterprise Edition Release 11.2.0.3.0 - 64bit Production
With the Partitioning, Real Application Clusters, Automatic Storage Management, Oracle Label Security,
OLAP, Data Mining, Oracle Database Vault and Real Application Testing options

SQL> create tablespace test EXTENT MANAGEMENT LOCAL SEGMENT SPACE MANAGEMENT AUTO DEFAULT STORAGE(ENCRYPT) ENCRYPTION USING 'AES256';

Tablespace created.

SQL> drop tablespace test;

Tablespace dropped.

SQL> exit
Disconnected from Oracle Database 11g Enterprise Edition Release 11.2.0.3.0 - 64bit Production
With the Partitioning, Real Application Clusters, Automatic Storage Management, Oracle Label Security,
OLAP, Data Mining, Oracle Database Vault and Real Application Testing options

#8 - Conexion via JDBC.

Si necesitamos probar la conexion via JDBC aqui esta un ejemplo:

import java.sql.*;
import java.security.Security;
import java.util.Properties;

public class TestSSL {

public static void main(String[] argv) throws Exception {

DriverManager.registerDriver(new oracle.jdbc.driver.OracleDriver());

Properties prop = new Properties();


Security.addProvider(new oracle.security.pki.OraclePKIProvider());

prop.setProperty("oracle.net.authentication_services","(TCPS)");
//prop.setProperty("oracle.net.wallet_location", "(SOURCE=(METHOD=file)(METHOD_DATA=(DIRECTORY=C:\\Users\\Downloads\\ssl-jdbc-demos)))");


String url = "jdbc:oracle:thin:@(DESCRIPTION=(ADDRESS=(PROTOCOL=tcps)(HOST=localhost)(PORT=2484))(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=dbtest)))";


//CASE #0: JUST CONNECTION

prop.setProperty("user", "system");
prop.setProperty("password", "oracle");

CASE #1: USE SSL FOR ENCRYPTION ONLY
/*
prop.setProperty("oracle.net.ssl_client_authentication", "false");
prop.setProperty("user", "system");
prop.setProperty("password", "oracle");
prop.setProperty("oracle.net.ssl_cipher_suites","(SSL_DH_anon_WITH_3DES_EDE_CBC_SHA, SSL_DH_anon_WITH_RC4_128_MD5,SSL_DH_anon_WITH_DES_CBC_SHA)");

*/
//CASE #2: USE SSL FOR ENCRYPTION AND SERVER AUTHENTICATION
/*
prop.setProperty("javax.net.ssl.trustStore","C:\\Users\\Downloads\\ssl-jdbc-demos\\ewallet.p12");
prop.setProperty("javax.net.ssl.trustStoreType","PKCS12");
prop.setProperty("javax.net.ssl.trustStorePassword","Welcome2");
*/
//CASE #3: USE SSL FOR ENCRYPTION AND AUTHENTICATION OF BOTH TIERS
/*
prop.setProperty("javax.net.ssl.trustStore","C:\\Users\\Downloads\\ssl-jdbc-demos\\ewallet.p12");
prop.setProperty("javax.net.ssl.trustStoreType","PKCS12");
prop.setProperty("javax.net.ssl.trustStorePassword","Welcome2");
*/

/*
//---------------------------------- JKS --------------------------------------------------------------------
prop.setProperty("javax.net.ssl.keyStore","C:\\Users\\Downloads\\ssl-jdbc-demos\\ewallet.jks");
prop.setProperty("javax.net.ssl.keyStoreType","JKS");
prop.setProperty("javax.net.ssl.keyStorePassword","Welcome2");

prop.setProperty("javax.net.ssl.trustStore","C:\\Users\\Downloads\\ssl-jdbc-demos\\ewallet.jks");
prop.setProperty("javax.net.ssl.trustStoreType","JKS");
prop.setProperty("javax.net.ssl.trustStorePassword","Welcome2");
//-----------------------------------------------------------------------------------------------------------
*/

//CASE #4: USE SSL AS AN AUTHENTICATION SERVICE IN THE DATABASE
/*
prop.setProperty("javax.net.ssl.trustStore","C:\\java\\cwallet.sso");
prop.setProperty("javax.net.ssl.trustStoreType","SSO");
prop.setProperty("javax.net.ssl.Store","C:\\java\\cwallet.sso");
prop.setProperty("javax.net.ssl.StoreType","SSO");
*/

Connection conn = DriverManager.getConnection(url,prop);

DatabaseMetaData dbmd = conn.getMetaData();

// Print out all loaded JDBC drivers.
    java.util.Enumeration e = java.sql.DriverManager.getDrivers();
    while (e.hasMoreElements()) {
      Object driverAsObject = e.nextElement();
      System.out.println("JDBC Driver=" + driverAsObject);
    }

    System.out.println("=====  Driver info =====");
    System.out.println("DriverName: " + dbmd.getDriverName() );
    System.out.println("DriverVersion: " + dbmd.getDriverVersion() );
    System.out.println("DriverMajorVersion: " + dbmd.getDriverMajorVersion() );
    System.out.println("DriverMinorVersion: " + dbmd.getDriverMinorVersion() );

Statement stmt = conn.createStatement();
ResultSet rset = stmt.executeQuery("select 'Hello Thin driver SSL "+ "tester '||USER||'!' result from dual");
while (rset.next())
System.out.println(rset.getString(1));
rset.close();
stmt.close();
conn.close();
}
}

Todos los casos representados en el programa (excepto el 0 y el ejemplo con JKS) provienen de un paper de nombre SSL With Oracle JDBC Thin Driver de Jean de Lavarene

viernes, 9 de agosto de 2013

Yo soy la Autoridad!

Este articulo tiene como finalidad mostrar el uso de openssl para firmar certificados.

Primero es necesario acondicionar nustro ambien para que el openssl pueda hacer su trabajo.

------------------------------------------------------------------------------------------------------------
#!/bin/bash
CAROOT=/path/to/ca
mkdir -p ${CAROOT}/ca.db.certs   # Signed certificates storage
touch ${CAROOT}/ca.db.index      # Index of signed certificates
echo 01 > ${CAROOT}/ca.db.serial # Next (sequential) serial number

# Configuration
cat>${CAROOT}/ca.conf<<'EOF'
[ ca ]
default_ca = ca_default

[ ca_default ]
dir = REPLACE_LATER
certs = $dir
new_certs_dir = $dir/ca.db.certs
database = $dir/ca.db.index
serial = $dir/ca.db.serial
RANDFILE = $dir/ca.db.rand
certificate = $dir/ca.crt
private_key = $dir/ca.key
default_days = 365
default_crl_days = 30
default_md = md5
preserve = no
policy = generic_policy
[ generic_policy ]
countryName = optional
stateOrProvinceName = optional
localityName = optional
organizationName = optional
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
EOF

sed -i "s|REPLACE_LATER|${CAROOT}|" ${CAROOT}/ca.conf

cd ${CAROOT}

# Generate CA private key
openssl genrsa -out ca.key 1024

# Create Certificate Signing Request
openssl req -new -key ca.key  \
                 -out ca.csr    

# Create self-signed certificate
openssl x509 -req -days 10000 \
              -in ca.csr      \
              -out ca.crt     \
              -signkey ca.key
------------------------------------------------------------------------------------------------------------                      
Este scrtip crea la llave (key) y el self-signed ca necesarios para firmar los CSR.

Lo puedes conseguir aqui: http://stackoverflow.com/questions/7768593/openssl-as-a-ca-without-touching-the-certs-crl-index-etc-environment

Al ejecutar el scrtip tenemos:

[oracle@oel new]$ ls -lrt
total 4
-rwxr-xr-x. 1 oracle oinstall 1207 Aug  9 12:29 setup.sh
[oracle@oel new]$ ./setup.sh
Generating RSA private key, 1024 bit long modulus
.++++++
.........++++++
e is 65537 (0x10001)
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [XX]:US
State or Province Name (full name) []:Minnesota
Locality Name (eg, city) [Default City]:St.Paul
Organization Name (eg, company) [Default Company Ltd]:UDO
Organizational Unit Name (eg, section) []:DB
Common Name (eg, your name or your server's hostname) []:nodo1
Email Address []:juanudo@hotmail.com

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:123456
An optional company name []:UDO
Signature ok
subject=/C=US/ST=Minnesota/L=St.Paul/O=UDO/OU=DB/CN=nodo1/emailAddress=juanudo@hotmail.com
Getting Private key

[oracle@oel new]$ ls -lrt
total 28
-rwxr-xr-x. 1 oracle oinstall 1207 Aug  9 12:29 setup.sh
drwxr-xr-x. 2 oracle oinstall 4096 Aug  9 12:29 ca.db.certs
-rw-r--r--. 1 oracle oinstall    3 Aug  9 12:29 ca.db.serial
-rw-r--r--. 1 oracle oinstall    0 Aug  9 12:29 ca.db.index
-rw-r--r--. 1 oracle oinstall  536 Aug  9 12:29 ca.conf
-rw-r--r--. 1 oracle oinstall  887 Aug  9 12:29 ca.key
-rw-r--r--. 1 oracle oinstall  745 Aug  9 12:30 ca.csr
-rw-r--r--. 1 oracle oinstall  924 Aug  9 12:30 ca.crt

El scrtip genero la llave (ca.key) y genero el Certificate Signing Request (ca.csr) y Root certificates self-signed (ca.crt) ademas del archivo de configuracion (ca.conf) y los directorios necesarios.

Ahora a trabajar con el Oracle wallet

- Primero creamos el wallet.

[oracle@oel new]$ orapki wallet create -wallet . -auto_login -pwd Welcome2
Oracle PKI Tool : Version 12.1.0.1
Copyright (c) 2004, 2012, Oracle and/or its affiliates. All rights reserved.

- Creamos el Common Name of the certificate owner (CN).

[oracle@oel new]$ orapki wallet add -wallet . -dn "CN=dbserver, OU=databse, O=UDO, L=StPaul, S=MN, C=US" -keysize 1024 -validity 365 -pwd Welcome2
Oracle PKI Tool : Version 12.1.0.1
Copyright (c) 2004, 2012, Oracle and/or its affiliates. All rights reserved.

- Se crea el CSR exportando el CN.

[oracle@oel new]$ orapki wallet export -wallet . -dn "CN=dbserver, OU=databse, O=UDO, L=StPaul, S=MN, C=US" -request client.csr -pwd Welcome2
Oracle PKI Tool : Version 12.1.0.1
Copyright (c) 2004, 2012, Oracle and/or its affiliates. All rights reserved.

- Se firma el CSR.

[oracle@oel new]$ openssl  x509  -req  -CA ca.crt -CAkey ca.key -in client.csr -out client.cer  -days 365  -CAcreateserial
Signature ok
subject=/C=US/ST=MN/L=StPaul/O=UDO/OU=databse/CN=dbserver
Getting CA Private Key

- Cargamos el Trusted Certificates dentro del wallet. (sin problema)

[oracle@oel new]$ orapki wallet add -wallet . -trusted_cert -cert client.cer -pwd Welcome2
Oracle PKI Tool : Version 12.1.0.1
Copyright (c) 2004, 2012, Oracle and/or its affiliates. All rights reserved.

- Cargamos (o intentamos cargar )el User Certificates dentro del wallet. (problemas!!!)

[oracle@oel new]$ orapki wallet add -wallet . -user_cert -cert client.cer -pwd Welcome2
Oracle PKI Tool : Version 12.1.0.1
Copyright (c) 2004, 2012, Oracle and/or its affiliates. All rights reserved.

PKI-04012: Incomplete certificate chain
Could not install user cert atclient.cer
Please add all trusted certificates before adding the user certificate

Esta es la razon de este articulo, el error PKI-04012.

"Incomplete certificate chain" hace refiere a que falta una cadena, pero cual?

La cadena que falta es el Root certificates self-signed (y las firmas intermedias a que diera lugar si fuese el caso).

- Cargamos el  Root certificates self-signed que usamos para firmar el CSR dentro del wallet.

[oracle@oel new]$ orapki wallet add -wallet . -trusted_cert -cert ca.crt -pwd Welcome2
Oracle PKI Tool : Version 12.1.0.1
Copyright (c) 2004, 2012, Oracle and/or its affiliates. All rights reserved.

- Cargamos el User Certificates dentro del wallet.

[oracle@oel new]$ orapki wallet add -wallet . -user_cert -cert client.cer -pwd Welcome2
Oracle PKI Tool : Version 12.1.0.1
Copyright (c) 2004, 2012, Oracle and/or its affiliates. All rights reserved.

- Finalmente vemos nuestro wallet como deberia quedar.

[oracle@oel new]$ orapki wallet display -wallet . -summary -pwd Welcome2
Oracle PKI Tool : Version 12.1.0.1
Copyright (c) 2004, 2012, Oracle and/or its affiliates. All rights reserved.

Requested Certificates:
User Certificates:
Subject:        CN=dbserver,OU=databse,O=UDO,L=StPaul,ST=MN,C=US
Trusted Certificates:
Subject:        EmailAddress=juanudo@hotmail.com,CN=nodo1,OU=DB,O=UDO,L=St.Paul,ST=Minnesota,C=US
Subject:        OU=Class 1 Public Primary Certification Authority,O=VeriSign\, Inc.,C=US
Subject:        CN=GTE CyberTrust Global Root,OU=GTE CyberTrust Solutions\, Inc.,O=GTE Corporation,C=US
Subject:        OU=Class 3 Public Primary Certification Authority,O=VeriSign\, Inc.,C=US
Subject:        OU=Class 2 Public Primary Certification Authority,O=VeriSign\, Inc.,C=US
Subject:        CN=dbserver,OU=databse,O=UDO,L=StPaul,ST=MN,C=US


jueves, 20 de septiembre de 2012

make: 1254-004 The error code from the last command is 12



Para una prueba de restauración del backup de un RAC se copio el ORACLE_HOME a un nuevo servidor, al momento de “apagar” la configuración  del RAC en los binarios se presentaron los siguientes problemas:

hcdatxx> /home/oracle10:database> cd $ORACLE_HOME/rdbms/lib
hcdatxx> /oracle/app/product/10.2.0/db/rdbms/lib:database> make -f ins_rdbms.mk rac_off
        rm -f /oracle/app/product/10.2.0/db/lib/libskgxp10.a
        cp /oracle/app/product/10.2.0/db/lib//libskgxpd.a /oracle/app/product/10.2.0/db/lib/libskgxp10.a
        rm -f /oracle/app/product/10.2.0/db/lib/libskgxn2.a
        cp /oracle/app/product/10.2.0/db/lib//libskgxns.a  /oracle/app/product/10.2.0/db/lib/libskgxn2.a
        /bin/ar -X64 cr /oracle/app/product/10.2.0/db/rdbms/lib/libknlopt.a /oracle/app/product/10.2.0/db/rdbms/lib/ksnkcs.o
hcdatxx> /oracle/app/product/10.2.0/db/rdbms/lib:database>

Problema #1

hcdatxx> /oracle/app/product/10.2.0/db/rdbms/lib:database> cd $ORACLE_HOME/bin
hcdatxx> /oracle/app/product/10.2.0/db/bin:database> relink oracle
        chmod 755 /oracle/app/product/10.2.0/db/bin

 - Linking Oracle
        rm -f /oracle/app/product/10.2.0/db/rdbms/lib/oracle
        ld -b64 -o /oracle/app/product/10.2.0/db/rdbms/lib/oracle -L/oracle/app/product/10.2.0/db/rdbms/lib/ -L/oracle/app/product/10.2.0/db/lib/ -bnoerrmsg  -bbigtoc -bnoipath -bI:/oracle/app/product/10.2.0/db/lib/ksms.imp /oracle/app/product/10.2.0/db/rdbms/lib/opimai.o /oracle/app/product/10.2.0/db/rdbms/lib/ssoraed.o /oracle/app/product/10.2.0/db/rdbms/lib/ttcsoi.o  -lperfsrv10 /oracle/app/product/10.2.0/db/lib/nautab.o /oracle/app/product/10.2.0/db/lib/naeet.o /oracle/app/product/10.2.0/db/lib/naect.o /oracle/app/product/10.2.0/db/lib/naedhs.o /oracle/app/product/10.2.0/db/rdbms/lib/config.o -bI:/usr/lib/aio.exp   -lserver10 /oracle/app/product/10.2.0/db/lib/libodm10.so -lnnet10  -lskgxp10 -lsthasgen10 /oracle/app/product/10.2.0/db/has/lib/clssgc.o /oracle/app/product/10.2.0/db/lib/libstskgxn2.a -lstocr10 -lstocrb10  -lstocrutl10 -lsthasgen10 /oracle/app/product/10.2.0/db/has/lib/clssgc.o /oracle/app/product/10.2.0/db/lib/libstskgxn2.a   -lclient10  -lvsn10  -lcommon10 -lgeneric10 `if [ -f /oracle/app/product/10.2.0/db/lib/libavserver10.a ] ; then echo "-lavserver10" ; else echo "-lavstub10"; fi` `if [ -f /oracle/app/product/10.2.0/db/lib/libavclient10.a ] ; then echo "-lavclient10" ; fi`  /oracle/app/product/10.2.0/db/rdbms/lib/defopt.o -lknlopt  `if /bin/ar -X64 tv /oracle/app/product/10.2.0/db/rdbms/lib/libknlopt.a | grep xsyeolap.o > /dev/null 2>&1 ; then echo "-loraolap10 -bE:/oracle/app/product/10.2.0/db/rdbms/lib/olap.exp" ; fi`  -lslax10 -lpls10  -lplp10 -bE:/oracle/app/product/10.2.0/db/rdbms/lib/plsqlncomp.exp  /oracle/app/product/10.2.0/db/lib/libstclsra10.a -lstdbcfg10 -lserver10 -lclient10  -lvsn10  -lcommon10 -lgeneric10  -lknlopt -lslax10 -lpls10  -lplp10  -ljox10 -bE:/oracle/app/product/10.2.0/db/rdbms/lib//oracle.exp   `sed -e 's/-ljava//g' /oracle/app/product/10.2.0/db/lib/ldflags`      -lncrypt10 -lnsgr10 -lnzjs10 -ln10  -lnnz10 -lnl10 -lnzjs10 -lnro10 `sed -e 's/-ljava//g' /oracle/app/product/10.2.0/db/lib/ldflags`      -lncrypt10 -lnsgr10 -lnzjs10 -ln10  -lnnz10 -lnl10 -lnzjs10 -lclient10  -lvsn10  -lcommon10 -lgeneric10   -lmm -lsnls10 -lnls10  -lcore10 -lsnls10  -lnls10 -lcore10 -lsnls10 -lnls10 -lxml10  -lcore10 -lunls10 -lsnls10 -lnls10 -lcore10 -lnls10 `sed -e 's/-ljava//g' /oracle/app/product/10.2.0/db/lib/ldflags`      -lncrypt10 -lnsgr10 -lnzjs10 -ln10  -lnnz10 -lnl10 -lnzjs10 -lnro10 `sed -e 's/-ljava//g' /oracle/app/product/10.2.0/db/lib/ldflags`      -lncrypt10 -lnsgr10 -lnzjs10 -ln10  -lnnz10 -lnl10 -lnzjs10 -lclient10  -lvsn10  -lcommon10 -lgeneric10 -lpls10   -lsnls10 -lnls10  -lcore10 -lsnls10  -lnls10 -lcore10 -lsnls10 -lnls10 -lxml10  -lcore10 -lunls10 -lsnls10 -lnls10 -lcore10 -lnls10  -lclient10  -lvsn10  -lcommon10 -lgeneric10 -lsnls10 -lnls10  -lcore10 -lsnls10  -lnls10 -lcore10 -lsnls10 -lnls10 -lxml10  -lcore10 -lunls10 -lsnls10 -lnls10 -lcore10 -lnls10 -lserver10 `if /bin/ar -X64 tv /oracle/app/product/10.2.0/db/rdbms/lib/libknlopt.a | grep "kxmnsd.o" > /dev/null 2>&1 ; then echo " " ; else echo "-lordsdo10"; fi` -lctxc10 -lctx10 -lzx10 -lgx10 -lctx10 -lzx10 -lgx10 -lordimt10  -lsnls10 -lnls10  -lcore10 -lsnls10  -lnls10 -lcore10 -lsnls10 -lnls10 -lxml10  -lcore10 -lunls10 -lsnls10 -lnls10 -lcore10 -lnls10 -lsnls10 -lunls10  -bE:/oracle/app/product/10.2.0/db/rdbms/lib//libcorejava.exp  -lld -lm `cat /oracle/app/product/10.2.0/db/lib/sysliblist`  -lm  `if [ "\`/usr/bin/uname -v\`" = "4" ]; \
        then echo "-bI:/oracle/app/product/10.2.0/db/lib/pw-syscall.exp"; fi;`  `if /bin/ar -X64 t /oracle/app/product/10.2.0/db/rdbms/lib/libknlopt.a | grep '^'kcsm.o > /dev/null 2>&1 ; then echo "-lha_gs_r -lha_em_r -lpthreads"; fi` -locijdbcst10  -lwwg  -bpT:0x100000000 -bpD:0x110000000 -bforceimprw
make: 1254-004 The error code from the last command is 12.
Stop.

 Los binarios nunca fueron modifcados.

Solución #1

La raíz de esté problema  fueron los recursos definidos a nivel de SO para el usuario dueño de los binarios de Oracle. Básicamente se le coloco unlimited a todo:

Esta es la documentacion de IBM:

http://publib.boulder.ibm.com/infocenter/tivihelp/v10r1/index.jsp?topic=%2Fcom.ibm.srm.doc_7.1%2Finstalling%2Fsrc%2Ft_ccmdb_setulimit.html

Esta es una nota de Oracle que habla sobre el error y su solución:

AIX Errors 0711-101 and 1254-004 Occur When Relinking The 9.2.0 $ORACLE_HOME/bin/oracle Executable [ID 251438.1]

Aunque en mi caso los binarios eran de la versión 10g, el problema era el mismo.

Problema #2

hcdatxx> /oracle/app/product/10.2.0/db/bin:database> sqlplus "/as sysdba"

SQL*Plus: Release 10.2.0.4.0 - Production on Thu Sep 20 10:13:04 2012

Copyright (c) 1982, 2007, Oracle.  All Rights Reserved.

Connected to an idle instance.

SQL> startup nomount
ORA-27504: IPC error creating OSD context
ORA-27300: OS system dependent operation:sendmsg failed with status: 59
ORA-27301: OS failure message: Message too long
ORA-27302: failure occurred at: sskgxpsnd1
ORA-27303: additional information: MTU verification failed to send msg.


Solución #2

El problema radicaba en la configuración de algunos para metros que manejan los protocolos
UDP and TCP. Con el usuario root se ejecutaron los siguientes comandos para darle solución al tema:

 no -o tcp_sendspace=262144
 no -o tcp_recvspace=262144
 no -o udp_sendspace=65536
 no -o udp_recvspace=262144
 no -o rfc1323=1

Esta es una nota de Oracle que habla sobre el error y su solución:

Ora-27302: sskgxpsnd1 - Starting Instance [ID 300956.1]




lunes, 10 de septiembre de 2012

Instalando Audit Vault




Estos pasos se realizaron posterior a la instalacion del producto Audit Vault (Audit Serevr), basicamente es la instalación y configuración para auditar un ambiente RAC.

1) Variables de ambientes en el servidor server16 - Audit Server

export ORACLE_HOME=/u02/app/oracle11/product/10.3.0
export ORACLE_SID=av

2) Registrar los agentes que se van a instalar en el Audit Server

$ORACLE_HOME/bin/avca add_agent -agentname avaudit_server67 -agenthost xx.xx.xx.67 -desc 'Agent for RAC node1'

$ORACLE_HOME/bin/avca add_agent -agentname avaudit_server47 -agenthost xx.xx.xx.47 -desc 'Agent for RAC node2'

3) Instalar el agente en los equipos que se van a auditar

4) Crear el usuario asociado a la fuente en la base de datos a auditar

5) Asginar los permisos necesarios para la conexion con el Audit Server (Ejecutar en la BD a ser auditada)

SQL> /AVAGENT/avagent103/av/scripts/streams/source/zarsspriv.sql
SP2-0734: unknown command beginning "/AVAGENT/a..." - rest of line ignored.
SQL> @/AVAGENT/avagent103/av/scripts/streams/source/zarsspriv.sql
Enter value for 1: srcav
Enter value for 2: SETUP
Granting privileges to SRCAV ... Done.

6) Registrar la fuente en el Audit Server

$ORACLE_HOME/bin/avorcldb add_source -src xx.xx.xx.67:1521:wmos -srcname WMOS

(Para este punto, al momento de escribir no me queda claro si por ser un RAC seria conveniente tener más de una fuente)

7) crear los colectore

$ORACLE_HOME/bin/avorcldb add_collector -srcname WMOS -agentname avaudit_server67 -colltype OSAUD -orclhome /oracle/app/product/10.2.0/db -instname wmos1  -collname OSAUD_Collector_server67

$ORACLE_HOME/bin/avorcldb add_collector -srcname WMOS -agentname avaudit_server47 -colltype OSAUD -orclhome /oracle/app/product/10.2.0/db -instname wmos2  -collname OSAUD_Collector_server47

$ORACLE_HOME/bin/avorcldb add_collector -srcname WMOS -agentname avaudit_server67 -colltype DBAUD -instname wmos1  -collname DBAUD_Collector_WMOS1

$ORACLE_HOME/bin/avorcldb add_collector -srcname WMOS -agentname avaudit_server47 -colltype DBAUD -instname wmos2  -collname DBAUD_Collector_WMOS2

8) Registrar la fuente en los agentes (IMPORTANTE)

$ORACLE_HOME/bin/avorcldb setup -srcname WMOS

9) Verificar que los agentes esten corriendo

$ORACLE_HOME/bin/avctl show_agent_status -agentname avaudit_server67

$ORACLE_HOME/bin/avctl show_agent_status -agentname avaudit_server47

9.1) Si es necesario iniciar los agentes

$ORACLE_HOME/bin/avctl show_agent_status -agentname avaudit_server67

$ORACLE_HOME/bin/avctl show_agent_status -agentname avaudit_server47

10) Iniciar los colectores

$ORACLE_HOME/bin/avctl start_collector -collname DBAUD_Collector_WMOS1 -srcname WMOS

$ORACLE_HOME/bin/avctl start_collector -collname DBAUD_Collector_WMOS2 -srcname WMOS

$ORACLE_HOME/bin/avctl start_collector -collname OSAUD_Collector_server67 -srcname WMOS

$ORACLE_HOME/bin/avctl start_collector -collname OSAUD_Collector_server47 -srcname WMOS

11) Verificar que todos los colectores esten funcionando

#SO
$ORACLE_HOME/bin/avctl show_collector_status -collname OSAUD_Collector_server47 -srcname WMOS

$ORACLE_HOME/bin/avctl show_collector_status -collname OSAUD_Collector_server67 -srcname WMOS

#BD
$ORACLE_HOME/bin/avctl show_collector_status -collname DBAUD_Collector_WMOS1 -srcname WMOS

$ORACLE_HOME/bin/avctl show_collector_status -collname DBAUD_Collector_WMOS2 -srcname WMOS

Todos los pasos aquí referenciados se realizan desde el Audit Server (server16) excepto el paso 5 que se ejecuta desde alguno de los nodos del RAC que se desea auditar.

sábado, 22 de octubre de 2011

Qué es el Query Rewrites?



El Query Rewrites es la capacidad que tiene el optimizador (en base a ciertos parámetros) de usar las tablas o las vistas maternizadas. Veamos un pequeño ejemplo:

1) Crear la vista materializada.

    CREATE MATERIALIZED VIEW cal_month_sales_mv
    FROM sales s, times t WHERE s.time_id = t.time_id
    ENABLE QUERY REWRITE AS
    SELECT t.calendar_month_desc, SUM(s.amount_sold) AS dollars
    FROM sales s, times t WHERE s.time_id = t.time_id
  5      GROUP BY t.calendar_month_desc
  6  /

Materialized view created.

2) Revisar los parámetros de configuración

SQL> show parameter query_rewrite_enabled   

NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
query_rewrite_enabled                string      FALSE


Dependiendo de la versión de BD donde se esté trabajando el valor por defecto de este parámetro puede ser TRUE (OPTIMIZER_FEATURES_ENABLE >= 10.0.0 ) o FALSE (OPTIMIZER_FEATURES_ENABLE <=  9.2.0). En nuestro caso de ejemplo el parámetro se encuentra en FLASE.

3) Evaluar la consulta que genera la vista materializada.

SQL> explain plan for
    SELECT t.calendar_month_desc, SUM(s.amount_sold) AS dollars
    FROM sales s, times t WHERE s.time_id = t.time_id
  4      GROUP BY t.calendar_month_desc
  5  /

------------------------------------------------------------------------------------------
| Id  | Operation             |  Name       | Rows  | Bytes | Cost (%CPU)| Pstart| Pstop |
------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT      |             |    48 |  1344 |   511   (8)|       |       |
|   1 |  SORT GROUP BY        |             |    48 |  1344 |   511   (8)|       |       |
|*  2 |   HASH JOIN           |             |  1015K|    27M|   487   (3)|       |       |
|   3 |    TABLE ACCESS FULL  | TIMES       |  1461 | 23376 |     7  (15)|       |       |
|   4 |    PARTITION RANGE ALL|             |       |       |            |     1 |    16 |
|   5 |     TABLE ACCESS FULL | SALES       |  1015K|    11M|   477   (2)|     1 |    16 |
------------------------------------------------------------------------------------------

En este caso se puede evidenciar que el optimizador accede directamente a las tablas SALES y TIMES sobre las cuales se genera la vista materialziada cal_month_sales_mv.

4) Que empiece la magia, simplemente alteremos el parameter query_rewrite_enabled.

SQL> alter system set query_rewrite_enabled=TRUE;

System altered.

5) Veamos que hace el optimizador ahora:

SQL> explain plan for
    SELECT t.calendar_month_desc, SUM(s.amount_sold) AS dollars
    FROM sales s, times t WHERE s.time_id = t.time_id
  4      GROUP BY t.calendar_month_desc
  5  /

---------------------------------------------------------------------------------
| Id  | Operation            |  Name               | Rows  | Bytes | Cost (%CPU)|
---------------------------------------------------------------------------------
|   0 | SELECT STATEMENT     |                     |   327 |  6213 |     3  (34)|
|   1 |  TABLE ACCESS FULL   | CAL_MONTH_SALES_MV  |   327 |  6213 |     3  (34)|
---------------------------------------------------------------------------------

Entonces que es el Query Rewrites y que bondades tiene? Esta funcionalidad le permitirle al optimizador usar las vistas materializadas (en lugar de las tablas bases) que cumplan exactamente con la consulta que se esté ejecutando.


domingo, 2 de octubre de 2011

Estadisticas de sistema para Oracle 9i



En versiones anteriores a 10g todo absolutamente todo lo relacionando con el motor recaía en el ser humano que tuviese la responsabilidad de velar por la base de datos. Como todo acto de un ser humano el mismo estaba sujeto a error, olvidos, desconocimiento, (la peor de todas) decidía,...etc.



Para que el optimizador de sentencia pueda elaborar el mejor plan de ejecución posible debe contar con las estadísticas del sistema donde “vive” la base de datos. Para tal fin le muestro el siguiente ejemplo:


Primero que nada vamos a usar la herramienta explain plan for  para mostrar el plan de ejecución de  un simple select sobre nuestra tabla de ejemplo EMP2 del usuario SCOTT

SQL> explain plan for select * from scott.emp2;
explain plan for select * from scott.emp2
                                     *
ERROR at line 1:
ORA-02402: PLAN_TABLE not found

Uupss olvide crear la tabla PLAN_TABLE, lo resolvemos de la siguiente forma:


SQL> @$ORACLE_HOME/rdbms/admin/utlxplan.sql

Table created.

SQL> explain plan for select * from scott.emp2;

Explained.

SQL> SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);


PLAN_TABLE_OUTPUT
--------------------------------------------------------------------
| Id  | Operation                        |  Name       | Rows  | Bytes | Cost  |
--------------------------------------------------------------------
|   0 | SELECT STATEMENT     |                  1792 | 66304 |     3 |
|   1 |  TABLE ACCESS FULL   | EMP2         1792 | 66304 |     3 |
--------------------------------------------------------------------

Note: cpu costing is off

9 rows selected.

Ok que quiere decir "cpu costing is off", básicamente lo que nos dice es que el motor de base de datos solo está tomando en cuenta para construir el plan de ejecución  las operaciones de I/O (8i) necesarias para completar la tarea.

Que hacer para activarla, bien una forma de hacerlo es la siguiente:

SQL> exec dbms_stats.gather_system_stats('START');

PL/SQL procedure successfully completed.

Esperamos un tiempo para que el motor pueda recolectar la mayor información del sistema posible, y simplemente después hacemos lo siguiente:

SQL> exec dbms_stats.gather_system_stats('STOP');

PL/SQL procedure successfully completed.


Al ejecutar nuevamente la operación inicial obtenemos lo siguiente:


SQL> explain plan for select * from scott.emp2;

Explained.

SQL> SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);

PLAN_TABLE_OUTPUT
-------------------------------------------------------------------------
| Id  | Operation                        |  Name       | Rows  | Bytes | Cost (%CPU)|
-------------------------------------------------------------------------
|   0 | SELECT STATEMENT     |                  |  1792 | 66304 |    31  (23)|
|   1 |  TABLE ACCESS FULL   | EMP2        |  1792 | 66304 |    31  (23)|
-------------------------------------------------------------------------

7 rows selected.

El punto a resaltar aquí es el cambio en el costo del plan de ejecución, pasamos de un costo de 3 (sin referencia al CPU) a un costo de 31 (con un 23% de uso del CPU). Si el optimizador dispone de la información de la actividad del sistema donde reside podrá construir planes de ejecución mas ajustados a la realidad.




sábado, 1 de octubre de 2011

Calculo de estadisticas de forma automatica en Oracle 9i


Uno de los grandes problemas con la tecnología en general es no conocer a cabalidad todo el conjunto de herramientas o funcionalidades disponibles.  En particular muchas de las funcionalidades que tienen los motores 10g y 11g ya existían en 9i, ejemplo de ello el cálculo de estadísticas de forma automática. Ejemplo:

A nivel de tabla

SQL> alter table SCOTT.EMP2 monitoring;

Table altered.

SQL> insert into scott.emp2 select * from scott.emp;

14 rows created.

SQL> commit;

Commit complete.

Cuando el motor determina que los datos de la tabla han cambiado en un 10% considera las estadisticas como STALE

SQL>  select table_name, num_rows, blocks, avg_row_len    from dba_tables where table_name='EMP2';

TABLE_NAME                       NUM_ROWS     BLOCKS AVG_ROW_LEN
------------------------------ ---------- ---------- -----------
EMP2                                   14          1          37

SQL> select * from sys.dba_tab_modifications;

no rows selected

SQL> exec dbms_stats.FLUSH_DATABASE_MONITORING_INFO();

PL/SQL procedure successfully completed.

SQL> select * from sys.dba_tab_modifications;

TABLE_OWNER                    TABLE_NAME
------------------------------ ------------------------------
PARTITION_NAME                 SUBPARTITION_NAME                 INSERTS
------------------------------ ------------------------------ ----------
   UPDATES    DELETES TIMESTAMP TRU DROP_SEGMENTS
---------- ---------- --------- --- -------------
SCOTT                          EMP2
                                                                      42
         0          0 01-OCT-11 NO              0

 Esta informacion la usara el motor para realziar el calculo de las estadisticas en caso de que sea necesario.

A nivel de esquema

SQL> EXEC DBMS_STATS.delete_table_stats('SCOTT', 'EMP2');

PL/SQL procedure successfully completed.

SQL>  select table_name, num_rows, blocks, avg_row_len    from dba_tables where table_name='EMP2';

TABLE_NAME                       NUM_ROWS     BLOCKS AVG_ROW_LEN
------------------------------ ---------- ---------- -----------
EMP2

SQL>  exec dbms_stats.ALTER_SCHEMA_TAB_MONITORING('SCOTT',TRUE);

PL/SQL procedure successfully completed.

SQL> exec dbms_stats.FLUSH_DATABASE_MONITORING_INFO();

PL/SQL procedure successfully completed.

SQL> select * from sys.dba_tab_modifications;

no rows selected

SQL> insert into scott.emp2 select * from scott.emp2;

84 rows created.

SQL> commit;

Commit complete.

SQL> select * from sys.dba_tab_modifications;

no rows selected

SQL> exec dbms_stats.FLUSH_DATABASE_MONITORING_INFO();

PL/SQL procedure successfully completed.

SQL> select * from sys.dba_tab_modifications;

TABLE_OWNER                    TABLE_NAME
------------------------------ ------------------------------
PARTITION_NAME                 SUBPARTITION_NAME                 INSERTS
------------------------------ ------------------------------ ----------
   UPDATES    DELETES TIMESTAMP TRU DROP_SEGMENTS
---------- ---------- --------- --- -------------
SCOTT                          EMP2
                                                                      84
         0          0 01-OCT-11 NO              0


La idea de todo esto es que el motor calcule selectivamente las estadísticas. Veamos que como interpreta la información anterior y nos permite recolectar automática y selectivamente las estadísticas de las tablas que hayan cambiado más del 10%

Lo primero será crear un Job que use el DBMS_STATS (para nuestro ejemplo) con la funcion gather_schema_stats y la opcion GATHER STALE.

DECLARE jobno number;
BEGIN
      DBMS_JOB.submit(jobno,'BEGIN DBMS_STATS.gather_schema_stats(ownname => ''SCOTT'',degree =>2,estimate_percent => 15,cascade => TRUE , OPTIONS => ''GATHER STALE''); END;',
     TO_DATE('01-10-11 06:35:00', 'DD-MM-YY HH:MI:SS'),
    'SYSDATE+5/(24*60)',
    TRUE);
COMMIT;
END;
/

Después de muchos insert y haber calculado las estadísticas nuestra tabla de ejemplo quedo de la siguiente manera:

SQL> select table_name, num_rows, blocks, avg_row_len,to_char(last_analyzed,'DD-MM-YY HH:MI:SS')    from dba_tables where owner='SCOTT';

TABLE_NAME                       NUM_ROWS     BLOCKS AVG_ROW_LEN TO_CHAR(LAST_ANAL
------------------------------ ---------- ---------- ----------- -----------------
BONUS                                   0          0           0 01-10-11 06:29:17
DEPT                                    4          1          20 01-10-11 06:29:17
EMP                                    14          1          37 01-10-11 06:29:17
EMP1                                   14          1          37 01-10-11 06:29:17
EMP2                                14336         87          37 01-10-11 06:49:35
EMP3                                   14          1          37 01-10-11 06:29:17
SALGRADE                                5          1          10 01-10-11 06:29:17

7 rows selected.

Cuando el job se dispare obtendrá la información de los cambios de la tabla  sys.dba_tab_modifications y calculara las estadísticas de manera automática.

SQL> select table_name, num_rows, blocks, avg_row_len,to_char(last_analyzed,'DD-MM-YY HH:MI:SS')    from dba_tables where owner='SCOTT' --table_name='EMP2';

TABLE_NAME                       NUM_ROWS     BLOCKS AVG_ROW_LEN TO_CHAR(LAST_ANAL
------------------------------ ---------- ---------- ----------- -----------------
BONUS                                   0          0           0 01-10-11 06:29:17
DEPT                                    4          1          20 01-10-11 06:29:17
EMP                                    14          1          37 01-10-11 06:29:17
EMP1                                   14          1          37 01-10-11 06:29:17
EMP2                                56906        340          37 01-10-11 06:54:36
EMP3                                   14          1          37 01-10-11 06:29:17
SALGRADE                                5          1          10 01-10-11 06:29:17