Anda di halaman 1dari 145

Curso

de Administracio n de Oracle
ndice
1

Introduccin ................................................................................................................................................................................................................................................................... 5

Qu es una base de datos? .................................................................................................................................................................................................................................... 5

Instalacin de Oracle................................................................................................................................................................................................................................................... 6

Arquitectura de la base de datos ........................................................................................................................................................................................................................... 7


4.1

Conexiones ......................................................................................................................................................................................................................................................... 10

4.2

Ficheros ................................................................................................................................................................................................................................................................ 12

4.2.1

Fichero de parmetros .......................................................................................................................................................................................................................... 13

4.2.2

Ficheros de datos .................................................................................................................................................................................................................................... 19

4.2.3

Diccionario del sistema ......................................................................................................................................................................................................................... 21

4.2.4

Ficheros temporales ............................................................................................................................................................................................................................... 22

4.2.5

Ficheros de control ................................................................................................................................................................................................................................. 22

4.2.6

Ficheros Redo Log .................................................................................................................................................................................................................................. 23

4.2.7

Undo, bloqueos y concurrencia ......................................................................................................................................................................................................... 30

4.2.8

Transacciones ........................................................................................................................................................................................................................................... 33

4.2.9

Flashback .................................................................................................................................................................................................................................................... 37

4.2.10

Tamao de la base de datos ............................................................................................................................................................................................................... 40

4.3

Estructuras de memoria ................................................................................................................................................................................................................................. 40

4.3.1

La cache de datos (database buffer cache) .................................................................................................................................................................................... 41

4.3.2

Shared Pool ............................................................................................................................................................................................................................................... 51

4.3.3

Administracin de la memoria ........................................................................................................................................................................................................... 53

4.4

Procesos ............................................................................................................................................................................................................................................................... 54

4.4.1

Process Monitor Process (PMON)..................................................................................................................................................................................................... 54

4.4.2

System monitor (SMON) ...................................................................................................................................................................................................................... 54

4.4.3

Database Writer Process (DBWn) ...................................................................................................................................................................................................... 54

4.4.4

Log Writer Process (LGWR) ................................................................................................................................................................................................................. 55

4.4.5

Checkpoint Process (CKPT) .................................................................................................................................................................................................................. 56

4.4.6

Archiver Processes (ARCn) ................................................................................................................................................................................................................... 57

4.4.7

Ficheros de trazas y fichero alert.log ............................................................................................................................................................................................... 57

Tablas ............................................................................................................................................................................................................................................................................. 57
5.1

Index Organized Tables (IOTs) .................................................................................................................................................................................................................... 57

5.2

Temporary Tables ............................................................................................................................................................................................................................................. 58

5.3

Lobs ....................................................................................................................................................................................................................................................................... 60

ndices ............................................................................................................................................................................................................................................................................ 62
6.1

B*Tree ................................................................................................................................................................................................................................................................... 66

6.2

ndices Bitmap ................................................................................................................................................................................................................................................... 68

6.3

ndices Bitmap Join .......................................................................................................................................................................................................................................... 69

6.4

Function-based indexes ................................................................................................................................................................................................................................. 71

Vistas y vistas materializadas ................................................................................................................................................................................................................................ 73

Sql*Loader .................................................................................................................................................................................................................................................................... 73

Tablas externas ........................................................................................................................................................................................................................................................... 76

10

SQL Tuning .............................................................................................................................................................................................................................................................. 79

10.1 Introduccin ....................................................................................................................................................................................................................................................... 79


10.2 Tipos de uniones (joins) ................................................................................................................................................................................................................................. 83
10.2.1

Nested-loop join ..................................................................................................................................................................................................................................... 83

10.2.2

Sort-Merge joins...................................................................................................................................................................................................................................... 87

10.2.3

Hash join ..................................................................................................................................................................................................................................................... 89

10.3 Estadsticas .......................................................................................................................................................................................................................................................... 89


10.3.1

Caso prctico ............................................................................................................................................................................................................................................ 92

10.4 Consejos generales .......................................................................................................................................................................................................................................... 95


10.5 Ordenacin ......................................................................................................................................................................................................................................................... 97
10.6 Anlisis y optimizacin de consultas ...................................................................................................................................................................................................... 101
10.6.1

Funcin DBMS_XPLAN.DISPLAY_CURSOR ................................................................................................................................................................................... 101

10.6.2

Funcin DBMS_XPLAN.DISPLAY_AWR .......................................................................................................................................................................................... 106

10.6.3

Real-time SQL monitoring ................................................................................................................................................................................................................. 107

10.6.4

Anlisis de un expediente X........................................................................................................................................................................................................... 110

10.6.5

Hints ms comunes .............................................................................................................................................................................................................................. 111

10.7 Consulta til para la monitorizacin de las ltimas consultas ejecutadas ............................................................................................................................... 117
11

El nuevo scheduler (jobs) ................................................................................................................................................................................................................................. 118

11.1 Programs ........................................................................................................................................................................................................................................................... 122

11.2 Schedules .......................................................................................................................................................................................................................................................... 124


11.3 Creacin de jobs ............................................................................................................................................................................................................................................. 124
11.4 Ejecucin de jobs externos ......................................................................................................................................................................................................................... 126
11.5 Ejemplos de programacin......................................................................................................................................................................................................................... 126
12

Miscelnea ............................................................................................................................................................................................................................................................. 130

12.1 Tipos de comandos ....................................................................................................................................................................................................................................... 130


12.2 Abrir una base de datos............................................................................................................................................................................................................................... 130
12.3 Parada de una base de datos .................................................................................................................................................................................................................... 133
12.4 Creacin del usuario CURSO...................................................................................................................................................................................................................... 135
12.5 Validacin de tablas e ndices ................................................................................................................................................................................................................... 135
12.6 Filas migradas y encadenadas ................................................................................................................................................................................................................... 136
12.6.1

Filas migradas ......................................................................................................................................................................................................................................... 136

12.6.2

Filas encadenadas ................................................................................................................................................................................................................................. 136

12.6.3

Bsqueda de filas migradas y encadenadas ............................................................................................................................................................................... 136

12.6.4

Eliminacin de filas migradas o encadenadas ........................................................................................................................................................................... 138

12.7 Recycle bin ........................................................................................................................................................................................................................................................ 139


12.8 Sql avanzado .................................................................................................................................................................................................................................................... 141
12.8.1

Contar das de la semana ................................................................................................................................................................................................................... 141

12.8.2

Eliminar registros duplicados ........................................................................................................................................................................................................... 142

12.9 Permisos y seguridad (algunas consulta tiles) .................................................................................................................................................................................. 143

1 Introduccin
Resultado de solicitar varias veces un curso de administracin de Oracle.
Mucha materia. Vamos a ver muchas cosas, pero no es exhaustivo.

Conceptos bsicos generales, arquitectura y funcionamiento.

Otros apartados ms especficos, tiles para el trabajo del da a da de algunos de nosotros.

Dificultad para estructurar la informacin. Muchos conceptos se entremezclan. No se pueden explicar las estructuras de memoria sin hablar
simultneamente los procesos, ni de ndices sin ver conceptos de optimizacin y estadsticas.
Conocimiento asistentes muy diferente. Es posible que durante las explicaciones algunos conceptos se supongan conocidos. Ante cualquier duda,
preguntar.
Es preferible que los asistentes no tengan ordenadores. Podemos ver ms materia.

2 Qu es una base de datos?


Hay distintos tipos de bases de datos. Oracle es una base de datos relacional.
A grosso modo, es un conjunto de ficheros en los que se almacena informacin de forma estructurada en forma de tablas. Cada tabla contiene
registros, formados a su vez por campos. Estos campos estn identificados con su nombre, tipo y tamao.
Otros componentes que tambin forman parte de una base de datos son, entre otros, las vistas, las funciones y procedimientos, las secuencias y
los disparadores (triggers) y los servicios necesarios para su funcionamiento.
Trminos con los que tenemos que estar familiarizados: tabla, registro, campo, vista, procedimiento, funcin, paquete, secuencia, disparador,
esquema, sinnimo, ndice.
Vista: agrupacin lgica de parte de una o ms tablas.

Esquema: conjunto de todos los objetos que pertenecen a un usuario.

3 Instalacin de Oracle
Oracle est disponible en la pgina web, sin restricciones (primera versin, sin parches)
Hay que distinguir entre la aplicacin cliente y el servidor.
3 de las mltiples diferencias entre la versin Standard y Entreprise:

Particiones de tablas

ndices bitmap

Uso de paralelismo

Scripts para instalaciones locales. De esta forma no es necesario tener los servicios levantados (ver servicios):
StartOracle.bat
netstartOracleOraDb11g_home1TNSListener
netstartOracleServiceORCL
pause
StopOracle.bat
netstopOracleServiceORCL
netstopOracleOraDb11g_home1TNSListener
pause

Puntos a tener en cuenta:

nombre (SID): identificador de la base de datos en un servidor

Contraseas de los usuarios sys y system

4 Arquitectura de la base de datos


Tres componentes principales:

Ficheros: de parmetros, de datos, de control, temporales y de redo log.

Estructuras de memoria: SGA (System Global Area)

Procesos

Dos trminos que causan confusin:

Database: una coleccin de ficheros

Instancia: conjunto de procesos y la SGA (System Global Area)

Una base de datos (conjunto de ficheros) puede ser montada y abierta por ms de una instancia (conjunto de procesos y la SGA), aunque en la
mayora de los casos la relacin es de 1 a 1.
En un ordenador para pruebas podemos tener una instancia y varias bases de datos y montar y abrir una de las bases de datos. Para ello
tendramos distintos ficheros de configuracin, cada uno de los cuales abrira una de las bases de datos. Una instancia solo puede estar conectada
a una base de datos.

La SGA contiene estructuras de datos a las que acceden los procesos, como son la cache de datos, la cache de redo de los datos modificados, los
planes de ejecucin de SQL, etc.
Si Oracle estuviese instalado en un servidor Unix podramos ver los procesos de fondo:
$/bin/psaef|grepora

En Windows, solo vemos el servicio Oracle.exe. Este servicio tiene varios hilos, uno por proceso, aunque para poder verlos necesitamos alguna
herramienta especial.
Esquema de conexin a Oracle:

El modo de conexin ms habitual es el de servidor dedicado. En este modo, Oracle crea un proceso para cada sesin. Este proceso hace de
interfaz entre el cliente y la base de datos. Recibe las sentencias que le enviamos, select, updates, etc., efecta las operaciones y nos devuelve las
respuestas. El cliente "habla" directamente con el proceso dedicated server a travs de TCP/IP u otro mecanismo de comunicacin.
Existe otro modo de trabajo: el de servidor multi-hilo (multi-threaded server o MTS). Este modo se utiliza cuando el nmero de clientes
conectados es muy grande. Con el modo de servidor dedicado, si queremos tener 10.000 conexiones abiertas, Oracle necesitara crear 10.0000
procesos. Con el modo MTS es posible que con 100 o 200 procesos (servidores compartidos) podamos dar servicio a esos 10.000 clientes.
Una diferencia importante entre este modo y el modo de servidor dedicado es que los clientes no se comunican directamente con los servidores
compartidos. En su lugar, los clientes se comunican con un proceso o conjunto de procesos llamados dispatchers. Estos dispatchers ponen las
peticiones de los clientes en una cola. El primer servidor compartido que queda libre toma la peticin de la cola, la procesa y deja el resultado en
una cola de respuestas. El dispatcher est continuamente monitorizando la cola de respuestas para enviar los resultados a los clientes
correspondientes.

Normalmente, los servidores compartidos (procesos) se crean al levantar la base de datos.

4.1 Conexiones
Cuando nos conectamos a Oracle con un comando como el siguiente:
C:\>sqlplusCURSO/curso@ORCL

la aplicacin cliente leer el fichero tnsnames.ora que suele estar en el directorio [ORACLE_HOME]\network\admin para averiguar la direccin del
servidor y el modo de conexin.
ORCL=
(DESCRIPTION=
(ADDRESS=(PROTOCOL=TCP)(HOST=localhost)(PORT=1521))
(CONNECT_DATA=
(SERVER=DEDICATED)
(SERVICE_NAME=ORCL)
)
)

Con esta informacin, el cliente ya puede establecer una conexin con la direccin IP localhost por el puerto 1521.

10

Si el servidor est bien configurado, debe haber un proceso llamado TNS Listener que est a la escucha de nuevas peticiones de conexin.
Si la conexin solicitada es de servidor dedicado, el listener crea un nuevo servidor dedicado (un proceso) y el cliente es redireccionado a este
nuevo proceso. La conexin est establecida.

Si por el contrario, la conexin solicitada es de servidor compartido, el listener, que conoce los dispatchers que se estn ejecutando en el servidor,
elegir uno y enviar al cliente los datos para que se pueda conectar a l. En ese momento, el cliente se desconecta del listener y se conecta al
dispatcher quedando la conexin establecida.

11

Una instancia de Oracle puede usar ambos tipos de conexiones simultneamente.

4.2 Ficheros
Ficheros que conforman la base de datos:

Ficheros de datos: contienen las tablas, ndices y otros segmentos.

Redo log files: ficheros en los que se van guardando las transacciones.

Ficheros temporales: usados como almacenamiento temporal y espacio para realizar ordenaciones en disco.

Ficheros de control: indican la localizacin de los ficheros de datos.

El nico fichero necesario para levantar una instancia es el fichero de parmetros.

12

4.2.1

Fichero de parmetros

Es un fichero de texto, conocido como fichero PFILE.


Se suele llamar ora<ORACLE_SID>.ora. As, si el nombre de nuestra base de datos es ORCL, el nombre del fichero de parmetros sera
oraORCL.ora.
Suele estar en el directorio %ORACLE_HOME%/database.
En muchos casos se puede comprobar que el fichero de parmetros contiene slo una lnea que apunta a otro fichero:
IFILE='C:\oracle\product\10.2.0\db_1\database\oraORCL.ora'
SPFILE='C:\oracle\product\10.2.0\db_1\database\spfileORCL.ora'

Tambin podemos arrancar la base de datos manualmente especificando como parmetro del comando startup un fichero diferente:
SQL>startuppfile='C:\oracle\pfile\init.ora'

Ejemplo de fichero de parmetros


db_name="ORCL"
db_block_size=4096
control_files=("C:\oradata\control01.ctl","C:\oradata\control02.ctl")
nls_territory=spain
nls_language=spanish

El nmero de parmetros as como el nombre de estos vara entre las diferentes versiones de Oracle.
En las versiones ms recientes de Oracle, se utiliza una variante del fichero PFILE conocida como SPFILE.
Se debe llamar SPFILE<ORACLE_SID>.ora.

13

A diferencia del anterior, este fichero est en formato binario (no se puede editar con un editor de texto).
Podemos crear un fichero SPFILE a partir de un fichero PFILE con el siguiente comando:
SQL>createspfilefrompfile='C:\oracle\pfile\init.ora';

y viceversa:
SQL>createpfile='oraORCL.ora'fromspfile='C:\oracle\product\10.2.0\db_1\database\spfileORCL.ora';
SQL>createpfilefromspfile;

Si no se especifican las rutas de los ficheros, se utiliza la ruta por defecto.


Si en el directorio %ORACLE_HOME%/databasehay un fichero de parmetros del tipo PFILE y otro del tipo SPFILE, Oracle arrancar con el SPFILE.
Una de las ventajas del nuevo formato es que los parmetros se pueden modificar mediante el comando alter system.
altersystemsetsessions=200scope=[SPFILE|MEMORY|BOTH]

Si el scope (mbito, alcance) es SPFILE, el nuevo parmetro se modifica en el fichero SPFILE y se activar al reiniciar la instancia.
Si es MEMORY se activa inmediatamente, sin modificar el fichero SPFILE.
Si la instancia se ha arrancado con un fichero PFILE solo se podr usar la opcin MEMORY que sera la opcin por defecto.
Si la instancia se ha arrancado con un fichero SPFILE el valor por defecto es BOTH.
Otra ventaja de usar un fichero SPFILE es que Oracle puede almacenar en l parmetros de ajuste internos calculados automticamente.
Ejemplos: vamos a ver el contenido de nuestro SPFILE:
Nota: hay que conectarse como sysdba para poder realizar esta operacin.

14

C:\>sqlplussys/sys@ORCLassysdba

SQL*Plus:Release11.2.0.1.0ProductiononJueSep1810:27:322014

Copyright(c)1982,2010,Oracle.Allrightsreserved.

Conectadoa:
OracleDatabase11gEnterpriseEditionRelease11.2.0.1.064bitProduction
WiththePartitioningoption

SQL>createpfilefromspfile;

Archivocreado.

SQL>exit
DesconectadodeOracleDatabase11gEnterpriseEditionRelease11.2.0.1.064bit
ProductionWiththePartitioningoption

C:\>typeC:\oracle\product\11.2.0\dbhome_1\database\initORCL.ora
orcl.__db_cache_size=771751936
orcl.__java_pool_size=16777216
orcl.__large_pool_size=16777216
orcl.__oracle_base='c:\oracle'#ORACLE_BASEsetfromenvironment
orcl.__pga_aggregate_target=570425344
orcl.__sga_target=1090519040
orcl.__shared_io_pool_size=0
orcl.__shared_pool_size=251658240
orcl.__streams_pool_size=16777216
*.audit_file_dest='c:\oracle\admin\ORCL\adump'
*.audit_trail='db'
*.compatible='11.2.0.0.0'
*.control_files='D:\oracle\ORCL\control01.ctl','D:\oracle\ORCL\control02.ctl'
*.db_block_size=8192

15

*.db_domain=''
*.db_name='ORCL'
*.diagnostic_dest='c:\oracle'
*.dispatchers='(PROTOCOL=TCP)(SERVICE=ORCLXDB)'
*.job_queue_processes=20
*.memory_target=1660944384
*.nls_language='SPANISH'
*.nls_territory='SPAIN'
*.open_cursors=300
*.processes=150
*.remote_login_passwordfile='EXCLUSIVE'
*.sec_case_sensitive_logon=FALSE
*.statistics_level='TYPICAL'
*.undo_tablespace='UNDOTBS1'

C:\>

Vamos a modificar el valor del parmetro sessions:


SQL>showparametersessions

NAMETYPEVALUE
java_max_sessionspace_sizeinteger0
java_soft_sessionspace_limitinteger0
license_max_sessionsinteger0
license_sessions_warninginteger0
sessionsinteger248
shared_server_sessionsinteger

SQL>altersystemsetsessions=200scope=SPFILE;

Sistemamodificado.

16

SQL>showparametersessions

NAMETYPEVALUE

java_max_sessionspace_sizeinteger0
java_soft_sessionspace_limitinteger0
license_max_sessionsinteger0
license_sessions_warninginteger0
sessionsinteger248
shared_server_sessionsinteger

SQL>createpfilefromspfile;
Archivocreado.

Podemos comprobar que el parmetro se ha establecido en el fichero SPFILE aunque todava no est activo.
Este parmetro en concreto no se puede modificar en memoria, por lo que si intentamos usar el scope MEMORY o BOTH nos aparecer un mensaje
de error.
4.2.1.1 Parmetro DB_NAME
Es el nico parmetro obligatorio en el fichero de parmetros.
Cuando se crea una base de datos, su nombre se almacena en los ficheros de datos, los ficheros de redo log y los ficheros de control. Si el nombre
de la base de datos en el fichero de parmetros no coincide con el nombre de la base de datos, no se podr arrancar.
4.2.1.2 Parmetro DB_BLOCK_SIZE
Es uno de los parmetros ms importantes de la base de datos.
Define la unidad mnima de lectura y escritura.

17

Se recomienda que sea mltiplo del tamao de bloque del sistema operativo.
El tamao que utiliza Oracle cuando se instala una base de datos suele ser correcto para la mayora de los casos.
Para averiguar el tamao de bloque del sistema operativo:
D:\Usuarios\aruiz>fsutilfsinfontfsinfoc:
LautilidadFSUTILrequiereprivilegiosadministrativos.

Ejecutamos la consola de comandos como administrador:


C:\Windows\system32>fsutilfsinfontfsinfoc:
NmerodeseriedevolumenNTFS:0x32423d91423d5b35
Versin:3.1
Nmerodesectores:0x000000000b1f3658
Totaldeclsteres:0x000000000163e6cb
Clsteresvacos:0x00000000005b5114
Totaldeclsteresreservados:0x0000000000000830
Bytesporsector:512
Bytesporsectorfsico:4096
Bytesporclster:4096
Bytesporsegmentoderegistrodearchivo:1024
Clsteresporsegmentoderegistrodearchivo:0
TamaovlidodedatosMFT:0x0000000013d00000
LCNdeiniciodeMFT:0x00000000000b65b2
LCNdeiniciodeMFT2:0x00000000003f47e0
IniciodezonaMFT:0x0000000000ff67c0
FindezonaMFT:0x0000000001001f00
Id.deAdministradorderecursos(RM):E6171C6C6A4811E2AED1AB806DF76A1E

El tamao a usar depende del tipo de aplicacin:

18

Pequeo: 2kb, 4kb, para sistemas OLTP (Online Transaction Processing)

Grande: 8kb, 16kb, 32kb, para sistemas DSS (Decision Support Systems)

En un sistema OLTP se hacen muchas lecturas aleatorias (dispersas). Si las filas son pequeas y el tamao del bloque es grande, como en cada
lectura se lee un bloque, estaramos leyendo muchas filas que quedaran en la cache y que nadie necesitara.
Por el contrario, en un sistema que hace un uso intensivo de consultas, caso de un sistema DSS, si el tamao de bloque es grande, se leern ms
filas con una sola operacin fsica de lectura, con lo que reducimos el nmero de lecturas necesarias, que es lo ms costoso.
En general, si los registros son grandes (con campos LOB) y las lecturas son secuenciales (full scan), es mejor usar un tamao de bloque mayor.
Si las filas son pequeas y hay muchos accesos aleatorios, es mejor usar un bloque pequeo.
As, por ejemplo, si tenemos un bloque de 8 kb y queremos leer una sola fila que ocupa 50 bytes, estaramos desperdiciando 8192 - 50 bytes de la
cache.
Con un bloque pequeo, se puede llegar a producir ms frecuentemente el efecto de filas encadenadas (row chaining,) si una fila no cabe en un
bloque.
El espacio se aprovecha mejor con bloques grandes, ya que la proporcin entre el espacio ocupado por la cabecera del bloque y el espacio para
los datos es menor.
4.2.2

Ficheros de datos

Son los ficheros donde se almacena la informacin.


La jerarqua de almacenamiento de Oracle es la siguiente:

Una base de datos est compuesta por uno o ms tablespaces.

Un tablespace est compuesto por uno o ms ficheros.

Las tablas, ndices, vistas materializadas, etc. se conocen como segmentos.

19

Los segmentos estn compuestos por una o ms extensiones, que son reas contiguas de almacenamiento en un fichero.

Una extensin es un conjunto contiguo de bloques.

Las extensiones que componen un segmento (una tabla p. ej.) no tienen por qu pertenecer a un mismo fichero, aunque si deben estar
en el mismo tablespace.

Un bloque es la unidad mnima de lectura y escritura.

Un segmento, para crecer, necesita aadir nuevas extensiones, que no tienen por qu ser contiguas a las existentes, pudiendo incluso pertenecer
a otro fichero, siempre que sea del mismo tablespace.
Si necesitamos ms espacio en un tablespace podemos bien aumentar el tamao de sus ficheros de datos, bien aadirle nuevos ficheros de datos.
Todos los bloques de un tablespace tienen el mismo tamao y estn divididos en tres partes: cabecera, datos y espacio libre.

