En PL/SQL, la ejecución de instrucciones en paralelo puede mejorar significativamente el rendimiento de las operaciones que implican grandes volúmenes de datos. Una técnica común para lograr esto es dividir los datos en «chunks» o trozos más pequeños y procesarlos de manera concurrente. En esta entrada vamos aprender cómo implementar esta estrategia y cómo puede beneficiar nuestras aplicaciones.

En qué nos ayuda la ejecución de instrucciones en paralelo?

La ejecución en paralelo permite aprovechar al máximo la capacidad de procesamiento de la base de datos al distribuir la carga de trabajo entre múltiples procesos. Esto es especialmente útil en situaciones donde una sola tarea podría tomar demasiado tiempo, como en operaciones de carga masiva, transformación de datos o procesamiento por lotes.

Nota: El uso de chunks esta disponible apartir de la versión 11g de base de datos.

Dividir los datos en chunks

La clave para ejecutar instrucciones en paralelo es dividir los datos en chunks manejables. Puedes hacerlo utilizando una combinación de cláusulas SQL como ROWNUM, ROWID o utilizando alguna lógica de partición específica de tu aplicación.

Por ejemplo, supongamos que deseas procesar una tabla mi_tabla con millones de registros. Puedes dividir estos registros en chunks de 1000 registros cada uno de la siguiente manera:

DECLARE
    CURSOR c_datos IS
        SELECT *
        FROM mi_tabla;
    TYPE t_datos IS TABLE OF c_datos%ROWTYPE;
    v_datos t_datos;
BEGIN
    OPEN c_datos;
    LOOP
        FETCH c_datos BULK COLLECT INTO v_datos LIMIT 1000;
        EXIT WHEN v_datos.COUNT = 0;
        
        -- Procesar los datos en paralelo
        FOR i IN 1..v_datos.COUNT LOOP
            -- Procesar cada registro de v_datos
            NULL;
        END LOOP;
    END LOOP;
    CLOSE c_datos;
END;

En este ejemplo, se procesan 1000 registros a la vez, pero puedes ajustar el tamaño del chunk según tus necesidades y la capacidad de tu sistema.

Tipos de ejecución en paralelo

CREATE_CHUNKS_BY_ROWID

CREATE_CHUNKS_BY_ROWID se basa en los ROWIDs de la tabla, lo que significa que cada chunk está definido por un rango de ROWIDs. Esto es útil cuando necesitas dividir una tabla en chunks de tamaño fijo sin tener en cuenta el contenido de las filas.

CREATE_CHUNKS_BY_SQL

CREATE_CHUNKS_BY_SQL permite definir los chunks basados en cualquier consulta SQL, lo que brinda mucha más flexibilidad para definir cómo se dividen los datos. Puede filtrar filas, ordenarlas, agruparlas, etc., antes de crear los chunks, lo que puede ser útil en situaciones más complejas.

Ejecución en paralelo usando CREATE_CHUNKS_BY_ROWID

Una vez que tengamos divididos los datos en chunks, se puede procesar cada chunk en paralelo utilizando procesos concurrentes. En Oracle Database, se puede lograr esto utilizando DBMS_PARALLEL_EXECUTE o mediante procesamiento en paralelo directamente en las consultas SQL.

Por ejemplo, utilizaremos la instrucción DBMS_PARALLEL_EXECUTE para ejecutar un procedimiento en paralelo para cada chunk:

DECLARE
    l_task_name VARCHAR2(255) := 'mi_tarea';
BEGIN
    DBMS_PARALLEL_EXECUTE.CREATE_TASK(task_name => l_task_name);
    DBMS_PARALLEL_EXECUTE.CREATE_CHUNKS_BY_ROWID(
        task_name => l_task_name,
        table_owner => 'USUARIO',
        table_name => 'MI_TABLA',
        by_row => TRUE,
        chunk_size => 1000
    );
    DBMS_PARALLEL_EXECUTE.RUN_TASK(
        task_name => l_task_name,
        sql_stmt => 'BEGIN MI_PROCEDIMIENTO(:start_id, :end_id); END;',
        language_flag => DBMS_SQL.NATIVE,
        parallel_level => 4
    );
END;
/

En este ejemplo, MI_PROCEDIMIENTO es el procedimiento que se desea ejecutar en paralelo. Puedes ajustar el nivel de paralelismo (parallel_level) según la capacidad de tu sistema y la carga de trabajo, este nivel significa la cantidad de procesos que se ejecutarán simultáneamente.

Ejecución en paralelo usando CREATE_CHUNKS_BY_SQL

Ahora bien, en caso de querer usar la ejecución de chunks basándonos en cualquier consulta SQL, para ello podemos usar DBMS_PARALLEL_EXECUTE.CREATE_CHUNKS_BY_SQL.

DECLARE
    l_task_name VARCHAR2(255) := 'mi_tarea';
BEGIN
    DBMS_PARALLEL_EXECUTE.CREATE_TASK(task_name => l_task_name);

    DBMS_PARALLEL_EXECUTE.CREATE_CHUNKS_BY_SQL(
        task_name => l_task_name,
        sql_stmt => 'SELECT * FROM mi_tabla WHERE status = ''ACTIVE''',
        by_row => TRUE,
        chunk_size => 1000
    );

    DBMS_PARALLEL_EXECUTE.RUN_TASK(
        task_name => l_task_name,
        sql_stmt => 'BEGIN MI_PROCEDIMIENTO(:start_id, :end_id); END;',
        language_flag => DBMS_SQL.NATIVE,
        parallel_level => 4
    );
END;
/

En este ejemplo, se crea un chunk para cada fila de la tabla mi_tabla donde el estado es ‘ACTIVE’.

La ejecución en paralelo de instrucciones en PL/SQL utilizando chunks puede mejorar significativamente el rendimiento de nuestras aplicaciones al distribuir la carga de trabajo de manera eficiente. Al dividir los datos en chunks manejables y procesarlos en paralelo, se puede reducir el tiempo de ejecución de tareas que involucran grandes volúmenes de datos. Experimenta con diferentes tamaños de chunk y niveles de paralelismo para encontrar la configuración óptima para su aplicación.

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *