Artículo
· 5 oct, 2023 Lectura de 9 min

CI/CD (Integración Continua/Entrega Continua) con IRIS SQL

En el vasto y variado mercado de las bases de datos SQL, InterSystems IRIS destaca como una plataforma que va mucho más allá de SQL, ofreciendo una experiencia multimodelo perfecta, y siendo compatible con un amplio conjunto de paradigmas de desarrollo. Especialmente el avanzado motor objeto-relacional ha ayudado a organizaciones a utilizar el enfoque de desarrollo más adecuado para cada una de sus cargas de trabajo intensivas en datos; por ejemplo, ingerir datos a través de Objetos y consultarlos simultáneamente mediante SQL. Las Clases Persistentes corresponden a tablas SQL, sus propiedades a columnas de la tabla y se accede fácilmente a la lógica de negocio utilizando Funciones Definidas por el Usuario o Procedimientos Almacenados. En este artículo, nos centraremos un poco en la magia que se encuentra justo debajo de la superficie y discutiremos cómo puede afectar vuestras prácticas de desarrollo e implementación. Esta es un área del producto que tenemos planificado evolucionar y mejorar, así que no dudéis en compartir vuestras opiniones y experiencias en los comentarios al artículo.

Cómo guardar la Definición de Almacenamiento

Escribir una nueva lógica de negocio es fácil, y suponiendo que tenéis APIs y especificaciones bien definidas, también lo es adaptarla o extenderla, generalmente. Pero cuando no se trata solo de lógica de negocio, sino que también involucra datos persistentes, cualquier cambio que se realice desde la versión inicial deberá poder utilizar los datos que se ingirieron a través de esa versión anterior.

En InterSystems IRIS, los datos y el código coexisten en un único motor de alto rendimiento, sin las numerosas capas de abstracción que se pueden encontrar en otros frameworks de programación 3GL o 4GL. Esto significa que solo hay un mapeo muy fino y transparente para convertir las propiedades de una clase a posiciones de $list en un nodo global por fila de datos cuando se utiliza el almacenamiento predeterminado. Si se añaden o eliminan propiedades, no se quiere que los datos de una propiedad eliminada aparezcan bajo una nueva propiedad. De este mapeo de las propiedades de clase es de lo que se encarga la Definición de Almacenamiento, un bloque XML algo críptico que se puede ver al final de la definición de clase. La primera vez que se compila una clase, se genera una nueva Definición de Almacenamiento basada en las propiedades y parámetros de la clase. Cuando se hacen cambios en la definición de clase, en el momento de la recompilación esos cambios se reconcilian con la Definición de Almacenamiento existente y se modifica para que siga siendo compatible con los datos existentes. Así que mientras uno se arriesga a refactorizar sus clases, la Definición de Almacenamiento considera cuidadosamente su creatividad anterior y se asegura de que tanto los datos antiguos como los nuevos sigan siendo accesibles. A esto le llamamos evolución del esquema.

En la mayoría de las otras bases de datos SQL, el almacenamiento físico de las tablas es mucho más opaco, si es que es visible, y los cambios solo se pueden realizar mediante sentencias ALTER TABLE. Son comandos DLL (Lenguaje de Definición de Datos) estándar, pero generalmente son mucho menos expresivos de lo que se puede lograr modificando directamente una definición de clase y código de procedimiento en IRIS. 

En InterSystems, nos esforzamos para ofrecer a los desarrolladores de IRIS la capacidad de separar de manera limpia su código y sus datos, ya que esto es crucial para garantizar un empaquetado e implementación sencilla de sus aplicaciones. La Definición de Almacenamiento juega un papel único en esto, ya que captura cómo se mapea uno al otro. Por eso, merece la pena analizarla más de cerca en el contexto de las prácticas generales de desarrollo y en particular en los flujos de CI/CD (Integración Continua/Entrega Continua).

Exportando a UDL