20

4.2.2.1 Caso prctico


CREATETABLESPACEINDX
DATAFILE'D:\ORACLE\ORADATA\SIPLAMA\INDX1.DBF'SIZE10GAUTOEXTENDONNEXT2GMAXSIZE32G;

ALTERTABLESPACEINDX
ADDDATAFILE'D:\ORACLE\ORADATA\SIPLAMA\INDX2.DBF'SIZE4G;

ALTERDATABASEDATAFILE'D:\ORACLE\ORADATA\SIPLAMA\INDX2.DBF'RESIZE10G;

ALTERDATABASEDATAFILE'D:\ORACLE\ORADATA\SIPLAMA\INDX2.DBF'AUTOEXTENDONNEXT2GMAXSIZE32G;

4.2.3

Diccionario del sistema

Las tablas del diccionario del sistema siempre estn en el tablespace SYSTEM.

21

Vamos a usar dos tablas del diccionario del sistema para ver informacin sobre los ficheros de datos:
selectdf.tablespace_name,df.file_name,
to_char(df.blocks,'999,999,999')asblocks,
to_char(df.bytes/1024/1024,'999,999,999')asMb,
to_char(fe.free_blocks,'999,999,999')asfree_blocks,
to_char(fe.free_bytes/1024/1024,'999,999,999')asfree_Mb
fromdba_data_filesdf,
(
selecttablespace_name,file_id,sum(blocks)asfree_blocks,sum(bytes)asfree_bytes
fromdba_free_space
groupbytablespace_name,file_id
)fe
wheredf.file_id=fe.file_id(+)
orderbydf.tablespace_name,df.file_name;

4.2.4

Ficheros temporales

Oracle utiliza los ficheros temporales para almacenar resultados intermedios y realizar operaciones de ordenacin grandes que no caben en
memoria. Tambin se almacenan en estos ficheros temporales las tablas e ndices temporales.
Estos ficheros estn en un tablespace especial del tipo temporal.
4.2.5

Ficheros de control

Es un fichero binario, sin el cual no es posible arrancar la BD. Por ello es conveniente mantener varias copias del mismo, preferiblemente en
diferentes discos.
Las distintas copias se encuentran situadas en las rutas especificadas en el fichero de parmetros.
Podemos ver la lista fe ficheros de control a travs de la vista del sistema v$controlfile.

22

Contienen informacin como el nombre y fecha de creacin de la base de datos, nombre de los tablespaces, nombre y localizacin de los ficheros
de datos y de redo, nmero de secuencia del redo log en curso, informacin de checkpoint, informacin del archivado de los redo log, etc.
Para aadir un fichero de control tenemos que parar la base de datos (shutdown), hacer una copia de uno de los ficheros de control a nivel de
sistema operativo, aadir la ruta de la copia en el parmetro control_files del fichero de parmetros init.ora o spfile y volver a arrancar la base
de datos (startup).
Es posible crear una copia visible del fichero control file con el comando:
SQL>alterdatabasebackupcontrolfiletotrace;

La traza se crea en el directorio indicado por el parmetro user_dump_dest.


SQL>select*fromv$parameterwherename='user_dump_dest';

Tambin podemos especificar la ruta en la que crear el fichero:


SQL>alterdatabasebackupcontrolfiletotraceas'D:\Usuarios\aruiz\Documents\Temp\controlfile.txt';

o hacer una copia binaria del fichero en una ruta concreta:


alterdatabasebackupcontrolfileto'D:\Usuarios\aruiz\Documents\Temp\controlfile.bak';

La vista v$databasenos proporciona informacin sobre algunos de los parmetros almacenados en el fichero de control.
4.2.6

Ficheros Redo Log

Comenzar explicando qu son las transacciones: Transacciones


Los ficheros redo log son cruciales para el funcionamiento de Oracle.
En ellos se guardan todas las transacciones que se realizan en la base de datos, con objeto de poder repetirlas ms adelante si es necesario:

23

Si insertamos un registro en un tabla, el resultado de la insercin se escribe en el redo log.

Si borramos un registro, el hecho de que lo hemos borrado se escribe en el redo log.

Si borramos una tabla, el contenido de la tabla no se escribe en el redo log, pero s la modificacin que se realiza en el diccionario de datos.

En definitiva, en los ficheros redo log se almacena la informacin necesaria para volver a repetir las ltimas operaciones realizadas.
Los utiliza Oracle para poder recuperar los datos en el caso de que se produzca un error en el sistema (hardware o software).
Como veremos ms adelante, tambin son una de las razones fundamentales de la eficiencia (velocidad) de Oracle.
En caso de un fallo de alimentacin elctrica, Oracle usar los redo log online para restaurar los datos al mismo estado en que estaban antes de
irse la luz.
Esta afirmacin necesita una explicacin. Si cada operacin que realizamos se escribe en los ficheros de datos no se debera perder informacin al irse
la luz.
Si un disco se rompe, Oracle puede usar los redo log archivados junto con los redo log online para restaurar un backup del disco al estado antes del
fallo.
Si un usuario borra una tabla accidentalmente, es posible restaurar un backup anterior y actualizar los datos hasta el momento anterior al
accidente.
qu son los redo log archivados? en qu se diferencian de los ficheros de redo log online?
Toda base de datos Oracle debe tener al menos dos ficheros de redo log online. por qu?
Oracle escribe en los redo log de una forma circular. Comienza escribiendo en el primero. Cuando este se llena comienza a sobrescribir el segundo
y as hasta el ltimo, despus del cual vuelve a comenzar por el primero.
Al cambio de un fichero de log a otro (cuando se pasa de escribir en uno a escribir en el siguiente) se le llama log switch. Este cambio puede hacer
que una base de datos que no est bien configurada se quede "parada" temporalmente. por qu?

24

Para entender cmo funcionan los ficheros de redo log online y alguna de las afirmaciones hechas anteriormente necesitamos comprender algunos
conceptos importantes como saber qu es un checkpoint, que es el buffer o cache de datos y que hace el proceso Database Block Writer
(DBWn).
El buffer o cache de datos es un rea de memoria, ms concretamente de la SGA (System Global Area), en la que se almacenan temporalmente
los bloques cuando se leen de los ficheros de datos. La idea es evitar tener que leerlos otra vez si los necesitamos ms adelante. Las operaciones
ms costosas de una base de datos son las de lectura y escritura (I/O). Si conseguimos disminuir estas operaciones, la respuesta de la base de
datos ser ms rpida. Cuando se modifica un registro, la modificacin se hace sobre el bloque que contiene el registro en el buffer de datos que
est en la memoria. El bloque del fichero de datos no se toca. La informacin necesaria para repetir la operacin tambin se guarda en otra rea de
la SGA conocida como redo log buffer. Cuando realizamos un commit para hacer los datos permanentes (finalizar la transaccin), Oracle no
escribe los bloques modificados de la SGA a disco inmediatamente. Tan solo escribe el contenido del redo log buffer al fichero de redo log online
activo. Mientras que el bloque modificado no se haya escrito en el disco, necesitamos el respaldo del fichero redo log online por si la base de
datos falla. Si despus de hacer commit la luz se va, el buffer de datos se perder y por lo tanto perderemos los bloques modificados. En este
caso, el nico registro que tenemos de los cambios realizados estar en el fichero de redo log online activo. Cuando levantemos otra vez la base
de datos, Oracle ejecutar las transacciones de este fichero, volviendo a realizar la modificacin en el bloque de la cache de datos. Es por este
motivo que hasta que los bloques modificados no se escriben en los ficheros de datos no se puede reutilizar el fichero de redo log online.

25

Es aqu cuando el proceso DBWn entra en escena. Es un proceso background de Oracle responsable de hacer sitio en el buffer de datos cuando se
llena y de hacer los checkpoints. Un checkpoint consiste en la escritura de los bloques modificados (dirty blocks) del buffer de datos a disco. Hay
varias circunstancias que pueden provocar un checkpoint, siendo la ms habitual el cambio de fichero de redo log activo. Cuando el fichero de
log 1 se llena, se cambia al fichero de log 2 y Oracle lanza un checkpoint. En ese momento el proceso DBW comienza a escribir a disco todos los
bloques modificados protegidos por el fichero de log 1. Hasta que el proceso DBWn no termina, Oracle no puede reutilizar el fichero de log 1. Si
se intenta utilizar antes de que el proceso DBWn haya terminado, se interrumpen todos los procesos hasta que el proceso DBWn finaliza el
checkpoint y se escribe en el fichero de trazas el indeseado mensaje "Checkpoint not complete" (el fichero de trazas contiene mensajes
informativos que genera el servidor relacionados con acciones como el arranque y parada de la instancia y eventos excepcionales como el que
acabamos de ver).

26

Siempre que veamos este mensaje, sabremos que estamos induciendo esperas innecesarias para el usuario final que pueden ser evitadas. Uno de
los objetivos de un DBA es definir el nmero suficiente y el tamao de los redo logs online necesario para evitar la reutilizacin de uno de ellos
antes de que finalice el checkpoint que gener cuando se llen.
Si queremos, podemos forzar un checkpoint manual con la siguiente sentencia:
SQL>altersystemcheckpoint;

Por qu no definimos muchos ficheros de redo log o hacemos que sean muy grandes y as evitamos siempre el problema?
Cada tipo de aplicacin genera diferentes cantidades de redo log. Un sistema DSS (Decision Support System) genera significativamente menos redo
log que un sistema OLTP (Transaction Processing). Una aplicacin que gestiones muchas imgenes en campos BLOB (Binary Large Objects) genera
ms redo log que un sistema de pedidos. Un sistema con 100 usuarios generar una dcima parte del redo log que genere una aplicacin con 1.000
usuarios.
No existe un valor nico apropiado para el nmero ni el tamao de los ficheros de redo log. Existen multitud de factores que hay que tener en
cuenta.
As, por ejemplo, para mantener una base de datos de consulta sincronizada con otra (Standby Database), como se sincronizan enviando los
ficheros de redo log que se van llenando, interesa usar muchos fichero pequeos para que la sincronizacin sea siempre cercana.
En una aplicacin en la que hay muchos usuarios modificando la misma informacin, interesa tener ficheros de redo log grandes para que los
bloques se modifiquen tantas veces como sea posible en memoria antes de enviarlos a disco. Esto, sin embargo, puede hacer que el tiempo de
recuperacin despus de una cada sea mayor.
Utilizar ficheros pequeos tambin puede disminuir la eficiencia de la base de datos al producirse un mayor nmero de checkpoints, pero por el
contrario, el tiempo de recuperacin en caso de fallo tambin ser menor.
Podemos ver la cantidad de redo generado (en bytes) (google: oracle statistics descriptions 11g)
selectn.name,s.value

27

fromv$mystats,v$statnamen
wheres.statistic#=n.statistic#
andn.namelike'redosize';

createtabletas
selectobject_id,object_name,created
fromall_objects
whererownum<=10;

4.2.6.1 Ficheros de redo log archivados


Una base de datos Oracle puede funcionar en los modos ARCHIVELOG y NOARCHIVELOG.
Cuando la base de datos est en modo ARCHIVEOG, Oracle guarda una copia del fichero redo log online antes de reutilizarlo.
La nica forma de garantizar que nunca se perder informacin es trabajando en modo ARCHIVELOG.
En modo ARCHIVELOG, si se produce un fallo, podemos recuperar una copia de seguridad anterior y aplicar los ficheros redo log archivados y los
ficheros redo log online y restaurar la base de datos a la misma situacin en la que estaba antes de la cada (o cualquier otro momento que
elijamos).
Podemos averiguar el modo de funcionamiento de la base de datos con la siguiente sentencia:
SQL>selectlog_modefromv$database;

Para activar el modo ARCHIVELOG hay que aadir los siguientes parmetros al fichero de parmetros:
log_archive_start=true(elarchivadodelosficherosderedologesautomticoenlugardemanual)
log_archive_dest_1=C:\oracle\oradata\orcl\arch(hasta10rutasdiferentes)
log_archive_format=arch_%t_%s.arc(nombreconelquesecopianlosficheros)

Para cambiar el modo de funcionamiento la base de datos debe estar montada pero no abierta:

28

SQL>startupmount;
SQL>alterdatabasearchivelog;
SQL>alterdatabaseopen;

4.2.6.2 Otra ventaja del uso de ficheros de redo log


Adems de todo lo visto anteriormente, existe otro motivo por el que Oracle decidi usar los ficheros de redo log.
Los ficheros de redo log se escriben de forma secuencial, y la escritura secuencial es mucho ms rpida que la escritura aleatoria.
Cuando hacemos un commit, slo tenemos que esperar a que finalice la escritura secuencial del redo log buffer al fichero de redo log online
activo para seguir trabajando, operacin que es mucho ms rpida que la escritura aleatoria de los bloques modificados en los ficheros de datos.
Otro motivo, como ya hemos visto, es el de reducir el nmero de escrituras a disco, lo que logramos dejando los bloques de datos modificados en
memoria tanto tiempo como sea posible, sin temor a la perdida de informacin por un fallo de la instancia.
4.2.6.3 Caso prctico
select*fromv$logfile;

select*fromv$log;

alterdatabasedroplogfilegroup1;

alterdatabaseaddlogfilegroup1'D:\ORACLE\ORADATA\SIPLAMA\REDO1.LOG'size100M;

alterdatabasedroplogfilegroup2;

alterdatabaseaddlogfilegroup2'D:\ORACLE\ORADATA\SIPLAMA\REDO2.LOG'size100M;

altersystemswitchlogfile;

alterdatabasedroplogfilegroup3;

29

alterdatabaseaddlogfilegroup3'D:\ORACLE\ORADATA\SIPLAMA\REDO3.LOG'size100M;

alterdatabaseaddlogfilegroup4'D:\ORACLE\ORADATA\SIPLAMA\REDO4.LOG'size100M;

alterdatabaseaddlogfilegroup5'D:\ORACLE\ORADATA\SIPLAMA\REDO5.LOG'size100M;

4.2.7

Undo, bloqueos y concurrencia

Como ya hemos visto, cuando Oracle modifica un registro, tambin aade los datos de la operacin realizada a los ficheros de redo log. Esta
informacin nos permite volver a repetir la operacin si fuese necesario.
Por otra parte, el registro modificado tambin se marca con el identificador de la transaccin que lo ha modificado.
Este identificador acta como un bloqueo de escritura sobre el registro. Si otro usuario intenta modificar este registro, Oracle comprobara que ya
est bloqueado por otra transaccin activa y no lo permitir.
Esta caracterstica ha permitido a Oracle implementar otra funcionalidad fundamental: el multi-versioning, que permite que Oracle nunca bloquee
la informacin en modo de lectura. Para entender este mecanismo hemos de ver primero que son los segmentos de rollback o segmentos de
undo.
Adems de la informacin de redo, Oracle tambin guarda la informacin necesaria para poder deshacer la operacin en caso de que la
transaccin no finalice correctamente. Esta informacin se conoce como de undo y se guarda en los segmentos de rollback o undo (rollback or
undo segments). En caso de que la transaccin falle, Oracle leer la imagen anterior de los segmentos de rollback y restaurar la informacin.
Supongamos ahora que hemos abierto un cursor (hecho un select) a las 10:00:00 contra una tabla con 100.000 registros. Empezamos a recorrerlo y
a las 10:00:05, cuando vamos por el registro nmero 20.000, un usuario modifica el registro nmero 25.000. Si seguimos recorriendo el cursor y al
llegar al registro nmero 25.000 el usuario todava no ha finalizado la transaccin, est claro que deberamos ver la informacin que haba antes de
la modificacin. Pero, qu pasa si ya ha hecho commit y la transaccin ha finalizado?

30

Pues que tambin debera ver el registro como estaba a las 10:00:00 cuando comenz la consulta (cuando se abri el cursor). Oracle consigue este
comportamiento comprobando que la hora a la que se realiz la modificacin (realmente el SCN: System Change Number) es posterior a la del
comienzo de la consulta, y en el caso de este registro, devolviendo la informacin que est almacenada en el segmento de undo.
Mediante este mecanismo, Oracle ha conseguido que las actualizaciones que estn realizando unos usuarios no afecten a las operaciones de
lectura que estn usando otros.
Cuando se hace un commit o un rollback, la transaccin, que se almacena en los segmentos de rollback se marca como activa o finalizada.

31

32

Finalizar explicacin transacciones: Transacciones


4.2.8

Transacciones

En teora, no sera demasiado complejo escribir nuestras aplicaciones para que lean y escriban los registros que necesitan directamente desde
ficheros. La principal diferencia entre usar este mecanismo y una base de datos como Oracle es el concepto de transaccin. Una base de datos nos
garantiza la integridad de los datos. Si una operacin requiere que se realicen modificaciones en dos ficheros (tablas), y el sistema se cae despus

33

de realizar la primera actualizacin, los datos podran quedar inconsistentes. Esto no ocurre usando una base de datos. La base de datos nos
garantiza la atomicidad de la operacin mediante el concepto de transaccin. La operacin se realiza completa o no se realiza, pero nunca se
queda a medias.
Otra propiedad importante de las transacciones es el aislamiento (isolation). Los cambios que est realizando una transaccin no finalizada no
deben ser visibles para el resto de transacciones en curso.
Existen dos comandos para controlar las transacciones: commit y rollback.
Commit finaliza una transaccin haciendo que los cambios sean permanentes.
Rollback tambin finaliza una transaccin, pero deshaciendo todos los cambios que se hubiesen realizado desde la transaccin anterior.
En muchas bases de datos como Informix, Sybase y SQLServer cada operacin es una transaccin en s misma. Si queremos que varias sentencias
formen parte de una misma transaccin es necesario comenzarla explcitamente. Oracle adopt el criterio opuesto. Todas las operaciones se
realizan en el mbito de una transaccin y no se hacen efectivas hasta que esta no se cierra.
Hace algunos aos (y an hoy con algunas bases de datos), si un usuario estaba modificando una tabla, otro usuario no poda leerla hasta que
finalizaba la operacin. Los registros que se estaban modificando o incluso la tabla entera se bloqueaban durante la transaccin. Adems, estos
bloqueos consuman muchos recursos. Esto motiv que muchos programadores intentaran que las transacciones fuesen lo ms cortas posibles.
As, por ejemplo, si queran actualizar todos los registros de una tabla con un milln de registros, podan escribir un procedimiento para
modificarlos de 1000 en mil. Este procedimiento, adems de ser ms complejo que una simple actualizacin, poda dar lugar a una inconsistencia
en los datos.
En Oracle, el tamao de una transaccin no es un problema. No se usa ms memoria ni se consumen ms recursos (por bloqueos) en una
transaccin grande que en una pequea. El tamao de las transacciones debe ser el que corresponda a cada operacin. Si queremos actualizar un
campo de una tabla con un milln de registros, lo correcto sera finalizar la transaccin cuando se hubiesen modificado todos los registros.
Enlace a Ficheros Redo Log

34

Realmente, las operaciones commit son casi inmediatas, independientemente del tamao de la transaccin. Cuando se realiza el commit la
informacin de redo y la de undo ya se ha generado, y los bloques de datos se han modificado en la cache. Si la transaccin es grande, dicha
informacin se ha ido volcando a disco.
La parte ms costosa de una transaccin es la escritura del redo log buffer a los ficheros de redo log online por el proceso LGWR, aunque esto no
suele ser un problema ya que este proceso suele estar enviando esta informacin continuamente:

Cada 3 segundos

Si se ha llenado un tercio del buffer.

Cuando se realiza un commit

puede un select generar redo?


Al hacer un commit, se hace una limpieza rpida (total o parcial) de las transacciones asociadas a los registros modificados (realmente bloques)
que todava estn en la cache. No as de los registros que el proceso DBWR ha volcado a los ficheros de datos y ya no estn en memoria (esta
situacin ocurre sobre todo en transacciones grandes). A este proceso se le llama commit cleanout. Posteriormente, otra sesin puede leer alguno
de estos bloques que tiene transacciones asociadas. Oracle comprueba si las transacciones ya han finalizado y limpia el bloque. Como esta
operacin no se hace como consecuencia de un commit, se le llama delayed block cleanout. Como se trata de una operacin que modifica los
bloques, se genera redo. Por este motivo, es posible que una sentencia select pueda generar redo, especialmente despus de una actualizacin
grande.
Realizar el block cleanout es conveniente para evitar que Oracle tenga que comprobar cada vez si el registro pertenece a una transaccin activa.
(*) En teora, no se podr limpiar la transaccin asociada a un registro si hay un cursor abierto antes del comienzo de la transaccin, aunque la
transaccin ya haya finalizado.
El caso del rollback es el opuesto del commit. El tiempo necesario para realizar un rollback depende directamente del volumen de datos
modificados. Oracle tiene que leer la informacin que haba antes del cambio de los segmentos de undo para revertir la operacin.
Conclusin: Oracle est optimizado para ser muy rpido haciendo commit a costa de que los rollback sean ms lentos y costosos.

35

Repaso de las acciones realizadas en un commit:


Antes de que se haga commit, ya se han realizado las siguientes acciones:

La informacin de undo se ha generado en la SGA.

Los bloques se han modificado en la SGA.

Se ha generado la informacin de redo de las dos acciones anteriores en la SGA. (ver Nota *)

Dependiendo del tamao de la transaccin y el tiempo que dure, parte de la informacin de los tres puntos anteriores puede que se
haya volcado a disco.

Se han activado los bloqueos correspondientes.

Despus del commit:

Se genera el System Change Number (SCN) de la transaccin.

El proceso LGWR escribe el resto del redo log buffer a disco y anota tambin el SCN.

La transaccin se marca como finalizada (committed).

Se liberan los bloqueos.

Se hace un barrido rpido de los bloques modificados que an estn en memoria para borrar la informacin sobre transacciones
finalizadas que puedan contener (commit cleanout).

La accin ms costosa es la escritura del resto del redo log buffer a disco, y esta accin siempre ser pequea porque Oracle ha ido realizando
la escritura de esta informacin de forma regular durante la transaccin. Aunque el proceso LGWR normalmente se ejecuta de forma asncrona,
esta ltima escritura se realiza de forma sncrona. Hasta que no finalice, Oracle no puede seguir trabajando.
Nota *: como hemos visto, en transacciones grandes puede ser que parte de la informacin ya se haya volcado a disco, aunque la transaccin no
haya an finalizado, por lo que la informacin de undo tambin tiene que estar protegida por los ficheros de redo, para, en caso de cada, despus
de recuperar el ltimo estado, poder realizar el rollback que no se pudo hacer por la cada.
Con la siguiente consulta podemos ver las transacciones activas y el nmero de bloques de undo que contienen:

36

selecta.sid,a.username,b.used_ublk
fromv$sessiona,v$transactionb
wherea.saddr=b.ses_addr;

Podemos averiguar el tiempo aproximado que le queda a un rollback para finalizar, viendo cuando se reduce el valor del campo USED_UBLK en un
intervalo de, digamos, 60 segundos.
4.2.9

Flashback

Mediante esta funcionalidad podemos consultar y recuperar datos pasados.


Utiliza la informacin de undo que generan las transacciones.
createtabletas
selectobject_id,object_name,created
fromall_objects
whereowner='DIMA'
andobject_type='TABLE'
orderbyobject_name;

select*fromtwhereobject_name='REPUESTOS_ET';

updatetsetobject_name='FOO'whereobject_name='REPUESTOS_ET';

select*fromtwhereobject_name='FOO';

selectt.*
fromtversionsbetweenscnminvalueandmaxvalue
whereobject_id=64508;

