Etiquetado de discos para ASM en Solaris.

* Con la ayuda de Sergio Ramírez en la parte de Solaris. Muchísimas gracias, compañero!.

Cuando he tenido que etiquetar discos en linux para que el ASM los reconozca para candidatos, la librería asmlib me lo ha puesto muy fácil, pues solamente era necesario marcar los discos de la siguiente forma.

[root@host Server]# /etc/init.d/oracleasm createdisk ASMDISK1_DATA /dev/mapper/racdb_asm1
Marking disk «ASMDISK1_DATA» as an ASM disk:               [  OK  ]

[root@host Server]# /etc/init.d/oracleasm createdisk ASMDISK1_FRA  /dev/mapper/racdb_asm2
Marking disk «ASMDISK1_FRA» as an ASM disk:                [  OK  ]

[root@cun0401 Server]# /etc/init.d/oracleasm listdisks
ASMDISK1_DATA
ASMDISK1_FRA
Pero esta librería no está disponible para Solaris y el proceso de etiquetar los discos para que ASM los vea como candidatos no resulta tan evidente como se describe en la documentación de instalación de grid en Solaris.
En concreto, una vez los discos están visibles y los dispositivos son del propietario grid:dba , en el comando format hay que modificar los volúmenes tal como se muestra.
root@host:~$ format
Searching for disks…done 

AVAILABLE DISK SELECTIONS:
       0. c0t0d0
          /pci@0,600000/pci@0/pci@8/pci@0/scsi@1/sd@0,0
       1. c0t1d0 Solaris
          /pci@0,600000/pci@0/pci@8/pci@0/scsi@1/sd@1,0
       2. c2t600A0B800029B03400001B474BE28D9Bd0
          /scsi_vhci/ssd@g600a0b800029b03400001b474be28d9b
       3. c2t600A0B800029B034000022A64DB65A53d0
          /scsi_vhci/ssd@g600a0b800029b034000022a64db65a53   –> Este es el disco a añadir
       4. c2t600A0B800029B034000020104C43B3C1d0
          /scsi_vhci/ssd@g600a0b800029b034000020104c43b3c1
       5. c2t600A0B800029B034000021104C612E6Dd0
          /scsi_vhci/ssd@g600a0b800029b034000021104c612e6d
       6. c2t600A0B8000269A3200007F3F4BE25284d0
          /scsi_vhci/ssd@g600a0b8000269a3200007f3f4be25284
       7. c2t600A0B8000269A32000084B24CC8D1D5d0
          /scsi_vhci/ssd@g600a0b8000269a32000084b24cc8d1d5
       8. c2t600A0B8000269A32000084C74CD0F3D2d0
          /scsi_vhci/ssd@g600a0b8000269a32000084c74cd0f3d2
       9. c2t600A0B8000269A320000802A4BF3820Ad0
          /scsi_vhci/ssd@g600a0b8000269a320000802a4bf3820a
      10. c2t600A0B8000269A320000834C4C439596d0
          /scsi_vhci/ssd@g600a0b8000269a320000834c4c439596
      11. c2t600A0B8000269A320000834F4C43960Fd0
          /scsi_vhci/ssd@g600a0b8000269a320000834f4c43960f
Specify disk (enter its number): 3 –> corresponde al identificador del disco a añadir
Select partitioning base:
        0. Current partition table (original)
        1. All Free Hog
Choose base (enter number) [0]? 1   –> para modificarlas todas las particiones



 Part      Tag    Flag     Cylinders         Size            Blocks
  0       root    wm       0                0         (0/0/0)             0
  1       swap    wu       0                0         (0/0/0)             0
  2     backup    wu       0 – 51197      100.00GB    (51198/0/0) 209707008
  3 unassigned    wm       0                0         (0/0/0)             0
  4 unassigned    wm       0                0         (0/0/0)             0
  5 unassigned    wm       0                0         (0/0/0)             0
  6        usr    wm       0                0         (0/0/0)             0
  7 unassigned    wm       0                0         (0/0/0)             0


Do you wish to continue creating a new partition
table based on above table[yes]? Yes  -> Confirmamos que deseamos crear nuestras particiones.
Free Hog partition[6]? 7  -> Determina que partición es la que almacena el espacio libre
Enter size of partition ‘0’ [0b, 0c, 0.00mb, 0.00gb]: 500mb  -> En la partición 0 definimos un tamaño de 500mb la que necesita ASM para su gestión.
Enter size of partition ‘1’ [0b, 0c, 0.00mb, 0.00gb]:    
Enter size of partition ‘3’ [0b, 0c, 0.00mb, 0.00gb]:
Enter size of partition ‘4’ [0b, 0c, 0.00mb, 0.00gb]:
Enter size of partition ‘5’ [0b, 0c, 0.00mb, 0.00gb]:
Enter size of partition ‘6’ [0b, 0c, 0.00mb, 0.00gb]: 99.50gb  -> Configuramos el resto del tamaño en una de las particiones
Part      Tag    Flag     Cylinders         Size            Blocks
  0       root    wm       0 –   249      500.00MB    (250/0/0)     1024000
  1       swap    wu       0                0         (0/0/0)             0
  2     backup    wu       0 – 51197      100.00GB    (51198/0/0) 209707008
  3 unassigned    wm       0                0         (0/0/0)             0
  4 unassigned    wm       0                0         (0/0/0)             0
  5 unassigned    wm       0                0         (0/0/0)             0
  6        usr    wm     250 – 51193       99.50GB    (50944/0/0) 208666624
  7 unassigned    wm   51194 – 51197        8.00MB    (4/0/0)         16384
Okay to make this the current partition table[yes]? Yes  -> Confirmamos que esta correcto tal cual la hemos definido
Enter table name (remember quotes): «asm»  -> Le ponemos un nombre al modelo de configuración de la tabla, para posteriores discos para la ASM del mismo tamaño.

Ready to label disk, continue? yes
partition> q –> salimos del menú de partición
FORMAT MENU:
        disk       – select a disk
        type       – select (define) a disk type
        partition  – select (define) a partition table
        current    – describe the current disk
        format     – format and analyze the disk
        repair     – repair a defective sector
        label      – write label to the disk
        analyze    – surface analysis
        defect     – defect list management
        backup     – search for backup labels
        verify     – read and display labels
        save       – save new disk/partition definitions
        inquiry    – show vendor, product and revision
        volname    – set 8-character volume name
        !     – execute , then return
        quit
format> verify  -> Mediante el comando verify comprobamos que esta correcto.
Primary label contents:
Volume name = <        >
ascii name  =
pcyl        = 51200
ncyl        = 51198
acyl        =    2
nhead       =   64
nsect       =   64
Part      Tag    Flag     Cylinders         Size            Blocks
  0       root    wm       0 –   249      500.00MB    (250/0/0)     1024000
  1       swap    wu       0                0         (0/0/0)             0
  2     backup    wu       0 – 51197      100.00GB    (51198/0/0) 209707008
  3 unassigned    wm       0                0         (0/0/0)             0
  4 unassigned    wm       0                0         (0/0/0)             0
  5 unassigned    wm       0                0         (0/0/0)             0
  6        usr    wm     250 – 51193       99.50GB    (50944/0/0) 208666624
  7 unassigned    wm   51194 – 51197        8.00MB    (4/0/0)         16384

format> q


Ahora, desde la interfaz gráfica (asmca) o desde sqlplus, Oracle es capaz de identificar los discos como candidatos para añadirlos al diskgroup ASM que corresponda.


-bash-3.00$ sqlplus / as sysasm


SQL> select path, name from v$asm_disk;


PATH                                               NAME
————————————————– ——————————
/dev/did/rdsk/d9s6
/dev/did/rdsk/d9s7
/dev/did/rdsk/d9
/dev/did/rdsk/d4s6                                 RECOVERY_0000
/dev/did/rdsk/d22s6                                DATOS_0001
/dev/did/rdsk/d18s6                                OCRVOTING_0000
/dev/did/rdsk/d19s6                                OCRVOTING_0001




Al aparecer los tres nuevos volúmenes como candidatos, ya es posible añadir el disco al diskgroup desde sqlplus conectado como SYSASM.


SQL> alter diskgroup DATOS add disk ‘/dev/did/rdsk/d9s6’;


