viernes, 13 de noviembre de 2015

In-Database Archiving :: Oracle 12c :: New Features

:: In-Database Archiving :: Oracle 12c :: New Features ::

Hola gente,

Uno de los nuevos features más interesantes que me he encontrado en 12c es el In-Database Archiving(IDA) que les voy a comentar en esta entrada del blog.

La idea del IDA es ayudarnos un poco con el tema del archiving haciendo más simple la administración de la data. Para esto la data es dividida o marcada en "archived" o "active".

Vamos más a fondo, si la data es marcada como "archived" se vuelve invisible para la aplicación y es comprimida.... así o mas genial!!!, si es marcada como "active" nada pasa, es data normal.

Por supuesto vamos al ejemplo:

En nuestra instancia 12C vamos a usar el schema HR para nuestra prueba.

Creamos una tabla a partir de alguna data:
CREATE TABLE hr.empleados_ida_test
AS
   SELECT employee_id, first_name, last_name
      FROM hr.employees
    WHERE employee_id IN (100, 101, 102, 103, 104, 105,
                                               106,107,108,109,110);

Luego por supuesto habilitamos el feature sobre nuestra nueva tabla:

Alter table hr.empleados_ida_test ROW ARCHIVAL;

Cuando habilitamos el feature sobre la tabla, se agregan algunas columnas ocultas que son utilizadas para indicar el estado del row o registro.

Noten que si le damos un describe a la tabla todo sigue normal:









Si vamos a crear la tabla desde cero podemos habilitar el feature desde el inicio:
CREATE TABLE SCHEMA.NOMBRE (COL1 VARCHAR2 (5))
TABLESPACE TBS_TEST
ROW ARCHIVAL;

Revisemos a fondo la tabla usando la vista USER_TAB_COLS o DBA_TAB_COLS: 

  SELECT TABLE_NAME,
                  COLUMN_NAME,
                  COLUMN_ID,
                  HIDDEN_COLUMN
      FROM dba_tab_cols
   WHERE OWNER = 'HR' AND table_name = 'EMPLEADOS_IDA_TEST'
ORDER BY 3;









Notamos que aparecen dos bellas columnas ocultas en nuestra tabla: ORA_ARCHIVE_STATE y SYS_NC00004$.

Ahora juguemos con la data:

Consultemos la tabla con un bello y simple:
SELECT * FROM HR.EMPLEADOS_IDA_TEST;

Vemos que nos retorna los 11 registros.

















Ahora resulta que queremos ocultar algunos registros dado que no los vamos a considerar en nuestra app por algún tiempo o hasta nuevo aviso, para esto utilizamos el paquete DBMS_ILM.ARCHIVESTATENAME donde le indicamos con el parámetro 0 que el registro es visible o con 1 que es invisible.

UPDATE HR.EMPLEADOS_IDA_TEST
   SET ORA_ARCHIVE_STATE = DBMS_ILM.ARCHIVESTATENAME (1)
 WHERE EMPLOYEE_ID IN (100,
                       101,
                       102,
                       103);

COMMIT;


Importante considerar que el registro sigue existiendo, lógicamente las operaciones que involucren validaciones contra la primary key siguen realizándose. Simplemente la data esta comprimida y no es visible.

Hagamos de nuevo un query en la tabla:
SELECT * FROM HR.EMPLEADOS_IDA_TEST;

Vemos que nos retorna 7 registros y no 11.















Los 7 registros que nos retorna son aquellos donde la columna ORA_ARCHIVE_STATE es igual a cero (Visible).











Si quisiera ver toda la data puedo indicarle a mi session que use las "gafas de visión de cosas invisibles" de la siguiente manera:

ALTER SESSION SET ROW ARCHIVAL VISIBILITY=ALL;



















Para volver a la "visión normal" y poder visualizar únicamente los registros en estado Active le hacemos un alter a la session:

ALTER SESSION SET ROW ARCHIVAL VISIBILITY=ACTIVE;

















Recuerden que los registros simplemente se encuentran en un estado Archive, esto no quiere decir que no existan. Las validaciones se siguen realizando sobre los mismos. 

Veamos un ejemplo considerando la Pk:

--Agrego un pk a mi tabla:

SQL> ALTER TABLE HR.EMPLEADOS_IDA_TEST
          ADD PRIMARY KEY (EMPLOYEE_ID);