selectora_rowscn,scn_to_timestamp(ora_rowscn),t.*
fromt
whereobject_id=64508;

37


select*
fromtasoftimestampto_timestamp('2014092217:30:30','YYYYMMDDHH24:MI:SS')
whereobject_id=64508;

select*
fromtasoftimestamp(systimestampinterval'20'minute)
whereobject_id=64508;

Incluso podemos buscar los registros eliminados o modificados recientemente:


deletefromtwhereobject_name='FOO';

commit;

select*
fromtasoftimestamp(systimestampinterval'10'minute)
minusselect*fromt;

El tiempo que se almacena depende del tamao del tablespace de undo y del parmetro undo_retention (en segundos).
El parmetro undo_retention debera ser superior al tiempo de ejecucin de la consulta ms larga.
select*fromv$parameterwherenamelike'%undo_%';

altersystemsetundo_retention=1800;

Para averiguar el tiempo que se estn guardando los segmentos de undo:


selectbegin_time,end_time,undoblks,txncount,maxquerylen,tuned_undoretention
fromv$undostat
orderbyend_timedesc;

Cada registro contiene las estadsticas en periodos de 10 minutos:

38

undoblks: nmero total de bloques de undo usados.

txncount: nmero de transacciones ejecutado en el periodo

maxquerylen: duracin en segundos de la consulta ms larga.

tuned_undoretention: tiempo de retencin de los datos de los bloques de undo

Tambin podemos investigar ms a fondo es estado de los segmentos de undo:


selectstatus,
round(sum_bytes/1024/1024)asMB,
round((sum_bytes/undo_size)*100)asPERC
from
(
selectstatus,sum(bytes)sum_bytes
fromdba_undo_extents
groupbystatus
),
(
selectsum(a.bytes)undo_size
fromdba_tablespacesc,
v$tablespaceb,
v$datafilea
wherec.contents='UNDO'
andc.status='ONLINE'
andb.name=c.tablespace_name
anda.ts#=b.ts#
);

Con esta consulta podemos ver la cantidad de undo en cada uno de los tres estados posibles:
ACTIVE

Espacio usado por las transacciones activas y que es necesario para poder realizar un rollback.
El parmetro undo_retention no se utiliza para este tipo de undo. Si no hubiese suficiente espacio en el tablaspace de undo para

39

guardar la informacin generada por la transaccin, se abortara la transaccin y se producira el error ORA30036unableto
extendsegmentinUndotablespace.

UNEXPIRED

EXPIRED

Informacin generada por transacciones finalizadas y antigedad inferior al parmetro undo_retention.. Es necesario para la
consistencia de las lecturas y las funciones de flashback. Si no est toda la informacin necesaria para realizar una lectura
consistente, aparecera el error ORA01555snapshottooold.
Informacin generada por transacciones finalizadas y antigedad superior al parmetro undo_retention. No es necesario para la
consistencia de las lecturas.

4.2.10 Tamao de la base de datos


select(a.data_size+b.temp_size+c.redo_size)/1024/1024/1024"GB",
free.bytes/1024/1024/1024"FreeGB"
from(selectsum(bytes)data_sizefromdba_data_files)a,
(selectnvl(sum(bytes),0)temp_sizefromdba_temp_files)b,
(selectsum(bytes)redo_sizefromv$log)c,
(selectsum(bytes)bytesfromdba_free_space)free;

4.3 Estructuras de memoria


Las estructuras bsicas de memoria de Oracle son la SGA (System Global Area) y la PGA (Program Global Area).

40

La SGA est compuesta por un grupo de estructuras de memoria compartida (componentes) que contienen datos e informacin de control de la
instancia.
La comparten todos los procesos, tanto los servidores dedicados (creados con cada sesin) como los procesos que funcionan en background.
Los componentes principales de la SGA son la cache de datos, los redo log buffers y el shared pool.
La PGA es una zona de memoria propia y exclusiva de cada proceso. Se conoce como PGA al conjunto de todas las PGAs.
En este rea se guarda informacin como los valores de las variables enlazadas (bind variables), el estado de ejecucin de la sentencia, cursores
abiertos y tambin se reserva espacio para realizar ordenaciones (sort area) y "joins" (hash rea y bitmap merge area). Si el espacio que se puede
reservar (suponiendo que estamos usando la gestin automtica de la memoria de la PGA) es demasiado pequeo en relacin con el tamao de la
operacin, el tiempo de respuesta puede dispararse ya que las operaciones han de realizarse sobre segmentos temporales en disco.
4.3.1

La cache de datos (database buffer cache)

Es uno de los componentes principales de la SGA.


Contiene una copia en memoria de los ltimos bloques que se han ledo y de los bloques modificados que an no se han escrito en los ficheros de
datos.

41

Esta lista de bloques es dinmica. Cuando un proceso necesita un registro (realmente un bloque), primero lo busca en la cache de datos. Si lo
encuentra, el bloque se coloca al comienzo de la lista, de forma que los bloques de la cache menos usados se van moviendo haca el final.
En realidad, actualmente se utiliza un mecanismo del tipo touch count, por el que cada vez que se accede a un bloque, se incrementa un contador
en dicho bloque, y cuando hay que hacer hueco para los nuevos bloques, Oracle intenta mantener los bloques ms usados, eliminado los que se
hayan usado menos veces.
Qu ocurre con la lectura de tablas grandes (full scan)? podran ocupar todo el buffer y hacer que perdamos los segmentos ms usados?
No. Oracle utiliza dos mecanismos para que esto no ocurra. En primer lugar, nunca utiliza ms del 25% del buffer cuando hace un full scan. Si la
tabla es mayor que el 25% del tamao del buffer, los bloques ms recientes van borrando a los ms antiguos de la misma tabla. En segundo lugar,
si el tamao de la tabla es mayor que el 10% del tamao del buffer, el contador de uso de los bloques no se incrementar con las siguientes
lecturas de la misma tabla, por lo que esos bloques sern los primeros en salir de la cache.
Este comportamiento podemos modificarlo a nivel de tabla mediante el keep y recycle pool, como veremos ms adelante.
Con la siguiente consulta podemos ver cmo de efectiva est siendo la cache de datos:
selectname,to_char(value/1024/1024,'999,999,999')asM_BLOCKS
fromv$sysstat
wherenamein
(
'physicalreadscache',
'consistentgetsfromcache',
'dbblockgetsfromcache'
);

42

Bufferhitratio=physicalreads/(consistentgetsfromcache+dbblockgetsfromcache)

Physical reads: los bloques de datos que Oracle lee de disco. Muy costosos.
Buffer gets y logical reads: nmero de veces que se solicita un bloque del buffer cache. Son prcticamente sinnimos. Si el bloque no est en el
buffer cache, la lectura lgica implica una lectura fsica (es uno de los campos de la vista v$sql_monitor que veremos ms adelante).
Consistent gets: son las lecturas de bloques consistentes con un instante determinado (o SCN).
Son las lecturas normales. La mayora de las veces, los bloques que estn en la cache son consistentes y no hay que hacer ninguna operacin
adicional para recuperar la informacin.
Cuando se crea un cursor (select) para acceder a una serie de registros, los valores de los registros deben ser consistentes con el momento de la
creacin del cursor, aunque otras sesiones modifiquen algunos de esos bloques antes de que hayan sido ledos. Si el bloque en la cache no es
consistente con el momento deseado, Oracle debe reconstruir el bloque con la informacin de los segmentos de rollback del tablespace de UNDO.
Si no tuvisemos suficientes segmentos de rollback para reconstruir el bloque, nos aparecera el error ORA1555"snapshottooold".
El nmero total de bloques ledos es la suma de Consistent Gets y DB Block gets.
DB block gets: cuando Oracle lee la versin del bloque que haya en la cache (la actual), sin importarle si se ha modificado o no. No est muy claro,
ni es muy importante.
Para los valores anteriores nos sale un buffer hit ratio de 0,6%.
Este ratio nos da una idea del porcentaje de veces que Oracle ha encontrado el bloque que necesitaba en la cache y por lo tanto no ha tenido que
leerlo de los ficheros de datos. Cuanto menor sea este valor, ms efectiva est siendo la cache.
Estos mismos indicadores podemos verlos a nivel de sesin:
selectnvl(n.username,'ORACLEPROC')||'('||n.sid||')'usernamex,
n.program,

43

n.machine,
t.name,
to_char(s.value,'999,999,999,999')asvalue,
round((sysdaten.logon_time)*24)ashoras,
to_char(s.value/(sysdaten.logon_time)/24,'999,999,999,999')asvalue_per_hour
fromv$sesstats,v$statnamet,v$sessionn
wheres.statistic#=t.statistic#
andn.sid=s.sid
andt.namein
(
'physicalreadscache',
'consistentgetsfromcache',
'dbblockgetsfromcache'
)
ands.value>0
orderbys.valuedesc;

o a nivel de pool:
selectname,physical_reads,db_block_gets,consistent_gets,
1(physical_reads/(db_block_gets+consistent_gets))"HitRatio"
fromv$buffer_pool_statistics;

44

Existe una vista que nos proporciona una idea de cmo podra variar este ratio en funcin del tamao de la cache.
selectsize_for_estimate,
to_char(buffers_for_estimate,'999,999,999')asbuffers_for_estimate,
estd_physical_read_factor,
to_char(estd_physical_reads,'999,999,999,999')asestd_physical_reads
fromv$db_cache_advice
wherename='DEFAULT'
andblock_size=(selectvaluefromv$parameterwherename='db_block_size')
andadvice_status='ON';

45

Este resultado nos indica que aumentando el tamao de la cache de los 3505 Mb actuales a 6048 Mb, la lectura fsica de bloques se reducira un
50%.
Tener una cache muy grande no siempre hace que Oracle vaya ms rpido. Cierto tipo de operaciones que deben recorrer todos los bloques en
memoria podrian verse afectadas negativamente si el nmero de bloques en la cache fuese muy grande.

46

Esta consulta nos muestra los objetos con ms bloques en la cache:


selecto.owner,o.object_name,o.object_type,count(*)asnb
fromdba_objectso,v$bhb
whereo.data_object_id=b.objd
andnoto.ownerlike'SYS%'
groupbyo.owner,o.object_name,o.object_type
havingcount(*)>=100
orderby4desc;

47

Vista para averiguar los objetos que ms tiempo han permanecido enla cache (hay que ejecutarla como sys):
withb1as
(
selectobj,max(tch)astch
fromx$bh
groupbyobj
orderby2desc
),
b2as
(

48

selectobj,tch
fromb1
wheretch>=10
)
selecto.owner,o.object_name,o.object_type,b2.tch
fromdba_objectso,b2
whereo.data_object_id=b2.obj
andnoto.ownerlike'SYS%'
orderby4desc;

Consulta para ver los objetos a los que se est accediendo ms frecuentemente:
selectobject_owner,object_name,count(*)
fromv$sql_plan
wherenotobject_ownerin('SYS','SYSTEM','SYSMAN','DBSNMP','APEX_030200','EXFSYS','MDSYS')
groupbyobject_owner,object_name
orderbycount(*)desc;

49

Oracle usa por defecto con un buffer de datos: DEFAULT, pero nos permite trabajar con dos ms, KEEP y RECYCLE.
Cuando se accede a un segmento grande (full scan o index range scan), los bloques pertenecientes a segmentos importantes que se usan ms a
menudo quizs no salgan del buffer, pero aquellos bloques pertenecientes a segmentos importantes que se hayan usado menos frecuentemente
es posible que s salgan. Para evitarlo Oracle nos permite definir dos buffers de datos adicionales:

50

KEEP pool: para mantener los bloques de los segmentos que sabemos que se van a usar muy frecuentemente y queremos que estn (casi) siempre
disponibles.
RECYCLE pool: para evitar que lecturas de segmentos grandes que sabemos que no se van a usar frecuentemente, eliminen a otros objetos de
acceso ms frecuente.
El funcionamiento de estos dos buffers es el mismo que el del buffer por defecto, por lo que tambin salen los bloques menos usados para que
entren otros ms recientes.
Es muy fcil que disminuyamos el rendimiento de la cache en general por un mal uso de estos buffers adicionales. Hay que tener en cuenta que el
espacion que destinamos a estos buffers adicionales lo estamos quitando del buffer por defecto.
Para usarlos, primero hemos de haberlos creado a nivel de instancia, mediante los parmetros de inicializacin buffer_pool_keep y
buffer_pool_recycle (se especifica el nmero de bloques).
Luego tenemos que asociar los segmentos a estos buffers.
CREATETABLEEMP(...)STORAGE(BUFFER_POOLKEEP)CACHE;
ALTERTABLE<tablename>STORAGE(BUFFER_POOLKEEP|RECYCLE|DEFAULT);
CREATEINDEX<indexname>STORAGE(BUFFER_POOLKEEP|RECYCLE|DEFAULT);
CREATETABLE<tablename>STORAGE(BUFFER_POOLKEEP|RECYCLE|DEFAULT);
ALTERINDEX<indexname>REBUILDSTORAGE(BUFFER_POOLKEEP|RECYCLE|DEFAULT);

4.3.2

Shared Pool

Es otro de los componentes fundamentales de la SGA.


Tres de los componentes fundamentales es este rea de memoria son:

Library cache: almacena las sentencias SQL y cdigo PL-SQL compilado.

Data dictionary: cache: almacena informacin del diccionario de datos.

Server result cache: almacena resultados de consultas (a partir de la versin 11g)

51

El tamao de estas reas se ajusta de forma automtica en funcin de las necesidades.


La compilacin de las sentencias SQL es una tarea muy costosa (query plan), por lo que es importante que las que se ejecutan con mayor
frecuencia estn compiladas y disponibles en la library cache. No encontrar una sentencia en la cache es bastante ms costoso que no encontrar un
bloque en la cache de datos.
El funcionamiento de esta cache es muy parecido al de la cache de datos.
Una buena manera de deteriorar el rendimiento de una base de datos consiste en usar sentencias SQL sin variables (bind variables). Oracle
entiende que cada sentencia es diferente, por lo que elimina sentencias importantes que no se han usado recientemente para almacenar otras que
con toda probabilidad no se van a volver a usar. Este problema empeora an ms aumentado el tamao de la library cache.
Respecto a la server result cache, Oracle asigna un 0,25% del parmetro MEMORY_TARGET a este rea, que va aumentando hasta llegar al valor
mximo permitido, que est definido en el parmetro de inicializacin result_cache_max_size.
select*fromv$parameterwherenamelike'result_cache%';

El valor por defecto del parmetro result_cache_mode es MANUAL, que indica que Oracle no almacena resultados a no ser que se especifique con
el hint /*+RESULT_CACHE*/ en la propia consulta. El otro valor posible es FORCE, que se puede activar a nivel de sesin.
El parmetro result_cache_max_result indica el mximo porcentaje de la cache que se puede almacenar en una consulta. Por defecto es un 5%.
Este mecanismo puede ser interesante en consultas que extraigan un volumen pequeo de informacin de la lectura de un gran nmero de
registros: agrupaciones, medias, etc., por ejemplo, si vamos a usar varias veces el nmero de movimientos por ao, suponiendo que la tabla
movimientos tiene muchos registros.

52

4.3.3

Administracin de la memoria

Oracle recomienda que usemos la gestin automtica de la memoria (Automatic Memory Management).
Con este modo, disponible a partir de Oracle 11g, el administrador tan slo establece el tamao total de la memoria para la instancia y Oracle se
encarga de repartir el espacio dinmicamente entre la SGA y la PGA.
Supongamos que queremos usar 5Gb de memoria con posibilidad de aumentar hasta 8Gb en el futuro:
altersystemsetmemory_max_target=8Gscope=spfile;
altersystemsetmemory_target=5Gscope=spfile;
altersystemsetpga_aggregate_target=0scope=spfile;
altersystemsetsga_target=0scope=spfile;
shutdownimmediate;
startup;

Al establecer los parmetros pga_aggregate_target y sga_target a 0, dejamos el control total a Oracle.


Con estos parmetros, los tamaos de la SGA y la PGA (suma de las PGAs de todos los procesos) se ajustan automticamente. Si establecisemos
valores para sga_target o pga_aggregate_target distintos de 0, los valores se usaran como valores mnimos para las respectivas reas de
memoria.
El parmetro memory_target se puede modificar dinmicamente, siempre que no supere el valor definido en el parmetro memory_max_target:
altersystemsetmemory_target=8G;

Tamao de las reas de memoria dinmicas:


select*fromv$memory_dynamic_components;

ltimas operaciones de redimensionamiento de memoria:


select*fromv$memory_resize_ops;

53

Informacin sobre la SGA y la PGA:


select*fromv$sgastat;
select*fromv$pgastat;

4.4 Procesos
selectpname,background
fromv$process
wherenotpnameisnull;

4.4.1

Process Monitor Process (PMON)

Es un monitorizador de procesos.
Si una sesin falla o se mata, este proceso es el encargado de iniciar un rollback de las transacciones en curso y liberar los recursos que estaba
usando: memoria, bloqueos, etc.
Tambin monitoriza al resto de procesos, para reiniciarlos en caso de que alguno falle, si es posible, o en caso contrario, parar la instancia.
4.4.2

System monitor (SMON)

Realiza la recuperacin de la instancia cuando se vuelve a iniciar despus de un fallo.


Tambin limpia los segmentos temporales que no estn en uso y desfragmenta el espacio libre en los ficheros.
4.4.3

Database Writer Process (DBWn)

Es el proceso encargado de escribir los bloques modificados (dirty blocks) de la cache a disco. Escribe los bloques que no se han usado
recientemente (algoritmo LRU Least Recently Used) intentando garantizar que siempre queden bloques libres en la cache para poder cargar nuevos
bloques.
Aunque un proceso (DBW0) es suficiente en la mayora de los casos, en sistemas con varios procesadores que modifiquen muchos datos puede ser
conveniente tener varios procesos DBWn funcionando simultneamente.

54

Aunque Oracle propone el nmero de procesos de escritura durante la instalacin, podemos modificar este valor con el parmetro
db_writer_processes.
Hay dos condiciones que hacen que los procesos DBWn escriban a disco:

Que un proceso no pueda encontrar bloques libres despus de buscar en un porcentaje del buffer de datos.

Para avanzar el checkpoint. Todos los bloques modificados del buffer de datos deben estar respaldados por los ficheros de redo (redo log).
Para poder reutilizar un fichero de redo, los procesos DBWn deben escribir los bloques modificados respaldados por dicho fichero.

4.4.4

Log Writer Process (LGWR)

Es el encargado de escribir las entradas del buffer de redo a los ficheros de redo en disco. Escribe todas las entradas nuevas desde que se realiz la
ltima escritura.
El buffer de redo es circular, es decir, las entradas que se van escribiendo en los ficheros de redo Oracle las va reescribiendo.
El proceso entra en funcionamiento en las siguientes circunstancias:

Cuando se realiza un commit

Cada 3 segundos

Si se ha llenado un tercio del buffer.

Cuando el proceso DBWn intenta escribir un buffer modificado a disco y comprueba que su entrada de redo asociada an no se ha escrito
a disco. En este caso avisa al proceso LGWR para que lo haga, quedndose a la espera de que este finalice para continuar.

Cada vez que se hace commit de una transaccin, Oracle asigna un nmero secuencial a la transaccin (SCN: system change number). Este
nmero se almacena con las entradas de redo log generadas por la transaccin.
Con objeto de maximizar la eficiencia del proceso, si durante una escritura generada por un commit se producen varios commit ms, estos se
ponen en cola y cuando la primera escritura finaliza, todas las dems se hacen a la vez.

55

4.4.5

Checkpoint Process (CKPT)

Cuando los procesos DBWn han escrito los bloques modificados a disco, se produce un checkpoint.
Este proceso, que realiza el checkpoint, escribe el SCN en la cabecera de los ficheros de datos y en los ficheros de control.

Un checkpoint finalizado garantiza que todos los datos son correctos hasta el ltimo SCN escrito. Si hay que realizar una recuperacin, tan solo
hay que volver a aplicar los cambios almacenados en los redo log posteriores al ltimo SCN almacenado (roll forward). Es posible que despus de
roll forward haya que realizar un rollback para deshacer las transacciones activas no finalizadas.

56

Oracle sabe si ha habido una cada y se necesita recuperacin si alguno de los SCNs de los ficheros de datos no coincide con el almacenado en el
fichero de control.
4.4.6

Archiver Processes (ARCn)

Es el proceso encargado de copiar los redo log online a los destinos especificados cuando la base est en modo ARCHIVELOG. Se lanza despus de
cada log switch. Puede haber hasta 10 de estos procesos y el proceso LGWR se encarga de lanzar ms instancias si el rendimiento de las que hay
activas no es suficiente. En el fichero alert.log queda constancia de la creacin de nuevos procesos ARCn. Se puede establecer el nmero mximo
mediante el parmetro log_archive_max_processes.
4.4.7

Ficheros de trazas y fichero alert.log

Los procesos descritos anteriormente dejan constancia de los problemas que puedan presentarse en su fichero de trazas. El nombre de estos
ficheros contiene el nombre del proceso que los escribe.
Tambin existe un fichero de trazas genrico llamado alert.log en el que Oracle escribe cronolgicamente mensajes de advertencias y errores:

Errores internos, corrupcin de bloques, deadlocks.

Tareas administrativas realizadas como la creacin o eliminacin de tablespaces, paradas y arranques de la instancia, finalizacin de
sesiones, etc.

Errores en el refresco de vistas materializadas y otros.

Los ficheros de trazas estn en el directorio:


select*fromv$parameterwherename='background_dump_dest';

5 Tablas
5.1 Index Organized Tables (IOTs)
ej. lookup tables

57

CREATETABLEDIMA.L_UNIDADES
(
CD_USUARIOVARCHAR2(8BYTE)NOTNULL,
CD_UNIDADVARCHAR2(8BYTE)NOTNULL,
CONSTRAINTL_UNIDADES_PKPRIMARYKEY(CD_USUARIO,CD_UNIDAD)
)
ORGANIZATIONINDEX
TABLESPACEDIMA;

5.2 Temporary Tables


Se usan para guardar resultados temporales.
Los datos que se insertan en las tablas temporales solo son visibles para la sesin que los inserta, aunque se haga commit.
Generan mucho menos redo que las tablas normales.
createglobaltemporarytabletemp_table
(
)
oncommitpreserverows;

Aunque la creemos con la clusula oncommitpreserverows, al cerrar la sesin los datos desaparecern.
createglobaltemporarytabletemp_table
(
)
oncommitdeleterows;

se genera redo al trabajar con tablas temporales?


SQL>createglobaltemporarytablegttoncommitpreserverowsasselect*fromall_objectswhere1=0;

58

Tablacreada.

SQL>setautotraceonstatistics
SQL>insertintogttselect*fromall_objects;

66107filascreadas.

Estadsticas

2144recursivecalls
5192dbblockgets
43211consistentgets
258physicalreads
367432redosize
854bytessentviaSQL*Nettoclient
794bytesreceivedviaSQL*Netfromclient
3SQL*Netroundtripsto/fromclient
1088sorts(memory)
0sorts(disk)
66107rowsprocessed

SQL>insert/*+append*/intogttselect*fromall_objects;

66107filascreadas.

Estadsticas

136recursivecalls
953dbblockgets
41219consistentgets
0physicalreads

59

68redosize
839bytessentviaSQL*Nettoclient
808bytesreceivedviaSQL*Netfromclient
3SQL*Netroundtripsto/fromclient
1042sorts(memory)
0sorts(disk)
66107rowsprocessed