SQL> select path, name from v$asm_disk;
PATH                                               NAME
————————————————– ——————————
/dev/did/rdsk/d9s7
/dev/did/rdsk/d9
/dev/did/rdsk/d4s6                                 RECOVERY_0000
/dev/did/rdsk/d9s6                                 DATOS_0000
/dev/did/rdsk/d22s6                                DATOS_0001
/dev/did/rdsk/d18s6                                OCRVOTING_0000
/dev/did/rdsk/d19s6                                OCRVOTING_0001

«La query que tumba la máquina».

Hace unos años publiqué un artículo llamado «PL/SQL y ejecuciones en host» en el que describía el paso a paso para poder, desde PL/SQL, ejecutar código en el sistema operativo.

Oracle no permite que los procedimientos y funciones puedan acceder al host, pero sí permite llamadas a funciones externas implementadas con C o PASCAL, y redireccionadas como librerías mediante un objeto library.

Mi intención inicial fue la de crear un procedimiento PL/SQL que realizara un backup en caliente del servidor, realizase un export, import, o cualquier otra invocación a un ejecutable residente en el sistema operativo.

Hoy he visto una configuración similar en una base de datos en un entorno de producción, que realizan la misma implementación pero mediante una función.

create or replace
FUNCTION sysrun (syscomm IN VARCHAR2)
  RETURN BINARY_INTEGER
  AS LANGUAGE C
  NAME «sysrun»
  LIBRARY shell_lib
  PARAMETERS(syscomm string);

De este modo, la función retorna un 0 si la llamada al SHELL_LIB se ha ejecutado correctamente, o un número si ha habido un error.
Hice esta prueba, y pude constatar un mito: La consulta que tumba el servidor existe!!.
SQL> select sysrun('sudo reboot') from dual;

Broadcast message from root (Thu Jan 27 13:16:34 2011):

The system is going down for reboot NOW!

SYSTEM.SYSRUN('SUDOREBOOT')
---------------------------
                          0

Mapa Mental 1: Oracle 10g RAC en Linux

En la instalación de un RAC sobre Linux es preciso tener en cuenta las características de la plataforma a los siguientes niveles:

1.- Red. ¿Existen tarjetas de red para conexiones privadas y públicas en todos los nodos? Es preciso configurarlas correctamente para que el cluster pueda manejar las tres direcciones (pública, privada y virtual). ¿Hay redundancia en las tarjetas? ¿está configurado correctamente el bonding?

2.- Almacenamiento. ¿ASM o OCFS2? O uno, u otro. Nunca los dos o una combinación de ambos en el mismo sistema, ya que puede llevar a conflictos. ¿Hay multipath? El almacenamiento con controladoras redundantes debe configurarse correctamente para evitar desastres.

3.- Sistema. ¿Todos los parches están instalados? ¿los parámetros de kernel y límites de sesión están definidos de forma persistente? ¿los privilegios sobre los dispositivos de almacenamiento tienen privilegios sobre root y oracle como corresponde?

Mapa mental 1: estrella

Quizás en estos casos pueda ayudar el siguiente mapa mental, a modo de guía paso a paso, adaptándolo a la plataforma y las características del entorno a instalar.

Mapa mental 2: vertical

Los procesos del mapa al detalle
·  Verificar red public y privada
o Ejecutar /sbin/ifconfig
El resultado debe ser dos tarjetas de red visibles, una con la dirección publica y otra con la privada (mas el tcploopback)
§ Configuración Bonding
Cuando hay redundancia de tarjetas es importante conocer la configuración de bonding para hacer referencia a las tarjetas virtuales y no a las físicas.
§ Configuración interconnect
El interconnect debe estar configurado correctamente para las pruebas de caída de servidores. Los switches deben contemplar las posibles caídas y sus enrutamientos.
o Registrar entradas /etc/hosts
Hay que añadir las direcciones IP para publica, privada y virtual.

La ip virtual no será visible hasta que los servicios de cluster se inicien con el vipca al final de la instalación del clusterware.

o Ping entradas /etc/hosts
Ping a los alias públicos y privados, con y sin nombre de dominio
·  Configurar storage
o Crear particiones con /sbin/fdisk
Crear particiones para OCR, voting y rawdevices para ASM.

Minimo:
120 Mb para OCR x 2
20 Mb para voting x 3

Si no se crean particiones, los discos deben estar preparados, así como sus dispositivos.

o Editar /etc/sysconfig/rawdevices
o Asignar privilegios a los rawdevices
Los dispositivos deben pertenecer al usuario Oracle y tener 660 (ocr) y 664 (voting)

Una vez creado el clusterware, los ocr pasaran a ser de root, y será necesario hacer persistentes los permisos al arranque en el fichero /etc/rc.d/rc.local

o Habilitar rawdevices nodo 1
o Propagar configuración nodo 2-3-x
El fichero /etc/sysconfig/rawdevices ha de propagarse al resto de nodos.

Una vez copiado el fichero, hay que actualizar la tabla de partición y habilitar los rawdevices en ese nodo.

services rawdevices start

o Los rawdevices están habilitados en todos los nodos
·  Crear grupos y usuarios
o Crear grupos dba y oinstall
o Crear usuario oracle
o chmod y chown a usuario
o Definir .bash_profile
o Configurar secure shell
Generar claves rsa y dsa para concatenar en todos los ficheros authorized_keys de los diferentes nodos.
o Comprobar ssh transparente entre nodos
·  Configuración OS
o Configuración Secure Shell
El usuario Oracle debe poder hacer ssh entre nodos sin necesidad de contraseña.
§ Crear claves rsa y dsa
/usr/bin/ssh-keygen -t rsa
/usr/bin/ssh-keygen -t dsa

Los ficheros de $HOME/.ssh id_dsa.pub y id_rsa.pub de todos los nodos han de unirse en uno nuevo llamado authorized_keys, que se copiará a los directorios .ssh del usuario oracle para cada nodo.

§ Añadir hosts a known_hosts
En cada ssh el sistema preguntará para añadir ese nodo a la lista de know_hosts. Solo se preguntará esta vez y las siguientes conexiones serán transparentes.
§ Test ssh nodos /etc/hosts
o Configuración hangcheck-timer
Según notas 811306.1 y 726833.1
Es necesario añadir la línea

/sbin/modprobe hangcheck-timer hangcheck_tick=1 hangcheck_margin=10 hangcheck_reboot=1

Y hacer este cambio permanente al reinicio del servidor en /etc/rc.d/rc.local

o Configurar hugepages
Según nota 361468.1
Es necesario añadir la siguiente línea a /etc/security/limits.conf

* hard memlock 5243000
* soft memlock 5243000

o Configurar kernel
o Configurar limites shell
Los limites de shell han de hacerse permanentes en el inicio de sesión. Para ello, hay que añadir la siguiente línea a /etc/pam.d/login

session required /lib/security/pam_limits.so

o rda hcve para cada nodo
o Cluvfy
§ Chequeo hardware y OS
./runcluvfy.sh stage -post hwos -n nodo1,nodo2,nodoN – verbose
§ Chequeo conectividaf
./runcluvfy.sh comp nodecon -n nodo1,nodo2,nodoN – verbose
§ Chequeo usuario
./runcluvfy.sh comp admprv -n nodo1,nodo2,nodoN – verbose -o user_equiv
§ PreCheck configuración servicios de cluster
./runcluvfy.sh stage -pre crsinst -n nodo1,nodo2,nodoN -r 10gR2
·  Ejecutar runInstaller clusterware software
Definir variables de entorno para ORA_CRS_HOME
o Seguir nota 414163.1 en RHL5 para errores conocidos
Existen tres errores conocidos en la instalación de RAC 10.2.0.1 en RHL5

– ejecutar el runinstaller con -ignoreSysPrereqs
– editar vipca y svrctl para añadir la línea «unset LD_ASSUME_KERNEL»
– La ejecución de root.sh fallará en el ultimo nodo y habrá que ejecutar el vipca manualmente tras configurar las tarjetas de red con

/bin # ./oifcfg setif -global eth0/192.168.1.0:public
/bin # ./oifcfg setif -global eth1/10.10.10.0:cluster_interconnect
/bin # ./oifcfg getif
eth0 192.168.1.0 global public
eth1 10.10.10.0 global cluster_interconnect