--Ingresamos un registro que considere un valor de pk de un registro existente y en estado Archive:

SQL> INSERT INTO HR.EMPLEADOS_IDA_TEST VALUES(101, 'MIGUEL','VEGA');
INSERT INTO HR.EMPLEADOS_IDA_TEST VALUES(101, 'MIGUEL','VEGA')
*
ERROR en linea 1:
ORA-00001: restriccion unica (HR.SYS_C0010036) violada

Y por supuesto la afectación a nivel de explain plan es mínima por no decir nula o casi imperceptible:

Explain plan del query mostrando 11 registros:

Explain plan del query mostrando 7 registros:




Espero que esta nota les sea de utilidad.

Saludos cordiales,

Miguel Vega

miércoles, 11 de noviembre de 2015

Crear particiones con o sin indices :: Oracle 12c :: New Features

:: Crear particiones con o sin indices :: Oracle 12c :: New Features

Saludos gente,

Este feature esta buenísimo, los que trabajamos con las particiones como DBA's Oracle sabemos que algunas veces seria mejor apagar ciertos indices sobre ciertas particiones.... esto por supuesto por una cantidad de temas: ahorro del espacio, muchas veces el indice no se necesita en todas las particiones, rendimiento(no le podemos andar metiendo mano al código pl/sql de la aplicación, a veces el indice ayuda y aveces no, etc, etc).

La gente de Oracle se invento en 12c este nuevo feature que nos permite sacarle provecho a los "indices parciales".

Con este feature cuando la clausula indexing off es establecida sobre una partición, la misma no va a tener particiones de indices disponibles, sea un indice parcial o global, particionado o no el indice. No hay data que considerar a nivel de indexado, dado que apagamos la data del Indice por decirlo de alguna manera.

Vamos al ejemplo:

Acá creamos la tabla HR,Productos particionada por "fecha_recepción":

CREATE TABLE hr.productos
(
   product_id        NUMBER,
   product_name      VARCHAR2 (15),
   fecha_recepcion   DATE,
   desc_producto     VARCHAR2 (255)
)
INDEXING OFF // *1
PARTITION BY RANGE
   (fecha_recepcion)
   (
      PARTITION
         PART_2011 VALUES LESS THAN (TO_DATE ('01-01-2012', 'DD-MM-YYYY')) INDEXING OFF,
      PARTITION
         PART_2012 VALUES LESS THAN (TO_DATE ('01-01-2013', 'DD-MM-YYYY')) INDEXING ON,
      PARTITION
         PART_2014 VALUES LESS THAN (TO_DATE ('01-01-2014', 'DD-MM-YYYY')))
ENABLE ROW MOVEMENT;

Acá pueden notar lo siguiente:


  • Primero nos encontramos un gran INDEXING OFF, que indica el estado default para los indices asociados a la partición de la tabla que no tenga la clausula indexing off/on especificada. (Ver *1)
  • Luego nos encontramos el INDEXING OFF o INDEXING ON que indica finalmente si la partición debe considerar indices o no.


Revisemos a fondo si las particiones pueden quedar indexadas o no:

SELECT table_name, partition_name, indexing
  FROM dba_tab_partitions
 WHERE table_name = 'PRODUCTOS'

Ahora creamos un indices global full y otro global partial:

CREATE INDEX idnx_full
   ON hr.productos (product_id)
   GLOBAL indexing full;

CREATE INDEX idnx_partial
   ON hr.productos (product_name)
   GLOBAL indexing partial;

Revisamos a fondo:
SELECT table_name, index_name, indexing
  FROM dba_indexes
 WHERE table_name = 'PRODUCTOS';

Ingresemos alguna data loca, un registro por partición:

Insert into HR.PRODUCTOS
   (PRODUCT_ID, PRODUCT_NAME, FECHA_RECEPCION, DESC_PRODUCTO)
 Values
   (3, 'Mermelada', TO_DATE('11/09/2011 00:00:00', 'MM/DD/YYYY HH24:MI:SS'), 'Producto para el pan');
Insert into HR.PRODUCTOS
   (PRODUCT_ID, PRODUCT_NAME, FECHA_RECEPCION, DESC_PRODUCTO)
 Values
   (2, 'Gel', TO_DATE('11/10/2012 00:00:00', 'MM/DD/YYYY HH24:MI:SS'), 'Producto para el cabello');
Insert into HR.PRODUCTOS
   (PRODUCT_ID, PRODUCT_NAME, FECHA_RECEPCION, DESC_PRODUCTO)
 Values
   (1, 'Shampoo', TO_DATE('11/11/2013 00:00:00', 'MM/DD/YYYY HH24:MI:SS'), 'Producto para el cabello');
COMMIT;


Ahora si, activen el auto trace on y revisen los explain plan de los querys. Y la data generada indexada o no.

Espero que les sea de utilidad.

Saludos a todos,

Miguel Vega





Mover una partición de tabla online :: Oracle 12c :: New Feature

Mover una partición de tabla online :: Oracle 12c :: New Feature

Hola gente,

Para los que trabajamos con muchísimos datos, acá les paso otro new feature:
Como mover una partición de tabla online con Oracle 12c.

Primero recuerden para tener particionamiento deben usar la versión Enterprise de Oracle y tener habilitado el particionamiento.... si por ambos tienen que pagar un montón de dinero en sus ambientes productivos, pero vale la pena si manejan millones de millones de registros.

Vamos de una vez al ejemplo:

Imaginemos que tenemos una partición de tabla muy importante para nuestro negocio, muy "hot" y queremos moverla a un dispositivo en el storage mas rápido.

Primero lógicamente creamos el nuevo tablespace en el dispositivo rápido. Pero viene el inconveniente que tenemos la necesidad de mover la partición online dado que NO podemos sacar a los usuarios, ni mucho menos detener la operativa de la empresa. Acá aparece el nuevo feature a salvarnos.

Creamos el tablespace target al cual queremos mover nuestra partición de forma online.

##En mi ambiente de test no tengo FLASH Device ni ASM = (, pero se lo imaginan ni modo.

CREATE TABLESPACE tbs_target DATAFILE
  '/u01/app/oracle/oradata/bdOrcl/pdbdemo/tbs_target01.dbf' 
  SIZE 1M AUTOEXTEND ON NEXT 1M MAXSIZE UNLIMITED
LOGGING
EXTENT MANAGEMENT LOCAL AUTOALLOCATE
BLOCKSIZE 8K
SEGMENT SPACE MANAGEMENT AUTO

FLASHBACK ON;

Creamos una tabla con una partición donde ejecutar nuestra prueba:

CREATE TABLE hr.facturas
(
   fac_numero     NUMBER (10) NOT NULL,
   id_cliente     VARCHAR2 (10) NOT NULL,
   fecha          DATE NOT NULL
)
PARTITION BY RANGE
   (fecha)
   INTERVAL ( NUMTODSINTERVAL (7, 'day') )
   (
      PARTITION
         p_antes_01_JAN_1982
         VALUES LESS THAN (TO_DATE ('01-01-1982', 'dd-mm-yyyy')))

ENABLE ROW MOVEMENT;

Insertamos un poco de registros, en mi caso inserte 2500 registros de la siguiente manera... ojo es data loca.

DECLARE
   V_CONSECUTIVO   NUMBER (5);
   V_FECHA         DATE;
   XY              NUMBER (10);
BEGIN
   V_CONSECUTIVO := 1000;
   V_FECHA := SYSDATE - 12500; -- Antes de 1982, jueguen con las fechas en su carga de datos.

   FOR X IN 1 .. 500
   LOOP
      INSERT INTO HR.FACTURAS (FAC_NUMERO, ID_CLIENTE, FECHA)
           VALUES (V_CONSECUTIVO, V_CONSECUTIVO, V_FECHA);

      V_CONSECUTIVO := V_CONSECUTIVO + 1;
      V_FECHA := V_FECHA + 1;
   END LOOP;

   COMMIT;

END;

Ejecutamos las estadísticas en la tabla:

execute dbms_stats.gather_table_stats('HR','FACTURAS')

Revisamos las particiónes, tablespaces y el numero registros que tengo de la tabla FACTURAS:

SELECT partition_name, num_rows, tablespace_name
  FROM DBA_tab_partitions
 WHERE table_name = 'FACTURAS'

 ORDER BY 2 DESC;