En el siglo actual, la administración del código fuente se basa en archivos, así que veamos primero el formato principal de exportación de archivos de IRIS. El Lenguaje de Descripción Universal (UDL) es, como su nombre indica, un formato de archivos universal para cualquier código que se escriba en InterSystems IRIS. Es el formato de exportación predeterminado cuando se trabaja con el plug-in ObjectScript-VS Code y genera archivos de fácil lectura que se asemejan casi exactamente a lo que se vería en un Entorno de Desarrollo Integrado (IDE), con un archivo .cls individual para cada clase (tabla) en la aplicación. Se puede utilizar $SYSTEM.OBJ.Export() para crear archivos UDL explícitamente, o simplemente aprovechar la integración con VS Code.

Desde la época de Studio, es posible que también recordéis un formato XML que capturaba la misma información que UDL y permitía agrupar varias clases en una sola exportación. Si bien esta última parte es conveniente en algunos escenarios, es mucho menos práctica para leer y rastrear diferencias entre versiones, por lo que lo ignoraremos por ahora.

Como UDL está diseñado para capturar todo lo que IRIS puede expresar sobre una clase, incluirá todos los elementos de una definición de clase, incluida la Definición de Almacenamiento completa. Al importar una definición de clase que ya incluye una Definición de Almacenamiento, IRIS verificará si esa Definición de Almacenamiento cubre todas las propiedades e índices de la clase y, en caso afirmativo, la tomará tal cual y sobrescribirá la Definición de Almacenamiento anterior para esa clase. Esto hace que UDL sea un formato práctico para la gestión de versiones de clases y sus Definiciones de Almacenamiento, ya que mantiene esa compatibilidad hacia atrás para los datos ingresados mediante versiones anteriores de la clase, sin importar dónde se implemente. 

Si eres un desarrollador aplicado, es posible que te preguntes si estas Definiciones de Almacenamiento siguen creciendo y si esta "carga" debe llevarse indefinidamente. El propósito de las Definiciones de Almacenamiento es preservar la compatibilidad con los datos preexistentes, por lo que si sabes que no hay ninguno de ellos y quieres deshacerte de una genealogía larga, puedes "reiniciar" tu Definición de Almacenamiento eliminándola de la definición de clase y permitiendo que el compilador de clase la genere de nuevo. Por ejemplo, puedes usar esto para aprovechar prácticas recomendadas más recientes, como el uso de Conjuntos de extensión, que implementan nombres globales hash y separan cada índice en su propio global, mejorando la eficiencia a bajo nivel. Para garantizar la compatibilidad con versiones anteriores dentro de las aplicaciones de los clientes, no podemos cambiar universalmente dichos valores predeterminados en la superclase %Persistent (aunque los aplicaremos al crear una tabla desde cero utilizando el comando DDL CREATE TABLE), por lo que vale la pena realizar una revisión periódica de tus clases y tu almacenamiento. También es posible editar directamente el XML de la Definición de Almacenamiento, pero los usuarios deben tener extrema precaución, ya que esto puede hacer que los datos existentes sean inaccesibles.

Hasta ahora, todo bien. Las Definiciones de Almacenamiento ofrecen un mapeo inteligente entre tus clases y se adaptan automáticamente a medida que el esquema evoluciona. ¿Qué más hay ahí?

¿Estático vs. Estadísticas?

Como probablemente sabes, el motor SQL de InterSystems IRIS hace uso avanzado de las estadísticas de tablas para identificar el plan de consulta óptimo para cualquier sentencia que el usuario ejecute. Las estadísticas de tablas incluyen métricas sobre el tamaño de una tabla, cómo se distribuyen los valores dentro de una columna y mucho más. Esta información ayuda al optimizador SQL de IRIS a decidir qué índice es más beneficioso, en qué orden unir tablas, etcétera. Así que, intuitivamente, cuanto más actualizadas estén las estadísticas, habrá más posibilidades de obtener planes de consulta óptimos. Desafortunadamente, hasta que introdujimos el muestreo rápido de bloques en IRIS 2021.2, recopilar estadísticas precisas de las tablas era una operación computacionalmente costosa. Por lo tanto, cuando los clientes implementaban la misma aplicación en muchos entornos en los que los patrones de datos eran en gran medida los mismos, tenía sentido considerar las estadísticas de las tablas como parte del código de la aplicación e incluirlas con las definiciones de las tablas.

Por eso en IRIS actualmente las estadísticas de las tablas se encuentran integradas dentro de la Definición de Almacenamiento. Cuando se recopilan estadísticas de tablas mediante una llamada manual a TUNE TABLE o de forma implícita mediante una consulta (ver más abajo), las nuevas estadísticas se escriben en la Definición de Almacenamiento, y los planes de consulta existentes para esta tabla se invalidan para que puedan aprovechar las nuevas estadísticas en la próxima ejecución. Como son parte de la Definición de Almacenamiento, estas estadísticas formarán parte de las exportaciones de clase UDL y, por lo tanto, pueden terminar en el repositorio de código fuente. En el caso de las estadísticas cuidadosamente revisadas para una aplicación empaquetada, esto es aconsejable, ya que se querrá que estas estadísticas específicas impulsen la generación de planes de consulta para todas las implementaciones de la aplicación.

Desde la versión 2021.2, IRIS recopila automáticamente estadísticas de tabla al inicio del plan de consultas cuando consulta una tabla que no tiene ningún tipo de estadísticas y es apta para el muestreo rápido de bloques. En nuestras pruebas, los beneficios de trabajar con estadísticas actualizadas frente a no tener estadísticas claramente superaron el coste de recopilar estadísticas en tiempo real. Sin embargo, para algunos clientes, esto ha tenido el desafortunado efecto secundario de que las estadísticas recopiladas automáticamente en la instancia del desarrollador terminan en la Definición de Almacenamiento en el sistema de control del código fuente y, finalmente, en la aplicación empaquetada. Obviamente, los datos en ese entorno de desarrollo y, por tanto, las estadísticas sobre ellos, pueden no ser representativas para una implementación real del cliente y conducir a planes de consulta no óptimos.

Este escenario es fácil de evitar. Las estadísticas de tablas se pueden excluir de la exportación de la definición de clase utilizando el calificador /exportselectivity=0 al llamar a $SYSTEM.OBJ.Export(). La configuración predeterminada del sistema para esta bandera se puede establecer utilizando [$SYSTEM.OBJ.SetQualifiers("/exportselectivity=0]. Luego se puede dejar que la recopilación automática, en la implementación final, recoja estadísticas representativas, haga que la recopilación explícita de estadísticas sea parte del proceso de implementación, lo que sobrescribirá cualquier cosa que pueda haber sido empaquetada con la aplicación, o administre las estadísticas de tablas por separado mediante sus propias funciones de importación/exportación: $SYSTEM.SQL.Stats.Table.Export() y Import().  

A largo plazo, tenemos la intención de trasladar las estadísticas de tablas para que convivan con los datos en vez de ser parte del código, y diferenciar de manera más clara entre las estadísticas configuradas explícitamente por un desarrollador y las recolectadas de los datos reales. Además, estamos planeando automatizar más el proceso de actualizar periódicamente esas estadísticas, en función de cuánto cambien los datos de la tabla con el tiempo. 

Conclusiones

En este artículo, hemos explicado el papel de una Definición de Almacenamiento en el motor IRIS ObjectRelational, cómo es compatible con la evolución del esquema y lo que implica incluirla en el sistema de control de código fuente. También hemos descrito por qué las estadísticas de tablas se almacenan actualmente en esa Definición de Almacenamiento y hemos sugerido prácticas de desarrollo para asegurarnos de que las implementaciones de las aplicaciones obtienen estadísticas que sean representativas para los datos reales del cliente. Como se mencionó anteriormente, estamos planeando mejorar aún más estas funciones, por lo que esperamos vuestros comentarios sobre la funcionalidad actual y la planificada, y mejoraremos nuestro diseño según corresponda.

Comentarios (0)1
Inicie sesión o regístrese para continuar