o Chequeo servicios
Ejecutar crs_stat -t

Los servicios de cluster deben estar arrancados.

o Instalar patchset 10.2.0.5 clusterware
Instalar la versión mas reciente del patchset.
Mucho mejor antes de que haya ASM y DB’s que deban pararse y parchearse.
·  Ejecutar runInstaller ASM software
Definir variables de entorno para ORA_ASM_HOME
o Instalar asmlib
Instalar librerias asmlib
o Configurar multipath para ASM
Seguir nota 564580.1 si hay redundancia de controladores de disco por multipath
o Creación de diskgroups
Crear dos diskgroups: uno para DATA y el otro para FRA

DG_DATA_1
DG_FRA_1

o Chequeo servicios
Ejecutar crs_stat -t

Los servicios de cluster deben estar arrancados incluyendo los de ASM.

o Instalar patchset 10.2.0.5 ASM
Instalar la versión mas reciente del patchset.
Mucho mejor antes de que haya ASM y DB’s que deban pararse y parchearse.
·  Ejecutar runInstaller DB software
Definir variables de entorno para ORACLE_HOME
o Crear bbdd RAC usando asm
Seguir nota 564580.1 si hay redundancia de controladores de disco por multipath
o Chequeo servicios
Ejecutar crs_stat -t

Los servicios de cluster deben estar arrancados incluyendo los de ASM y los de base de datos.

o Instalar patchset 10.2.0.5 ASM
Instalar la versión mas reciente del patchset.
Mucho mejor antes de que haya ASM y DB’s que deban pararse y parchearse.

Acceso a una bbdd MSAccess desde Oracle.

Es posible acceder a bases de datos no oracle de forma transparente con Oracle Transparent Gateways.

Esta funcionalidad permite configurar una entrada DNS de ODBC como si se tratara de un servicio Oracle cualquiera. De este modo, mediante un dblink, un usuario podría acceder a una tabla de una base de datos access (o SQLServer o MySQL, por ejemplo) desde una query o desde PL/SQL.

La arquitectura de servicios heterogeneos se basa en la siguiente configuración:

Se especifica una entrada de TNS en el fichero tnsnames.ora que resuelva una conexión al host, puerto y nombre de servicio determinado, con el parámetro HS=OK (Oracle Heterogeneous Services).

Por otro lado, el listener destino tiene definido para ese servicio la invocación a un programa llamado «hsodbc» que, mediante un fichero de parámetros llamado init.ora accede al DNS asociado a la base de datos MSAccess concreta.

De este modo, y creando un dblink, cualquier usuario podría hacer una select que cruzara datos de su esquema Oracle y de una bbdd Access.

PASOS A SEGUIR
1.- Instalar en el diccionario los servicios heterogeneos.
2.- Configurar el tnsnames.ora
3.- Configurar el listener.
4.- Comprobar que el listener y el tnsnames.ora funcionan correctamente.
5.- Configurar el ODBC para la bbdd access.
6.- Crear el DBLINK hacia la bbdd access.
7.- Crear el fichero init.ora
8.- Ejecutar una consulta mediante ese dblink.


1.- Instalar en el diccionario los servicios heterogeneos
@?/rdbms/admin/caths.sql

NOTA: puede que estas vistas estén instaladas ya en la bbdd.

2.- Configurar el tnsnames.ora
bbdd_access =
   (DESCRIPTION=
      (ADDRESS= (PROTOCOL=tcp)
               (HOST=192.168.2.4)
               (PORT=1521)
     )
     (CONNECT_DATA =
         (SERVICE_NAME=odbc_access)
     )
     (HS = OK)
)

3.- Configurar el listener. (la entrada en negrita es la que hay que añadir)…

LISTENER =
  (DESCRIPTION_LIST =
    (DESCRIPTION =
      (ADDRESS_LIST =
        (ADDRESS = (PROTOCOL = IPC)(KEY = EXTPROC0))
      )
      (ADDRESS_LIST =
         (ADDRESS = (PROTOCOL = TCP)(HOST = 192.168.2.4)(PORT = 1521))
      )
    )
  )

SID_LIST_LISTENER =
   (SID_LIST =
    (SID_DESC =
       (SID_NAME = PLSExtProc)
      (ORACLE_HOME = D:oracleora92)
      (PROGRAM = extproc)
    )
    (SID_DESC =
      (GLOBAL_DBNAME = orcl)
      (ORACLE_HOME = D:oracleora92)
      (SID_NAME = orcl)
    )
     (SID_DESC =
      (ORACLE_HOME = D:oracleora92)
      (SID_NAME = odbc_access)
       (PROGRAM = hsodbc)
    )
  )

4.- Comprobar que el listener y el tnsnames.ora funciona correctamente.

C:Documents and SettingsAdministrador>tnsping bbdd_access

TNS Ping Utility for 32-bit Windows: Version 9.2.0.1.0 – Production on 08-SEP-2006 18:19:42

Copyright (c) 1997 Oracle Corporation.  All rights reserved.

Archivos de parßmetros utilizados:
D:oracleora92networkadminsqlnet.ora

Adaptador TNSNAMES utilizado para resolver el alias
Attempting to contact (DESCRIPTION= (ADDRESS= (PROTOCOL=tcp) (HOST=192.168.2.4) (PORT=1521)) (CONNECT_DATA = (SERVICE_NAME=odbc_access)) (HS = OK))
Realizado correctamente (50 mseg)

5.- Configurar el ODBC para la bbdd access.
La base de datos access utilizada en el ejemplo tiene una única tabla con cuatro filas de ejemplo…

create table ejemplo

   (id counter,
    valor text)

Es preciso crear un ODBC para acceder a la bbdd access determinada. Desde Windows esta opción se configura en Panel de control, Herramientas administrativas, Administrador ODBC y la pestaña DNS de sistema.

desde ahí se crea el driver    odbc_access vinculado a la base de datos que uso: «test_hs.mdb» con esta tabla de ejemplo.

NOTA: esta bbdd access tiene password «tesths»

6.- Crear el DBLINK hacia la bbdd access.

SQL> CREATE DATABASE LINK bbdd_access
2      CONNECT TO ADMIN IDENTIFIED BY TESTHS
3      USING ‘bbdd_access’;

Enlace con la base de datos creado.

7.- Crear el fichero init.ora en el directorio de ORACLE_HOME   /hs/admin/

— FICHERO initODBC_ACCESS.ora
#
# HS init parameters
#

HS_FDS_CONNECT_INFO = odbc_access
HS_FDS_TRACE_LEVEL = 0
HS_FDS_TRACE_FILE_NAME = odbc_access.trc
HS_AUTOREGISTER = TRUE

8.- Lanzar la query via ese dblink

SQL> column «valor» format a40
SQL> set pages 1000
SQL> set lines 120
SQL> select * from ejemplo@bbdd_access;

        id valor
———- —————————————-
         1 dato1
         2 dato2
         3 dato3
         4 dato4

Oracle Enterprise Manager. Ejemplo de uso.

Oracle Enterprise Manager (OEMGR) es una herramienta que permite monitorizar bases de datos Oracle mediante dos tipos de conexiones:
Standalone (o modo autónomo)
Mediante OMS (Oracle Management Server)

El modo Standalone funciona como una aplicación estándar cliente/servidor, mientras que la conexión a un OMS utiliza un repositorio intermedio con información global sobre las bases de datos registradas.

(ver el video en pantalla completa)

00:15 – Autentificación con el OMS.

00:30 – Packs de aplicaciones disponibles en OEMGR

01:00 – Conexión a una base de datos y cambios en la SGA (memória). Monitorización de sesiones.

02:00 – Monitorización y gestión de tablespaces. Añadir un datafile a un tablespace y visualización del SQL generado.

03:30 – Monitorización de varias bases de datos de forma global. Sobre estas bases de datos OEMGR permite implementar trabajos (jobs) y alertas que actuen ante cualquier cambio de interés a monitorizar.

03:55 – Creación de una alerta sobre una bbdd.

05:30 – La alerta, creada correctamente, hace visualizar en el mapa una bandera verde que confirma que todo funciona correctamente.

Uso de logminer.

En alguna ocasión he necesitado recuperar una transacción validada con COMMIT, pero no deseada o errónea. Pongo un ejemplo:

– Usuario borra una fila.
– Por accidente.
– No sabe de qué fila se trata, pero ‘algo’ ha dicho «registro borrado».
(…borrado y validado).
– Ni idea de qué datos tenía la fila.
– Ni él, ni nadie.
– Desde ese momento, la fila X ha desaparecido sin rastro.

Con variaciones, éste caso es bastante frecuente, y si el usuario que ha borrado el registro es lo suficientemente rápido, existe una posibilidad de recuperar los datos perdidos.

Generalmente, todas las transacciones convencionales procesan la información pasando por las áreas de redo log. En estos archivos está toda la información correspondiente al nuevo cambio. Oracle basa toda su actividad en el buen funcionamiento del registro de redo log y, por tanto, en esta área únicamente almacena los datos físicos elementales para rehacer la operación. Por tanto, no se almacena información sobre los valores anteriores.

Lo cual sí sucede en el área de rollback, y ¡la gestión de rollback también pasa por redolog!.

Oracle dispone de un paquete, el LOG MINER que permite rastrear los redo logs (online y archivados) junto con la información de rollback disponible también en éstos. Una vez ejecutado el paquete que crea el fichero de diccionario de objetos, Oracle es capaz de interpretar esos redologs y mostrar información tan válida como el SQL generado y el SQL inverso para «reparar» la acción.


SQL> connect / as sysdba
Conectado.
SQL> show parameters utl

NAME                                 TYPE        VALUE
———————————— ———– ——————————
utl_file_dir                         string      c:oraclefiles

SQL> exec DBMS_LOGMNR_D.BUILD( DICTIONARY_FILENAME =>’dictionary.ora’, DICTIONARY_LOCATION => ‘c:oraclefiles’);

Procedimiento PL/SQL terminado correctamente.

SQL> select member from v$logfile;

MEMBER
——————————————————————————–
C:ORACLEORADATAORCLREDO04A.LOG
C:ORACLEORADATAORCLREDO04B.LOG
C:ORACLEORADATAORCLREDO05A.LOG
C:ORACLEORADATAORCLREDO05B.LOG
C:ORACLEORADATAORCLREDO06A.LOG
C:ORACLEORADATAORCLREDO06B.LOG

6 filas seleccionadas.

SQL> exec DBMS_LOGMNR.add_logfile(‘C:ORACLEORADATAORCLREDO04A.LOG’);

Procedimiento PL/SQL terminado correctamente.

SQL> exec DBMS_LOGMNR.add_logfile(‘C:ORACLEORADATAORCLREDO05A.LOG’);

Procedimiento PL/SQL terminado correctamente.

SQL> exec DBMS_LOGMNR.add_logfile(‘C:ORACLEORADATAORCLREDO06A.LOG’);

Procedimiento PL/SQL terminado correctamente.

SQL> EXECUTE DBMS_LOGMNR.START_LOGMNR(DICTFILENAME =>’c:oraclefilesdictionary.ora’);

Procedimiento PL/SQL terminado correctamente.

SQL> set pages 100
SQL> set lines 120
SQL> column sql_redo format a50
SQL> column sql_undo format a50

SQL> select sql_redo, sql_undo from v$logmnr_contents where rownum<10;

SQL_REDO                                           SQL_UNDO
————————————————– ————————————————–
insert into «DISCOVERER9I».»EUL5_MV101651″(«Import delete from «DISCOVERER9I».»EUL5_MV101651″ where «
e SUM»,»Importe COUNT»,»Importe MAX»,»Importe MIN» Importe SUM» = ‘170,01’ and «Importe COUNT» = ‘1’
,»Importe AVG»,»Ciudad»,»Pais»,»Rango Edad»,»Sexo» and «Importe MAX» = ‘170,01’ and «Importe MIN» = ‘
,»Detalle Vuelo») values (‘170,01′,’1′,’170,01′,’1 170,01’ and «Importe AVG» = ‘170,01’ and «Ciudad»
70,01′,’170,01′,’Madeira’,’Portugal’,’Mayores de 5 = ‘Madeira’ and «Pais» = ‘Portugal’ and «Rango Eda
0 a±os’,’Mujer’,’VUELO52149′);                     d» = ‘Mayores de 50 a±os’ and «Sexo» = ‘Mujer’ and
                                                    «Detalle Vuelo» = ‘VUELO52149’ and ROWID = ‘AAALV
                                                   mAAPAAAAn8AAA’;

insert into «DISCOVERER9I».»EUL5_MV101651″(«Import delete from «DISCOVERER9I».»EUL5_MV101651″ where «
e SUM»,»Importe COUNT»,»Importe MAX»,»Importe MIN» Importe SUM» = ‘112,95’ and «Importe COUNT» = ‘1’
,»Importe AVG»,»Ciudad»,»Pais»,»Rango Edad»,»Sexo» and «Importe MAX» = ‘112,95’ and «Importe MIN» = ‘
,»Detalle Vuelo») values (‘112,95′,’1′,’112,95′,’1 112,95’ and «Importe AVG» = ‘112,95’ and «Ciudad»
12,95′,’112,95′,’Madeira’,’Portugal’,’Mayores de 5 = ‘Madeira’ and «Pais» = ‘Portugal’ and «Rango Eda
0 a±os’,’Mujer’,’VUELO52206′);                     d» = ‘Mayores de 50 a±os’ and «Sexo» = ‘Mujer’ and
                                                    «Detalle Vuelo» = ‘VUELO52206’ and ROWID = ‘AAALV
                                                   mAAPAAAAn8AAB’;

insert into «DISCOVERER9I».»EUL5_MV101651″(«Import delete from «DISCOVERER9I».»EUL5_MV101651″ where «
e SUM»,»Importe COUNT»,»Importe MAX»,»Importe MIN» Importe SUM» = ‘123,29’ and «Importe COUNT» = ‘1’
,»Importe AVG»,»Ciudad»,»Pais»,»Rango Edad»,»Sexo» and «Importe MAX» = ‘123,29’ and «Importe MIN» = ‘
,»Detalle Vuelo») values (‘123,29′,’1′,’123,29′,’1 123,29’ and «Importe AVG» = ‘123,29’ and «Ciudad»
23,29′,’123,29′,’Madeira’,’Portugal’,’Mayores de 5 = ‘Madeira’ and «Pais» = ‘Portugal’ and «Rango Eda
0 a±os’,’Mujer’,’VUELO52331′);                     d» = ‘Mayores de 50 a±os’ and «Sexo» = ‘Mujer’ and
                                                    «Detalle Vuelo» = ‘VUELO52331’ and ROWID = ‘AAALV
                                                   mAAPAAAAn8AAC’;

insert into «DISCOVERER9I».»EUL5_MV101651″(«Import delete from «DISCOVERER9I».»EUL5_MV101651″ where «
e SUM»,»Importe COUNT»,»Importe MAX»,»Importe MIN» Importe SUM» = ‘178,55’ and «Importe COUNT» = ‘1’
,»Importe AVG»,»Ciudad»,»Pais»,»Rango Edad»,»Sexo» and «Importe MAX» = ‘178,55’ and «Importe MIN» = ‘
,»Detalle Vuelo») values (‘178,55′,’1′,’178,55′,’1 178,55’ and «Importe AVG» = ‘178,55’ and «Ciudad»
78,55′,’178,55′,’Madeira’,’Portugal’,’Mayores de 5 = ‘Madeira’ and «Pais» = ‘Portugal’ and «Rango Eda
0 a±os’,’Mujer’,’VUELO52419′);                     d» = ‘Mayores de 50 a±os’ and «Sexo» = ‘Mujer’ and
                                                    «Detalle Vuelo» = ‘VUELO52419’ and ROWID = ‘AAALV
                                                   mAAPAAAAn8AAD’;