Ojo
Para los que se preguntan en que momento cree las 340 restantes particiones, la respuesta es muy simple... use el feature INTERVAL durante la creación de la tabla, el cual va creando particiones en el momento en que lo necesita, caso contrario tendría que haber creado esa cantidad de particiones de tabla de forma manual o el insert de los nuevos registros que se encuentran fuera del rango daría error.

Ahora si el momento de la verdad, muevo la partición de la tabla de forma ONLINE:

 ALTER TABLE hr.facturas
 MOVE PARTITION p_antes_01_jan_1982 COMPRESS BASIC
 TABLESPACE tbs_target
 UPDATE INDEXES ONLINE;

Revisamos de nuevo las particiones de la tabla:
SELECT partition_name, num_rows, tablespace_name
  FROM DBA_tab_partitions
 WHERE table_name = 'FACTURAS'

 ORDER BY 2 DESC;




Y como pueden notar el tablespace de la partición "P_ANTES_01_JAN_1982" es ahora TBS_TARGET.

Y colorin colorado este cuento se ha acabado.

Suerte a todos,

Miguel Vega


martes, 10 de noviembre de 2015

With Clause :: New Feature :: 12c

:: With Clause :: New Feature :: 12c

Algunos amigos no conocen mucho la clausula with, la cual es conocida como la clausula "subquery factoring clause".

En resumen y para no irme en mucha charla técnica, la clausula pre-materializa los resultados de los querys(los subquerys son prematerializados) antes de que los mismos sean ejecutados.

Veamos este tema con números mejor.

Utilizando el schema de ejemplo HR ejecutamos y analizamos el siguiente query:

SELECT a.first_name, b.DEPARTMENT_NAME
  FROM hr.employees a, hr.departments b
 WHERE     a.department_id = b.department_id

       AND b.department_id < (SELECT AVG (department_id) FROM hr.departments);

El plan de ejecución es el siguiente:


Ahora utilizando la clausula With:

WITH TEMP_TABLE
     AS (SELECT AVG (department_id) DEPT_RESULT FROM hr.departments)
SELECT a.first_name, b.DEPARTMENT_NAME
  FROM hr.employees a, hr.departments b, TEMP_TABLE C
 WHERE a.department_id = b.department_id AND b.department_id < C.DEPT_RESULT

El plan de ejecución es el siguiente:



El costo en bytes pasa de 338 a 195, y aunque para este ejemplo pareciera poco. En un ambiente con millones de registros, operaciones, etc, etc la ganancia seria muy representativa y va a implicar una enorme mejoría en performance.

Saludos cordiales,

Miguel Vega

Como instalar los schemas de ejemplo :: Oracle 12c ::

Como instalar los schemas de ejemplo en Oracle Database 12c

Hace algunos día una compañero me envió un email, preguntándome como podemos crear los schemas de ejemplo en 12c si no los elegimos durante la creación de la instancia.


Es simple, lo primero que tenemos que hacer es instalar el paquete de ejemplos, descargamos el software desde el sitio de Oracle:

http://www.oracle.com/technetwork/database/enterprise-edition/downloads/database12c-linux-download-2240591.html



Pasamos el software via ftp, usb o disco al server.

Posteriormente ejecutamos el unzip -t linuxamd64_12102_examples.zip para revisar que el software se pasara a nuestro servidor sin problema algún. No queremos que la perdida de bits nos hagan una mala broma.


La comprobación nos debe salir sin errores y todo OK.


Ahora descomprimimos el software con  unzip linuxamd64_12102_examples.zip

Tenemos como siempre que exportar el ambiente gráfico o ingresar al server. También lo podemos hacer en modo silencioso. En mi caso para documentarles el proceso utilizo el ambiente gráfico:

Ahora estamos listos para ejecutar el ./runInstaller


En la siguiente pantalla es importante seleccionar bien el Oracle Home donde tenemos instalado el 12c:

Revisión de pre requisitos:


Resumen de la instalación: 



Avance de la instalación:



Fin de la instalación de los schemas de ejemplo:


Posteriormente tenemos que instalar los schemas de ejemplo de manera manual.
En la ruta $ORACLE_HOME/demo/schema van a encontrar los scripts para instalar los schemas de ejemplo que deseen.

En mi caso voy a instalar en mi pluggable pdbdemo el schema HR:

[oracle@poas12c schema]$ . oraenv
ORACLE_SID = [bdOrcl] ? bdOrcl -- Es el nombre de mi instancia
The Oracle base remains unchanged with value /u01/app/oracle
[oracle@poas12c schema]$ sqlplus / as sysdba

SQL*Plus: Release 12.1.0.2.0 Production on Tue Nov 10 12:54:24 2015

Copyright (c) 1982, 2014, Oracle.  All rights reserved.

Conectado a:
Oracle Database 12c Enterprise Edition Release 12.1.0.2.0 - 64bit Production
With the Partitioning, OLAP, Advanced Analytics and Real Application Testing options

SQL> alter session set container=PDBDEMO;
Sesion modificada.

SQL> @/u01/app/oracle/product/12.1.0.2/db_1/demo/schema/human_resources/hr_main.sql

specify password for HR as parameter 1:
Introduzca un valor para 1: hr

specify default tablespeace for HR as parameter 2:
Introduzca un valor para 2: tbs_test

specify temporary tablespace for HR as parameter 3:
Introduzca un valor para 3: temp

specify password for SYS as parameter 4:
Introduzca un valor para 4: xxxxxxxx

specify log path as parameter 5:
Introduzca un valor para 5: $ORACLE_HOME/demo/schema/log

Listo es todo.

Pueden encontrar mas info sobre los schemas de ejemplo en los sitios oficiales de Oracle:

12c: http://docs.oracle.com/database/121/COMSC/installation.htm#COMSC001

11g: http://docs.oracle.com/cd/E11882_01/server.112/e10831/installation.htm#COMSC001

Saludos cordiales,

Miguel Vega



New Features Oracle 12c :: Crear multiples indices en el mismo set de columnas ::

Hola gente,

Saludos a todos,

Varios amigos me han solicitado compartir un poco de mis largas lecturas de libros y exploración de productos Oracle. Mas aun, considerando que nunca les publique todo lo que pude investigar y aprendí de Oracle Times Ten.... queda pendiente!!!

Así que para compartir un poco he decidido comenzar a escribirles sobre los new features de Oracle database 12c.

Hablemos de: :: Crear multiples indices en el mismo set de columnas  :: 

Con Oracle 12c tenemos la opción de crear múltiples indices en el mismo set o listado de columnas. 

Para los que somos Oracle DBA's suena extraño eso, de hecho no se podía realizar en versiones anteriores, pero ya es posible realizarlo en 12c.

 Veamos un ejemplo:

CREATE TABLE alumnos
(
   alum_id     NUMBER,
   nombre      VARCHAR2 (150),
   apellido1   VARCHAR2 (150),
   apellido2   VARCHAR2 (150),
   ingreso     DATE,
   estado      CHAR (1)
);

 ---Primer indice
 CREATE INDEX idx_alumnos_01 ON alumnos (alumn_id, estado);

 --Tenemos que poner nuestro primer indice invisible para que podamos crear un segundo indice.
ALTER INDEX idx_alumnos_01 INVISIBLE

--Creación del segundo indice utilizando las mismas columnas y el mismo orden.
CREATE BITMAP INDEX idx_alumnos_bit_02 ON alumnos (alumn_id, estado);


Para que nos sirve esto?

Primero pensemos en disponibilidad. Tenemos la opción de "transformar" un indice B-Tree a Bitmap sin afectar nuestra operativa(posteriormente borraríamos el indice anterior y haríamos visible el nuevo indice). O supongamos que necesitamos tomar un indice no particionado y particionarlo sin afectar la operación.

También nos resulta genial, para evaluar cual de los tipos de indices nos brinda un mejor performance, mas considerando el enorme listado de tipos de indices que podemos crear: B-Tree, Index Organized Table, Unique, Reverse-Key, Key-Compressed, Descending, Bitmap, Bitmap Join, Function-Based, Indexed Virtual Columns, Virtual, Invisible, Global Partitioned, Local partitioned, Domain, B-tree cluster, Hash Cluster..... se me olvido algún otro?, creo que no.

Consideraciones:
Oracle les va a permitir esto siempre y cuando se cumplan las siguientes condiciones,

  • Los indices son de tipo diferente.
  • Los indices usan diferentes particiones.
  • Los indices tienen diferentes propiedades de unicidad.


Espero que la pequeña nota les sea de utilidad.

Saludos cordiales,

Miguel Vega