Query Performance Detector

(This article is also available in English as appeared translated in Salesfoceben on July 2019).

En la última entrada sobre Optimización de Queries en Salesforce, destapaba unos de los problemas más evidentes de cualquier proyecto: la degradación de rendimiento de los elementos que consultan datos en Salesforce.

Es decir, a medida que nuestra ORG crece, las consultas que inicialmente diseñamos (que quizás optimizamos o quizás no) pueden sufrir degradación. Pero no estoy hablando sólo de las Queries de los Developers con SOQL, estoy hablando de List Views, Reports y Dashboards que crean los usuarios.

Además, esta degradación se realiza en silencio, inadvertida, y solo es visible con incidencias de rendimiento en Producción, cuando ya es demasiado tarde, y las acciones correctoras (creación de índices, re-organización de datos, etc.) no serán inmediatas.

Por ello, y porque existen diversos componentes, que puestos a trabajar de forma conjunta, permiten obtener esta información simplemente, he creado una herramienta, que he denominado: Query Performance Detector ( un nombre poco original, pero significativo 🙂 ).

Esta herramienta, permite obtener para ListViews, Reports y Dashboards, cómo el Optimizador de Salesforce está evaluando cada una de ellas:

  • su coste
  • el número de filas retornado
  • el plan de acceso
  • con los datos presentes en la ORG

Destaca aquellas que tienen un coste no-selectivo, para que las optimices de forma prioritaria, especialmente si tienen un volumen muy elevado de registros.

No son un conjunto de consultas cualquiera, sino que son las que los usuarios han utilizado, por tanto, tu máximo objetivo de optimización.

Con esta información podemos:

  1. Detectar aquellas consultas, que no son eficientes, su coste es elevado y seguramente su volumen de registros también, para eficientarlas de inmediato.
  2. Consultar el histórico del rendimiento y evaluar aquellas que están empeorando para iniciar un proceso de optimización.
  3. Obtener el listado de Queries SOQL, para saber sobre cuales debemos centrar nuestros esfuerzos de optimización.

Por tanto, nuestros esfuerzos de optimización se verán reflejados de inmediato en la percepción del usuario. A continuación te describo la herramienta en detalle.

Introducción

Como una imagen vale más de mil palabras, esta vez he compuesto un vídeo, para que puedas ver la herramienta en funcionamiento (90» aproximadamente):

Sus características técnicas principales son:

  • 100% Apex y VisualForce (aún necesito aprender más Lightning)
  • 1 único objeto creado en la ORG para guardar el histórico de resultados
  • Todos los procesos de cálculo son Batchable, para que su ejecución no perjudique el trabajo de los usuarios
  • Se consultan objetos internos de Salesforce y se invoca a la Tooling API

Es decir, básicamente lo que he realizado ha sido, utilizar componentes/funcionalidades/datos  que ya existen dentro de la plataforma de Salesforce y ponerlos a trabajar para solucionar el problema, volviendo a demostrar la gran versatilidad y potencia que tenemos disponible.

Objetos Creados

Esta vez he utilizado únicamente 2 objetos:

  1. QueryCostHistory__c: que almacena los resultados de los escaneos de todos los objetos, ya sean List Views, Reports, Dashboards o investigación de Logs de usuario en busca de SOQL Queries
  2. Process_Log__c: que me permite recojer trazas que no quiero que se muestren o que no se muestran en el Log de Salesforce (lo utilizo en otras herramientas que he creado)

Para mi es importante, que este tipo de herramientas, creen el menor número de objetos adicionales.

Clases y VisualForce Pages

En la siguiente captura puedes ver el conjunto de clases y páginas que he creado:

  • 4 páginas VisualForce
  • 11 clases APEX
Listado de clases y Páginas VF del proyecto

Esquema de ejecución

El esquema de ejecución es muy sencillo:

  • Desde el que Controller principal QP_MainController, se invocan al resto de Controllers para obtener la información. Cada controller obtiene la lista de los objetos que gestiona (ListViews, Reports, etc., ) dentro del período seleccionado por el usuario y lo deposita como pendientes de análisis en el objeto QueryCostHistory__c
  • El Controller QP_ToolingAPIRequester se encarga de invocar a la Tooling API para obtener los Query Plans, recorriendo la tabla en busca de los pendientes. Invoca a la API para obtener con Batches, y registra los resultados en el mismo objeto.
    • Los Controllers que realizan las búsquedas de elementos son los denominados  QP_GetLast*
  • Posteriormente, los Controllers y las páginas VisualForce de detalle e históricos se encargan de mostrar los resultados individuales y acumulados respectivamente al usuario.
    • Los Controllers que muestran datos son los denominados QP_Show*
  • Finalmente hay 2 objetos DAOs de apoyo al almacenamiento de datos en listas

No es complejo.

Características a destacar

Objetos Internos

Para obtener la información de las ListViews, Reports, Dashboards utilizados en un período se consultan tablas internas, ni se crean nuevos datos, ni se hacen cosas raras.

Todos los procesos implementan la @Batchable

Como comentaba anteriormente, me obsesiona que el trabajo de los usuarios no sea afectado por las herramientas que hago, ni quiero que se llegue nunca a afectar a los límites, por tanto, utilizo la interfaz @Batchable y la ejecución segmentada mediante chunks, que es un parámetro del método Database.ExecuteBatch.

De esta manera, por muy grande que sean los volúmenes, las ejecuciones nunca superan los límites  y el consumo de recursos de la Flex Queue y de las colas asíncronas es mínimo (además siempre menos prioritario que el consumo síncrono por supuesto).

A continuación te muestro una captura de pantalla del consumo en mi ORG:

Listado de Jobs, donde puedes que cada ejecución queda circunscrita a un Batch con múltiples ejecuciones

Ejecución Paralelizable

Dado que utilizo los recursos asíncronos, esto me permite lanzar las peticiones en paralelo. Es decir, si planificamos (mediante @Schedule) el proceso de forma nocturna, por ejemplo, puedas lanzar los procesos de forma simultánea, consumiendo 1/4 del tiempo que consumirías si lo tuvieras que lanzar uno detrás de otro.

Envío de notificaciones (cada uno …)

No he implementado ni la interfaz  @Schedulable ni un sistema de avisos, para planificar ni generar avisos respectivamente, porque no  he querido ampliar el código innecesariamente para que fuera más legible.

Con total seguridad, ya sabes hacerlo, y existe mucha documentación al respecto, pero tan solo implementando la interfaz @Schedulable, en los Controllers, sería suficiente para su cronificación. Para la generación de eventos y avisos, cada maestrillo tiene su librillo y para gustos los colores, con lo que…

Conclusiones

Nuevamente me demuestro, que conocer la plataforma, me proporciona las capacidades de extenderla para conseguir herramientas con funcionalidades que inicialmente no existen, pero que podemos construir.

Esta herramienta es un punto de partida de un problema evidente en todas las ORGS que crecen con datos, o van cambiando de datos, y que sin ninguna duda acaban siendo incidencias en Producción difíciles de diagnosticar, y que si podemos adelantarnos, nos ahorraremos dolores de cabeza.

Repositorio de Código disponible

El código completo de esta herramienta está disponible  en este repositorio de Bitbucket, para que lo puedas utilizar como quieras, y seguro mejorar.

Espero que sea de ayuda.

Anuncio publicitario

4 comentarios sobre “Query Performance Detector

Deja una respuesta

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Salir /  Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Salir /  Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Salir /  Cambiar )

Conectando a %s

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.