SQL>setautotraceoff

Al usar la clusula /*+append*/ estamos usando lo que se conoce como direct-path insert.
En este modo, los datos se escriben directamente en los ficheros de datos sin pasar por el buffer cache y por lo tanto sin generar redo. Tampoco se
reutilizan los espacios libres en los bloques ni se tienen en cuenta las restricciones de integridad.
Para poder usar este mecanismo en tablas no temporales, hay que crearlas con el atributo NOLOGGING.

5.3 Lobs
Los campos LOBs (Large Objects) pueden tener un tamao de hasta 4Gb. (similares a los campos MEMO de Access)
Adems del segmento que se crea al crear una tabla, Oracle crea dos segmentos adicionales, LOB SEGMENT y LOB INDEX, por cada campo LOB que
contenga la tabla.
El motivo es que si los objetos son muy grandes es ms eficiente guardarlos en segmentos independientes, en lugar de meterlos en la fila dentro
del bloque. Adems, estos objetos grandes se almacenan en trozos (chunks). El tamao de estos chunks es configurable. De ah la necesidad del
segmento LOB INDEX.
Como veremos ahora, estos segmentos no tienen por qu estar en el mismo tablespace que la tabla, lo cual puede simplificar las tareas
administrativas (backup, gestin del espacio, etc.)
Otro motivo fundamental es que los objetos LOB, por defecto, no se cachean en el buffer cache.

60

createtablet1(c1number,c2clob);
select*fromuser_segments;

Hasta que no insertamos un registro no se crean los segmentos:


insertintot1(c1,c2)values(1,null);

La definicin completa de la tabla podemos verla con la sentencia:


selectdbms_metadata.get_ddl('TABLE','T1')fromdual;

Se puede modificar la propiedad de cache:


ALTERTABLEtabnameMODIFYLOB(lobname)(CACHE);

61

ALTERTABLEtabnameMODIFYLOB(lobname)(CACHEREADS);
ALTERTABLEtabnameMODIFYLOB(lobname)(NOCACHE);defecto

Por defecto, si los objetos no ocupan ms de 4Kb, Oracle los guarda junto con la fila en el mismo bloque, lo que hace que el funcionamiento sea
ms eficiente. Este comportamiento se puede modificar cambiando la clusula ENABLE STORAGE IN ROW por DISABLE STORAGE IN ROW en el script de
creacin de la tabla, o posteriormente con la siguiente sentencia:
ALTERTABLEtestMOVE
TABLESPACEtbs1
LOB(lob1,lob2)
STOREAS(
TABLESPACEtbs2
DISABLESTORAGEINROW);

6 ndices
Los ndices contienen adems de los campos que los definen, un campo adicional llamado ROWID.
Este campo contiene la informacin del fichero de datos y el bloque dentro del fichero de datos que contiene el registro. Con esta informacin
Oracle puede acceder rpidamente a un registro. Es la forma ms rpida de acceder a un registro (aunque no necesariamente a varios).
Se deberan disear al mismo tiempo que las tablas, no luego sobre la marcha.
En general, no es buena idea aadir ndices a una tabla que ya est en produccin.
Mi apreciacin es que en muchos casos se utilizan demasiados ndices y adems, suelen estar mal diseados.
Ejemplo de lo que no se debera hacer (15 ndices en una misma tabla):
CREATETABLEDIMA.COSES1
(
ID_COSES1NUMBER,

62

ANOVARCHAR2(4BYTE)NOTNULL,
CO_TIPVARCHAR2(1BYTE)NOTNULL,
NOCVARCHAR2(13BYTE)NOTNULL,
NU_SERIE_ETVARCHAR2(15BYTE)NOTNULL,
CO_UNIDAD_ASIGNADAVARCHAR2(8BYTE),
DS_UCO_ASIGNADAVARCHAR2(25BYTE),
DS_BRIGADAVARCHAR2(25BYTE),
DS_CABECERAVARCHAR2(40BYTE),
DS_VOCES_COLECTIVASVARCHAR2(40BYTE),
DS_SERVVARCHAR2(50BYTE),
DS_NOMBRE_FAMILIA_CUFVARCHAR2(45BYTE),
DS_FAM_ACPLAVARCHAR2(100BYTE),
DS_CONTROL_VIDA1VARCHAR2(40BYTE),
DS_CONTROL_VIDA2VARCHAR2(40BYTE),
DS_CONTROL_VIDA3VARCHAR2(40BYTE),
CA_CONTROL_VIDA1NUMBER,
CA_CONTROL_VIDA2NUMBER,
CA_CONTROL_VIDA3NUMBER,
COSNUMBER,
CMNUMBER,
CODNUMBER,
COINUMBER,
YOLDNUMBER,
COPNUMBER,
COCNUMBER,
ESCALONNUMBERNOTNULL,
A02PNUMBER,
A02CNUMBER,
ETVARCHAR2(2BYTE)DEFAULT'ET'NOTNULL
);

CREATEINDEXDIMA.COSES1_CO_TIP_INDXONDIMA.COSES1(CO_TIP);
CREATEINDEXDIMA.COSES1_CO_UNIDAD_ASIG_INDXONDIMA.COSES1(CO_UNIDAD_ASIGNADA);

63

CREATEINDEXDIMA.COSES1_DS_BRIGADA_INDXONDIMA.COSES1(DS_BRIGADA);
CREATEINDEXDIMA.COSES1_DS_CABECERA_INDXONDIMA.COSES1(DS_CABECERA);
CREATEINDEXDIMA.COSES1_DS_DS_CNTR_VIDA1_INDXONDIMA.COSES1(DS_CONTROL_VIDA1);
CREATEINDEXDIMA.COSES1_DS_DS_CNTR_VIDA2_INDXONDIMA.COSES1(DS_CONTROL_VIDA2);
CREATEINDEXDIMA.COSES1_DS_DS_CNTR_VIDA3_INDXONDIMA.COSES1(DS_CONTROL_VIDA3);
CREATEINDEXDIMA.COSES1_DS_FAM_ACPLA_INDXONDIMA.COSES1(DS_FAM_ACPLA);
CREATEINDEXDIMA.COSES1_DS_NOMBRE_FAM_CUF_INDXONDIMA.COSES1(DS_NOMBRE_FAMILIA_CUF);
CREATEINDEXDIMA.COSES1_DS_SERV_INDXONDIMA.COSES1(DS_SERV);
CREATEINDEXDIMA.COSES1_DS_UCO_ASIGNADA_INDXONDIMA.COSES1(DS_UCO_ASIGNADA);
CREATEINDEXDIMA.COSES1_DS_VOC_COLECTIV_INDXONDIMA.COSES1(DS_VOCES_COLECTIVAS);
CREATEINDEXDIMA.COSES1_ESC_INDX1ONDIMA.COSES1(ESCALON);
CREATEUNIQUEINDEXDIMA.COSES1_PKONDIMA.COSES1(ID_COSES1);
CREATEUNIQUEINDEXDIMA.COSES1_U01ONDIMA.COSES1(ANO,CO_TIP,NOC,NU_SERIE_ET,ESCALON);
CREATEINDEXDIMA.COSES1_YOLD_INDXONDIMA.COSES1(YOLD);

Consultas til para la consulta de ndices:


selecttable_name,count(*)
fromdba_indexes
wheretable_owner='DIMA'
groupbytable_name
orderby2desc;

selecttable_owner,table_name,index_name,column_name,column_position
fromdba_ind_columns
wheretable_owner='DIMA'
orderbytable_name,index_name,column_position;

Desventajas de definir muchos ndices y/o ndices con muchas columnas:

Las actualizaciones de las tablas son ms costosas. Por cada registro que se inserte, modifique o borre, hay que actualizar todos los ndices
de la tabla.

La eleccin del plan de ejecucin ser ms compleja, aumentando la probabilidad de que el optimizador elija uno que no sea ptimo.

64

Si un ndice contiene muchos campos, se necesitarn ms lecturas para leerlo y ocupar ms espacio en memoria, por lo que penalizar a
todos los usuarios.

Cuando se cargan o se eliminan grandes cantidades de registros de una tabla puede ser bastante ms eficiente deshabilitar algunos ndices y
recrearlos al finalizar la operacin:
ALTERINDEX<index>UNUSABLE;
ALTERINDEX<index>REBUILD;

Tipos de ndices:

B*Tree

Index Organized Tables (IOT)

Birmap

Bitmap Join

Function-based indexes

65

6.1 B*Tree

Los nodos finales (leaf nodes) que contienen la clave y el RowId del registro estn enlazados por una doble lista enlazada que permite el barrido
de los registros secuencialmente (index rage scan).
Una de las propiedades de este tipo de rboles es que todos los nodos finales estn al mismo nivel, que se conoce como la profundidad (height)
del ndice. La mayora de los ndices tienen una profundidad de 2 o 3, aunque tengan millones de registros, por lo que solo se necesitan dos o tres
lecturas para llegar al registro deseado. Otra propiedad es que los rboles se crean perfectamente balanceados, aunque tras mltiples inserciones e
eliminaciones este balanceo se puede ir deteriorando.

66

Importante: solo debemos acceder a una tabla mediante un ndice cuando queremos acceder a un pequeo subconjunto de registros. El
porcentaje depende de la anchura de la tabla. En una tabla fina (pocos campos y no muy anchos) el porcentaje puede estar entre 2 y 3%. En una
tabla ancha (muchos campos y grandes) este porcentaje puede subir al 20 - 25%.
Si vamos a acceder a muchos registros, es mejor hacer un full scan.
Uno de los motivos es que es bastante ms eficiente leer los bloques de forma secuencial que aleatoria.
Nota: el parmetro db_file_multiblock_read_count indica el mximo nmero de bloques a los que acceder simultneamente en las lecturas
secuenciales. Se expresa en bloques, y Oracle le asigna el valor ptimo para el servidor. En sistema OLTP (Online Transaction Processing) suele
estar entre 4 y 16. Los sistemas DSS (Decision Support Systems) y Data Warehouses, son ms eficientes con valores superiores. De hecho, el
optimizador favorecer los full table scan frente al uso de un ndice cuanto mayor sea el valor de este parmetro.
Siguiendo el orden del ndice, cada bloque hay que leerlo varias veces, aunque la lectura no sea siempre fsica, ya que despus de la lectura es muy
probable que el bloque ya est en el buffer de datos. Veamos un ejemplo:
Supongamos que tenemos una tabla con 100.000 registros, con una anchura de 80 bytes por registro (una tabla fina). Hagamos una consulta que
devuelva un 20% de los registros, es decir 20.000 registros. Si usamos un ndice, tendremos que hacer 20.000 lecturas del tipo TABLEACCESSBY
ROWID, por lo que tendremos que procesar 20.000 bloques. Si usamos un full scan, tan solo tendremos que procesar 1.000 bloques (cada bloque
contiene 100 registros suponiendo un tamao de bloque de 8 Kb), lo que supone 20 veces menos bloques. Incluso aunque aumentramos el
tamao de los registros a 800 bytes, tendramos 10 registros por bloque por lo que necesitaramos hacer 10.000 lecturas, la mitad que usando el
ndice.
Otro factor que puede afectar bastante a la eficiencia del uso de un ndice es el orden de insercin de los registros. Si los registros se insertaron en
el orden de la primary key, y utilizamos la misma primary key para acceder a la tabla, es muy probable que la mayor parte de los bloques que
vamos necesitando ya estn en la cache, ya que los registros se fueron insertando en los bloques en ese orden.
El grado de ordenacin de los datos respecto del ndice se conoce como clustering_factor y podemos consultarlo en la tabla DBA_INDEXES.
Realmente es el nmero de bloques que Oracle tendra que leer si accediese a todos los registros siguiendo el ndice de forma secuencial. Si este

67

valor se aproxima al nmero de bloques de la tabla, significa que los datos en la tabla estn muy ordenados respecto al ndice. Sin embargo, si el
valor es cercano al nmero de registros, los datos estn muy desordenados y su uso sera poco eficiente.
Es uno de los factores que el optimizador tiene en cuenta a la hora de decidir el plan de ejecucin para una consulta.
Hay que tener en cuenta que solo un ndice de data tabla puede tener un buen clustering_factor.
Hay veces que Oracle puede darnos el resultado de una consulta accediendo nicamente al ndice, como por ejemplo, si queremos conocer el
nmero de registros de una tabla.
Existe un modo rpido de lectura de ndices llamado fast full scan, con el que se leen los bloques del ndice sin un orden en particular. El resultado
de esta lectura no est ordenado.

6.2 ndices Bitmap


No estn disponibles en la versin Standard, solo en la Enterprise.

Son adecuados para columnas en las que hay pocos valores diferentes comparados con el nmero total de registros en la tabla.
Ejemplo del tipo de consulta en la que son muy eficientes.
selectcount(*)
fromT

68

wheregenero='H'
andprovinciain(1,10,30)
andgrupo_de_edad='41ysuperior';

Esta consulta sera muy poco eficiente si se utilizan ndices B*Tree, sobre todo si no conocemos a priori cules son las condiciones que se aplicarn.
Estn orientados a sistemas DSS (Decision Support Systems) y Data Warehouses, no sistemas OLTP (Online Transaction Processing).
Cuando se modifican los datos, Oracle necesita bloquear gran parte del ndice para poder recrearlo, lo que podra degradar el funcionamiento de
sistemas OLTP, en los que varios usuarios pueden estar modificando datos simultneamente.

6.3 ndices Bitmap Join


Permiten realizar una desnormalizacin, pero no en los datos sino en el ndice.
Veamos un ejemplo:
La tabla DIMA.REPUESTOS_ET tiene el campo ID_TIPOS_DE_ARTICULOS.
Este campo es una referencia a la tabla DIMA.TIPOS_DE_ARTICULOS:

Si queremos hacer una consulta por el cdigo del tipo de artculo, no nos queda ms remedio que hacer un join:
selectcount(*)

69

fromREPUESTOS_ETR,TIPOS_DE_ARTICULOST
whereR.ID_TIPOS_DE_ARTICULOS=T.ID_TIPOS_DE_ARTICULOS
andT.CO_TIPOS_DE_ARTICULOS='G';

|Id|Operation|Name|Rows|Bytes|Cost(%CPU)|Time|

|0|SELECTSTATEMENT||1|8|5992(1)|00:01:12|
|1|SORTAGGREGATE||1|8|||
|*2|HASHJOIN||86228|673K|5992(1)|00:01:12|
|*3|TABLEACCESSFULL|TIPOS_DE_ARTICULOS|1|5|3(0)|00:00:01|
|*4|TABLEACCESSFULL|REPUESTOS_ET|517K|1515K|5988(1)|00:01:12|

PredicateInformation(identifiedbyoperationid):

2access("R"."ID_TIPOS_DE_ARTICULOS"="T"."ID_TIPOS_DE_ARTICULOS")
3filter("T"."CO_TIPOS_DE_ARTICULOS"='G')
4filter("R"."ID_TIPOS_DE_ARTICULOS"ISNOTNULL)

Oracle nos permite crear el siguiente ndice, con el que asociamos al ndice de una tabla un campo de otra tabla:
createbitmapindexREPUESTOS_ET_TIPO_ART_IDX
onREPUESTOS_ET(T.CO_TIPOS_DE_ARTICULOS)
fromREPUESTOS_ETR,TIPOS_DE_ARTICULOST
whereR.ID_TIPOS_DE_ARTICULOS=T.ID_TIPOS_DE_ARTICULOS;

Con este ndice, podemos conseguir el resultado de la consulta accediendo tan solo al ndice.
La lnea 2 es un error del optimizador, que aade una condicin que en este caso es innecesaria y que obliga a Oracle a leer los registros que
cumplen la condicin principal.

70


|Id|Operation|Name|Rows|Bytes|Cost(%CPU)|Time|

|0|SELECTSTATEMENT||1|3|4(0)|00:00:01|
|1|SORTAGGREGATE||1|3|||
|*2|TABLEACCESSBYINDEXROWID|REPUESTOS_ET|103K|302K|4(0)|00:00:01|
|3|BITMAPCONVERSIONTOROWIDS||||||
|*4|BITMAPINDEXSINGLEVALUE|REPUESTOS_ET_TIPO_ART_IDX|||||

PredicateInformation(identifiedbyoperationid):

2filter("R"."ID_TIPOS_DE_ARTICULOS"ISNOTNULL)
4access("R"."SYS_NC00089$"='G')

6.4 Functionbased indexes


select*
fromUNIDAD
whereUpper(DS_NOMBRE_CORTO)='GACAI/63';

|Id|Operation|Name|Rows|Bytes|Cost(%CPU)|Time|

|0|SELECTSTATEMENT||14|2492|13(0)|00:00:01|
|*1|TABLEACCESSFULL|UNIDAD|14|2492|13(0)|00:00:01|

PredicateInformation(identifiedbyoperationid):

1filter(UPPER("DS_NOMBRE_CORTO")='GACAI/63')

71

createindexUNIDAD_NOMBRE_CORTO_IDX
onUNIDAD(DS_NOMBRE_CORTO);

|Id|Operation|Name|Rows|Bytes|Cost(%CPU)|Time|

|0|SELECTSTATEMENT||14|2492|13(0)|00:00:01|
|*1|TABLEACCESSFULL|UNIDAD|14|2492|13(0)|00:00:01|

PredicateInformation(identifiedbyoperationid):

1filter(UPPER("DS_NOMBRE_CORTO")='GACAI/63')
dropindexUNIDAD_NOMBRE_CORTO_IDX;

createindexUNIDAD_NOMBRE_CORTO_IDX
onUNIDAD(Upper(DS_NOMBRE_CORTO));

|Id|Operation|Name|Rows|Bytes|Cost(%CPU)|Time|

|0|SELECTSTATEMENT||14|2492|6(0)|00:00:01|
|1|TABLEACCESSBYINDEXROWID|UNIDAD|14|2492|6(0)|00:00:01|
|*2|INDEXRANGESCAN|UNIDAD_NOMBRE_CORTO_IDX|6||1(0)|00:00:01|

PredicateInformation(identifiedbyoperationid):

72

2access(UPPER("DS_NOMBRE_CORTO")='GACAI/63')

Importante: para poder usar funciones en este tipo de ndices, es necesario marcarlas como DETERMINISTIC, para indicar a Oracle que para un
mismo parmetro la funcin siempre devolver el mismo resultado.
functionmi_funcion(parametroinvarchar2)returnvarchar2deterministicas
begin
...
end;

Otro caso til: supongamos que tenemos una tabla PEDIDOS con un campo ENVIADO que puede tomar los valores S y N. Cuando tiene el valor
S debe rellenarse el campo NUM_ENVIO. En caso contrario permanece a nulo. En principio no podemos definir un ndice nico por los campos
ENVIADO y NUM_ENVIO porque habra muchos registros con los valores (N, NULL). Puesto que en los ndices B*Tree no se almacenan los
registros en los que todos los campos del ndice sean nulos, podemos definirlo del siguiente modo:
createuniqueindexPEDIDOS_IDX
onPEDIDOS(casewhenENVIADO='N'thenNULLend,NUM_ENVIO);

Nota: Oracle nunca podr usar un ndice en el que todos sus campos puedan ser nulos para realizar un count(*).
La vista dba_ind_expressions nos permite consultar los ndices basados en funciones.

7 Vistas y vistas materializadas


Breve descripcin.
Cuando se utiliza una vista, Oracle sustituye la vista por su cdigo.

8 Sql*Loader
CREATEUSERCURSO

73

IDENTIFIEDBYcurso
DEFAULTTABLESPACEUSERS
TEMPORARYTABLESPACETEMP
PROFILEDEFAULT
ACCOUNTUNLOCK;

Comprobamos que no podemos iniciar una sesin.


GRANTCREATESESSIONTOCURSO;

Creamos la tabla para rellenar a partir de un fichero externo:


CREATETABLECURSO.LDR_TEST
(
CAMPO1VARCHAR2(20)NOTNULL,
CAMPO2VARCHAR2(12),
CAMPO3INTEGERNOTNULL,
CAMPO4NUMBER,
CAMPO5DATE,
CAMPO6DATE,
CAMPO7VARCHAR2(2000)
);

El usuario no tiene permisos para crear una tabla.


GRANTCREATETABLETOCURSO;

El usuario todava no puede insertar registros en la tabla:


ORA01950:noexistenprivilegiosentablespace'USERS'
GRANTUNLIMITEDTABLESPACETOCURSO;

74

insertintoCURSO.LDR_TEST(CAMPO1,CAMPO2,CAMPO3,CAMPO4)
values('ABC','FOO',15,10.34);

Vamos a cargar el siguiente fichero:


test.csv
uno;sdfg;dos;tres;cuatro;cinco;seis;siete
Prueba1;foo;texto1;115;616,33;04/10/2014;06/10/2014;Comentario1
Prueba2;;texto2;72;;;07/10/201410:15:30;"Comentario2"
Prueba3;;;101
Prueba4;;;225
Prueba5
Prueba6;;;badnumber

Necesitamos un fichero de control de carga:


test.ctl
LOADDATA
TRUNCATE
INTOTABLELDR_TEST
WHENCAMPO1<>'Prueba4'
FIELDSTERMINATEDBY';'
TRAILINGNULLCOLS
(
CAMPO1,
NO_IMPORTAFILLER,
CAMPO2"upper(:CAMPO2)",
CAMPO3INTEGEREXTERNAL,
CAMPO4DECIMALEXTERNALNULLIFCAMPO4=BLANKS,
CAMPO5DATE"dd/mm/yyyy",
CAMPO6"casewhenlength(:CAMPO6)<=10thento_date(:CAMPO6,'dd/mm/yyyy')elseto_date(:CAMPO6,'dd/mm/yyyyhh24:mi:ss')end",
CAMPO7optionallyenclosedby'"'
)

75

Para evitar tener que especificar en la lnea de comandos todos los parmetros que necesita el comando SqlLdr, creamos un fichero de
parmetros:
test.par
userid=CURSO/curso@ORCL
direct=true
silent=(FEEDBACK,HEADER,DISCARDS)
skip=1
control=test.ctl
data=test.csv
log=test.log
bad=test.bad
discard=test.dis

Ya podemos ejecutar el comando:


C:\>sqlldrparfile=test.par

El fichero test.dis contendr los registros que no cumplen el formato especificado en el fichero de control. El nmero de registros rechazados se
puede limitar con el parmetro DISCARDMAX. Por defecto tiene el valor ALL pero se podra poner a 1.
El fichero test.bad contendr los registros que no se han podido insertar porque se ha producido algn error.
En el fichero test.log contendr las estadsticas de la carga y el motivo de los errores si se han producido.
En el fichero de control podramos haber especificado APPEND en lugar de TRUNCATE.

9 Tablas externas
Desde un usuario autorizado creamos un directorio de Oracle en el que estar el fichero que queremos leer como si fuese una tabla:
createorreplacedirectoryEXT_TBLas'C:\Users\Alex\Temp\SqlLoader';

76

Utilizaremos el mismo fichero test.csv usado en el captulo sobre Sql Loader.


El usuario CURSO no tiene acceso al directorio:
selectowner,directory_name,directory_path
fromall_directories;

Habilitamos al acceso del usuario CURSO al directorio EXT_TBL en modo lectura, y escritura porque Oracle generar ficheros de log.
grantread,writeondirectoryEXT_TBLtoCURSO;
CREATETABLETEST_EXT
(
CAMPO1VARCHAR2(20BYTE),
NO_VALEVARCHAR(10BYTE),
CAMPO2VARCHAR2(12BYTE),
CAMPO3VARCHAR2(16BYTE),
CAMPO4VARCHAR2(16BYTE),
CAMPO5VARCHAR2(10BYTE),
CAMPO6VARCHAR2(19BYTE),
CAMPO7VARCHAR2(2000BYTE)
)
ORGANIZATIONEXTERNAL
(
TYPEORACLE_LOADER
DEFAULTDIRECTORYEXT_TBL
ACCESSPARAMETERS
(
RECORDSDELIMITEDBYNEWLINE
LOGFILE'test.log'
BADFILE'test.bad'
SKIP1
FIELDSTERMINATEDBY';'OPTIONALLYENCLOSEDBY'"'LDRTRIM

77

MISSINGFIELDVALUESARENULL
REJECTROWSWITHALLNULL
FIELDS
)
LOCATION('test.csv')
)
REJECTLIMITUNLIMITED;

Ya podemos consultar la tabla:


select*fromtest_ext;

Aadimos las conversiones necesarias para poder insertar los datos en la tabla LDR_TEST:
selectCAMPO1,
upper(CAMPO3),
to_number(CAMPO3),
to_number(CAMPO4),
to_date(CAMPO5,'dd/mm/yyyy'),
to_date(CAMPO6,'dd/mm/yyyyhh24:mi:ss'),
CAMPO7
fromTEST_EXT;

Se produce un error porque no se puede convertir el nmero del ltimo registro.


Si intentamos hacer la insercin en la tabla se produce el mismo error:
insertintoLDR_TEST(CAMPO1,CAMPO2,CAMPO3,CAMPO4,CAMPO5,CAMPO6,CAMPO7)
selectCAMPO1,
upper(CAMPO3),
to_number(CAMPO3),
to_number(CAMPO4),
to_date(CAMPO5,'dd/mm/yyyy'),

78

to_date(CAMPO6,'dd/mm/yyyyhh24:mi:ss'),
CAMPO7
fromTEST_EXT;

Podemos solucionarlo asociando a la tabla en la que vamos a insertar los registros una tabla de errores:
execdbms_errlog.create_error_log('LDR_TEST');
insertintoLDR_TEST(CAMPO1,CAMPO2,CAMPO3,CAMPO4,CAMPO5,CAMPO6,CAMPO7)
selectCAMPO1,
upper(CAMPO3),
to_number(CAMPO3),
to_number(CAMPO4),
to_date(CAMPO5,'dd/mm/yyyy'),
to_date(CAMPO6,'dd/mm/yyyyhh24:mi:ss'),
CAMPO7
fromTEST_EXT
logerrorsrejectlimitunlimited;

Los errores quedan registrados en la tabla ERR$_LDR_TEST.

10 SQL Tuning
10.1 Introduccin
Para ejecutar una consulta, Oracle debe realizar una serie de pasos:

Parser: anlisis sintctico y semntico de la sentencia. Se utiliza el diccionario de datos para chequear la existencia de tablas y campos, el
tipo de los campos, los permisos, etc.

Reescritura y normalizacin de la sentencia (reformulacin algebraica) (ver PLAN_HASH_VALUE de v$sqlarea)

79

Decidir el algoritmo o plan ptimo de ejecucin para ejecutar la sentencia de la forma ms eficiente: cmo acceder a los datos, cmo unir y
filtrar los datos, en qu orden, etc.

Realmente, Oracle crea varios planes de ejecucin y asigna a cada uno un coste. Ejecutar el que tenga el menor coste (Cost-Based Optimizer)
El coste de cada plan de ejecucin, en realidad de cada paso de cada plan de ejecucin, se calcula en funcin de la cantidad de recursos necesarios:
operaciones de lectura-escritura, cantidad de memoria necesaria y uso de CPU.
Veamos un ejemplo simplificado:
select*
fromEMPLEADOSE,DEPARTAMENTOSE
whereE.DEPT_NO=D.DEPT_NO
andE.EMPLEO='SUPERVISOR'
andD.CIUDAD='MADRID';

Supongamos que la tabla EMPLEADOS tiene 2.000 filas, la tabla DEPARTAMENTOS 40 filas, existe un supervisor por departamento y hay 10
departamentos en Madrid.
Supongamos tambin que solo podemos leer y escribir un registro cada vez (en la realidad la lectura y escritura se hace a nivel de bloque), que
Oracle escribe cada paso intermedio a disco (no siempre es as en la realidad), y que las tablas no tienen ndices definidos.
Para este ejemplo tampoco vamos a tener en cuenta el coste asociado al volumen de memoria necesario ni al uso de CPU.
Con estas premisas vamos a analizar el coste de tres posibles planes de ejecucin:
I.

Producto cartesiano
1. Leemos todos los registros: 2.000 + 40 = 2.040 lecturas
2. Generamos el producto cartesiano: 2.000 * 40 = 80.000 escrituras
3. Leemos el producto cartesiano y aplicamos las condiciones: 2.000 * 40 = 80.000 lecturas

80

4. Total: 2.040 + 80.000 + 80.000 = 162.040 operaciones de lectura/escritura.

II.

Unin (join) de las dos tablas


1. Leemos todos los registros: 2.000 + 40 = 2.040 lecturas
2. Unir las tablas aplicando la condicin DEP_NO: 2.000 escrituras
3. Leer el resultado del join anterior filtrando por las condiciones: 2.000 lecturas
4. Total: 2.040 + 2.000 + 2.000 = 6.040 operaciones de lectura/escritura.

III.

Unin de las tablas previamente filtradas


1. Leer todos los registros de la tabla EMPLEADOS: 2.000 lecturas
2. Escribir los empleados que son supervisores: 40 escrituras
3. Leer todos los registros de la tabla DEPARTAMENTOS: 40 lecturas
4. Escribir los departamentos de Madrid: 10 escrituras
5. Leer los dos resultados intermedios anteriores: 40 + 10 = 50 lecturas
6. Unimos los dos resultados anteriores por el campo DEP_NO: 10 escrituras
7. Leer el resultado: 10 lecturas
8. Total: 2.000 + 40 + 40 + 10 + 50 + 10 + 10 = 2.160 operaciones de lectura/escritura.

Oracle suele seguir una serie de reglas bsicas para optimizar la ejecucin de las consultas:

Eliminar todas las filas posibles en las primeras operaciones, para disminuir el volumen de filas con las que va a trabajar ms adelante.

Trabajar solo con las columnas que necesita.

Realizar primero las uniones (joins) que generen los resultados con menor nmero de registros.

Guardar el resultado de expresiones comunes para calcularlas una sola vez.

81

Para que el optimizador pueda elegir el plan ms ptimo necesita hacer un uso intensivo de las estadsticas (ver apartado de estadsticas).
Tres de los factores que ms influyen en los recursos (tiempo) que consume una consulta son:

Modo de optimizacin

Modo de acceso a los datos (access path)

Uniones (joins)

El parmetro optimizer_mode puede influir considerablemente en la eleccin del plan de ejecucin.


Puede tomar los valores ALL_ROWS, FIRST_ROWS_10, FIRST_ROWS_100 o FIRST_ROWS_1000. El valor por defecto es ALL_ROWS.
selectvaluefromv$parameterwherename='optimizer_mode';

Una de las decisiones ms importantes del optimizador es elegir adecuadamente el modo de acceso a los datos (access path). Los ms habituales
son la lectura completa de la tabla (full table scan) y la lectura completa de un ndice (index full scan). Tambin es habitual el fast full index scan.
Hemos que tener en cuenta que Oracle nunca lee un solo registro. Las lecturas se realizan a nivel de bloque. El tamao de un bloque suele ser el
mismo a nivel de la base de datos:
selectvaluefromv$parameterwherename='db_block_size';
selectnum_rows,avg_row_len,blocksfromuser_tableswheretable_name='REPUESTOS_ET';

El optimizador suele leer las tablas pequeas usando un full_table_scan. Habitualmente es lo ms rpido.
Los full_table_scan de tablas grandes se hacen leyendo un conjunto de bloques de una vez. Este nmero de bloques se configura con el parmetro
db_file_multiblock_read_count.
select*fromv$parameterwherenamelike'%multiblock%';

82

10.2 Tipos de uniones (joins)


Cuando necesitamos acceder a campos que proceden de mltiples tablas, Oracle las une segn los campos especificados. El modo de unirlas se
selecciona en funcin de las estadsticas y de los ndices que haya definidos en las tablas.
En la mayora de los casos, las uniones se hacen por la primary key. La primary key de una tabla es un campo o combinacin de campos que
identifican unvocamente un registro. Los campos de la primary key no pueden ser nulos. La primary key no es obligatoria, aunque una tabla solo
puede tener una primary key. Una primary key es una constraint (restriccin) que se impone con la ayuda de un ndice. Si no se especifica el ndice,
Oracle lo crea automticamente.
CREATETABLEtable_name
(
column1datatypenull/notnull,
column2datatypenull/notnull,
...

CONSTRAINTconstraint_namePRIMARYKEY(column1,column2,...column_n)
);
altertableREPUESTOS_ET
add(constraintREPUESTOS_ET_PKprimarykey(ID_ART)usingindexREPUESTOS_ET_PK);

Las uniones ms comunes son:


10.2.1 Nestedloop join
Supongamos que nos dan una lista de 20 nombres y un listn telefnico, y nos piden averiguar el nmero de telfono de cada uno de los nombres.
Para este tipo de operacin utilizaramos este tipo de unin. Cogeramos el primer nombre de la lista y lo buscaramos en el listn, luego el
segundo, y as sucesivamente hasta terminar.
Este tipo de unin interesa cuando la tabla externa (outer o driving table) es pequea y la tabla interna (inner table) tiene un ndice nico o clave
primaria para acceder rpidamente al registro deseado, o al menos tiene un ndice no nico con un alto grado de selectividad.

83

Una de las ventajas principales de este tipo de uniones es que se pueden recuperar las primeras filas del resultado sin tener que esperar a
completar el bucle externo completamente.
Vamos a ver el explain plan de la siguiente consulta con Toad.
selectUS.CD_USUARIO,US.CO_UNIDAD,UN.DS_NOMBRE_CORTO
from(
selectCD_USUARIO,CO_UNIDAD
fromUSUARIOS
whereCD_USUARIOlike'MA%'
)US,
UNIDADUN
whereUN.CO_UNIDAD=US.CO_UNIDAD;

Vamos a verlo ahora desde Sql-Plus:


D:\>cdD:\Usuarios\aruiz\Documents\Temp
D:\>sqlplusDIMA/xxx@ORCL
SQL>setlinesize512
SQL>spoolresult.txt
SQL>select*fromFAMILIA_APOYO_ETwhererownum<5;
SQL>spooloff
SQL>setautotraceon
SQL>select*fromFAMILIA_APOYO_ETwhererownum<5;
SQL>setautotracetraceonly
SQL>select*fromFAMILIA_APOYO_ETwhererownum<5;
SQL>spoolresult.txtappend
SQL>spooloff
SQL>exit

Y ahora con una herramienta tipo Sql Developer:


explainplanfor

84

selectUS.CD_USUARIO,US.CO_UNIDAD,UN.DS_NOMBRE_CORTO
from(
selectCD_USUARIO,CO_UNIDAD
fromUSUARIOS
whereCD_USUARIOlike'MA%'
)US,
UNIDADUN
whereUN.CO_UNIDAD=US.CO_UNIDAD;

select*fromtable(dbms_xplan.display);

|Id|Operation|Name|Rows|Bytes|Cost(%CPU)|Time|

|0|SELECTSTATEMENT||3|99|65(0)|00:00:01|
|1|NESTEDLOOPS||||||
|2|NESTEDLOOPS||3|99|65(0)|00:00:01|
|*3|TABLEACCESSFULL|USUARIOS|3|33|62(0)|00:00:01|
|*4|INDEXUNIQUESCAN|UNIDAD_PK|1||0(0)|00:00:01|
|5|TABLEACCESSBYINDEXROWID|UNIDAD|1|22|1(0)|00:00:01|

PredicateInformation(identifiedbyoperationid):

3filter("CO_UNIDAD"ISNOTNULLAND"CD_USUARIO"LIKE'MA%')
4access("UN"."CO_UNIDAD"="CO_UNIDAD")

Oracle ha tomado la tabla USUARIOS como tabla externa porque sabe (por las estadsticas) que tiene menos registros (supone que 3).

85

En teora, Oracle debera haber accedido a los registros que cumplen la condicin whereCD_USUARIOlike'MA%' mediante la primary key que
est definida sobre el campo CD_USUARIO (campo nico, que identifica unvocamente a cada registro y que no puede ser nulo), sin embargo
vemos que ha preferido hacer un full scan de la tabla USUARIOS. por qu?
Existen dos motivos:
1. La tabla es pequea, y seguramente es menos costoso leer todos los registros de forma secuencial (posiblemente una sola lectura) que
hacer tres lecturas individuales, una para cada uno de los registros ->
2. La primary key no contiene el campo CO_UNIDAD que necesitamos para obtener el campo DS_NOMBRE_CORTO de la tabla UNIDAD, por lo que
sera necesario hacer una lectura (por ROWID) para cada uno de los cdigos de usuarios que cumplen la condicin.
De hecho, si cambiamos el orden de las tablas en la consulta, veremos que el plan de ejecucin no cambia:
selectUS.CD_USUARIO,US.CO_UNIDAD,UN.DS_NOMBRE_CORTO
fromUNIDADUN,
(
selectCD_USUARIO,CO_UNIDAD
fromUSUARIOS
whereCD_USUARIOlike'MA%'
)US
whereUN.CO_UNIDAD=US.CO_UNIDAD;

El primer nested loop (lnea 2 de explain plan) obtiene para cada usuario el RowId de su unidad asociada, mediante la primary key de la tabla
UNIDAD.
El nested loop externo (lnea 1 del explain plan) debe recorrer cada uno de los registros del join anterior para acceder mediante los RowIds de la
tabla UNIDAD al registro completo y as poder leer el campo DS_NOMBRE_CORTO.
Podemos comprobar cmo si eliminamos la condicin para los usuarios, el explain plan cambia totalmente.
selectUS.CD_USUARIO,US.CO_UNIDAD,UN.DS_NOMBRE_CORTO

86

fromUNIDADUN,USUARIOSUS
whereUN.CO_UNIDAD=US.CO_UNIDAD;

|Id|Operation|Name|Rows|Bytes|Cost(%CPU)|Time|

|0|SELECTSTATEMENT||243|8019|76(2)|00:00:01|
|*1|HASHJOIN||243|8019|76(2)|00:00:01|
|*2|TABLEACCESSFULL|USUARIOS|243|2673|62(0)|00:00:01|
|3|TABLEACCESSFULL|UNIDAD|1449|31878|13(0)|00:00:01|

Por qu supone el optimizador que la tabla USUARIOS tendr del orden de 243 registros si la tabla tiene realmente 15.625 registros?
selectcount(*)fromUSUARIOS;

Porque la unin solo se puede hacer para los usuarios que tienen una unidad asociada, es decir, con el campo CO_UNIDAD no nulo y Oracle tiene
este factor en cuenta.
selectcount(*)
fromUSUARIOS
wherenotCO_UNIDADisNULL;

10.2.2 SortMerge joins


Se ordenan los registros de las dos tablas por los campos de unin y se unen (un puntero en cada lista, barridos simultneos).
Este tipo de unin es muy eficiente, pero las ordenaciones pueden consumir muchos recursos (I/O y espacio en disco). El rendimiento puede
mejorarse si se accede a los datos, de al menos una de las tablas, por un ndice definido sobre los campos de unin, pero hemos de tener en
cuenta que acceder a muchos registros a travs de un ndice tambin puede ser muy costoso.
Solo se pueden usar para condiciones de igualdad (equi-joins), no mayor que, menor que, distinto, etc.

87

Uno de los problemas principales que surgen al usar este tipo de uniones es el espacio necesario para realizar la ordenacin.
select/*+USE_MERGE(USUN)*/
US.CD_USUARIO,US.CO_UNIDAD,UN.DS_NOMBRE_CORTO
fromUNIDADUN,
(
selectCD_USUARIO,CO_UNIDAD
fromUSUARIOS
whereCD_USUARIOlike'MA%'
)US
whereUN.CO_UNIDAD=US.CO_UNIDAD;

Como Oracle prefiere usar para esta consulta un nested loop join, forzamos un merge join mediante un hint:

|Id|Operation|Name|Rows|Bytes|Cost(%CPU)|Time|

|0|SELECTSTATEMENT||3|99|77(3)|00:00:01|
|1|MERGEJOIN||3|99|77(3)|00:00:01|
|2|SORTJOIN||3|33|63(2)|00:00:01|
|*3|TABLEACCESSFULL|USUARIOS|3|33|62(0)|00:00:01|
|*4|SORTJOIN||1449|31878|14(8)|00:00:01|
|5|TABLEACCESSFULL|UNIDAD|1449|31878|13(0)|00:00:01|

PredicateInformation(identifiedbyoperationid):

3filter("CO_UNIDAD"ISNOTNULLAND"CD_USUARIO"LIKE'MA%')
4access("UN"."CO_UNIDAD"="CO_UNIDAD")
filter("UN"."CO_UNIDAD"="CO_UNIDAD")

88

10.2.3 Hash join


Se crea una tabla de hash en memoria, a partir de la clave de unin de la menor de las tablas (o resultado intermedio). Luego se hace un barrido de
la otra tabla (o resultado intermedio) y se va devolviendo el resultado de la unin.
Es muy efectivo si la tabla de la que se hace el hash cabe en memoria.
Este tipo de join es bastante efectivo cuando no existen ndices que favorezcan el uso de una unin del tipo nested loop. Tambin tiene la ventaja
frente a los sort-merge de que solo hay que ordenar un conjunto de datos. Otra ventaja frente a la unin nested loop es que la comparacin de
cada uno de los registros contra una tabla hash en memoria es ms rpida que la bsqueda de un registro en un ndice de estructura b-tree.
selectUS.CD_USUARIO,US.CO_UNIDAD,UN.DS_NOMBRE_CORTO
fromUSUARIOSUS,UNIDADUN
whereUN.CO_UNIDAD=US.CO_UNIDAD;

|Id|Operation|Name|Rows|Bytes|Cost(%CPU)|Time|

|0|SELECTSTATEMENT||243|8019|76(2)|00:00:01|
|*1|HASHJOIN||243|8019|76(2)|00:00:01|
|*2|TABLEACCESSFULL|USUARIOS|243|2673|62(0)|00:00:01|
|3|TABLEACCESSFULL|UNIDAD|1449|31878|13(0)|00:00:01|

10.3 Estadsticas
Encontrar el plan de ejecucin ptimo puede ser complicado. En una consulta con cuatro tablas, estas se pueden ordenar de 24 formas diferentes.
El mtodo con el que se acceda a cada una de ellas depender de los ndices que haya definidos, y adems, hay que elegir el mtodo ptimo de
unin entre los diferentes conjuntos de datos. El optimizador siempre intentar unir las tablas de forma que se vaya eliminando el mayor nmero
de registros posible.
El optimizador depende enormemente de que las estadsticas sean correctas.

89

La recoleccin de estadsticas suele ser un proceso automtico, aunque tambin se puede hacer de forma manual.
Algunos ejemplos de las estadsticas que recopila Oracle:

De tabla: nmero de filas, nmero de bloques, nmero de registros por bloque, longitud media de los registros, etc.
selecttable_name,num_rows,blocks,avg_row_len,last_analyzed
fromdba_tables
whereowner='DIMA'
andtable_name='REPUESTOS_ET';

De columnas: nmero de valores diferentes en la columna, nmero de nulos, histogramas, etc.


selecttable_name,column_name,num_distinct,num_nulls,density,last_analyzed,histogram
fromdba_tab_col_statistics
whereowner='DIMA'
andtable_name='REPUESTOS_ET';

De ndices: nmero de bloques finales, nmero de niveles y clustering factor.


selecttable_name,index_name,num_rows,blevel,leaf_blocks,distinct_keys,clustering_factor,last_analyzed
fromdba_indexes
whereowner='DIMA'
andtable_name='REPUESTOS_ET';

El clustering_factor determina la eficiencia de un ndice. Es el nmero de lecturas a disco que necesitara hacer Oracle para leer todos los registros
de una tabla, accediendo a travs del ndice (por ROWID) en el orden del ndice. Si los registros en la tabla estn en un orden parecido al del ndice,
este valor ser menor, y se aproximar al nmero de bloques de la tabla.
Si los datos estn dispersos respecto al orden del ndice, el clustering factor se podra acercar al nmero de registros de la tabla, y su uso no sera
eficiente al realizar un index range scan.
Si en una consulta se filtra por dos campos y para cada uno de ellos existe un ndice, Oracle usar el ndice ms selectivo.

90

El uso de funciones como SUBSTR, INSTR, TO_DATE y TO_NUMBER deshabilita el uso de ndices a no ser que se creen ndices por funciones.
Las estadsticas se recopilan con el paquete DBMS_STATS:
Procedimiento

Obtiene

GATHER_INDEX_STATS

Estadsticas de ndices

GATHER_TABLE_STATS

Estadsticas de tablas, columnas e ndices.

GATHER_SCHEMA_STATS

Estadsticas de todos los objetos de un esquema.

GATHER_DATABASE_STATS

Estadsticas de todos los objetos de la base de datos.

GATHER_SYSTEM_STATS

Estadsticas de CPU y I/O del sistema.

GATHER_DICTIONARY_STATS

Estadsticas de los objetos del diccionario.

Ejemplos:
begin
dbms_stats.gather_table_stats(
ownname=>'DIMA',
tabname=>'REPUESTOS_ET'
);
end;
executedbms_stats.gather_schema_stats(ownname=>'SITRANS');

Para que el coste calculado por el optimizador para cada plan de ejecucin sea lo ms real posible, y as elegir el que realmente sea ms eficiente,
Oracle necesita conocer los tiempos reales para cada una de las operaciones un una situacin de carga real del sistema, teniendo en cuenta el
nmero de sesiones, la memoria disponible para cada proceso, los tiempos reales de lectura y escrituras secuenciales y aleatorias, la velocidad de la
CPU, etc.

91

Como Oracle no sabe cundo es una situacin de carga real, por defecto toma lo que se conoce como No Workload Statistics. Esta funcin realiza
varias lecturas y escrituras durante unos minutos. Se realiza una vez, de forma automtica, al crear la base de datos.
executedbms_stats.gather_system_stats();

Podemos calcular las estadsticas del sistema durante un periodo con las siguientes sentencias:
dbms_stats.gather_system_stats('start');
dbms_stats.gather_system_stats('stop');
dbms_stats.gather_system_stats('interval',interval=>n);

donde n es el nmero de minutos durante los que se recopilan las estadsticas.


El resultado de estas estadsticas se puede ver en la tabla sys.aux_stats$.
Nota: Debido a un error en Oracle 11.2, el valor de los parmetros sreadtim (tiempo de lectura de un bloque en milisegundos) and mreadtim
(tiempo de lectura de una lectura de bloques mltiple) se calcula mal, lo que induce a que a veces se elijan planes de ejecucin que distan de ser los
ms ptimos. Este error se solucion a partir de la versin 11.2.0.3.
10.3.1 Caso prctico
createtablepruebaas
selectdecode(mod(level,2),0,1,decode(mod(level,3),0,1,level))asidfromdualconnectbylevel<=100000;
select*fromprueba;
createindexprueba_idx_idonprueba(id);

Vamos a comprobar que solo se han calculado las estadsticas del ndice (las del ndice exactas).
selecttable_name,num_rows,blocks,avg_row_len,last_analyzed
fromdba_tables

92

whereowner='CURSO'
andtable_name='PRUEBA';

selecttable_name,index_name,num_rows,blevel,leaf_blocks,distinct_keys,clustering_factor,last_analyzed
fromdba_indexes
whereowner='CURSO'
andtable_name='PRUEBA';

selecttable_name,column_name,num_distinct,num_nulls,density,last_analyzed,histogram
fromdba_tab_col_statistics
whereowner='CURSO'
andtable_name='PRUEBA';

Calculamos las estadsticas de la tabla:


execdbms_stats.gather_table_stats(ownname=>'CURSO',tabname=>'PRUEBA');

Comprobamos que las del ndice se han vuelto a calcular (esta vez no son exactas, Oracle ha hecho un muestreo).
La densidad de un campo es la fraccin de registros que se devolveran filtrando por ese campo. As, por ejemplo, la densidad de un campo que
solo puede tomar los valores S o N, es 0,5. Normalmente equivale a 1/num_distinct.
Volvemos a calcularlas, esa vez exactas.
Aunque no es necesario borrar las estadsticas anteriores, lo podemos hacer con la siguiente sentencia:
execdbms_stats.delete_table_stats(ownname=>'CURSO',tabname=>'PRUEBA');
execdbms_stats.gather_table_stats(ownname=>'CURSO',tabname=>'PRUEBA',estimate_percent=>100);

Por defecto, para el campo ID no se han calculado los histogramas de distribucin.

93

Para poder observar las diferencias de comportamiento entre usar o no los histogramas, vamos a modificar el parmetro
optimizer_dynamic_sampling:
select*fromv$parameterwherename='optimizer_dynamic_sampling';

altersessionsetoptimizer_dynamic_sampling=0;

Vamos a ver la diferencia en los planes de ejecucin de estas dos consultas:


select*frompruebawhereid=1;

select*frompruebawhereid=7;

|Id|Operation|Name|Rows|Bytes|Cost(%CPU)|Time|

|0|SELECTSTATEMENT||3|12|1(0)|00:00:01|
|*1|INDEXRANGESCAN|PRUEBA_IDX_ID|3|12|1(0)|00:00:01|

No existen diferencias.
Vamos a calcular de nuevo las estadsticas, indicando ahora que se calculen los histogramas de los campos indexados:
execdbms_stats.gather_table_stats(ownname=>'CURSO',tabname=>'PRUEBA',method_opt=>'forallindexedcolumnssize254');

Los planes de ejecucin cambian considerablemente entre la primera y la segundo consulta.


qu ocurre si borramos las estadsticas y volvemos a poner el parmetro optimizer_dynamic_sampling en su valor original?
execdbms_stats.delete_table_stats(ownname=>'CURSO',tabname=>'PRUEBA');

altersessionsetoptimizer_dynamic_sampling=2;

94

Podemos ver en el plan de ejecucin que a falta de estadsticas Oracle ha usado el dynamic sampling:

|Id|Operation|Name|Rows|Bytes|Cost(%CPU)|Time|

|0|SELECTSTATEMENT||69067|876K|47(3)|00:00:01|
|*1|TABLEACCESSFULL|PRUEBA|69067|876K|47(3)|00:00:01|

PredicateInformation(identifiedbyoperationid):

1filter("ID"=1)

Note

dynamicsamplingusedforthisstatement(level=2)

10.4 Consejos generales


Algunos consejos generales para hacer que las consultas sean ms eficientes:

Intentar siempre que sea posible usar equi joins (inner join con =) frente a nonequi joins (inner join con operaciones del tipo <>, >, <, !=,
BETWEEN).

Reducir el nmero de registros con sentencias where lo antes posible, de forma que los conjuntos de registros a unir sean lo menores
posible.

Evitar usar subconsultas para calcular datos parciales. Es mejor usar la sentencia case.
Evitar sobre todo llamadas a funciones Pl-Sql para obtener resultados que se podran obtener mediante joins.

De forma general, leer el mnimo nmero de registros posible.


select
(selectcount(*)fromREPUESTOS_ETwhereIN_REPARABLEisNULL)SIN_DEFINIR,

95

(selectcount(*)fromREPUESTOS_ETwherenotIN_REPARABLEisNULL)DEFINIDO
fromdual;

|Id|Operation|Name|Rows|Bytes|Cost(%CPU)|Time|

|0|SELECTSTATEMENT||1||2(0)|00:00:01|
|1|SORTAGGREGATE||1|2|||
|*2|TABLEACCESSFULL|REPUESTOS_ET|101K|198K|5990(1)|00:01:12|
|3|SORTAGGREGATE||1|2|||
|*4|TABLEACCESSFULL|REPUESTOS_ET|517K|1010K|5990(1)|00:01:12|
|5|FASTDUAL||1||2(0)|00:00:01|

selectSum(casewhenIN_REPARABLEisNULLthen1else0end)asSIN_DEFINIR,
Sum(casewhenIN_REPARABLEisNULLthen0else1end)asDEFINIDO
fromREPUESTOS_ET;

selectSum(Nvl2(IN_REPARABLE,0,1))asSIN_DEFINIR,
Sum(Nvl2(IN_REPARABLE,1,0))asDEFINIDO
fromREPUESTOS_ET;

|Id|Operation|Name|Rows|Bytes|Cost(%CPU)|Time|

|0|SELECTSTATEMENT||1|2|5990(1)|00:01:12|
|1|SORTAGGREGATE||1|2|||
|2|TABLEACCESSFULL|REPUESTOS_ET|618K|1208K|5990(1)|00:01:12|

96

10.5 Ordenacin
Situaciones en las que Oracle realiza ordenaciones:

Sentencias order by

Sentencias group by

Creacin de un ndice

Al realizar un merge sort si no existen ndices adecuados

Cada sesin dedicada tiene un rea de memoria para realizar las ordenaciones. Si no hay suficiente espacio en memoria para realizar la ordenacin,
hay que utilizar espacio en disco. Las ordenaciones en disco son unas 14.000 veces ms lentas que en memoria.
Con la siguiente sentencia podemos ver las ordenaciones realizadas a nivel de sistema:
selectname,valuefromv$sysstatwherenamelike'sort%';

NAMEVALUE

sorts(memory)411308465
sorts(disk)3388
sorts(rows)6,9050E+10
selectsysdatestartup_timefromv$instance;

70.000millonesdeordenacionesen85das:

y con esta otra, a nivel de sesin:


withRas
(
selects.valueasn_rows,s.sid
fromv$sesstats,v$statnamet

97

wheres.statistic#=t.statistic#
andt.name='sorts(rows)'
ands.value>0
orderby1desc
)
selectnvl(n.username,'ORACLEPROC')||'('||n.sid||')'username,
n.program,
n.machine,
R.n_rows,
(
selects.value
fromv$sesstats,v$statnamet
wheres.sid=R.sid
ands.statistic#=t.statistic#
andt.name='sorts(memory)'
)as"sorts(memory)",
(
selects.value
fromv$sesstats,v$statnamet
wheres.sid=R.sid
ands.statistic#=t.statistic#
andt.name='sorts(disk)'
)as"sorts(disk)",
(sysdaten.logon_time)*24ashoras
fromR,v$sessionn
whereR.sid=n.sid;

USERNAMEPROGRAMN_ROWSsorts(memory)sorts(disk)HORAS

DIMA(365)w3wp.exe10377251658000,62
K02(17)toad.exe537712062872272772,117222
ORACLEPROC(359)ORACLE.EXE(MMON)16597581134284502039,82639
ORACLEPROC(363)ORACLE.EXE(CJQ0)16503606266914402038,97417

98

DIMA_WEB(144)JDBCThinClient2327067375905,38833333
DIMA_WEB(264)JDBCThinClient2085935382305,51
DIMA_WEB(138)JDBCThinClient2045157397905,50083333
ORACLEPROC(120)ORACLE.EXE(SMON)186940524124402039,82639
ORACLEPROC(242)ORACLE.EXE(Q001)67872511397002039,82056
DATOUNICO(376)CargaWebServices_2010.exe480699358210131,383333
DIMA_WEB(387)JDBCThinClient290250228104,31083333
ORACLEPROC(240)ORACLE.EXE(RECO)1216402360502039,82639
DATOUNICO(21)w3wp.exe5749931701,05222222
DIMARO(123)Toad.exe4371546201,03361111
ORACLEPROC(4)ORACLE.EXE(MMNL)433521075602039,82611
DIMARO(127)Toad.exe40999165506,24972222
K02(27)Toad.exe1327695507,78916667
ORACLEPROC(238)ORACLE.EXE(DBRM)7585135702039,82639
RIESGOS(370)JDBCThinClient354754105,51388889
ORACLEPROC(132)ORACLE.EXE(Q000)2792391091,8838889
SICETRO(126)ORACLE.EXE146710105,59472222
DIMAAPOYO(23)Toad.exe136919603,40694444

Las operaciones que necesitan ms memoria, como las ordenaciones y la creacin de tablas de hash se dividen en tres categoras:
Optimal: la operacin se realiza en la memoria disponible
One-pass: cuando es necesario escribir resultados parciales en disco (una vez) por falta de memoria. Es este caso se divide el bloque de datos en
tres partes, cada una de las cuales cabe en la memoria disponible. Ordenamos cada una de ellas y guardamos cada resultado parcial en disco. A
continuacin se vuelven a leer para realizar la fusin, que se vuelve a guardar en disco. Con tan solo 22 Mb se puede ordenar 1 Gb de informacin.
Multi-pass: cuando es necesario escribir resultados parciales en disco (ms de una vez) por falta de memoria. La ejecucin se degrada
enormemente.
Vamos a ver la memoria usada por los distintos pasos del plan de ejecucin de una consulta:
withSas

99

(
selectFX_MOVIMIENTO,NOC,CO_UNIDAD,CO_TIPO_MOVIMIENTO,
row_number()over(orderbyFX_MOVIMIENTOdesc)asRN
fromDIMA.MOVIMIENTO_ARTICULOS
)
select/*q001*/FX_MOVIMIENTO,NOC,CO_UNIDAD,CO_TIPO_MOVIMIENTO
fromS
whereRN=5000000;

|Id|Operation|Name|Rows|Bytes|TempSpc|Cost(%CPU)|Time|

|0|INSERTSTATEMENT||1|97||1(0)|00:00:01|
|0|SELECTSTATEMENT||18M|628M||206K(1)|999:59:59|
|*1|VIEW||18M|628M||206K(1)|999:59:59|
|*2|WINDOWSORTPUSHEDRANK||18M|541M|773M|206K(1)|999:59:59|
|3|INDEXFASTFULLSCAN|MOVIMIENTO_ARTICULOS_IDS_IDX5|18M|541M||50905(0)|999:59:59|

PredicateInformation(identifiedbyoperationid):

1filter("RN"=5000000)
2filter(ROW_NUMBER()OVER(ORDERBYINTERNAL_FUNCTION("FX_MOVIMIENTO")DESC)<=5000000)

Averiguamos el identificador de esta consulta:


selectsql_id,sql_textfromv$sqlwheresql_textlike'%q001%';
selectoperation,options,object_namename,
trunc(bytes/1024/1024/1024)"input(GB)",
trunc(last_memory_used/1024/1024)last_mem,
trunc(estimated_optimal_size/1024/1024)opt_mem,

100

trunc(estimated_onepass_size/1024/1023)onepass_mem,
decode(optimal_executions,null,null,
optimal_executions||'/'||onepass_executions||'/'||multipasses_executions)"O/1/M"
fromv$sql_planp,v$sql_workareaw
wherep.address=w.address(+)
andp.hash_value=w.hash_value(+)
andp.id=w.operation_id(+)
andp.sql_id='6xjv9qujyntmv';
orderbyp.id;

10.6 Anlisis y optimizacin de consultas


10.6.1 Funcin DBMS_XPLAN.DISPLAY_CURSOR
Ya vimos en el apartado de los nested loop joins como consultar el plan de ejecucin de una consulta.
La funcin display_cursor del paquete dbms_xplan tambin nos permite ver el plan de ejecucin de las consultas (cursores) que estn en la
memoria:
dbms_xplan.display_cursor(
sql_idINVARCHAR2DEFAULTNULL,
cursor_child_noINNUMBERDEFAULT0,
formatINVARCHAR2DEFAULT'TYPICAL');
selectsql_id,child_number,sql_textfromv$sqlwheresql_textlike'%q001%';

101


|Id|Operation|Name|Rows|Bytes|TempSpc|Cost(%CPU)|Time|

|0|SELECTSTATEMENT|||||238K(100)||
|*1|VIEW||17M|634M||238K(1)|00:47:41|
|*2|WINDOWSORTPUSHEDRANK||17M|551M|805M|238K(1)|00:47:41|
|3|TABLEACCESSFULL|MOVIMIENTO_ARTICULOS|17M|551M||82354(1)|00:16:29|

PredicateInformation(identifiedbyoperationid):

1filter("RN"=5000000)
2filter(ROW_NUMBER()OVER(ORDERBYINTERNAL_FUNCTION("FX_MOVIMIENTO")DESC)<=5000000)

Esta funcin tambin nos permite ver las estadsticas del plan de ejecucin, siempre que las activemos previamente.
Podemos activarlas de dos formas: aadiendo el hint gather_plan_statistics o estableciendo el parmetro statistics_level al valor ALL.
select/*+gather_plan_statisticsq002*/count(*)
fromDIMA.MOVIMIENTO_ARTICULOSM,
DIMA.REPUESTOS_ETR
whereR.NOC=M.NOC
andM.CO_TIPO_MOVIMIENTO='A'
andM.CO_UNIDADin('213G9003','50000005')
andR.CO_FAMILIA_APOYOin('003108','310200');

selectsql_id,child_number,sql_textfromv$sqlwheresql_textlike'%q002%';

select*fromtable(dbms_xplan.display_cursor('3junahtay3a82',0,'TYPICALIOSTATSLAST'));

|Id|Operation|Name|Starts|ERows|EBytes|Cost(%CPU)|ETime|ARows|ATime|Buffers|Reads|

102

|0|SELECTSTATEMENT||1|||27027(100)||1|00:02:31.53|67223|78669|
|1|SORTAGGREGATE||1|1|46|||1|00:02:31.53|67223|78669|
|*2|HASHJOIN||1|561|25806|27027(1)|00:05:25|1580|00:02:33.23|67223|78669|
|3|INLISTITERATOR||1|||||28881|00:02:15.30|45373|56823|
|*4|TABLEACCESSBYINDEXROWID|MOVIMIENTO_ARTICULOS|2|16889|412K|21048(1)|00:04:13|28881|00:02:16.07|45373|56823|
|*5|INDEXRANGESCAN|MOVIMIENTO_ARTICULOS_IDS_IDX6|2|21356||100(0)|00:00:02|46110|00:00:00.13|214|220|
|*6|TABLEACCESSFULL|REPUESTOS_ET|1|20555|421K|5979(1)|00:01:12|21311|00:00:02.47|21850|21846|

PredicateInformation(identifiedbyoperationid):

2access("R"."NOC"="M"."NOC")
4filter("M"."CO_TIPO_MOVIMIENTO"='A')
5access(("M"."CO_UNIDAD"='213G9003'OR"M"."CO_UNIDAD"='50000005'))
6filter(("R"."CO_FAMILIA_APOYO"='003108'OR"R"."CO_FAMILIA_APOYO"='310200'))

Si en el parmetro format no utilizsemos LAST a continuacin de IOSTATS, los valores estadsticos seran los acumulados de todas las ejecuciones
de la consulta. Con LAST solo se muestran los valores asociados a la ltima ejecucin.
Es muy interesante comparar el nmero de filas devuelto y el tiempo estimado en cada paso con los valores reales. Si los valores estimados difieren
mucho de los reales, posiblemente las estadsticas no estn actualizadas. EL plan de ejecucin se decide a partir de los valores estimados, por lo
que es posible que no sea el ms ptimo.
Como hemos dicho anteriormente, podramos activar la recopilacin de las estadsticas para todas las consultas de una sesin o para todo el
sistema:
selectvaluefromv$parameterwherename='statistics_level';

altersessionsetstatistics_level='ALL';

En la consulta anterior se utiliza un hash join. La tabla hash se genera a partir de la tabla MOVIMIENTO_ARTICULO porque el optimizador piensa que
hay menos registros que cumplen las condiciones en esta tabla. En las estadsticas podemos ver que el nmero de registros que cumplen la
condicin es menor en el caso de la tabla REPUESTOS_ET. Vamos a usar un hint para que la tabla de hash sea REPUESTOS_ET.
select/*+LEADING(R)q004*/count(*)
fromDIMA.MOVIMIENTO_ARTICULOSM,

103

DIMA.REPUESTOS_ETR
whereR.NOC=M.NOC
andM.CO_TIPO_MOVIMIENTO='A'
andM.CO_UNIDADin('213G9003','50000005')
andR.CO_FAMILIA_APOYOin('003108','310200');

selectsql_id,child_number,sql_textfromv$sqlwheresql_textlike'%q004%';

select*fromtable(dbms_xplan.display_cursor('8w3m5452cx08y',0,'IOSTATSLAST'));

Ntese que ahora no hemos usado el hint gather_plan_statistics.

|Id|Operation|Name|Starts|ERows|ARows|ATime|Buffers|Reads|

|0|SELECTSTATEMENT||1||1|00:00:02.69|67222|21845|
|1|SORTAGGREGATE||1|1|1|00:00:02.69|67222|21845|
|*2|HASHJOIN||1|561|1580|00:00:02.69|67222|21845|
|*3|TABLEACCESSFULL|REPUESTOS_ET|1|20555|21311|00:00:02.57|21849|21845|
|4|INLISTITERATOR||1||28881|00:00:00.10|45373|0|
|*5|TABLEACCESSBYINDEXROWID|MOVIMIENTO_ARTICULOS|2|16889|28881|00:00:00.10|45373|0|
|*6|INDEXRANGESCAN|MOVIMIENTO_ARTICULOS_IDS_IDX6|2|21356|46110|00:00:00.01|214|0|

PredicateInformation(identifiedbyoperationid):

2access("R"."NOC"="M"."NOC")
3filter(("R"."CO_FAMILIA_APOYO"='003108'OR"R"."CO_FAMILIA_APOYO"='310200'))
5filter("M"."CO_TIPO_MOVIMIENTO"='A')
6access(("M"."CO_UNIDAD"='213G9003'OR"M"."CO_UNIDAD"='50000005'))

Vamos ahora a forzar el uso del ndice por el campo NOC de la tabla REPUESTOS_ET:
select/*+INDEX(RREPUESTOS_ET_NOC_U)q005*/count(*)

104

fromDIMA.MOVIMIENTO_ARTICULOSM,
DIMA.REPUESTOS_ETR
whereR.NOC=M.NOC
andM.CO_TIPO_MOVIMIENTO='A'
andM.CO_UNIDADin('213G9003','50000005')
andR.CO_FAMILIA_APOYOin('003108','310200');

selectsql_id,child_number,sql_textfromv$sqlwheresql_textlike'%q005%';

select*fromtable(dbms_xplan.display_cursor('fw4w9g3k4mbpa',0,'IOSTATSLAST'));

el plan de ejecucin cambia completamente:

|Id|Operation|Name|Starts|ERows|ARows|ATime|Buffers|Reads|

|0|SELECTSTATEMENT||1||1|00:00:38.81|129K|11626|
|1|SORTAGGREGATE||1|1|1|00:00:38.81|129K|11626|
|2|NESTEDLOOPS||1||1580|00:00:38.81|129K|11626|
|3|NESTEDLOOPS||1|561|28881|00:00:05.62|102K|1787|
|4|INLISTITERATOR||1||28881|00:00:00.29|45373|0|
|*5|TABLEACCESSBYINDEXROWID|MOVIMIENTO_ARTICULOS|2|16889|28881|00:00:00.28|45373|0|
|*6|INDEXRANGESCAN|MOVIMIENTO_ARTICULOS_IDS_IDX6|2|21356|46110|00:00:00.04|214|0|
|*7|INDEXUNIQUESCAN|REPUESTOS_ET_NOC_U|28881|1|28881|00:00:05.30|57055|1787|
|*8|TABLEACCESSBYINDEXROWID|REPUESTOS_ET|28881|1|1580|00:00:33.17|26931|9839|

PredicateInformation(identifiedbyoperationid):

5filter("M"."CO_TIPO_MOVIMIENTO"='A')
6access(("M"."CO_UNIDAD"='213G9003'OR"M"."CO_UNIDAD"='50000005'))
7access("R"."NOC"="M"."NOC")
8filter(("R"."CO_FAMILIA_APOYO"='003108'OR"R"."CO_FAMILIA_APOYO"='310200'))

105

En este nuevo plan de ejecucin podemos comprobar que para cada uno de los 28.881 registros de MOVIMIENTO_ARTICULO que cumplen la
condicin, se accede a la tabla REPUESTOS_ET por su ndice. Solo entonces podemos aplicar la condicin por el campo CO_FAMILIA_APOYO.
10.6.2 Funcin DBMS_XPLAN.DISPLAY_AWR
La versin de Oracle 10g incorpor el Automatic Workload Repository (AWR) que recopila multitud de estadsticas, entre las que estn las
sentencias sql que consumen ms recursos.
Para activarlo, el parmetro statistics_level tiene que estar a TYPICAL o ALL. El valor por defecto es TYPICAL por lo que por defecto est activado.
AWR recopila la informacin en vistas que comienzan con DBA_HIST:
select*fromall_viewswhereview_namelike'DBA_HIST%';

Por defecto, las estadsticas se recopilan en intervalos de una hora y se almacenan por un periodo de ocho das:
selectsnap_id,begin_interval_time,end_interval_time
fromdba_hist_snapshot
orderby1desc;

La tabla DBA_HIST_WR_CONTROL contiene los intervalos y el periodo de retencin que hay definidos:
select*fromdba_hist_wr_control;

106

Estos parmetros podemos modificarlos con el siguiente comando:


execdbms_workload_repository.modify_snapshot_settings(retention=>20160,interval=>15);

donde los parmetros retention e interval estn expresados en minutos.


Tambin podemos tomar un "snapshot" manualmente en cualquier momento:
execdbms_workload_repository.create_snapshot;

o borrar un rango de "snapshots":


execdbms_workload_repository.drop_snapshot_range(low_snap_id=>35,high_snap_id=>37);

Lo ms interesante de este mecanismo es que podemos consultar los planes de ejecucin de consultas pasadas que ya no estn en la SGA:
selects.snap_id,
s.disk_reads_deltareads_delta,s.executions_deltaexec_delta,
round(s.disk_reads_delta/decode(s.executions_delta,0,1,s.executions_delta))rds_exec_ratio,
s.sql_id,dbms_lob.substr(t.sql_text,4000)
fromdba_hist_sqlstats,dba_hist_sqltextt
wheret.sql_id=s.sql_id
ands.disk_reads_delta>1000
orderbys.disk_reads_deltadesc;
select*fromtable(dbms_xplan.display_awr('fw4w9g3k4mbpa'));

10.6.3 Realtime SQL monitoring


Es el mecanismo ms efectivo para identificar sentencias problemticas. Se ha introducido en la versin 11g.
Oracle 11g monitoriza automticamente todas las sentencias que se ejecuten en paralelo o cuya ejecucin dure ms de 5 segundos. Adems,
permite la monitorizacin de las sentencias en tiempo real, aunque an se estn ejecutando.

107

La monitorizacin est activada si el parmetro statistics_level est a TYPICAL or ALL, y el parmetro control_management_pack_access tiene el valor
DIAGNOSTIC+TUNING.

select*fromv$parameterwherenamein('statistics_level','control_management_pack_access');

Por defecto est activo.


La siguiente vista muestra un listado de las sentencias que se han monitorizado y an estn en la memoria:
selectsql_exec_start,status,username,round(elapsed_time/1000000,2)seconds,
fetches,buffer_gets,disk_reads,direct_writes,
sql_id,sql_text
fromv$sql_monitor
orderby1desc;

y el plan de ejecucin, finalizado o no:


selectdbms_sqltune.report_sql_monitor(
sql_id=>'g5hb0m0wq3s1v',
type=>'TEXT',
report_level=>'ALL')asreport
fromdual;

Incluso podemos consultar las variables que se han usado:


select/*+monitor*/*
fromREPUESTOS_ET
whereCO_FAMILIA_APOYO=:cdFamilia;148000

selectsql_id,replace(sql_text,chr(10),'')sql_text
fromv$sql_monitor
orderbysql_exec_startdesc;

108

selectxmltype(binds_xml)fromv$sql_monitorwheresql_id='fjcgkv750xnm3';

Vamos a lanzar una consulta larga desde otra sesin (usuario CURSO) para comprobar cmo podemos monitorizarla e incluso ver cunto le queda
para finalizar:
selectcount(*)
fromDIMA.MOVIMIENTO_ARTICULOSM,
DIMA.REPUESTOS_ETR
whereR.NOC=M.NOC
andM.CO_TIPO_MOVIMIENTO='A'
andM.CO_UNIDADin('213G9003','50000005')
andR.CO_FAMILIA_APOYOin('003108','310200');

Tenemos que dar permisos al usuario CURSO para que pueda leer estas dos tablas del usuario DIMA:
grantselectonDIMA.REPUESTOS_ETtoCURSO;

grantselectonDIMA.MOVIMIENTO_ARTICULOStoCURSO;
selectsql_id,replace(sql_text,chr(10),'')sql_textfromv$sql_monitororderbysql_exec_startdesc;

selectdbms_sqltune.report_sql_monitor(
sql_id=>'9mk98zvcvdrp3',
type=>'TEXT',
report_level=>'ALL')asreport
fromdual;

Es muy importante a la hora de analizar una consulta ser consciente de que existe la cache de datos, por lo que es posible que los datos ya estn
en la cache y el tiempo de respuesta no sea real.
Vamos a lanzar otra consulta larga desde el usuario CURSO:

109

select/*+index(RREPUESTOS_ET_PK)*/count(distinctCO_FAMILIA_APOYO)fromDIMA.REPUESTOS_ETR;

por qu es larga?
La monitorizamos desde nuestra sesin y tarda ms de un minuto.
qu ocurre si la volvemos a lanzar?
Para evitar esto, podemos borrar la cache con la siguiente sentencia:
altersystemflushbuffer_cache;

Ahora, si la volvemos a lanzar, tendr que volver a leer los bloques de la tabla REPUESTOS_ET.
La compilacin de las sentencias tambin tarda algo de tiempo. Si tambin queremos tener en cuenta el tiempo de la compilacin, podemos borrar
la library cache con la sentencia:
altersystemflushshared_pool;

Ejecutar este comando de vez en cuando puede ser interesante para eliminar sentencias sql no reusables, como por ejemplo, las que usan
parmetros fijos en lugar de variables (y de esas tenemos bastantes).
Ver demostracin de dbms_sqltune.report_sql_monitor con el parmetro type=>ACTIVE (desde Oracle 11g Release 2).
10.6.4 Anlisis de un expediente X
El campo CO_FAMILIA_APOYO de la tabla REPUESTOS_ET es una foreign key de la tabla FAMILIA_APOYO_ET.
Cmo podemos averiguar cuntos de los registros de la tabla FAMILIA_APOYO_ET no se usan en la tabla REPUESTOS_ET?
select/*+monitor*/*
fromFAMILIA_APOYO_ET
whereCO_FAMILIA_APOYOnotin(selectCO_FAMILIA_APOYOfromREPUESTOS_ET);

110

La consulta devuelve el resultado muy rpido. Seguramente la tabla REPUESTOS_ET est en la cache.
altersystemflushbuffer_cache;

La volvemos a ejecutar y tarda lo mismo.


Vamos a ver su plan de ejecucin:
selectsql_id,replace(sql_text,chr(10),'')sql_textfromv$sql_monitororderbysql_exec_startdesc;

selectdbms_sqltune.report_sql_monitor(
sql_id=>'b5z2d6cjxzw9c',
type=>'TEXT',
report_level=>'ALL')asreport
fromdual;

solo ha ledo 149 registros de REPUESTOS_ET con dos lecturas fsicas cuando el plan de ejecucin dice que se hace una lectura completa de
REPUESTOS_ET?

cmo es posible?

De hecho, el resultado es incorrecto


10.6.5 Hints ms comunes
10.6.5.1 FIRST_ROWS y ALL_ROWS
Si no se indica nada, se utiliza el modo definido en el parmetro optimizer_mode:
select*fromv$parameterwherename='optimizer_mode';
select*
fromMOVIMIENTO_ARTICULOSM,REPUESTOS_ETR
whereM.NOC=R.NOC
andM.CA_MOVIMIENTO>100000

111

andR.IN_REPARABLE='S';

|Id|Operation|Name|Rows|Bytes|TempSpc|Cost(%CPU)|Time|

|0|SELECTSTATEMENT||1035K|366M||196K(1)|00:39:17|
|*1|HASHJOIN||1035K|366M|9528K|196K(1)|00:39:17|
|*2|TABLEACCESSFULL|REPUESTOS_ET|36955|9094K||5992(1)|00:01:12|
|*3|TABLEACCESSFULL|MOVIMIENTO_ARTICULOS|17M|1968M||82416(1)|00:16:29|

select/*+FIRST_ROWS(10)*/*
fromMOVIMIENTO_ARTICULOSM,REPUESTOS_ETR
whereM.NOC=R.NOC
andM.CA_MOVIMIENTO>100000
andR.IN_REPARABLE='S';

|Id|Operation|Name|Rows|Bytes|Cost(%CPU)|Time|

|0|SELECTSTATEMENT||11|4081|21(0)|00:00:01|
|1|NESTEDLOOPS||||||
|2|NESTEDLOOPS||11|4081|21(0)|00:00:01|
|*3|TABLEACCESSFULL|REPUESTOS_ET|36955|9094K|2(0)|00:00:01|
|*4|INDEXRANGESCAN|MOVIMIENTO_ARTICULOS_IDS_IDX5|16||3(0)|00:00:01|
|*5|TABLEACCESSBYINDEXROWID|MOVIMIENTO_ARTICULOS|10|1190|19(0)|00:00:01|

El parmetro de este hint puede tomar los valores 1, 10, 100 o 1000.
Al usarlo, el plan de ejecucin intenta devolver las primeras filas lo ms rpido posible, aunque si se seleccionan ms filas sera ms lento.

112

10.6.5.2 INDEX y NO_INDEX


select/*+FIRST_ROWS(10)NO_INDEX(MMOVIMIENTO_ARTICULOS_IDS_IDX5)*/*
fromMOVIMIENTO_ARTICULOSM,REPUESTOS_ETR
whereM.NOC=R.NOC
andM.CA_MOVIMIENTO>100000
andR.IN_REPARABLE='S';

|Id|Operation|Name|Rows|Bytes|Cost(%CPU)|Time|

|0|SELECTSTATEMENT||10|3710|339(0)|00:00:05|
|1|NESTEDLOOPS||||||
|2|NESTEDLOOPS||10|3710|339(0)|00:00:05|
|*3|TABLEACCESSFULL|MOVIMIENTO_ARTICULOS|168|19992|3(0)|00:00:01|
|*4|INDEXUNIQUESCAN|REPUESTOS_ET_NOC_U|1||1(0)|00:00:01|
|*5|TABLEACCESSBYINDEXROWID|REPUESTOS_ET|1|252|2(0)|00:00:01|

select/*+FIRST_ROWS(10)NO_INDEX(M)*/*
fromMOVIMIENTO_ARTICULOSM,REPUESTOS_ETR
whereM.NOC=R.NOC
andM.CA_MOVIMIENTO>100000
andR.IN_REPARABLE='S';

|Id|Operation|Name|Rows|Bytes|Cost(%CPU)|Time|

|0|SELECTSTATEMENT||10|3710|339(0)|00:00:05|
|1|NESTEDLOOPS||||||
|2|NESTEDLOOPS||10|3710|339(0)|00:00:05|
|*3|TABLEACCESSFULL|MOVIMIENTO_ARTICULOS|168|19992|3(0)|00:00:01|
|*4|INDEXUNIQUESCAN|REPUESTOS_ET_NOC_U|1||1(0)|00:00:01|

113

|*5|TABLEACCESSBYINDEXROWID|REPUESTOS_ET|1|252|2(0)|00:00:01|

10.6.5.3 FULL y INDEX_FFS


FULL

fuerza un full scan sobre la tabla especificada:

select/*+FIRST_ROWS(10)FULL(M)*/*
fromDIMA.MOVIMIENTO_ARTICULOSM,DIMA.REPUESTOS_ETR
whereM.NOC=R.NOC
andM.CA_MOVIMIENTO>100000
andR.IN_REPARABLE='S';

|Id|Operation|Name|Rows|Bytes|Cost(%CPU)|Time|

|0|SELECTSTATEMENT||10|3710|339(0)|00:00:05|
|1|NESTEDLOOPS||||||
|2|NESTEDLOOPS||10|3710|339(0)|00:00:05|
|*3|TABLEACCESSFULL|MOVIMIENTO_ARTICULOS|168|19992|3(0)|00:00:01|
|*4|INDEXUNIQUESCAN|REPUESTOS_ET_NOC_U|1||1(0)|00:00:01|
|*5|TABLEACCESSBYINDEXROWID|REPUESTOS_ET|1|252|2(0)|00:00:01|

INDEX_FFS

fuerza un fast full index scan por el ndice especificado en lugar de realizar un full scan.

Se puede aplicar cuando todos los campos que se necesitan estn contenidos en el ndice.
selectCO_UNIDAD,ANO,FX_MOVIMIENTO
fromMOVIMIENTO_ARTICULOSM
whereCO_UNIDAD='213G9003'
andANO=2012;

114

|Id|Operation|Name|Rows|Bytes|Cost(%CPU)|Time|

|0|SELECTSTATEMENT||593|13046|633(0)|00:00:08|
|1|TABLEACCESSBYINDEXROWID|MOVIMIENTO_ARTICULOS|593|13046|633(0)|00:00:08|
|*2|INDEXRANGESCAN|MOVIMIENTO_ARTICULOS_IDS_IDX6|593||51(0)|00:00:01|

select/*+INDEX_FFS(MMOVIMIENTO_ARTICULOS_IDS_IDX5)*/
CO_UNIDAD,ANO,FX_MOVIMIENTO
fromDIMA.MOVIMIENTO_ARTICULOSM
whereCO_UNIDAD='213G9003'
andANO=2012;

|Id|Operation|Name|Rows|Bytes|Cost(%CPU)|Time|

|0|SELECTSTATEMENT||593|13046|35011(1)|00:07:01|
|*1|INDEXFASTFULLSCAN|MOVIMIENTO_ARTICULOS_IDS_IDX5|593|13046|35011(1)|00:07:01|

10.6.5.4 LEADING y ORDERED


select/*+LEADING(MR)*/*
fromDIMA.MOVIMIENTO_ARTICULOSM,DIMA.REPUESTOS_ETR
whereM.NOC=R.NOC
andM.CA_MOVIMIENTO>100000
andR.IN_REPARABLE='S';

|Id|Operation|Name|Rows|Bytes|TempSpc|Cost(%CPU)|Time|

|0|SELECTSTATEMENT||1035K|366M||196K(1)|00:39:17|
|*1|HASHJOIN||1035K|366M|2167M|196K(1)|00:39:17|

115

|*2|TABLEACCESSFULL|MOVIMIENTO_ARTICULOS|17M|1968M||82416(1)|00:16:29|
|*3|TABLEACCESSFULL|REPUESTOS_ET|36955|9094K||5992(1)|00:01:12|

El hint ORDERED hace que el optimizador intente hacer los joins en el mismo orden en el que las tablas aparecen en la clusula FROM:
select/*+ORDERED*/*
fromDIMA.MOVIMIENTO_ARTICULOSM,DIMA.REPUESTOS_ETR
whereM.NOC=R.NOC
andM.CA_MOVIMIENTO>100000
andR.IN_REPARABLE='S';

|Id|Operation|Name|Rows|Bytes|TempSpc|Cost(%CPU)|Time|

|0|SELECTSTATEMENT||1035K|366M||196K(1)|00:39:17|
|*1|HASHJOIN||1035K|366M|2167M|196K(1)|00:39:17|
|*2|TABLEACCESSFULL|MOVIMIENTO_ARTICULOS|17M|1968M||82416(1)|00:16:29|
|*3|TABLEACCESSFULL|REPUESTOS_ET|36955|9094K||5992(1)|00:01:12|

10.6.5.5 Join hints

USE_NL

NO_USE_NL

USE_MERGE

NO_USE_MERGE

USE_HASH

NO_USE_HASH

INDEX_JOIN

116

Si todas las filas que necesitamos se pueden extraer de varios ndices, estos se pueden unir como si fuesen tablas ms pequeas y de ese modo no
sera necesario acceder a la tabla:
select/*+INDEX_JOIN(MMOVIMIENTO_ARTICULOS_IDS_IDX5MOVIMIENTO_ARTICULOS_IDS_IDX6)*/
CO_UNIDAD,ANO,FX_MOVIMIENTO,NU_MOVIMIENTO
fromDIMA.MOVIMIENTO_ARTICULOSM
whereCO_UNIDAD='213G9003'
andANO=2012;

|Id|Operation|Name|Rows|Bytes|Cost(%CPU)|Time|

|0|SELECTSTATEMENT||593|16011|99156(1)|00:19:50|
|*1|VIEW|index$_join$_001|593|16011|99156(1)|00:19:50|
|*2|HASHJOIN||||||
|*3|INDEXRANGESCAN|MOVIMIENTO_ARTICULOS_IDS_IDX6|593|16011|52(2)|00:00:01|
|*4|INDEXFASTFULLSCAN|MOVIMIENTO_ARTICULOS_IDS_IDX2|593|16011|123K(1)|00:24:46|

10.7 Consulta til para la monitorizacin de las ltimas consultas ejecutadas


selectnvl(s.username,'ORACLEPROC')||'('||s.sid||')'username,
s.program,
s.machine,
ltrim(to_char(floor(s.last_call_et/3600),'09'))||':'||
ltrim(to_char(floor(mod(s.last_call_et,3600)/60),'09'))||':'||
ltrim(to_char(mod(s.last_call_et,60),'09'))runtime,
ltrim(to_char(floor(q.elapsed_time/decode(q.executions,0,1,q.executions)/3600000000),'09'))
||':'||
ltrim(to_char(floor(mod(q.elapsed_time/decode(q.executions,0,1,q.executions),3600000000)/60000000),'09'))
||':'||
ltrim(to_char(floor(mod(q.elapsed_time/decode(q.executions,0,1,q.executions),60000000)/1000000),'09'))
avg_elapsed_time,

117

q.executions,
round((q.disk_reads/decode(q.executions,0,1,q.executions)))disk_reads_per_exec,
100round(100*q.disk_reads/greatest(q.buffer_gets,1),2)hit_ratio,
q.first_load_time,
q.last_load_time,
q.sql_id,
q.child_number,
q.sql_text,
q.sql_fulltext
fromv$sessions,
v$sqlq
wheres.status='ACTIVE'
ands.usernameisnotnull
ands.sql_address=q.address
ands.sql_hash_value=q.hash_value
ands.audsid<>userenv('SESSIONID')
orderbyruntimedesc,1;

11 El nuevo scheduler (jobs)


Oracle 10g introdujo el paquete dbms_scheduler para sustituir al conocido dbms_job.
EL paquete dbms_scheduler es ms flexible y potente.
Sintaxis para la creacin bsica de un job:
DBMS_SCHEDULER.CREATE_JOB(
job_nameINVARCHAR2,
job_typeINVARCHAR2,
job_actionINVARCHAR2,
number_of_argumentsINPLS_INTEGERDEFAULT0,
start_dateINTIMESTAMPWITHTIMEZONEDEFAULTNULL,
repeat_intervalINVARCHAR2DEFAULTNULL,

118

end_dateINTIMESTAMPWITHTIMEZONEDEFAULTNULL,
job_classINVARCHAR2DEFAULT'DEFAULT_JOB_CLASS',
enabledINBOOLEANDEFAULTFALSE,
auto_dropINBOOLEANDEFAULTTRUE,
commentsINVARCHAR2DEFAULTNULL);

Ejemplo:
begin
dbms_scheduler.create_job(
job_name=>'prueba_01_job',
job_type=>'PLSQL_BLOCK',
job_action=>'BEGINNULL;END;',
start_date=>SYSTIMESTAMP,
repeat_interval=>'freq=hourly;byminute=0;bysecond=0;',
enabled=>TRUE,
comments=>'JobdefinidocompletamentemedianteelprocedimientoCREATEJOB.');
end;

Aunque hemos creado el job, todava no se ha ejecutado. Se ejecutar cuando se cumpla la condicin especificada en el parmetro
repeat_interval. Podemos comprobarlo con la siguiente consulta:
selectjob_name,job_action,repeat_interval,enabled,
last_start_date,last_run_duration,next_run_date,
run_count,failure_count,state
fromall_scheduler_jobs
whereowner='CURSO';

selectjob_name,job_action,repeat_interval,enabled,
last_start_date,last_run_duration,next_run_date,
run_count,failure_count,state
fromuser_scheduler_jobs;

119

Es habitual crear los jobs sin especificar que el parmetro enabled sea true (el valor por defecto es false) y activarlo de forma manual
posteriormente:
execdbms_scheduler.disable('prueba_01_job');
execdbms_scheduler.enable('prueba_01_job');

Podemos consultar el histrico de lanzamientos de un job mediante va vista all_scheduler_job_log:


select*
fromall_scheduler_job_log
whereowner='CURSO';

select*fromuser_scheduler_job_log;

Es posible cambiar los atributos de un job mediante la funcin set_attribute:


execdbms_scheduler.set_attribute('prueba_01_job','repeat_interval','freq=minutely;interval=5;bysecond=0;');

Si se produce algn error, podemos consultarlo en el campo ADDITIONAL_INFO de la tabla all_scheduler_job_run_details.


Vamos a generar un error:
execdbms_scheduler.set_attribute('prueba_01_job','job_action','beginfoo;end;');

El campo status de la tabla user_scheduler_job_log aparecer como FAILED.


selectlog_date,job_name,additional_infofromuser_scheduler_job_run_details;

Un job finaliza bien cuando alcanza la fecha indicada en el parmetro end_date, bien cuando se ejecuta el nmero de veces especificado en el
parmetro max_runs. Lo que ocurre cuando finaliza depende del valor del parmetro auto_drop. Si es true el job se borra. En caso contrario, su
estado pasa a COMPLETED.

120

Otro atributo interesante es max_failures. Con l podemos limitar el nmero mximo de errores antes de que el job se deshabilite con el estado
BROKEN.

execdbms_scheduler.set_attribute('prueba_01_job','max_failures','3');

Un job en ejecucin se puede parar con el procedimiento:


DBMS_SCHEDULER.STOP_JOB(
job_nameINVARCHAR2
forceINBOOLEANDEFAULTFALSE);
execdbms_scheduler.stop_job('prueba_01_job');

Si el job no para de forma normal, se puede forzar la parada con el parmetro force (en este caso no se pueden recopilar las estadsticas).
Eliminacin de un job:
execdbms_scheduler.drop_job('prueba_01_job');

En la versin 12 de Oracle se ha incluido el parmetro defer en la funcin drop_job de forma que si se establece a true, el job se eliminar cuando
termine o se produzca el primer error.
Un job se puede lanzar manualmente sin que esto afecte a su programacin:
DBMS_SCHEDULER.RUN_JOB(
job_nameINVARCHAR2,
use_current_sessionINBOOLEANDEFAULTTRUE);
execdbms_scheduler.run_job('prueba_01_job');

Cuando el parmetro use_current_session es true (es el valor por defecto):

121

El job se ejecuta con el usuario que lanza el procedimiento, de forma sncrona.

Se puede ver el resultado de la ejecucin en lnea.

Los campos RUN_COUNT, LAST_START_DATE, LAST_RUN_DURATION, y FAILURE_COUNT, no se actualizan.

La tabla La tabla dba_scheduler_job_log s se actualiza.

Se puede lanzar el job aunque haya otra instancia ejecutndose en ese momento.

Cuando use_current_session es false:

Se ejecuta con la sesin del dueo del job, de forma asncrona (igual que cuando se ejecuta de forma programada)

Los errores hay que verlos en la tabla dba_scheduler_job_log.

Se actualizan los campos RUN_COUNT, LAST_START_DATE, LAST_RUN_DURATION, y FAILURE_COUNT.

La funcin falla si el job se est ejecutando.

Los lanzamientos manuales quedan registrados en el campo ADDITIONAL_INFO de la tabla dba_scheduler_job_log.

11.1 Programs
El programador permite crear tareas o acciones sin que estn asociadas a una programacin (o calendario). Posteriormente, se podrn crear jobs
asociados a estas tareas (programs).
DBMS_SCHEDULER.CREATE_PROGRAM(
program_nameINVARCHAR2,
program_typeINVARCHAR2,
program_actionINVARCHAR2,
number_of_argumentsINPLS_INTEGERDEFAULT0,
enabledINBOOLEANDEFAULTFALSE,
commentsINVARCHAR2DEFAULTNULL);

El parmetro program_type puede ser del tipo PLSQL_BLOCK, EXECUTABLE o STORED_PROCEDURE.


begin

122

dbms_scheduler.create_program(
program_name=>'test_plsql_block_prog',
program_type=>'PLSQL_BLOCK',
program_action=>'begindbms_stats.gather_schema_stats(''SITRANS'');end;',
enabled=>true,
comments=>'ProgramapararecopilarestadsticasdelusuarioSITRANSusandounbloquePL/SQL.');
end;

No se puede crear un program con number_of_arguments > 0 con el atributo enabled a true.
Una vez creado el job, tendremos que asignar los parmetros necesarios.
begin
dbms_scheduler.create_program(
program_name=>'test_stored_procedure_prog',
program_type=>'STORED_PROCEDURE',
program_action=>'dbms_stats.gather_schema_stats',
number_of_arguments=>1,
enabled=>false,
comments=>'Programapararecopilarestadsticasdeunusuariousandounprocedimientoalmacenado.');

dbms_scheduler.define_program_argument(
program_name=>'test_stored_procedure_prog',
argument_name=>'ownname',
argument_position=>1,
argument_type=>'VARCHAR2',
default_value=>'SITRANS');

dbms_scheduler.enable(name=>'test_stored_procedure_prog');
end;
selectprogram_name,program_action,number_of_arguments,enabled
fromdba_scheduler_programs

123

whereowner='DIMA';

Los programas se pueden borrar con el procedimiento drop_program:


dbms_scheduler.drop_program(program_name=>'test_stored_procedure_prog');

11.2 Schedules
Las programaciones tambin se pueden almacenar de forma independiente:
begin
DBMS_SCHEDULER.create_schedule(
schedule_name=>'test_hourly_schedule',
start_date=>SYSTIMESTAMP,
repeat_interval=>'freq=hourly;byminute=0',
end_date=>NULL,
comments=>'Repite,cadahora,parasiempre.');
end;

