A medida que los bloques van siendo alocados, la HWM se posiciona en el último bloque para mostrarnos la cantidad total de bloques alocados hasta el momento y estaban disponibles para ser usados.
Un error común es pensar que a medida que eliminamos datos de los bloques, la HWM se refresca para mostrarnos que estamos utilizando menos bloques; pero la realidad es que la HWM se mantiene siempre apuntando al último bloque alocado.
Sabemos que cuando realizamos un Full Scan, son leídos secuencialmente todos los bloques de la tabla hasta la HWM, por lo cual, debemos tener en claro que aunque eliminemos datos de una tabla, ese espacio "vacío" se va a seguir leyendo, lo cual trae como consecuencia la lectura de bloques innecesarios.
Veamos un ejemplo:
SQL_9iR2> CREATE TABLE emp
2 (id NUMBER , sexo VARCHAR2(1 ) ;
Table created.
SQL_9iR2> INSERT INTO emp
2 SELECT level , 'M'
3 FROM dual
4 CONNECT BY level <= 800000 ;
800000 rows created.
SQL_9iR2> INSERT INTO emp
2 SELECT level , 'F'
3 FROM dual
4 CONNECT BY level <= 200000 ;
200000 rows created.
SQL_9iR2> ANALYZE TABLE emp COMPUTE STATISTICS ;
Table analyzed.
SQL_9iR2> SET AUTOTRACE TRACEONLY
SQL_9iR2> SELECT sexo
2 FROM emp
3 WHERE id = 900000 ;
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=160 Card=10000 Bytes=60000)
1 0 TABLE ACCESS (FULL) OF 'EMP' (Cost=160 Card=10000 Bytes=60000)
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
1655 consistent gets
0 physical reads
0 redo size
213 bytes sent via SQL*Net to client
363 bytes received via SQL*Net from client
1 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
0 rows processed
SQL_9iR2> DELETE FROM emp
2 WHERE sexo = 'M' ;
800000 rows deleted.
SQL_9iR2> SET AUTOTRACE TRACEONLY
SQL_9iR2> SELECT sexo
2 FROM emp
3 WHERE id = 900000 ;
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=160 Card=10000 Bytes=60000)
1 0 TABLE ACCESS (FULL) OF 'EMP' (Cost=160 Card=10000 Bytes=60000)
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
1655 consistent gets
419 physical reads
0 redo size
213 bytes sent via SQL*Net to client
363 bytes received via SQL*Net from client
1 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
0 rows processed
Como pudimos ver, aunque hayamos eliminados datos de la tabla, seguimos leyendo la misma cantidad de bloques que antes porque la HWM no se refrescó y sigue apuntando al último bloque alocado en el segmento.
Para solucionar éste problema, podemos realizar...
1) TRUNCATE ...
- Si la tabla esta vacia podemos hacer un TRUNCATE para resetear la HWM. Sino, podemos hacer un export de los datos, luego truncar la tabla y realizar un import.
2) ALTER TABLE ... MOVE
- De ésta manera reorganizamos la tabla. Tener en cuenta que luego de ejecutar el ALTER, hay que hacer un REBUILD de todos los índices de la tabla!
3) Dropear y recrear el objeto (export/import)
4) ALTER TABLE ... SHRINK SPACE | SHRINK SPACE COMPACT
- Para 10g en adelante.
Apliquemos a nuestro ejemplo el punto 2...
SQL_9iR2> ALTER TABLE emp MOVE ;
Table altered.
SQL_9iR2> ANALYZE TABLE emp COMPUTE STATISTICS ;
Table analyzed.
SQL_9iR2> SET AUTOTRACE TRACEONLY
SQL_9iR2> SELECT sexo
2 FROM emp
3 WHERE id = 900000 ;
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=33 Card=2000 Bytes=12000)
1 0 TABLE ACCESS (FULL) OF 'EMP' (Cost=33 Card=2000 Bytes=12000)
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
335 consistent gets
0 physical reads
0 redo size
213 bytes sent via SQL*Net to client
363 bytes received via SQL*Net from client
1 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
0 rows processed
Como vemos, la HWM se refresco y ahora estamos leyendo sólo los bloques que contienen nuestros datos.
12 comentarios:
Gracias, tu explicacion de lo que es el HWM es muy clara y concisa y me sirvio de gran ayuda.
Te felicito por la explicacion Leonardo, muy clara.
Leonardo, como me puedo comunicar contigo o lanzarte una consulta acerca de compresion de tablas en Oracle 10g??
Buenas, puedes hacerme una consulta acerca de compresión de tablas en Oracle 10g a través de éste Blog insertando un comment.
Saludos.
Hola Leonardo:
primero para felicitarte de todos los tips que nos escribes en tu página, están muy claros, por otro lado, donde o como consigo el explains ya que lo he buscado en donde esta instalado oracle y no xiste, podrías mandarmelo por correo a: ray_garcia66@hotmail.com, te lo agradecere infinitamente
Gracias y Saludos
RAY MÉXICO
Hola Ray,
- Para crear la tabla PLAN_TABLE, hay que ejecutar el script
UTLXPLAN.sql ubicado en $ORACLE_HOME/rdbms/admin
- Para ver el Explain Plain, hay que ejecutar el script
UTLXPLS.sql (para ejecuciones en serial) o
UTLXPLP.sql (para ejecuciones en paralelo) ubicado en
$ORACLE_HOME/rdbms/admin
Saludos.
Hola, Leonardo.
Gran blog en general y gran explicación del High Water Mark en particular. Me ha sido muy util para mejorar el rendimiento de una bbdd 9i. Tengo una pregunta: ¿Cómo se hace un move en tablas particionadas? O mejor, ¿cómo se reorganizan tablas que están particionadas?
Muchas gracias y un saludo,
Angel.
Hola Angel,
Para hacer un MOVE en tablas particionadas puedes guiarte por el siguiente ejemplo:
SQL> CREATE TABLE estudiantes
2 (
3 legajo NUMBER(5),
4 nombre VARCHAR2(30),
5 ingreso DATE
6 )
7 PARTITION BY RANGE(ingreso)
8 (
9 PARTITION ingreso_2006 VALUES LESS THAN(TO_DATE('01/01/2007','DD/MM/YYYY'))
,
10 PARTITION ingreso_2007 VALUES LESS THAN(TO_DATE('01/01/2008','DD/MM/YYYY'))
11 ) ;
Table created.
SQL> ALTER TABLE estudiantes MOVE PARTITION ingreso_2006;
Table altered.
Saludos
Leonardo, tengo la siguiente consulta: Dispongo de 2 esquemas ( X1 , Y1). En X1 se realizan todas las transacciones.En el esquema Y1 se copia el contenido (aprox. 920M ) de la tabla 'TxDia' del esquema X1 de manera diaria. He creado dicha tabla 'TxDia' en el esquema Y1 con storage ( initial 900M next 5M ) ya que es lo que aprox. pesa en el esquema X1. Diariamente en el esquema Y1 la tabla TxDia se tiene que truncar antes de copiar el contenido. Mi consulta es ya que se realiza en el esquema Y1 un truncado y luego una copia de contenido (insert into ..select) desde otra tabla, estas tareas serían mas optimas si ejecuto el truncate con la opción de reuse storage.
Saludos
Luis
Luis,
Si, podría beneficiarte la opción de REUSE STORAGE para el insert que realizas diariamente. Pero me gustaría darte una idea para ver si podés resolver esto de la carga de datos diaria de alguna otra manera. Supongamos que la tabla del esquema X1 se carga diariamente con 2 millones de datos. En vez de truncar diariamente la tabla del esquema Y1 para realizar el insert con los datos de esa tabla, y si, la gran mayoria de los datos que vas a insertar ya se encontraban en la tabla TxDia, podés utilizar Vistas Materializadas para capturar sólo los datos "que cambiaron" y luego copiar "sólo" esos datos. No se si ésto te ayuda, pero es sólo una idea que a lo mejor te sea útil.
Saludos
Master
¿Cual es la mejor método de Reducir el tamaño de una tabla?
¿y Bajar la HWM?
Mi tabla pesa 3gb, el export e import no me sirve se demora 36 horas, y solo tenemos 24 horas para realizar dicho proceso.
Hola Gangsta,
Esto dependerá de la versión de base de datos en la cual estes trabajando.
Probaste los métodos 2 y 4 que coloqué en el post?
Saludos
Publicar un comentario