11 de octubre de 2018

ODC Appreciation Day: Minimizando contención con “scalable sequences” en Oracle 18c

Es la primera vez que participo en el Oracle Development Community Appreciation Day, promovido por Tim Hall  para contribuir con la comunidad publicando algo de información sobre la tecnología Oracle que utilizamos a diario. 
En mi caso, trataré en este artículo una nueva funcionalidad incorporada en el último release de Oracle Database 18c.

Con la versión 18.1, se ha introducido una nueva funcionalidad en la base de datos Oracle: Las  "secuencias escalables” o en inglés  "Scalable Sequences".
Se trata de la capacidad de poder crear secuencias escalables para mejorar el rendimiento durante la carga masiva de datos, en tablas que utilizan como claves el valor generado por una secuencia. Las secuencias escalables optimizan el proceso de generación de valores secuenciales mediante el uso de una combinación única del número de instancia y el número de sesión para minimizar la contención sobre los bloques “leaf” en índices durante cargas masivas. Esta es una de las pocas funciones que no es habilita automáticamente y requiere la intervención del DBA para garantizar que su implementación no afecte ni cambie la lógica de negocio necesaria.
Por su parte, desde el punto de vista de negocio, esta funcionalidad brinda una mejora notable en los procesos de carga masiva de datos al reducir, como comenté anteriormente, la contención generada al insertar  datos en tablas que utilizan valores de secuencia.
Al incorporar la capacidad de poder crear valores de secuencias con componente de instancia e identificadores de sesión agregados al valor propio de la secuencia, la contención en la generación  y en las inserciones en bloques de índice para los valores clave, se reduce significativamente. Esto significa que Oracle Database es aún más escalable para la carga de datos y puede admitir tasas de rendimiento en este tipo de operaciones todavía más altas.
La sintaxis para definir una secuencia como escalable es la siguiente:

create /alter  sequence nombre_de_secuencia  scale [extend | noextend] | noscale
  
CREATE | ALTER SEQUENCE [ schema. ]sequence
[ { INCREMENT BY | START WITH } integer
| { MAXVALUE integer | NOMAXVALUE }
| { MINVALUE integer | NOMINVALUE }
| { CYCLE | NOCYCLE }
| { CACHE integer | NOCACHE }
| { ORDER | NOORDER }
| { SCALE {EXTEND | NOEXTEND} | NOSCALE}

SCALE / NOSCALE
Cuando se especifica la opción SCALE,  se establece un prefijo numérico al comienzo de la secuencia (por defecto de 6 dígitos) con el formato:
 [ iii || sss || ... ]
En donde "iii" determina un offset de 3 dígitos, correspondiente al id de instancia, dado por [(id de instancia% 100) + 100] y  "sss" es un offset, también de tres dígitos, correspondiente al ID de sesión, dado en este caso por [id de sesión% 1000]. Finalmente “||” es el operador de concatenación usado entre iii,sss y el valor de la secuencia.
Resumiendo entonces, de los 6 dígitos usados por el offset,  tres dígitos corresponden al número de instancia y tres al ID de sesión.

EXTEND/NOEXTEND
Cuando se especifica EXTEND junto a la palabra clave SCALE, los valores de secuencia generados son todos de longitud (x + y), donde “x” es la longitud del desplazamiento escalable (valor predeterminado 6), e “y”es el número máximo de dígitos en la secuencia acorde al valor máximo. Por lo tanto, para una secuencia ascendente con un valor máximo de 100 y SCALABLE EXTEND especificados, los valores de secuencia generados son de la forma:
 iii || sss || 001, iii || sss || 002,…, iii || sss || 100

La configuración predeterminada para la cláusula SCALE es NOEXTEND. Con la configuración NOEXTEND, los valores de secuencia generados son a lo sumo tan anchos como el número máximo de dígitos en la secuencia maxvalue/minvalue. La base de datos agrega la escala de 6 dígitos en la parte superior del dígito para el valor máximo. Esta configuración es útil para la integración con aplicaciones existentes donde las secuencias se utilizan para rellenar columnas de ancho fijo. Al invocar NEXTVAL en una secuencia con SCALABLE NOEXTEND especificado, se genera un error de usuario si el valor generado requiere más dígitos de representación que el valor máximo/mínimo de la secuencia.

La adición de 100 en la generación iii garantiza que todos los valores generados tengan la misma longitud y, por lo tanto, no habrá duplicados en los valores generados en todas las instancias.

La longitud predeterminada del desplazamiento de secuencia escalable es 6.
Así que en el siguiente ejemplo, la secuencia escalable será de 13 dígitos (número de desplazamiento escalable de 6 dígitos + valor máximo de 7 dígitos)

Algunos ejemplos:

Datos de la sesión que usaremos:

SQL> select instance_number from v$instance;
INSTANCE_NUMBER
---------------
1

SQL> select sys_context('userenv','sid') from dual;
SYS_CONTEXT('USERENV','SID')
---------------------------------------------
34

Creamos una secuencia estándar:

SQL> create sequence tst_sequence;
Sequence created.

Verificamos que no tiene habilitadas las opciones SCALE y EXTEND:

SQL> select sequence_name, scale_flag, extend_flag from user_sequences;

SEQUENCE_NAME  S E 
------------- -- --
TST_SEQUENCE   N N

Creamos ahora la secuencia con máximo default (9999999999999999999999999999-28 digitos) y SCALE habilitado pero no EXTEND

SQL> create sequence tst_sequence scale;
Sequence created.

Verificamos:

SQL> select sequence_name,max_value,scale_flag, extend_flag from user_sequences;
SEQUENCE_NAME  MAX_VALUE                     S E
-------------  ---------------------------  -- --
TST_SEQUENCE   9999999999999999999999999999  Y N

Al no estar habilitado EXTEND utiliza SCALE iii/sss en la parte superior del máximo (28 digitos)

SQL> select tst_sequence.nextval from dual;
NEXTVAL
----------------------------
1010340000000000000000000001

Creamos ahora la secuencia con maxvalue en 9999999(7 digitos) y scale extend habilitado:

SQL> create sequence test_seq maxvalue 9999999 scale extend;
Sequence created.

El numero de secuencia es entonces 0000001 y se agrega en la parte superior los 6 digitos correspondientes a sesión 034 e instancia 101(instance_id + 100)

SQL> select test_seq.nextval from dual;
NEXTVAL
-------------
1010340000001

En el siguiente caso, el maxvalue es 9999999, scale y extend habilitado.

SQL> create sequence test_seq maxvalue 9999999 scale extend;
Sequence created.

Al estar habilitado EXTEND se adiciona a los 3 digitos del maxvalue(100)el numero de sesión e instancia.

SQL> select test_seq.nextval from dual;
NEXTVAL
-----------
1010340000001

Si por el contrario se especifica NOEXTEND, el offset de instancia (iii) y sesión (sss) van a ser contemplado en el maxvalue que es de 100(3 digitos) por lo tanto nos va a devolver un error:

SQL> create sequence seq_noextend start with 1 increment by 1 minvalue 1 maxvalue 100 scale noextend;
Sequence created.

SQL> select seq_noextend.nextval from dual;
select seq_noextend.nextval from dual
*
ERROR at line 1:
ORA-64603: NEXTVAL cannot be instantiated for SEQ_NOEXTEND. Widen the sequence by 4 digits or alter sequence with SCALE EXTEND.

En este caso, creamos la secuencia con un máximo de 9999999 (7 digitos) como indicamos extent a scale

Se puede realizar un alter de las cláusulas “extend” y “noextend” y también de puede cambiar una secuencia escalable a secuencia normal y viceversa.
Oracle recomienda que no especifique ordenamiento  para una secuencia escalable, ya que los números de secuencia escalables están desordenados a nivel global.

SQL> alter sequence test_seq maxvalue 9999999 scale noextend;
Sequence altered.

SQL> alter sequence test_seq maxvalue 9999999 noscale;
Sequence altered.

SQL> alter sequence test_seq maxvalue 9999999 scale;
Sequence altered.

Espero les resulte interesante.

No hay comentarios:

Publicar un comentario