select*fromdba_scheduler_schedules;

11.3 Creacin de jobs


begin
JobdefinidodeformacompletamedianteelprocedimientoCREATEJOB.
dbms_scheduler.create_job(
job_name=>'test_full_job',
job_type=>'PLSQL_BLOCK',
job_action=>'begindbms_stats.gather_schema_stats(''SITRANS'');end;',
start_date=>SYSTIMESTAMP,
repeat_interval=>'freq=hourly;byminute=0',
end_date=>NULL,
enabled=>TRUE,
comments=>JobdefinidodeformacompletamedianteelprocedimientoCREATEJOB.');

124


Jobdefinidousandounprogramyunscheduleexistentes.
dbms_scheduler.create_job(
job_name=>'test_prog_sched_job',
program_name=>'test_plsql_block_prog',
schedule_name=>'test_hourly_schedule',
enabled=>false,
comments=>Jobdefinidousandounprogramyunscheduleexistentes.');

Jobdefinidomedianteunprogramexistenteyunscheduleenlnea.
dbms_scheduler.create_job(
job_name=>'test_prog_job_definition',
program_name=>'test_plsql_block_prog',
start_date=>SYSTIMESTAMP,
repeat_interval=>'freq=hourly;byminute=0',
end_date=>NULL,
enabled=>true,
comments=>Jobdefinidomedianteunprogramexistenteyunscheduleenlinea.');

Jobdefinidoporunscheduleexistenteyunprogramenlnea.
dbms_scheduler.create_job(
job_name=>'test_sched_job_definition',
schedule_name=>'test_hourly_schedule',
job_type=>'PLSQL_BLOCK',
job_action=>'begindbms_stats.gather_schema_stats(''SITRANS'');end;',
enabled=>true,
comments=>'Jobdefinidoporunscheduleexistenteyunprogramenlnea.');
end;

select*fromdba_scheduler_jobswhereowner='DIMA';

Los programs y schedules no se pueden eliminar si estn siendo usados por algn job.

125

11.4 Ejecucin de jobs externos


begin
dbms_scheduler.create_job(job_name=>'mkdir_job',
job_type=>'EXECUTABLE',
job_action=>'e:\temp\mkdir1.bat',
number_of_arguments=>1,
enabled=>false
);

dbms_scheduler.set_job_argument_value('mkdir_job',1,'nuevo_directorio');

dbms_scheduler.enable('mkdir_job');
end;

Contenido del fichero mkdir1.bat:


mkdire:\%1

Este job crea el directorio nuevo_directorio en el directorio raz de la unidad E del servidor.
Importante: para que funcionen los jobs externos, es necesario que este levantado el servicio OracleJobScheduler.
Como no hemos establecido la propiedad auto_drop => false ni repeat_interval, el job se borrar una vez que se ejecute, aunque s quedar
registrado en la tabla de log.

11.5 Ejemplos de programacin


repeat_interval=frequency_clause
[;interval=?][;bymonth=?][;byweekno=?]
[;byyearday=?][;bymonthday=?][;byday=?]
[;byhour=?][;byminute=?][;bysecond=?]

126

frequency_clause="FREQ""="frequency
frequency="YEARLY"|"MONTHLY"|"WEEKLY"|"DAILY"|
"HOURLY"|"MINUTELY"|"SECONDLY"

Para probar algunos ejemplos creamos el procedimiento test_calendar_string:


createorreplaceproceduretest_calendar_string(p_calendar_stringinVARCHAR2,p_iterationsinINTEGER)is
l_start_dateTIMESTAMP:=TO_TIMESTAMP('27AGO201408:04:32','DDMONYYYYHH24:MI:SS');
l_return_date_afterTIMESTAMP:=l_start_date;
l_next_run_dateTIMESTAMP;
begin
dbms_output.put_line('calendar_string:'||p_calendar_string||'iterations:'||p_iterations);
foriin1..p_iterationsloop
dbms_scheduler.evaluate_calendar_string(
calendar_string=>p_calendar_string,
start_date=>l_start_date,
return_date_after=>l_return_date_after,
next_run_date=>l_next_run_date);

dbms_output.put_line('NextRunDate:'||l_next_run_date);
l_return_date_after:=l_next_run_date;
endloop;
end;

begintest_calendar_string('freq=daily;',4);end;

calendar_string:freq=daily;iterations:4
NextRunDate:28/08/1408:04:32,000000
NextRunDate:29/08/1408:04:32,000000
NextRunDate:30/08/1408:04:32,000000
NextRunDate:31/08/1408:04:32,000000

127

begintest_calendar_string('freq=daily;byhour=0;byminute=0;bysecond=0;',3);end;

calendar_string:freq=daily;byhour=0;byminute=0;bysecond=0;iterations:3
NextRunDate:28/08/1400:00:00,000000
NextRunDate:29/08/1400:00:00,000000
NextRunDate:30/08/1400:00:00,000000

begintest_calendar_string('freq=minutely;bysecond=0;',3);end;

calendar_string:freq=minutely;bysecond=0;iterations:3
NextRunDate:27/08/1408:05:00,000000
NextRunDate:27/08/1408:06:00,000000
NextRunDate:27/08/1408:07:00,000000

begintest_calendar_string('freq=minutely;interval=5;bysecond=0;',3);end;

calendar_string:freq=minutely;interval=5;bysecond=0;iterations:3
NextRunDate:27/08/1408:09:00,000000
NextRunDate:27/08/1408:14:00,000000
NextRunDate:27/08/1408:19:00,000000

begintest_calendar_string('freq=weekly;byday=mon;byhour=9;byminute=0;bysecond=0;',3);end;

calendar_string:freq=weekly;byday=mon;byhour=9;byminute=0;bysecond=0;iterations:3
NextRunDate:01/09/1409:00:00,000000
NextRunDate:08/09/1409:00:00,000000
NextRunDate:15/09/1409:00:00,000000

128

begintest_calendar_string('freq=weekly;byday=mon,wed,fri;byhour=6;byminute=0;bysecond=0;',3);end;

calendar_string:freq=weekly;byday=mon,wed,fri;byhour=6;byminute=0;bysecond=0;iterations:3
NextRunDate:29/08/1406:00:00,000000
NextRunDate:01/09/1406:00:00,000000
NextRunDate:03/09/1406:00:00,000000

El primer lunes de enero, abril, julio y octubre:


begintest_calendar_string('freq=monthly;bymonth=1,4,7,10;byday=1mon;byhour=6;byminute=0;bysecond=0;',4);end;

calendar_string:freq=monthly;bymonth=1,4,7,10;byday=1mon;byhour=6;byminute=0;bysecond=0;iterations:4
NextRunDate:06/10/1406:00:00,000000
NextRunDate:05/01/1506:00:00,000000
NextRunDate:06/04/1506:00:00,000000
NextRunDate:06/07/1506:00:00,000000

Ejemplos para start_date y end_date:


Maana a esta misma hora: 'sysdate+1'
Maana a las 06:00: 'trunc(sysdate)+1+6/24'
Al comienzo de la prxima hora: 'trunc(sysdate,''HH24'')+1/24'
Dentro de un minuto: 'sysdate+1/24/60'
El siguiente minuto exacto: 'trunc(sysdate,''MI'')+1/24/60'
En cinco minutos: 'trunc(sysdate,''MI'')+5/24/60'
El prximo mircoles a las 09:00: 'trunc(next_day(sysdate,''mircoles''))+9/24'

129

El prximo lunes, mircoles o viernes a las 06:00: 'trunc(least(next_day(sysdate,''lunes''),next_day(sysdate,''mircoles''),


next_day(sysdate,''viernes'')))+(6/24)'
El primer lunes del prximo trimestre: 'next_day(add_months(trunc(sysdate,''q''),3),''lunes'')'

12 Miscelnea
12.1 Tipos de comandos
DDL Data Definition Language sentencias que modifican la estructura de los objetos:

CREATE creacin de objetos

ALTER modificacin de objetos

DROP eliminacin de objetos

TRUNCATE elimina todos los registros de una tabla y el espacio que ocupan

COMMENT aade un comentario a un objeto

RENAME renombrar un objeto

DML Data Manipulation Language sentencias de manipulacin de datos:

SELECT consulta de informacin

INSERT insercin

UPDATE actualizacin

DELETE elimina registros de una tabla, pero no el espacio que ocupan

MERGE combinacin de los datos de dos tablas

12.2 Abrir una base de datos


C:\>setoracle_sid=ORCL
C:\>sqlplussysassysdba

130

SQL*Plus:Release10.1.0.2.0ProductiononMonFeb2112:35:48

Enterpassword:xxxx
Connectedtoanidleinstance.

SQL>startup
ORACLEinstancestarted.

TotalSystemGlobalArea251658240bytes
FixedSize788368bytes
VariableSize145750128bytes
DatabaseBuffers104857600bytes
RedoBuffers262144bytes
Databasemounted.
Databaseopened.

Tambin se puede especificar la contrasea en el propio comando:


C:\>sqlplussys/passwdassysdba

Este comando abre la base de datos en tres pasos:


1. Startup (nomount)
Lee los parmetros de inicializacin (del spfile o pfile) y los utiliza para crear la SGA (reservar la memoria) y lanzar los "background
processes". La instancia est levantada.

SQL>startupnomount;

131

2. Mount
Lee el fichero de control, que contiene informacin importante, como la localizacin de los ficheros de datos y otros recursos. Sin el fichero
de control no es posible montar la base de datos. Por este motivo es importante tener ms de una copia de este fichero y hacer copias de
seguridad.
SQL>startupmount

Si la base de datos ya est levantada en modo "nomount" se puede montar con el comando:
SQL>alterdatabasemount;

En este modo ya es posible acceder a las tablas fijas y vistas del diccionario de datos (tablas internas de configuracin de Oracle), por
ejemplo:
SQL>selectstatusfromv$instance;

STATUS

MOUNTED

SQL>

3. Open
Accede a los ficheros de datos y comprueba que son consistentes.
SQL>startup

Si la base de datos ya est levantada en modo "mount" se puede abrir con el comando:
SQL>alterdatabaseopen;

132

Existe la posibilidad de abrir la base de datos en modo restringido, de forma que solo los administradores (DBAs) puedan acceder a ella.
Tcnicamente la base de datos est abierta:
SQL>startuprestrict

Es posible cambiar la instanca del modo normal al modo restringido y viceversa con los comandos:
SQL>altersystemenablerestrictedsession;

SQL>altersystemdisablerestrictedsession;

aunque los usuarios que estuviesen conectados al restringir la instancia seguiran conectados.
Tambin es posible arrancar una base de datos con un fichero de parmetros distinto al habitual:
SQL>startuppfile=C:\oracle\database\init2.ora

12.3 Parada de una base de datos


La parada de Oracle se realiza mediante el comando shutdown despus de haber establecido una conexin como sys as sysdba.
Existen tres tipos de shutdown:
1. shutdown normal
2. shutdown immediate
3. shutdown abort

Shutdown normal
SQL>shutdown

133

No se utiliza habitualmente ya que espera a que todos los usuarios se desconecten de forma ordenada, por lo que el proceso podra tardar horas.
Tambin podra haber procesos "zombies" (Oracle cree que hay alguien conectado pero realmente no lo hay) que habra que matar manualmente
para que la base de datos se cerrase.
Espera a que los usuarios conectados actualmente finalicen todas las operaciones.
Evita nuevas conexiones. Los usuarios que intentan conectarse reciben el mensaje "Shutdown in progress".
Cierra y desmonta la base de datos.
No se necesita recuperacin al arrancar la base de datos. Se cierra en un modo consistente.
Shutdown immediate
SQL>shutdownimmediate

Funciona la mayora de las veces.


Espera a que las transacciones finalizadas (committed) se completen, es decir, las modificaciones realizadas en memoria se envan a los
ficheros de datos.
Evita nuevas transacciones y nuevas conexiones.
Se finalizan las sesiones no activas y se hace un rollback de aquellas transacciones que no estn validadas (uncommitted)
Cierra y desmonta la base de datos.
No se necesita recuperacin al arrancar la base de datos. Se cierra en un modo consistente.
Shutdown transactional
Igual que el shutdown immediate pero esperando que la transacciones no validadas terminen (que se realize el commit de las transacciones
comenzadas). No hace rollback.
Shutdown abort
SQL>shutdownabort

134

Parada drstica, no espera a que los usuarios conectados finalicen sus transacciones.
No se realiza rollback de las transacciones pendientes.
Se necesita recuperacin al arrancar la base de datos.

12.4 Creacin del usuario CURSO


CREATEUSERCURSO
IDENTIFIEDBYcurso
DEFAULTTABLESPACEDATA
TEMPORARYTABLESPACETEMP
PROFILEDEFAULT
ACCOUNTUNLOCK;

GRANTDBATOCURSO;
GRANTUNLIMITEDTABLESPACETOCURSO;
GRANTEXECUTE,READ,WRITEONDIRECTORYTOAD_TRACEFILE_DIRTOCURSOWITHGRANTOPTION;

12.5 Validacin de tablas e ndices


Aunque no es habitual, en algn caso una tabla o un ndice pueden corromperse.
Podemos comprobar si una tabla tiene algn problema con el siguiente comando:
analyzetableDIMA.REPUESTOS_ETvalidatestructure;

Si aadimos la clusula cascade, tambin se analizan sus ndices asociados:


analyzetableDIMA.REPUESTOS_ETvalidatestructurecascade;

Con la clusula adicional fast, la comprobacin es ms rpida, pero solo se indica que hay un error, no cul es el error.
As que es mejor realizar la comprobacin con la clusula fast, y solo en caso de error, la volvemos a ejecutar sin ella.

135

analyzetableDIMA.REPUESTOS_ETvalidatestructurecascadefast;

12.6 Filas migradas y encadenadas


12.6.1 Filas migradas
Son filas que, al aumentar de tamao tras una sentencia update, no caben en el bloque en el que estn y se mueven a otro bloque. El problema es
que no se pueden mover sin ms, debido a que los ndices siguen apuntando al bloque inicial. Lo que hace Oracle es dejar en la posicin original
un enlace a la nueva posicin del registro. El problema que tienen estos registros, es que cuando se intenta acceder a ellos y el registro no est, es
necesario leer tambin el nuevo bloque, por lo que es necesario hacer una lectura adicional.
12.6.2 Filas encadenadas
Son filas mayores que el tamao de un bloque, por lo que se almacenan en ms de un bloque.
Estas filas suelen aparecer en tablas con campos de tamao variable: VARCHAR2, CHAR, CLOB, etc.
12.6.3 Bsqueda de filas migradas y encadenadas
select'analyzetableDIMA.'||table_name||'listchainedrows;'
fromall_tables
whereowner='DIMA';

analyzetableDIMA.ERMACSlistchainedrows;
analyzetableDIMA.ERMACOlistchainedrows;
analyzetableDIMA.ERMACFlistchainedrows;
analyzetableDIMA.COSNSAlistchainedrows;
...

selectowner_name,table_name,count(*)
fromchained_rows
groupbyowner_name,table_name
orderby3desc;

136

OWNER_NAME,TABLE_NAME,COUNT(*)
DIMA,ORTR_0,302259
DIMA,CUF_ET_REPUESTOS_ET,268745
DIMA,PET_MTO_0,264051
DIMA,COSNSA,199784
DIMA,COSANO2,170114
DIMA,PET_AV_ABTO2,68273
DIMA,CONS_12_MESES_ATRAS,59214
DIMA,CONSUMO,53712
DIMA,OS2,29503
DIMA,REP_DB,13954
DIMA,REPUESTOS_ET_UNIDAD,11242
DIMA,ERMANS,10036
DIMA,COSANO,9184
DIMA,NUMEROS_SERIE_ET,5365
DIMA,REPUESTOS_ET,4668
DIMA,LINEAS_PET_AV_ABTO2,3957
DIMA,ORTR_TAREA_0,1678
DIMA,FAM_MT_STD_ANO,1127
DIMA,CUF_ET,726
DIMA,USUARIOS,416
DIMA,COS,378
DIMA,COSES2,285
DIMA,SUMI_ET,243
DIMA,ERMACS,185
DIMA,FALTANTES,72
DIMA,COSSUB,33
DIMA,COSTAS,23
DIMA,FAM_MT_STD,21
DIMA,LINEAS_OS2,15
DIMA,COS2,13
DIMA,UNIDAD,10
DIMA,ALERTAS,1

137

DIMA,TALLER,1

12.6.4 Eliminacin de filas migradas o encadenadas


analyzetableDIMA.REPUESTOS_ETlistchainedrows;

select*
fromchained_rows
whereowner_name='DIMA'
andtable_name='REPUESTOS_ET';

createtableTMP_REPUESTOS_ETas
select*
fromDIMA.REPUESTOS_ET
whererowidin
(
selecthead_rowid
fromchained_rows
whereowner_name='DIMA'
andtable_name='REPUESTOS_ET'
);

delete
fromDIMA.REPUESTOS_ET
whererowidin
(
selecthead_rowid
fromchained_rows
whereowner_name='DIMA'
andtable_name='REPUESTOS_ET'
);

insertintoDIMA.REPUESTOS_ET
select*fromTMP_REPUESTOS_ET;

138


droptableTMP_REPUESTOS_ET;

delete
fromchained_rows
whereowner_name='DIMA'
andtable_name='REPUESTOS_ET';

A continuacin volvemos a analizar la tabla.


Si aparece alguna fila, debe ser encadenada. No siempre se pueden eliminar las filas encadenadas. Si el tamao del bloque es inferior al tamao del
registro, no se puede evitar.

12.7 Recycle bin


A partir de la versin 10g, cuando se elimina una tabla, lo que hace Oracle es renombrarla, y tambin renombra todos sus objetos relacionados:
ndices, triggers, segmentos de LOB, etc.
Se activa con un parmetro de inicializacin de la base de datos. Por defecto est activado:
select*fromv$parameterwherename='recyclebin';

Puede activarse y desactivarse a nivel de sesin:


altersessionsetrecyclebin=off;

Ejemplos:
createtabletst(colvarchar2(10),row_chng_dtdate);

insertintotstvalues('Version1',sysdate);

select*fromtst;

139


droptabletst;

selectobject_name,original_name,type,can_undropas"UND",can_purgeas"PUR",droptime
fromrecyclebin;

select*from"BIN$aaEKgrOgSSqPsf+xD0hC9Q==$0";

flashbacktabletsttobeforedrop;

Si se crea de nuevo una tabla que se haba eliminado, y se vuelve a eliminar, en la papelera existirn dos versiones.
Si existen varias versiones, especificar en el flashback el nombre que tiene en la papelera:
flashbacktable"BIN$aaEKgrOgSSqPsf+xD0hC9Q==$0"tobeforedrop;

Se pueden eliminar objetos de la papelera con el comando purge table y purge index:
purgetable"BIN$aaEKgrOgSSqPsf+xD0hC9Q==$0";

Los objetos permanecen en el tablespace mientras que haya sitio disponible.


Si no queda espacio (no se utiliza el autoextend para almacenar elementos eliminados), se van eliminando los ms antiguos.
Para eliminar todos los elementos de la papelera (del usuario), usar el siguiente comando:
purgerecyclebin;

recyclebin es un sinnimo para user_recyclebin. La papelera global es dba_recyclebin.


select*fromdba_recyclebin;
purgedba_recyclebin;

140

12.8 Sql avanzado


12.8.1 Contar das de la semana
Cuntos martes y jueves hay en un periodo determinado, entres las fechas :desde y :hasta?
Vamos a crear la funcin get_weekday que nos devuelva el da de la semana de una fecha:
Necesitamos permisos para poder crear una funcin:
grantcreateanyproceduretoCURSO;
createorreplacefunctionget_weekday(dateinDATE)returnINTEGERas
begin
returnto_number(to_char(date,'D'));
endget_weekday;
selectget_weekday(sysdate)fromdual;
select:desde+1fromdual;
select:hasta:desde+1fromdual;
selectlevelfromdualconnectbylevel<=5;
select:desde+level1fromdualconnectbylevel<=:hasta:desde+1;
select:desde+level1,get_weekday(:desde+level1)
fromdual
whereget_weekday(:desde+level1)in(2,4)
connectbylevel<=:hasta:desde+1;

141

selectcount(*)
fromdual
whereget_weekday(:desde+level1)in(2,4)
connectbylevel<=:hasta:desde+1;

12.8.2 Eliminar registros duplicados


12.8.2.1 Mtodo 1 respecto a unas claves conocidas:
deletefromtable_namea
whererowid<>
(
selectmin(rowid)
fromtable_nameb
wherea.key_values=b.key_values
);

12.8.2.2 Mtodo 2 eliminar duplicados idnticos:


SQL>createtabletable_name2asselectdistinct*fromtable_name1;
SQL>droptabletable_name1;
SQL>renametable_name2totable_name1;

Este mtodo es muy rpido, pero hay que recrear los ndices, constraints (restricciones), triggers (disparadores), etc.
12.8.2.3 Mtodo 3 Usando funciones analticas:
deletetable_namewhererowidin
(
selectlead(rowid)over(partitionbykey_valuesorderbynull)
fromtable_name
);

Las funciones analticas permiten realizar consultas contra ms de una fila, para cada fila, sin tener que hacer un join de la tabla consigo misma.

142

La operacin opuesta a lead es lag.

12.9 Permisos y seguridad (algunas consulta tiles)


Usuarios con contraseas por defecto. Deberan estar bloqueados:
selectu.username,u.account_status
fromdba_users_with_defpwdd,dba_usersu
whered.username=u.username;

Usuarios con permisos sensibles:


select*
fromdba_sys_privsp,dba_usersu
wherep.grantee=u.username
andp.privilegein('SELECTANYTABLE','SELECTANYDICTIONARY')
andnotu.account_statuslike'%LOCKED%';
select*
fromdba_sys_privs
whereprivilegelike'%ANY%'
orderbygrantee;

Generacin de la lista de usuarios como una cadena separados por comas:


selectlistagg(''''||username||'''',',')withingroup(orderbyusername)fromall_users;

Permisos asignados a un usuario:


select*
fromdba_tab_privs
wheregrantee='SITRANS';

143

Roles asignados a un usuario:


selectgrantee,granted_rolefromdba_role_privs;

Todo lo que tiene asignado un usuario:


selectprivilege
fromdba_sys_privs
wheregrantee='DBSNMP'
unionall
selectgranted_roleprivilege
fromdba_role_privs
wheregrantee='DBSNMP'
unionall
selectprivilege||'on'||owner||'.'||table_nameprivilege
fromdba_tab_privs
wheregrantee='DBSNMP';

Lista de los permisos que un usuario tiene sobre los objetos de otro esquema, en este caso del usuario NOGAL sobre los objetos del esquema
DIMA:
select*fromdba_role_privswheregrantee='NOGAL';
withSas
(
selecttable_name,privilege,'S'asdirecto
fromdba_tab_privs
wheregrantee='NOGAL'
andowner='DIMA'
union
selecttable_name,privilege,'N'asdirecto
fromdba_tab_privs
wheregrantee='NOGAL_ROLE'

144

andowner='DIMA'
)
selecta.object_type,a.object_name,S.privilege,S.directo
fromall_objectsa,S
wherea.owner='DIMA'
anda.object_typein('PROCEDURE','FUNCTION','PACKAGE','TABLE','VIEW')
anda.object_name=S.table_name(+)
orderbya.object_type,a.object_name,S.privilege,S.directo;

145

Anda mungkin juga menyukai