Tempfile no ocupa el espacio en disco hasta que lo necesita... | ExpoDBA

Tempfile no ocupa el espacio en disco hasta que lo necesita...

Tempfile no ocupa el espacio en disco hasta que lo necesita...

Al momento de crear un TEMPFILE, el TEMPFILE es creado casi instantaneamente, sin importar si el TEMPFILE es de 200 Kb  o de 200 Gb.

¿Porque es tan rápido crear un TEMPFILE y tan lento un datafile?

La respuesta es que el TEMPFILE no ocupa realmente el espacio en disco, sino que simplemente indica que bloques va a usar cuando necesite el espacio.

 

En este tema hay que tener mucho cuidado porque con este criterio podríamos crear TEMPFILES de tamaño mucho mayor al que tenemos disponible, y ni Oracle ni el Sistema Operativo se enterarán hasta que oracle quiera ocupar ese bloque con datos.

 

Es más, el df -k no mostrará el espacio ocupado por los TEMPFILE (porque realmente no están ocupados) pero si lo mostrará Oracle y el comando ls -lrt.

 

Veamoslo en un ejemplo:

 

Verificamos el espacio disponible en FS donde queremos crear el TEMPFILE:

 

oracle> df -k /oracle/datos/dat_41
Filesystem    1024-blocks      Free %Used    Iused %Iused Mounted on
/dev/vx/dsk/iserver_oracle_dg/oracle_dat_41   419430400  18043512   96%     7726     1% /oracle/datos/dat_41

 

Podemos ver que en el FS hay aún 18Gb disponibles, por lo tanto solo podríamos crear un TEMPFILE de hasta 18Gb (o 18043512 kb), pero para verificar que lo crea igual vamos a crear uno de 30Gb.

 

 

SQL> ALTER tablespace TMP_ORACLE add TEMPFILE '/oracle/datos/dat_41/tmp_oracle_53.dbs' size 30000M;

Tablespace modificado.

Transcurrido: 00:00:00.05

 

En 5 centécimas de segundo creó el TEMPFILE, y no creo que sea porque tenemos discos muy rápidos.

 

Veamos si existe realmente el TEMPFILE:

 

 

oracle> ls -lrt /oracle/datos/dat_41/tmp_oracle_53.dbs
-rw-r-----    1 oracle   dba      31457288192 May 24 18:43 /oracle/datos/dat_41/tmp_oracle_53.dbs

 

Podemos ver que realmente el archivo existe y "APARENTEMENTE" ocupa 30Gb.

Esto realmente es imposible, ya que el FS vimos que solo tenía 18Gb libres, por lo tanto jamás podría haber creado un archivo nuevo de 30Gb.

 

Veamos el espacio disponible en disco:

 

 

oracle> df -k /oracle/datos/dat_41/

Filesystem    1024-blocks      Free %Used    Iused %Iused Mounted on
/dev/vx/dsk/iserver_oracle_dg/oracle_dat_41   419430400  18043422   96%     7727     1% /oracle/datos/dat_41

 

Aqui se puede ver que aún hay 18Gb libres, por lo tanto el archivo realmente no ocupa el espacio que dice que ocupa.

 

Esto sucede porque Oracle hace una Quick Call al SO, de manera tal que solo le informa cuanto hasta donde va a asignar y la dirección del archivo. Unix entonces marca el espacio que utilizará, pero no lo reserva realmente, sino que solo lo marca.

 

La inconsistencia se encuentra al consultar con ls -l el espacio del archivo y al consultar df -k el espacio en el FS.

 

A medida que Oracle requiera ocupar el espacio del Tablespace Temporal, irá reclamando esos i-nodos marcados, pero teniendo en cuenta de que realmente no están reservados, nada nos asegura que realmente tengamos disponible el espacio en el momento que lo necesitemos.

 

Ejemplo:

Momento 1) Hay 20Gb libres y creamos un TEMPFILE de 10Gb. No se utiliza ningún ordenamiento, por lo que el espacio no se reclama

Momento 2) Otro DBA verifica con df -k que hay 20 Gb disponibles en el FS y lo utiliza para crear un datafile de 18Gb.

