Buenas prácticas de programación con SQL y PL/SQL

Extraído de una presentación de Steven Feurestein https://community.oracle.com/servlet/JiveServlet/download/915011-2-163991/Make%20No%20Small%20Plans%20PDF.pdf

  • Reutilización
  • Acceso a Datos
    • Calcula estadísticas de tablas, columnas e índices
    • El acceso más rápido a un datos es obteniendo directamente la fila (ROWID).
    • Revisa el plan de ejecución (explain plan)
  • Seguridad
    • Usa bind variables.
    • El usuario que ejecuta la aplicación NO puede ser el propietario de las tablas.
    • Construye una API con PL/SQL para consultar y actualizar los datos, de forma que el usuario que ejecuta la aplicación NO tenga acceso directo a las tablas.
  • Con PL/SQL solo se comparten en SGA las constantes estáticas de paquete (p.e. valor fijo de nº o string, pero NO un valor de secuencia).
  • Minimizar los cambios de contexto entre motor PL/SQL y SQL, que ocurren cada vez que se ejecuta una sentencia SQL dentro de PL/SQL.
    • No repetir sentencias (usar funciones/procedures)
    • Usar BULK COLLECT y FORALL
    • Una función en una sentencia SQL, a su vez, NO puede contener ninguna sentencia SQL (debe ser determinística).
  • Hacer GTs para estandarizar la escritura de SQL:
    • Estar al día sobre las novedades en SQL
    • ¿cómo, cuándo y dónde escribir SQL?
  • Novedades SQL
    • Funciones analíticas, como LAG y LEAD q permiten trabajar con las filas anterior y siguiente para calcular diferencias.
    • WITH, para definir “vistas” reutilizables en una sentencia compleja.
    • Flasback query.
    • ANSI JOIN: cambiar “(+)” por sintaxis completa.
    • Usar subconsultas como si fuesen funciones.
    • Novedades 12.1
      • Patrones (patter matching) y limit (row limiting)
      • Columnas en memoria (in-memory column store)
      • JSON nativo
  • Simplificar SQL (fuera sentencias complejas)
    • NUNCA repitas una sentencia SQL.
    • Oculta las sentencias SQL en una capa de acceso a datos.
    • SQL como servicio = vistas + paquetes
    • Gestión de excepciones
    • NO consultes tablas directamente, hazlo mediante vistas.
    • Separa datos y código en esquemas diferentes.
    • Rutas absolutas para todas las columnas y variables q referencias en una consulta.
  • Gestión de excepciones (ejemplo Sistema de Error Logger https://github.com/OraOpenSource/Logger)
    • Pasarle al Sistema de Log las variables locales y el estado de la app.
    • Usar transacciones autónomas para el Sistema de Log.
    • Usar EXCEPTION_INIT para asignarle nombre a los errores, NO usar directamente nºs y/o mensajes de error.
  • Trazas (solo en el entorno de producción, por defecto desactivada).
  • Testing
  • Escribe Código Mantenible
    • Regression test
    • NO repetir nada (no solo constantes, tampoco varchar2 y lógica de negocio).
    • Usar %TYPE y %ROWTYPE (en lugar de varchar2)
    • Usar funciones para encapsular fórmulas y lógica de negocio
    • Minimizar la parte ejecutable de los bloques, NO más de 50 líneas.
    • Ocultar expresiones complejas en constantes o funciones.
  • Optimizar el código
    • Cachear (function result cache, q solo está en versión enterprise de Oracle)
    • IMPORTANTE: la optimización de BD (DBA) no llega a más del 20% del efecto, el 80% se consigue escribiendo código mantenible.
    • Identificar cuellos de botella haciendo tuning más granular, usando DBMS_PROFILER y DBMS_HPROF.
    • Usar variables de paquete (colecciones) para cachear tablas pequeñas de códigos, estáticas, teniendo en cuenta q SOLO sirve para mantener los datos durante la MISMA SESION (mejor en procesos batch, OJO con apps web q usarn datasource donde la sesión web NO ES IGUAL a la sesión de BD). Consumen PGA.
    • Function RESULT CACHE.
      • No se cachean tipos complejos como registros (record) con CLOBS, colecciones, etc.
      • Solo se cachean los parámetros de entrada y el valor de salida
      • Si usar INVOKER RIGHTS necesitas v12.1 para q use result cache
      • OJO si usas VPD (virtual private database) y/o contextos (SYS_CONTEXT)
      • Sobre todo cachear tablas cuyos datos no cambian durante una sesión
    • BULK COLLECT. Se usa en SELECTs para cargar todas las filas en una colección, de un golpe.
      • Ejemplos sencillos
                            SELECT * BULK COLLECT INTO collection(s) FROM TABLE;
                            FETCH cur BULK COLLECT INTO collection(s);
                            EXECUTE IMMEDIATE query BULK COLLECT INTO collection(s); 
      • No sirve NO_DATA_FOUND, hay q controlar cuando se vacía la colección.
      • Se puede usar LIMIT para limitar el nº de filas a procesar
                        OPEN emps_in_dept_cur; 
                        LOOP
                          FETCH emps_in_dept_cur
                            BULK COLLECT INTO emps LIMIT 1000;
                          EXIT WHEN emps.COUNT = 0;
                          process_emps (emps);
                        END LOOP;
      • NO USES Bulk Collect si tu bucle funciona bien, o si NO contiene sentencias DMLs.
    • FORALL. Se usa en UPDATE/INSERT/DELETE, para actualizar todas las filas de un golpe, desde una colección.
      • Ejemplo
                       FORALL indx IN low_value .. high_value
                          UPDATE employee
                             SET salary = newsal_in
                           WHERE employee_id = list_of_emps (indx);
      • SQL%ROWCOUNT cuento el total de filas modificadas por todo el FORALL
      • SQL%BULK_ROWCOUNT cuenta el nº de filas modificadas en cada ciclo del bucle FORALL
    • Si tienes bucles q contienen sentencias DML, cambia el proceso por otro en 3 fases:
      • Primero, usa BULK COLLECT para cargar los datos en una colección.
      • Segundo, haz los cambios en la colección.
      • Tercero, usa FORALL para aplicar los cambios en la BD desde la colección.

:!: Este contenido es una copia de https://wiki.um.es/wikis/programador/doku.php?id=plsql:optimizacion

JUAN LUIS SERRADILLA AMARILLA 15/09/2022

  • fdw2.0/fundeweb2.0/gt/buenas_practicas_de_programacion_plsql.txt
  • Última modificación: 14/09/2023 17:08
  • por JUAN LUIS SERRADILLA AMARILLA