insert into «DISCOVERER9I».»EUL5_MV101651″(«Import delete from «DISCOVERER9I».»EUL5_MV101651″ where «
e SUM»,»Importe COUNT»,»Importe MAX»,»Importe MIN» Importe SUM» = ‘107,36’ and «Importe COUNT» = ‘1’
,»Importe AVG»,»Ciudad»,»Pais»,»Rango Edad»,»Sexo» and «Importe MAX» = ‘107,36’ and «Importe MIN» = ‘
,»Detalle Vuelo») values (‘107,36′,’1′,’107,36′,’1 107,36’ and «Importe AVG» = ‘107,36’ and «Ciudad»
07,36′,’107,36′,’Madeira’,’Portugal’,’Mayores de 5 = ‘Madeira’ and «Pais» = ‘Portugal’ and «Rango Eda
0 a±os’,’Mujer’,’VUELO52488′);                     d» = ‘Mayores de 50 a±os’ and «Sexo» = ‘Mujer’ and
                                                    «Detalle Vuelo» = ‘VUELO52488’ and ROWID = ‘AAALV
                                                   mAAPAAAAn8AAE’;

insert into «DISCOVERER9I».»EUL5_MV101651″(«Import delete from «DISCOVERER9I».»EUL5_MV101651″ where «
e SUM»,»Importe COUNT»,»Importe MAX»,»Importe MIN» Importe SUM» = ‘120,5’ and «Importe COUNT» = ‘1’ a
,»Importe AVG»,»Ciudad»,»Pais»,»Rango Edad»,»Sexo» nd «Importe MAX» = ‘120,5’ and «Importe MIN» = ’12
,»Detalle Vuelo») values (‘120,5′,’1′,’120,5′,’120 0,5’ and «Importe AVG» = ‘120,5’ and «Ciudad» = ‘M
,5′,’120,5′,’Madeira’,’Portugal’,’Mayores de 50 a± adeira’ and «Pais» = ‘Portugal’ and «Rango Edad» =
os’,’Mujer’,’VUELO52561′);                          ‘Mayores de 50 a±os’ and «Sexo» = ‘Mujer’ and «De
                                                   talle Vuelo» = ‘VUELO52561’ and ROWID = ‘AAALVmAAP
                                                   AAAAn8AAF’;

insert into «DISCOVERER9I».»EUL5_MV101651″(«Import delete from «DISCOVERER9I».»EUL5_MV101651″ where «
e SUM»,»Importe COUNT»,»Importe MAX»,»Importe MIN» Importe SUM» = ‘109,01’ and «Importe COUNT» = ‘1’
,»Importe AVG»,»Ciudad»,»Pais»,»Rango Edad»,»Sexo» and «Importe MAX» = ‘109,01’ and «Importe MIN» = ‘
,»Detalle Vuelo») values (‘109,01′,’1′,’109,01′,’1 109,01’ and «Importe AVG» = ‘109,01’ and «Ciudad»
09,01′,’109,01′,’Madeira’,’Portugal’,’Mayores de 5 = ‘Madeira’ and «Pais» = ‘Portugal’ and «Rango Eda
0 a±os’,’Mujer’,’VUELO52690′);                     d» = ‘Mayores de 50 a±os’ and «Sexo» = ‘Mujer’ and
                                                    «Detalle Vuelo» = ‘VUELO52690’ and ROWID = ‘AAALV
                                                   mAAPAAAAn8AAG’;

insert into «DISCOVERER9I».»EUL5_MV101651″(«Import delete from «DISCOVERER9I».»EUL5_MV101651″ where «
e SUM»,»Importe COUNT»,»Importe MAX»,»Importe MIN» Importe SUM» = ‘174,91’ and «Importe COUNT» = ‘1’
,»Importe AVG»,»Ciudad»,»Pais»,»Rango Edad»,»Sexo» and «Importe MAX» = ‘174,91’ and «Importe MIN» = ‘
,»Detalle Vuelo») values (‘174,91′,’1′,’174,91′,’1 174,91’ and «Importe AVG» = ‘174,91’ and «Ciudad»
74,91′,’174,91′,’Madeira’,’Portugal’,’Mayores de 5 = ‘Madeira’ and «Pais» = ‘Portugal’ and «Rango Eda
0 a±os’,’Mujer’,’VUELO52693′);                     d» = ‘Mayores de 50 a±os’ and «Sexo» = ‘Mujer’ and
                                                    «Detalle Vuelo» = ‘VUELO52693’ and ROWID = ‘AAALV
                                                   mAAPAAAAn8AAH’;

insert into «DISCOVERER9I».»EUL5_MV101651″(«Import delete from «DISCOVERER9I».»EUL5_MV101651″ where «
e SUM»,»Importe COUNT»,»Importe MAX»,»Importe MIN» Importe SUM» = ‘131,5’ and «Importe COUNT» = ‘1’ a
,»Importe AVG»,»Ciudad»,»Pais»,»Rango Edad»,»Sexo» nd «Importe MAX» = ‘131,5’ and «Importe MIN» = ’13
,»Detalle Vuelo») values (‘131,5′,’1′,’131,5′,’131 1,5’ and «Importe AVG» = ‘131,5’ and «Ciudad» = ‘M
,5′,’131,5′,’Madeira’,’Portugal’,’Mayores de 50 a± adeira’ and «Pais» = ‘Portugal’ and «Rango Edad» =
os’,’Mujer’,’VUELO52951′);                          ‘Mayores de 50 a±os’ and «Sexo» = ‘Mujer’ and «De
                                                   talle Vuelo» = ‘VUELO52951’ and ROWID = ‘AAALVmAAP
                                                   AAAAn8AAI’;

9 filas seleccionadas.

Tremendas artimañas

En uno de los proyectos en los que estoy trabajando, los desarrolladores utilizan clandestinamente la herramienta TOAD para operar con la base de datos. Por un problema de licencias, se les ha pedido a los desarrolladores que no utilicen esta aplicación, y utilicen otros programas que, para lo que necesitan, cumplen la funcionalidad necesaria.

Parece que TOAD, de Quest, es una herramienta demasiado atractiva para algunos. Incluso ofreciendo alternativas gratuítas al respecto.

Tras comprobar que seguían utilizando TOAD, incluso contra las bases de datos de producción, decidimos implementar el siguiente trigger after logon:


create or replace trigger logon_program after logon on database
declare r_session v$session%rowtype;
begin
    — Tomamos info de la sesion que se conecta
    select * into r_session
    from v$session
    where audsid=userenv(‘SESSIONID’);
    
    if ((upper(r_session.program) like ‘%T%O%A%D%’)
           or (upper(r_session.program) like ‘%TOAD%’))
    then
           raise_application_error(-20002,’Hacking detected. Application not supported.’);
    end if;    
end;
/

No obstante, hay gente que se sigue resignando a usar sustitutivos a TOAD, y recurren a estratégias tan imaginativas como renombrar el ejecutable TOAD.EXE por SQLPLUSW.EXE

Vamos, casi ni se nota!


SQL> select sid, serial#, program, module, osuser from v$session;

       SID    SERIAL# PROGRAM                        MODULE                                        OSUSER
———- ———- —————————— ——————————————— ————–
         1          1 ORACLE.EXE                                                                   SYSTEM
         2          1 ORACLE.EXE                                                                   SYSTEM
         3          1 ORACLE.EXE                                                                   SYSTEM
         4          1 ORACLE.EXE                                                                   SYSTEM
         5          1 ORACLE.EXE                                                                   SYSTEM
         6          1 ORACLE.EXE                                                                   SYSTEM
         7          1 ORACLE.EXE                                                                   SYSTEM
         8          1 ORACLE.EXE                                                                   SYSTEM
        10       1293 jrew.exe                       jrew.exe                                      bbdd
        11        333 sqlplus.exe                    sqlplus.exe                                   bbdd
*       13        583 sqlplusw.exe                   T.O.A.D.                                      slaborda
        14          2 JDBC Thin Client               OWB Runtime Service – Infrastructure          SYSTEM
*       17       1091 sqlplusw.exe                   T.O.A.D.                                      slaborda
        18       1006 OraEdit.exe                    OraEdit.exe                                   bbdd
        19        385 QueryReporter.exe              PL/SQL Developer                              bbdd
*       22        819 sqlplusw.exe                   T.O.A.D.                                      slaborda
        23         30 PLSQLDev.exe                   PL/SQL Developer                              bbdd
        37         75 jrew.exe                       jrew.exe                                      fdomingues
*       44         21 FCBARCELONA5-REALMADRID0.exe   T.O.A.D.                                      slaborda
        53        196 JDBC Thin Client               JDBC Thin Client                              fdomingues
        61        413 JDBC Thin Client               JDBC Thin Client                              fdomingues
*       62         50 FCBARCELONA5-REALMADRID0.exe   T.O.A.D.                                      slaborda

22 filas seleccionadas.

Impresionante…

Clientes gratuitos. Clientes ligeros.

Uno de los principales problemas al desarrollar con PL/SQL sobre bases de datos es el uso de una buena herramienta de gestión del código. Los DBA’s estamos bastante acostumbrados a trabajar con SQL*Plus, la aplicación consola en modo texto, donde tecleamos con más o menos acierto el código SQL que necesitamos para ejecutar comandos de gestión.

No obstante, programar paquetes en PL/SQL donde puede haber miles de líneas de código, o ejecutar consultas sobre un número elevado de tablas, que pueden devolver un número también elevado de filas, implica necesitar un entorno un poco más cómodo para la programación de estos lenguajes contra la base de datos.

Todos los desarrolladores que conozco tienen predilección por Toad, de Quest Software. Lo entiendo. Es una de las mejores herramientas para desarrolladores y DBA’s que conozco. No obstante, es un cliente que lanza muchísimas consultas al diccionario por la gran cantidad de información que presenta y esto puede hacer que la aplicación funcione lenta al compilar, consultar dependencias de objetos y demás. Respecto al desarrollo, Toad no me parece la mejor aplicación para programar en PL/SQL.

Para los desarrolladores suelo recomendar PL/SQL Developer de Allround Automations. Mucho más ergonómica en la debugación, mayor comodidad en la gestión del código y, aunque no posea las herramientas de control de sesiones, comparación de base de datos o traceado de sesiones, lo cierto es que para el trabajo cotidiano del programador, la aplicación resulta mucho más cómoda.

No obstante, estas dos aplicaciones tienen un elevado coste de licencias que muchas empresas no pueden costearse. Mucho menos quien maneja Oracle para su aprendizaje, o programadores de otras áreas que puntualmente tienen que acceder a un servidor Oracle.

Para usuarios con una red lenta, que necesiten un cliente ligero o para programadores que únicamente necesiten ejecutar SQL plano a una base de datos, o para quienes no pueden permitirse licencias de Toad o PL/SQL Developer, aquí paso una relación de herramientas FREEWARE orientadas a plataformas Oracle y muy ligeras de instalar y ejecutar.

Query Reporter, de Allround Automations.

Se trata de una herramienta de SQL que genera los resultados en HTML. Muy cómoda, ligera y fácil de usar. El fabricante es el mismo que el de PL/SQL developer. Esta herramienta sería el «SQL Developer». Puede descargarse directamente aquí.

DBDesigner4, de Fabforce.

Herramienta CASE de modelaje de bases de datos. Cómoda y funcional, genera el código del modelo casi sin retoques. En esta página es posible descargar el programa para Windows y para Linux. Además, incluye manuales disponibles en HTML y PDF.

SQL Tools for Oracle, de SQLTools.

Esta herramienta de código abierto me ha sorprendido por lo versátil que es. Tanto permite sin más problemas resolver un plan de ejecución de una query como extraer la sentencia DDL de creación de un objeto y navegar por todos los objetos y sus dependencias de un usuario concreto. Una herramienta muy bien resuelta, con tutoriales en PDF. Puede descargarse aquí.

DB Comp, de Funduc.

Sobre esta herramienta poco tengo que decir, ya que no la he probado, pero es gratuita y los comentarios que he leído mencionan que es bastante buena. Puede descargarse aquí.

Espero que estos enlaces puedan resultar de utilidad a más de uno.

Búsquedas fuzzy, índices context y gestión documental con Oracle. Parte II.

(Continua a partir de parte I).

Recientemente he estado hablando con gente interesada en la gestión de contenidos de documentos y, en general, la mayoría utiliza formatos PDF. El anterior artículo se basaba únicamente en documentos word, y he creído interesante hacer un ejemplo de como Intermedia realiza la indexación de documentos word y PDF de forma totalmente transparente.

Algo importante a mencionar sobre los índices context es que éstos no se mantienen automáticamente con las inserciones. Hay una causa mayor referente al impacto del rendimiento que tendría dicha reconstrucción. En este caso, se incluyen seis nuevas filas BFILE vinculadas a ficheros PDF existentes en el mismo directorio. Posteriormente a la inserción, es preciso reconstruir el índice para recrearlo con la nueva relación de términos.

Para la implementación completa del ejemplo (creación de la tabla, el índice, el objeto directory y temas relativos a privilegios) es preciso seguir los pasos de la Parte I.

Pasos:

Parte I.

       1.- Creación de una tabla con columna BFILE
       2.- Creación de un DIRECTORY oracle para vincular los documentos Word.
       3.- Concesión de privilegios sobre el DIRECTORY al usuario CTXSYS, propietario de Oracle Context.
       4.- Inserción de las filas en la tabla DOCUMENTOS.
       5.- Indexación de la columna BFILE.
       6.- Ejemplos de consultas.

Parte II.

       7.- Inserción de las filas de documentos PDF.
       8.- Reconstrucción del índice context.
       9.- Ejemplos de consultas.


SQL> host dir c:documentos
El volumen de la unidad C no tiene etiqueta.
El número de serie del volumen es: 2416-B169

Directorio de c:documentos

09/05/2005  09:31       <DIR>          .
09/05/2005  09:31       <DIR>          ..
25/04/2005  13:21              271.360 EntornosNoProd_Permisos extendidos.doc
25/04/2005  13:21               31.232 normas_dba.doc
25/04/2005  13:21              379.904 creacion_entorno_bbdd.doc
25/04/2005  13:21              252.928 CREACION_INSTANCIA_DE_ORACLE_EN_UNIX_v2_4.doc              
04/06/2002  21:58            1.479.383 Oracle9i – New Features for Administrators – Vol I.pdf
04/06/2002  21:59            1.542.651 Oracle9i – New Features for Administrators – Vol II.pdf
04/06/2002  21:55            1.244.186 Oracle9i – New Features for Developers – Vol I.pdf
04/06/2002  21:57            2.342.972 Oracle9i – New Features for Developers – Vol II.pdf
04/06/2002  21:13            1.245.254 Oracle9i – New Features Overview – Vol I.pdf
04/06/2002  21:14              801.119 Oracle9i – New Features Overview – Vol II.pdf

10 archivos        9.935.424 bytes
               2 dirs   4.970.479.616 bytes libres

SQL> — Inserción de los seis documentos PDF sobre la tabla
SQL> — y recreación del índice CONTEXT
SQL> ———————————————————————————–
SQL> insert into documentos values
  2  (5,’PDF’,’Oracle9i – New Features for Administrators – Vol I.pdf’,
  3  BFILENAME(‘DOCUMENTOS_WORD’,’Oracle9i – New Features for Administrators – Vol I.pdf’));

1 row created.

SQL> insert into documentos values
  2  (6,’PDF’,’Oracle9i – New Features for Administrators – Vol II.pdf’,
  3  BFILENAME(‘DOCUMENTOS_WORD’,’Oracle9i – New Features for Administrators – Vol II.pdf’));

1 row created.

SQL> insert into documentos values
  2  (7,’PDF’,’Oracle9i – New Features for Developers – Vol I.pdf’,
  3  BFILENAME(‘DOCUMENTOS_WORD’,’Oracle9i – New Features for Developers – Vol I.pdf’));

1 row created.

SQL> insert into documentos values
  2  (8,’PDF’,’Oracle9i – New Features for Developers – Vol II.pdf’,
  3  BFILENAME(‘DOCUMENTOS_WORD’,’Oracle9i – New Features for Developers – Vol II.pdf’));

1 row created.

SQL> insert into documentos values
  2  (9,’PDF’,’Oracle9i – New Features Overview – Vol I.pdf’,
  3  BFILENAME(‘DOCUMENTOS_WORD’,’Oracle9i – New Features Overview – Vol I.pdf’));

1 row created.

SQL> insert into documentos values
  2  (10,’PDF’,’Oracle9i – New Features Overview – Vol II.pdf’,
  3  BFILENAME(‘DOCUMENTOS_WORD’,’Oracle9i – New Features Overview – Vol II.pdf’));

1 row created.

SQL> commit;

Commit complete.

SQL> ALTER INDEX idx_documentos_doc REBUILD;

Index altered.

