Curso Administración Oracle
Curso Administración Oracle
Curso Administración Oracle
de Administracio n de Oracle
ndice
1
Introduccin ................................................................................................................................................................................................................................................................... 5
Instalacin de Oracle................................................................................................................................................................................................................................................... 6
Conexiones ......................................................................................................................................................................................................................................................... 10
4.2
Ficheros ................................................................................................................................................................................................................................................................ 12
4.2.1
4.2.2
4.2.3
4.2.4
4.2.5
4.2.6
4.2.7
4.2.8
Transacciones ........................................................................................................................................................................................................................................... 33
4.2.9
Flashback .................................................................................................................................................................................................................................................... 37
4.2.10
4.3
4.3.1
4.3.2
4.3.3
4.4
Procesos ............................................................................................................................................................................................................................................................... 54
4.4.1
4.4.2
4.4.3
4.4.4
4.4.5
4.4.6
4.4.7
Tablas ............................................................................................................................................................................................................................................................................. 57
5.1
5.2
5.3
Lobs ....................................................................................................................................................................................................................................................................... 60
ndices ............................................................................................................................................................................................................................................................................ 62
6.1
B*Tree ................................................................................................................................................................................................................................................................... 66
6.2
6.3
6.4
Sql*Loader .................................................................................................................................................................................................................................................................... 73
10
10.2.2
Sort-Merge joins...................................................................................................................................................................................................................................... 87
10.2.3
10.6.2
10.6.3
10.6.4
10.6.5
10.7 Consulta til para la monitorizacin de las ltimas consultas ejecutadas ............................................................................................................................... 117
11
12.6.2
12.6.3
12.6.4
12.8.2
1 Introduccin
Resultado de solicitar varias veces un curso de administracin de Oracle.
Mucha materia. Vamos a ver muchas cosas, pero no es exhaustivo.
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.
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
Procesos
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.
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
4.2 Ficheros
Ficheros que conforman la base de datos:
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.
12
4.2.1
Fichero de parmetros
Tambin podemos arrancar la base de datos manualmente especificando como parmetro del comando startup un fichero diferente:
SQL>startuppfile='C:\oracle\pfile\init.ora'
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 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:\>
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.
18
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
19
Los segmentos estn compuestos por una o ms extensiones, que son reas contiguas de almacenamiento en un fichero.
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 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
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
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 vista v$databasenos proporciona informacin sobre algunos de los parmetros almacenados en el fichero de control.
4.2.6
23
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;
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;
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
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
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
35
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.
El proceso LGWR escribe el resto del redo log buffer a disco y anota tambin el SCN.
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
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;
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;
38
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.
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
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
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
51
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;
53
4.4 Procesos
selectpname,background
fromv$process
wherenotpnameisnull;
4.4.1
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
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
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:
Cada 3 segundos
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
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
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
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:
Tareas administrativas realizadas como la creacin o eliminacin de tablespaces, paradas y arranques de la instancia, finalizacin de
sesiones, etc.
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;
Aunque la creemos con la clusula oncommitpreserverows, al cerrar la sesin los datos desaparecern.
createglobaltemporarytabletemp_table
(
)
oncommitdeleterows;
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;
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);
selecttable_owner,table_name,index_name,column_name,column_position
fromdba_ind_columns
wheretable_owner='DIMA'
orderbytable_name,index_name,column_position;
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
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.
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.
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')
|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.
8 Sql*Loader
CREATEUSERCURSO
73
IDENTIFIEDBYcurso
DEFAULTTABLESPACEUSERS
TEMPORARYTABLESPACETEMP
PROFILEDEFAULT
ACCOUNTUNLOCK;
74
insertintoCURSO.LDR_TEST(CAMPO1,CAMPO2,CAMPO3,CAMPO4)
values('ABC','FOO',15,10.34);
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
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
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;
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;
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;
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.
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
II.
III.
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.
Realizar primero las uniones (joins) que generen los resultados con menor nmero de registros.
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
Uniones (joins)
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
CONSTRAINTconstraint_namePRIMARYKEY(column1,column2,...column_n)
);
altertableREPUESTOS_ET
add(constraintREPUESTOS_ET_PKprimarykey(ID_ART)usingindexREPUESTOS_ET_PK);
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;
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;
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
|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';
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
GATHER_SCHEMA_STATS
GATHER_DATABASE_STATS
GATHER_SYSTEM_STATS
GATHER_DICTIONARY_STATS
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);
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';
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);
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;
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');
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)
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.
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
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:
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)
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;
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'));
|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'));
|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
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'));
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');
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;
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?
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
|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|
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|
|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|
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|
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;
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');
select*fromuser_scheduler_job_log;
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');
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');
121
Se puede lanzar el job aunque haya otra instancia ejecutndose en ese momento.
Se ejecuta con la sesin del dueo del job, de forma asncrona (igual que cuando se ejecuta de forma programada)
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);
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';
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;
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
dbms_scheduler.set_job_argument_value('mkdir_job',1,'nuevo_directorio');
dbms_scheduler.enable('mkdir_job');
end;
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.
126
frequency_clause="FREQ""="frequency
frequency="YEARLY"|"MONTHLY"|"WEEKLY"|"DAILY"|
"HOURLY"|"MINUTELY"|"SECONDLY"
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
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
129
12 Miscelnea
12.1 Tipos de comandos
DDL Data Definition Language sentencias que modifican la estructura de los objetos:
TRUNCATE elimina todos los registros de una tabla y el espacio que ocupan
INSERT insercin
UPDATE actualizacin
130
SQL*Plus:Release10.1.0.2.0ProductiononMonFeb2112:35:48
Enterpassword:xxxx
Connectedtoanidleinstance.
SQL>startup
ORACLEinstancestarted.
TotalSystemGlobalArea251658240bytes
FixedSize788368bytes
VariableSize145750128bytes
DatabaseBuffers104857600bytes
RedoBuffers262144bytes
Databasemounted.
Databaseopened.
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
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
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.
GRANTDBATOCURSO;
GRANTUNLIMITEDTABLESPACETOCURSO;
GRANTEXECUTE,READ,WRITEONDIRECTORYTOAD_TRACEFILE_DIRTOCURSOWITHGRANTOPTION;
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;
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
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';
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";
140
141
selectcount(*)
fromdual
whereget_weekday(:desde+level1)in(2,4)
connectbylevel<=:hasta:desde+1;
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
143
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