Momento 3) Se genera un ordenamiento que requiere 1Gb de espacio temporal. Oracle reclama al SO esos bloques para el archivo y todo funciona bien.

Momento 4) Otra sesion requiere 4Gb de temporal, 1Gb, está asignado, El SO comienza  a asignar los bloques restantes, llega a asignar 1Gb más, y llega a los 20Gb reales del disco, por lo tanto cuando intenta reclamar el otro bloque recibe un error muy parecido a este en el alert, terminando la sesion del usuario que reclamó el espacio:

 

 

Errors in file /oracle/trace/oracle_ora_12402720.trc:
ORA-01114: error de E/S al escribir el bloque en el archivo 4502 (bloque número 331631)
ORA-27063: skgfospo: el número de bytes leídos/escritos es incorrecto
IBM AIX RISC System/6000 Error: 28: No space left on device
Additional information: -1
Additional information: 212992

 

Hay varias situaciones por las que se puede dar esto, pero todo recae en lo mismo: Falta de espacio.

Algunas son:

  • Se creo un TEMPFILE más grande de lo que entra en el disco
  • Luego de crearse el TEMPFILE se crearon otros archivos que ocuparon su espacio

 

En el documento oficial de Oracle Oracle® Database SQL Reference 10g Release 2 (10.2) aclara que en algunos sistemas operativos los TEMPFILE no ocupan el espacio indicado hasta que no es reclamado, logrando de esta forma acelerar la creacion y resize de TEMPFILES.

 

Unworkaround para este problema, es reclamar todo el espacio del TEMPFILE al momento de crearlo.

Por medio de Oracle esto no es posible, pero si a traves del SO.

Lo que hay que hacer es crear un archivo del tamaño del TEMPFILE en la ubicación que queremos que quede.

Al tratarse de un archivo creado por nosotros, ocupará el espacio real.

Luego hacer un alter del tablespace temporal reutilizando el archivo creado como TEMPFILE.

 

Ejemplo:

 

#utilizamos el comando dd para crear un archivo de un solo bloque y saber que tamaño de bloque tiene el sistema
#(Hay otros métodos, pero a este tenemos acceso más que seguro)
dd of=prueba.pru seek=1 <<EOF

#Esto nos deja un prompt del dd, por lo que escribimos
EOF <enter>

#Ahora verificamos el tamaño del archivo para conocer el tamaño de bloque:
oracle> ls -l prueba.pru
-rw-r--r--    1 oracle   dba             512 May 24 19:08 prueba.pru
oracle> rm prueba.pru

#El Bloque tiene 512 bytes, por lo que ahora debemos calcular cuantos bloques necesitamos para crear un 
#archivo de 3000 Mb
#Cantidad de bloques = <tamaño de archivo>*1024*1024/<Tamaño de bloque>
#Cantidad de bloques = 3000*1024*1024/512=6144001
#Ejecutamos dd con estos datos
dd if=/dev/zero of=borrar.dbf bs=512 count=6144001

#Verificamos el archivo creado
oracle> ls -lrt borrar.dbf
-rw-r-----    1 oracle  dba      3145728512 May 24 19:42 borrar.dbf

 

Ahora solo queda conectarnos a la base y hacer un add TEMPFILE reuse.

 

 

alter tablespace TMP_ORACLE add tempfile '/oracle/datos/dat_41/borrar.dbf' size 3000M reuse;

 

Si bien esta operatoria es más lenta, nos aseguramos de que el TEMPFILE tendrá reservado en el SO todo el espacio que requiere y evitaremos problemas posteriores.

 

Formas de evitar este problema:

  1. Tener muy en cuenta el espacio disponible para crear el TEMPFILE
  2. Asegurarse que ese FS solo se utiliza para TEMPFILES o que si hay otros archivos, estos no crezcan.
  3. Crear el archivo del TEMPFILE con dd y luego agregarlo al Tablespace temporal

 

Referencias:

Oracle documentation

Ask TOM

 

Agradecimientos:

Gracias a Pablo Svampa y Eloy Casin - DBA's Oracle Senior por su colaboración en la creación de este documento.