— Las búsquedas CONTEXT sobre índices domain se realizan con la cláusula CONTAINS
— más documentación al respecto en   http://download-west.oracle.com/docs/cd/B10501_01/text.920/a96518/cqoper.htm )
————————————————————

— documentos con la palabra ‘tablespace’ cerca de ‘storage’
SQL> select tipo, titulo
  2  from documentos
  3  where CONTAINS(documento, ‘tablespace near storage’) &gt 0;

TIPO TITULO
—- ————————————————————
PDF  Oracle9i – New Features Overview – Vol II.pdf
PDF  Oracle9i – New Features Overview – Vol I.pdf
WORD Creación de instancia Oracle en UNIX.
WORD Normativa de DBA.

— documentos con una palabra parecida a ‘locally’ en un 70%
SQL> select tipo, titulo
  2  from documentos
  3  where CONTAINS(documento, ‘fuzzy(locally, 70, 6, weight)’, 1) &gt 0;

TIPO TITULO
—- ————————————————————
PDF  Oracle9i – New Features Overview – Vol II.pdf
PDF  Oracle9i – New Features Overview – Vol I.pdf
WORD Creación de un entorno de BBDD.

— documentos con una palabra parecida a ‘locally’ en un 60%
— nota: la palabra LOCAL aparece en estos dos nuevos documentos
SQL> select tipo, titulo
  2  from documentos
  3  where CONTAINS(documento, ‘fuzzy(locally, 60, 6, weight)’, 1) &gt 0;

TIPO TITULO
—- ————————————————————
PDF  Oracle9i – New Features Overview – Vol II.pdf
PDF  Oracle9i – New Features Overview – Vol I.pdf
WORD Creación de instancia Oracle en UNIX.
WORD Creación de un entorno de BBDD.
WORD Entornos no producción. Permisos extendidos.

— documentos que hablen sobre ‘listener’
SQL> select tipo, titulo
  2  from documentos
  3  where CONTAINS(documento, ‘about(listener)’) &gt 0;

TIPO TITULO
—- ————————————————————
PDF  Oracle9i – New Features Overview – Vol II.pdf
WORD Creación de instancia Oracle en UNIX.
WORD Normativa de DBA.

— relevancia de documentos que hablan de ‘listener’
— nota: en ‘Normativa de DBA’, efectivamente, se habla bastante menos sobre el listener.
SQL> select tipo, CONTAINS(documento, ‘about(listener)’)||’%’ relevancia, titulo
  2  from documentos
  3  where CONTAINS(documento, ‘about(listener)’) &gt 0;

TIPO RELEVANCIA TITULO
—- ———- ————————————————————
PDF  41%        Oracle9i – New Features Overview – Vol II.pdf
WORD 91%        Creación de instancia Oracle en UNIX.
WORD 23%        Normativa de DBA.


Más información en http://download-west.oracle.com/docs/cd/B10501_01/text.920/a96518/csql.htm#21732

Defragmentación de un tablespace mediante scripts.

En muchas ocasiones recurro a generar scripts a partir de consultas.
Ejecuto en SQL*Plus algo parecido a:


SQL> select ‘alter package ‘||owner||’.’||object_name||’ compile;’ sentencia
  2> from dba_objects where status=’INVALID’ and object_type =’PACKAGE BODY’;

SENTENCIA
——————————————————————
alter package USUARIO.MAP02_CUACON02 compile;
alter package USUARIO.MAP01_CUACON03 compile;
alter package USUARIO.MAP01_FLUXHISTO03_CI compile;
alter package USUARIO.MAP01_BALANCEBE03 compile;
alter package USUARIO.MAP01_PAHISTOACT03 compile;
alter package USUARIO.MAP01_RAPPELS03 compile;

6 filas seleccionadas.

y simplemente copio y pego las filas como comandos en la consola SQL.

El procedimiento podrá parecer tosco, pero resulta muy versátil ejecutar una consulta que construya dinámicamente todas las sentencias SQL que se precisan para una determinada tarea y, lo más importante, que se adapten a cualquier entorno.

Un ejemplo de ésto podría ser aplicado a la reorganización de los segmentos de un tablespace.

Para la defragmentación de un tablespace, los objetos deben reconstruirse de la siguiente forma:

   – Tablas:   ALTER TABLE xxxx MOVE STORAGE INITIAL tamaño K/M);
   – Índices:   ALTER INDEX xxxx REBUILD [online];
   – Tablas particionadas:  ALTER TABLE xxxx MOVE PARTITION …….;
   – Índices particionados: ALTER INDEX xxxx REBUILD PARTITION …… [online];

Teniendo en cuenta que mover una tabla en Oracle9i deja inválidos los índices, una vez ejecutados estos comandos por todas las tablas e índices del tablespace, sería preciso comprobar qué índices (o partitiones de índice) pueden haber quedado afectados y reconstruirlos.

Habría otro detalle a tener presente: los segmentos reconstruidos sobre el mismo tablespace, dificilmente consiguen liberar el espacio contiguo al final de los ficheros, por lo que sería útil hacer un doble movimiento: mover primero a un tablespace vacío, y posteriormente mover los objetos al tablespace original de vuelta.

Si bien esto no es complicado, sí resulta minucioso. Este script, en este caso, puede resultar tremendamente útil.

Una vez defragmentado el tablespace, es preciso ejecutar el segundo script para reconstruir índices, lo que evitará que éstos se queden inválidos después del transporte.

* Nota: Es preciso tener en cuenta el tamaño total de los objetos. Si éstos son grandes, conviene aumentar el tamaño definido como inicial. Lo mejor es utilizar tablespaces gestionados localmente con gestión automática de las extensiones para que Oracle decida, en tablas grandes, hacer extensiones mayores dinámicamente.


— DEFRAGMENTA_TABLESPACE.SQL —
set verify off
set lines 120
set pages 1000
define tablespace_origen =&TABLESPACE_DATOS
define tablespace_destino=&TABLESPACE_VACIO  
define t_extension_inicial=&TAMAÑO_EXTENSION_INICIAL
select ‘alter table ‘||owner||’.’||table_name||
       ‘ move tablespace &tablespace_destino storage (initial &t_extension_inicial M);’
from dba_tables
where upper(tablespace_name)=’&tablespace_origen’
union all
select ‘alter table ‘||table_owner||’.’||table_name||
       ‘ move partition ‘||partition_name||
       ‘ tablespace &tablespace_destino storage (initial &t_extension_inicial M);’
from dba_tab_partitions
where upper(tablespace_name)=’&tablespace_origen’
union all
select ‘alter index ‘||owner||’.’||index_name||
       ‘ rebuild tablespace &tablespace_destino storage (initial &t_extension_inicial M);’
from dba_indexes
where upper(tablespace_name)=’&tablespace_origen’
union all
select ‘alter index ‘||index_owner||’.’||index_name||
       ‘ rebuild partition ‘||partition_name||
       ‘ tablespace &tablespace_destino storage (initial &t_extension_inicial M);’
from dba_ind_partitions
where upper(tablespace_name)=’&tablespace_origen’
union all
select ‘alter table ‘||owner||’.’||table_name||
       ‘ move tablespace &tablespace_origen storage (initial &t_extension_inicial M);’
from dba_tables
where upper(tablespace_name)=’&tablespace_origen’
union all
select ‘alter table ‘||table_owner||’.’||table_name||
       ‘ move partition ‘||partition_name||
       ‘ tablespace &tablespace_origen storage (initial &t_extension_inicial M);’
from dba_tab_partitions
where upper(tablespace_name)=’&tablespace_origen’
union all
select ‘alter index ‘||owner||’.’||index_name||
       ‘ rebuild tablespace &tablespace_origen storage (initial &t_extension_inicial M);’
from dba_indexes
where upper(tablespace_name)=’&tablespace_origen’
union all
select ‘alter index ‘||index_owner||’.’||index_name||
       ‘ rebuild partition ‘||partition_name||
       ‘ tablespace &tablespace_origen storage (initial &t_extension_inicial M);’
from dba_ind_partitions
where upper(tablespace_name)=’&tablespace_origen’;

— RECONSTRUYE_INDICES.SQL —
select ‘alter index ‘||index_owner||’.’||index_name||
       ‘ rebuild partition ‘||partition_name||
       ‘ tablespace &tablespace_origen storage (initial &t_extension_inicial M);’ SENTENCIA
from dba_ind_partitions
where upper(tablespace_name)=’&tablespace_origen’
union all
select ‘alter index ‘||owner||’.’||index_name||’ rebuild;’
from dba_indexes
where status=’UNUSABLE’
union all
select ‘alter index ‘||index_owner||’.’||index_name||
       ‘ rebuild partition ‘||partition_name||’;’
from dba_ind_partitions
where status=’UNUSABLE’;

TEST
====
SQL> @c:reorganiza_tablespace
Introduzca un valor para tablespace_datos: DM_ACTIVIDAD01
Introduzca un valor para tablespace_vacio: TS_VACIO
Introduzca un valor para tama±o_extension_inicial: 1

‘ALTERTABLE’||OWNER||’.’||TABLE_NAME||’MOVETABLESPACETS_VACIOSTORAGE(INITIAL1M);’
————————————————————————————————————–
alter table USUARIO.TABLA_XXX02 move tablespace TS_VACIO storage (initial 1 M);
alter table USUARIO.TABLA_XXXX02 move tablespace TS_VACIO storage (initial 1 M);
alter table USUARIO.TABLA_XXXASMA02 move tablespace TS_VACIO storage (initial 1 M);
alter table USUARIO.TABLA_XXXXX02 move tablespace TS_VACIO storage (initial 1 M);
alter table USUARIO.TABLA_XXXXXX02 move tablespace TS_VACIO storage (initial 1 M);
alter table USUARIO.TABLA_XXXPMA02 move tablespace TS_VACIO storage (initial 1 M);
alter table USUARIO.TABLA_XXXP02 move tablespace TS_VACIO storage (initial 1 M);
alter table USUARIO.TABLA_XXXAS02 move tablespace TS_VACIO storage (initial 1 M);
alter table USUARIO.TABLA_XXXON02 move tablespace TS_VACIO storage (initial 1 M);
alter table USUARIO.TABLA_XXXPMES02 move tablespace TS_VACIO storage (initial 1 M);
alter table USUARIO.TABLA_XXXASMES02 move tablespace TS_VACIO storage (initial 1 M);
alter table USUARIO.TABLA_XXXCIBOSMES02 move tablespace TS_VACIO storage (initial 1 M);
alter table USUARIO.TABLA_XXXCIBOSMA02 move tablespace TS_VACIO storage (initial 1 M);
alter table USUARIO.TABLA_XXXCIBOS02 move tablespace TS_VACIO storage (initial 1 M);
alter table USUARIO.TABLA_XXXTASMES02 move tablespace TS_VACIO storage (initial 1 M);
alter table USUARIO.TABLA_XXXTAS02 move tablespace TS_VACIO storage (initial 1 M);
alter table USUARIO.TABLA_XXXTASMA02 move tablespace TS_VACIO storage (initial 1 M);
alter table USUARIO.TABLA_XXXXXXY02 move tablespace TS_VACIO storage (initial 1 M);
alter table USUARIO.TABLA_XXXMA02 move tablespace TS_VACIO storage (initial 1 M);
alter table USUARIO.TABLA_XXXMES02 move tablespace TS_VACIO storage (initial 1 M);
alter table USUARIO.TABLA_XXXACION02 move tablespace TS_VACIO storage (initial 1 M);
alter table USUARIO.TABLA_XXXACIONMA02 move tablespace TS_VACIO storage (initial 1 M);
alter table USUARIO.TABLA_XXXACIONMES02 move tablespace TS_VACIO storage (initial 1 M);
alter table USUARIO.TABLA_XXXTVS02 move tablespace TS_VACIO storage (initial 1 M);
alter table USUARIO.TABLA_XXXTVSMA02 move tablespace TS_VACIO storage (initial 1 M);
alter table USUARIO.TABLA_XXXTVSMES02 move tablespace TS_VACIO storage (initial 1 M);
alter table USUARIO.TABLA_XXXYY02 move tablespace DM_ACTIVIDAD01 storage (initial 1 M);
alter table USUARIO.TABLA_XXXY02 move tablespace DM_ACTIVIDAD01 storage (initial 1 M);
alter table USUARIO.TABLA_XXXASMA02 move tablespace DM_ACTIVIDAD01 storage (initial 1 M);
alter table USUARIO.TABLA_XXX02 move tablespace DM_ACTIVIDAD01 storage (initial 1 M);
alter table USUARIO.TABLA_XXX02 move tablespace DM_ACTIVIDAD01 storage (initial 1 M);
alter table USUARIO.TABLA_XXXPMA02 move tablespace DM_ACTIVIDAD01 storage (initial 1 M);
alter table USUARIO.TABLA_XXXP02 move tablespace DM_ACTIVIDAD01 storage (initial 1 M);
alter table USUARIO.TABLA_XXXAS02 move tablespace DM_ACTIVIDAD01 storage (initial 1 M);
alter table USUARIO.TABLA_XXXON02 move tablespace DM_ACTIVIDAD01 storage (initial 1 M);
alter table USUARIO.TABLA_XXXPMES02 move tablespace DM_ACTIVIDAD01 storage (initial 1 M);
alter table USUARIO.TABLA_XXXASMES02 move tablespace DM_ACTIVIDAD01 storage (initial 1 M);
alter table USUARIO.TABLA_XXXCIBOSMES02 move tablespace DM_ACTIVIDAD01 storage (initial 1 M);
alter table USUARIO.TABLA_XXXCIBOSMA02 move tablespace DM_ACTIVIDAD01 storage (initial 1 M);
alter table USUARIO.TABLA_XXXCIBOS02 move tablespace DM_ACTIVIDAD01 storage (initial 1 M);
alter table USUARIO.TABLA_XXXTASMES02 move tablespace DM_ACTIVIDAD01 storage (initial 1 M);
alter table USUARIO.TABLA_XXXTAS02 move tablespace DM_ACTIVIDAD01 storage (initial 1 M);
alter table USUARIO.TABLA_XXXTASMA02 move tablespace DM_ACTIVIDAD01 storage (initial 1 M);
alter table USUARIO.TABLA_XXX02 move tablespace DM_ACTIVIDAD01 storage (initial 1 M);
alter table USUARIO.TABLA_XXXMA02 move tablespace DM_ACTIVIDAD01 storage (initial 1 M);
alter table USUARIO.TABLA_XXXMES02 move tablespace DM_ACTIVIDAD01 storage (initial 1 M);
alter table USUARIO.TABLA_XXXACION02 move tablespace DM_ACTIVIDAD01 storage (initial 1 M);
alter table USUARIO.TABLA_XXXACIONMA02 move tablespace DM_ACTIVIDAD01 storage (initial 1 M);
alter table USUARIO.TABLA_XXXACIONMES02 move tablespace DM_ACTIVIDAD01 storage (initial 1 M);
alter table USUARIO.TABLA_XXXTVS02 move tablespace DM_ACTIVIDAD01 storage (initial 1 M);
alter table USUARIO.TABLA_XXXTVSMA02 move tablespace DM_ACTIVIDAD01 storage (initial 1 M);
alter table USUARIO.TABLA_XXXTVSMES02 move tablespace DM_ACTIVIDAD01 storage (initial 1 M);

52 filas seleccionadas.

Una vez ejecutados todos estos comandos, lanzamos el script que consulta los índices inválidos con el fin de recompilarlos.


SQL> @c:reconstruye_indices
SENTENCIA
——————————————————————-
alter index USUARIO.INDICEXXXOSP02_01 rebuild;
alter index USUARIO.INDICEXXXURAS02_01 rebuild;
alter index USUARIO.INDICEXXXSION02_01 rebuild;
alter index USUARIO.INDICEXXXOSPMES02_01 rebuild;
alter index USUARIO.INDICEXXXRECIBOS02_01 rebuild;
alter index USUARIO.INDICEXXXABTAS02_01 rebuild;
alter index USUARIO.INDICEXXXDA02_01 rebuild;
alter index USUARIO.INDICEXXXCIACION02_01 rebuild;
alter index USUARIO.INDICEXXXTVS02_01 rebuild;
alter index USUARIO.INDICEXXXTVSMA02_01 rebuild;
alter index USUARIO.INDICEXXXTVSMES02_01 rebuild;

11 filas seleccionadas.