Rendimiento

Reducir bases de datos (shrink)

En nuestro pasado artículo hablamos del crecimiento de las bases de datos. Entre otras cosas, os expliqué las diferencias entre espacio utilizado y espacio total del fichero y a que eran debidas. También vimos los errores más comunes que nos pueden llevar a que nuestras bases de datos crezcan más de lo necesario. En el artículo de hoy vamos a ver las técnicas de reducción de espacio de una base de datos con la operación shrink. El objetivo es que entendamos cuándo y por qué usar esta herramienta y si tienes que usarla, al final del artículo te diré cómo.

Espacio ocupado y utilizado

Como explicamos en el pasado artículo, aunque muy por encima, el espacio que ocupan nuestras bases de datos SQL Server en disco no es el tamaño real que tienen ocupado los datos. Por temas de rendimiento, el espacio que se asigna al fichero es mayor, o debería serlo, al que realmente ocupan los datos. Esto es así porque los tiempos de las operaciones de escritura podemos dividirlos en dos, por un lado reservar el espacio necesario en disco para los datos y por último escribir los datos. Aunque con técnicas como la inicialización instantánea de ficheros podemos agilizar mucho el proceso de crecimiento de los ficheros, si el espacio ya está previamente reservado, es decir, ocupado por el fichero pero no utilizado, será mucho más rápido el proceso de escritura. 

Reducir una base de datos

Cuando hablamos de reducir una base de datos, lo único que vamos a poder hacer sin eliminar datos es liberar ese espacio que tenía el fichero reservado pero no en uso. Es decir, reducir el tamaño del fichero hasta como mínimo el tamaño máximo de los datos. En el pasado artículo ya hablamos de las técnicas para que los datos ocupen menos y esto nos puede servir para reducir su tamaño, sin embargo, ninguna de estas técnicas va a reducir por sí misma el tamaño de los ficheros, para eso tenemos que recurrir a una reducción de ficheros o de base de datos también conocida como shrink.

¿Qué es el shrink?

El shrink es un proceso mediante el cual se reduce el tamaño físico de un archivo de base de datos, ya sea de datos o de log. Este comando libera espacio no utilizado y lo devuelve al sistema operativo. Aunque a primera vista puede parecer una herramienta útil para gestionar el espacio en disco, es fundamental entender cómo funciona realmente y los efectos que puede tener en el rendimiento de la base de datos. Empecemos por el principio, podemos hacer un shrink de toda la base de datos o de solo unos ficheros (ya sean de datos o de log), esta última opción es la más recomendable ya que nos permite un mayor control sobre la operación. 

Tipos de Shrink

Por otro lado, existen tres tipos de shrink, debido a que solo se puede liberar el espacio libre al final del fichero nos encontramos con un shrink truncateonly donde solo se libera ese espacio libre al final del fichero pero el espacio que hay entre los datos (fragmentación) sigue ocupado, este tipo de shrink es el más rápido y menos invasivo. 

El tipo más efectivo para liberar espacio es cuando definimos un tamaño que será el tamaño total que ocupe el fichero tras el proceso, en este caso, para conseguir liberar todo el espacio, SQL Server moverá físicamente los datos dentro del fichero eliminando los espacios libres y dejándolos al final para así poder liberar todo ese espacio. Esta operación en ficheros de datos es complicada, no solo por lenta, sino porque desfragmenta los índices. Al mover los datos de sitio los índices ya no apuntan al sitio correcto y hay que reconstruirlos después o no serán usables. El problema con esto, es que al reconstruir los índices, SQL Server crea un nuevo índice y al terminar borra el antiguo y si, durante este proceso vuelve a consumir espacio del fichero de datos. En concreto el espacio que ocupa el índice. 

Por último, cuando tenemos varios ficheros de base de datos del mismo filegroup podemos hacer un shrink en uno de ellos que lo vacíe por completo moviendo los datos al resto de ficheros. Esto también nos va a generar los problemas de fragmentación comentados anteriormente.

Ventajas del Uso del Shrink

Una de las ventajas más obvias del shrink es la liberación de espacio en disco. Esto nos será especialmente útil en situaciones donde el almacenamiento sea limitado o costoso. Además, el shrink puede ser una solución rápida para situaciones de emergencia en las que se necesita liberar espacio inmediatamente. Podemos ejecutar un shrink de forma fácil, incluso podemos programarlo en jobs para que se ejecute automáticamente. Incluso podemos configurar nuestras bases de datos para que liberen el espacio libre por defecto de manera automática.

Otra ventaja es que el shrink puede ayudar en la gestión de archivos de log de transacciones, que a menudo crecen considerablemente en bases de datos con muchas transacciones. En este contexto, el shrink puede reducir el tamaño de estos archivos después de una copia de seguridad del log, evitando así que ocupen espacio innecesario. En este mismo contexto, podemos hacer un shrink sobre la base de datos tempdb cuando haya crecido más de la cuenta debido a una transacción grande.

Inconvenientes y Riesgos del Shrink

A pesar de sus ventajas aparentes, como ya hemos comentado, nos podemos encontrar con muchos inconvenientes si ejecutamos un shrink sin ser cuidadosos. Uno de los principales problemas es la fragmentación de los índices. El proceso de shrink puede reorganizar los datos de manera que los índices queden fragmentados, lo que puede degradar significativamente el rendimiento de las consultas. La fragmentación aumenta el tiempo de respuesta de las consultas y la carga sobre el sistema, lo cual es contraproducente en entornos de alta demanda.

Además, el shrink es un proceso que consume recursos, muchos recursos. Durante su ejecución, puede aumentar la carga de trabajo del servidor, afectando a otras operaciones. Tendremos que tener un especial cuidado en bases de datos grandes o en sistemas con recursos limitados. También es importante mencionar que el espacio liberado por el shrink no se puede recuperar sin expandir el archivo nuevamente, lo cual podría ser necesario si la base de datos vuelve a crecer rápidamente.

Prácticas Recomendadas para el Uso del Shrink

Dado que el shrink puede tener efectos adversos en el rendimiento, es crucial seguir ciertas prácticas recomendadas para minimizar sus desventajas. Primero, no debemos usar el shrink como una solución de gestión de espacio a largo plazo. Normalmente si ya hemos utilizado un espacio vamos a necesitarlo en un futuro. Por tanto, es mejor emplearlo en situaciones específicas, como después de la eliminación masiva de datos o en la gestión de archivos de log de transacciones. Como ya habrás adivinado, cuando hacemos un shrink del log de transacciones o de la tempdb no vamos a vernos afectados por la fragmentación de índices.

También es recomendable realizar el shrink en momentos de baja actividad para minimizar el impacto en el rendimiento del sistema. Posteriormente, deberemos realizar una reconstrucción de índices para solucionar la fragmentación causada por el proceso de shrink. Esto ayuda a restaurar el rendimiento óptimo de las consultas.

Por último, debemos tener una previsión del espacio que van a necesitar nuestros ficheros de bases de datos y reducirlos siempre dejando el suficiente espacio libre para unas escrituras óptimas.

Alternativas al Shrink

El shrink más eficiente es el que no se hace. En este sentido, existen alternativas que pueden ser más adecuadas en ciertas circunstancias. La gestión proactiva del espacio, como la eliminación de datos obsoletos o el archivo de datos antiguos, puede reducir la necesidad de realizar un shrink. Además, la implementación de prácticas de mantenimiento regulares, como el reindexado y la actualización de estadísticas, puede ayudar a mantener la base de datos en buen estado sin los efectos adversos del shrink.

Conclusión

El shrink en SQL Server es una herramienta que debe ser utilizada con precaución y entendimiento. Aunque puede ofrecer una solución rápida para liberar espacio en disco, sus efectos secundarios, como la fragmentación de índices y el consumo de recursos, deben ser cuidadosamente gestionados. Es fundamental considerar el shrink como una herramienta de última instancia y explorar alternativas y prácticas de mantenimiento regulares para mantener una base de datos saludable y eficiente. La clave está en el balance y en la planificación proactiva, asegurando que el rendimiento y la integridad de los datos no se vean comprometidos.

Si has llegado hasta aquí esperando ver cómo hacer un shrink te diré que este no era el objetivo de este artículo, tienes eso en un vídeo aquí. Hoy quería contarte todo lo que rodea a esta operación, para mi, es más importante saber cuándo y por que hacer un shrink que saber hacerlo.

Si tenéis alguna duda o sugerencia, podéis dejarla en Twitter, por mail o dejarnos un mensaje en los comentarios. Y recuerda que también tenemos un grupo de Telegram y un canal de YouTube a los que te puede unir. ¡Hasta la próxima!

No te vayas aun. Hemos creado una página donde estamos recopilando todos estos artículos que dan respuesta a estas preguntas frecuentes de SQL Server. Pásate por aquí a echar un vistazo.

Publicado por Roberto Carrancio en Cloud, Rendimiento, SQL Server, 0 comentarios

SQL Server Profiler

Hoy os quiero hablar de SQL Server Profiler. Aunque su soporte está discontinuado y en un futuro será eliminado de las características de SQL Server en favor de otras herramientas como xEvents, sigue siendo una de las herramientas más poderosas y versátiles a nuestra disposición cuando estamos depurando un problema con consultas SQL.

Durante las próximas líneas, veremos en profundidad el uso del SQL Server Profiler, sus funcionalidades avanzadas, su impacto en los recursos del sistema y cómo puede ayudarnos a mantener nuestros sistemas SQL Server funcionando de manera eficiente.

¿Qué es el SQL Server Profiler?

El SQL Server Profiler es una herramienta nativa de SQL Server que nos permite crear trazas para capturar y analizar eventos que ocurren principalmente en instancias de SQL Server. Aunque su uso principal es para capturar eventos de SQL Server, también es posible conectarlo a una instancia de SQL Server Analysis Services y, por tanto, a un modelo de Power BI. Los eventos que vamos a poder capturar pueden ser consultas T-SQL, procedimientos almacenados, transacciones y mucho más, dependerá de a qué tipo de servidor estemos conectados. Como habrás imaginado ya, poder monitorizar y registrar estos eventos es crucial para ayudarnos en la resolución de problemas, la optimización del rendimiento y la auditoría de actividades en nuestras bases de datos.

Principales Características del SQL Server Profiler

SQL Server Profiler, como hemos visto, nos puede ser de gran utilidad para descubrir qué es lo que está pasando en nuestro SQL Server. Esto lo hace una herramienta ideal para cualquier DBA que persiga un problema de rendimiento o para un desarrollador que necesite depurar una aplicación. Para ello, podemos destacar estas características principales de la herramienta:

  • Monitorización en Tiempo Real y más: SQL Server Profiler nos permite observar la actividad sobre la base de datos a medida que ocurre, lo cual es esencial para identificar y solucionar problemas de rendimiento de manera inmediata. Pero no solo eso, también nos permite guardar esos archivos para analizarlos en detalle más adelante.
  • Filtrado de Eventos: Como el resultado de registrar toda la actividad puede ser un fichero tan grande que sea casi imposible de consumir, SQL Server Profiler implementa una serie de filtros específicos para centrarnos en eventos particulares, evitando así la sobrecarga de información y facilitando la identificación de problemas concretos.
  • Reproducción de Trazas: Como ya os comentaba antes, podemos guardar los archivos de trazas pero, no solo para su visualización. SQL Server Profiler nos da la capacidad de abrir esas trazas conectados en un entorno de prueba, por ejemplo, y reproducir paso a paso, todos los eventos de la traza. Esto es increíblemente útil para el análisis de problemas y depuración de código sin afectar el sistema de producción.

Configuración y Uso del SQL Server Profiler

Cuando queremos usar SQL Server Profiler primero debemos iniciar una nueva sesión de traza. Al hacerlo, se nos presentará una serie de opciones de configuración que nos permitirán personalizar la traza según nuestras necesidades. Veamos los pasos.

Pasos Básicos para Iniciar una Nueva Trazabilidad

  1. Abrir SQL Server Profiler: Lo encontramos en el menú de herramientas de SQL Server Management Studio (SSMS) o como aplicación instalada en tu sistema operativo.
  2. Crear Nueva Traza: Seleccionamos «File» > «New Trace» y nos conectamos a la instancia que queremos monitorizar. Recuerda que puede ser SQL Server (on premise o Azure), SSAS o un modelo de Power BI.
  3. Seleccionar Plantilla: Podremos elegir una de las plantillas predefinidas, si es que se ajustan a nuestras necesidades, o configurar una nueva.
  4. Configurar Eventos y Columnas: En esta pestaña podremos personalizar los eventos y columnas que queremos capturar y mostrar. Abajo a la derecha encontrarás unos checks para mostrar todos los eventos y columnas, recuerda activarlos para ver todas las opciones disponibles.
  5. Aplicar Filtros: Podremos configurar filtros específicos para reducir la cantidad de datos capturados y enfocarnos en eventos relevantes. Es interesante por ejemplo el filtro por base de datos o por usuario si es que tenemos claro donde está más o menos localizado el problema.
  6. Iniciar la Traza: Una vez configurada, iniciamos la traza y comenzamos a monitorizar los eventos en tiempo real.
  7. Una vez con la traza iniciada la podremos pausar y reanudar a nuestro gusto. También detener definitivamente la captura de eventos. Una vez finalizado podremos guardar el fichero para analizarlo o reproducirlo más tarde.

Análisis de Datos Capturados

Una vez que hemos capturado una traza, el siguiente paso es analizar los datos para identificar posibles problemas de rendimiento o errores en la aplicación.

Uno de los usos más comunes del SQL Server Profiler es identificar consultas lentas que pueden estar afectando el rendimiento de la base de datos. Podemos buscar eventos específicos como «SQL» o «RPC» y revisar las métricas de tiempo de ejecución, CPU y lecturas/escrituras de disco para cada consulta.

Los bloqueos y deadlocks también pueden ser un gran problema que queramos analizar, sobre todo en sistemas con alta concurrencia (y sin un nivel de aislamiento Read Committed Snapshot). Utilizando eventos como «Lock» y «Lock Chain», podemos identificar las transacciones involucradas en deadlocks y tomar medidas para resolverlos, ya sea optimizando las consultas o ajustando la configuración de bloqueo.

Impacto de SQL Server Profiler en el rendimiento

Como puedes imaginar todo esto tiene una gran contrapartida y es su impacto en el rendimiento. El SQL Server Profiler puede generar una cantidad significativa de datos, especialmente en sistemas con alta actividad. Cada evento capturado se guarda en un archivo de traza, lo que puede resultar en un uso considerable del espacio en disco. Si no tenemos cuidado podemos llegar a llenar el disco. 

Para evitar este problema de consumo excesivo de disco debemos tomar precauciones y aplicar filtros para capturar solo los eventos necesarios, de esta manera reduciremos la cantidad de datos registrados. También es importante configurar límites de tamaño para los archivos de traza y habilitar la opción de sobrescribir los archivos más antiguos. Por último debemos asegurarnos de que las trazas se almacenan en volúmenes con suficiente capacidad para evitar problemas de espacio en disco.

Otro de los problemas principales que podemos encontrar durante el proceso de captura y registro de eventos por parte del SQL Server Profiler es que puede afectar el rendimiento del servidor. El impacto varía según la cantidad de eventos capturados y la configuración de la traza. A mayor frecuencia de eventos capturados, mayor será el impacto en el rendimiento. Capturar una gran cantidad de eventos y columnas innecesarias aumenta la carga en el sistema, como es obvio.

Trata de acotar tus trazas en el tiempo y de capturar los eventos mínimos imprescindibles para evitar saturar la CPU y RAM de tu servidor, utilizar plantillas predefinidas optimizadas para tareas específicas puede ayudarte en este sentido. Es vital en este sentido programar la captura de trazas durante periodos de baja actividad del sistema o solo durante el tiempo que tengas localizado que se produce el error que tratas de depurar en lugar de mantenerlas activas por tiempo prolongado.

Casos de Uso Avanzados del SQL Server Profiler

Como has podido ver en lo que llevamos de artículo, SQL Server Profiler es una herramienta muy útil para depurar código o localizar problemas de rendimiento. Pero, no solo nos va a servir para eso, a continuación os presento otros escenarios en los que nos puede ser de utilidad.

Auditoría de Seguridad

Aunque no es lo ideal, SQL Server Profiler también puede ser utilizado para auditorías de seguridad. Podemos capturar eventos relacionados con el acceso a datos sensibles, cambios en la configuración del servidor y actividades de inicio de sesión. Esto nos permite mantener un registro detallado de las acciones realizadas en la base de datos, lo cual es esencial para cumplir con normativas de seguridad y auditoría. Sin embargo, sus especificaciones y consumo de recursos hacen que no sea la herramienta ideal. En este sentido podremos usar mejor los eventos extendidos o la auditoría nativa de SQL Server.

Optimización de Procedimientos Almacenados

La optimización de procedimientos almacenados es una tarea crítica. Muchas aplicaciones usan estos objetos para sus procesos en lugar de ejecutar código Ad Hoc. Utilizando el Profiler, podemos capturar la ejecución de procedimientos y analizar su rendimiento. Esto nos va a permitir identificar procedimientos que requieren optimización, ya sea mediante la revisión del código T-SQL, la reestructuración de índices y estadísticas o la modificación de la lógica de las consultas.

Diagnóstico de Problemas de Red

En entornos distribuidos, los problemas de red pueden afectar significativamente al rendimiento de SQL Server. El Profiler nos permite capturar eventos relacionados con conexiones y desconexiones, así como latencias en la comunicación. Con esta información, podemos trabajar junto con los administradores de red para resolver problemas de conectividad y mejorar el rendimiento general del sistema.

Uso del SQL Server Profiler para Monitorizar Power BI

Aunque es un proceso no documentado, podemos usar el Profiler para capturar las consultas DAX de Power BI. Yo esto lo he visto funcionando en una charla de Francisco Gutierrez en los Power BI Days de Bilbao y me dejó sorprendido. No esperaba que una herramienta discontinuada por Microsoft tuviera la capacidad de interactuar con Power BI. 

Conclusión

El SQL Server Profiler es una herramienta muy potente para cualquier DBA que busque mantener el rendimiento de sus bases de datos SQL Server. Desde la identificación de consultas lentas hasta la auditoría de actividades y la resolución de problemas de red, el Profiler nos proporciona una visión detallada y en tiempo real del comportamiento de nuestro sistema. Su capacidad para personalizar la captura de eventos y analizar datos detallados lo convierte en una herramienta versátil y poderosa. Sin embargo, es importante ser conscientes del impacto que el Profiler puede tener en los recursos del sistema y aplicar estrategias adecuadas para minimizar su uso de disco y su impacto en el rendimiento. Además, siempre que podamos, deberemos usar los eventos extendidos y familiarizarnos con ellos ya que al SQL Server Profiler no le queda mucho entre nosotros.

 Si tenéis alguna duda o sugerencia, podéis dejarla en Twitter, por mail o dejarnos un mensaje en los comentarios. Y recuerda que también tenemos un grupo de Telegram y un canal de YouTube a los que te puede unir. ¡Hasta la próxima!

Publicado por Roberto Carrancio en Cloud, Rendimiento, SQL Server, 2 comentarios

DATETRUNC: Una novedad de SQL Server 2022

Aunque ya ha pasado un tiempo desde la llegada de SQL Server 2022 no es raro encontrarse con gente que está empezando a adoptarlo o, con gente que aun llevando tiempo trabajando en esta versión no conoce todas sus novedades. Entre estas nuevas funcionalidades, una de las más destacadas es la función DATETRUNC. Esta nueva función integrada de fecha y hora simplifica enormemente el trabajo con fechas, permitiendo a los desarrolladores y administradores de bases de datos realizar tareas comunes de manera más eficiente y con menos código.

Hasta ahora, manipular fechas en SQL Server requería el uso de múltiples funciones y a menudo resultaba en código complicado y difícil de leer. Aunque si has visto nuestro video sobre el tema ya serás un experto. Con la llegada de DATETRUNC, estas tareas se simplifican significativamente. La función DATETRUNC nos permite truncar una fecha a una parte específica, como año, mes, día, hora, minuto, etc., eliminando la necesidad de combinaciones complejas de funciones de fecha.

¿Qué es DATETRUNC?

La función DATETRUNC recibe como parámetro una fecha que le pasemos y la trunca al nivel de precisión que hayamos especificado. Esto es especialmente útil cuando necesitamos agrupar datos por períodos específicos, como meses o trimestres, o simplemente cuando queremos estandarizar las fechas a un nivel común para comparaciones más precisas.

Sintaxis de DATETRUNC

La sintaxis de la función DATETRUNC es sencilla y directa, solo tendremos que pasar el nivel de precisión al que queremos truncar y un valor tipo fecha o fecha y hora:

  1. datepart: Especifica la parte de la fecha a la que queremos truncar. Puede ser año, trimestre, mes, día, hora, minuto, segundo, etc.
  2. date: La fecha que queremos truncar.

Ejemplos Prácticos de DATETRUNC

Por si han quedado dudas, y como a caminar se aprende caminando vamos con algunos ejemplos prácticos:

Truncar a Año

Imaginemos que tenemos una fecha y queremos truncarla al inicio del año:

Este código devolverá: 2023-01-01 00:00:00.000. Hemos truncado la fecha al primer día del año 2023.

DATETRUNC-1

Truncar a Mes

Si queremos truncar una fecha al inicio del mes seguiremos la misma lógica:

El resultado será: 2023-07-01 00:00:00.000. La fecha se trunca al primer día del mes de julio de 2023.

DATETRUNC-2

Truncar a Día

Para truncar una fecha al inicio del día:

El resultado será: 2023-07-15 00:00:00.000. En este caso, la hora, los minutos y los segundos se eliminan, dejando solo la fecha.

DATETRUNC-3

Aplicaciones Prácticas en el Mundo Real

Todo esto es muy bonito pero, lo importante es cómo usarlo y cuando. Ahora te voy a contar algunos ejemplos útiles que se me ocurren para DATETRUNC. Seguro que a nuestros amigos de BI que siempre están jugando con dimensiones de fechas se le ocurren un montón más de ejemplos.

Agrupación de Datos

Una de las aplicaciones más comunes de DATETRUNC es en la agrupación de datos. Por ejemplo, podemos querer agrupar ventas por mes:

Este ejemplo agrupa las ventas por mes, facilitando la generación de reportes mensuales.

DATETRUNC-4

Comparaciones de Fechas

Otra aplicación que nos va a ser muy útil es en las comparaciones de fechas. Si queremos comparar sólo la parte de la fecha sin considerar la hora, podemos utilizar DATETRUNC:

Aquí, estamos comparando solo la parte de la fecha de EventDate con el 15 de julio de 2023, ignorando la hora.

Ventajas de Usar DATETRUNC

Como podrás imaginar, si le he dedicado un tiempo a este artículo es porque creo que DATETRUNC tiene alguna ventaja para ti. Como ya hemos comentado una de sus grandes bazas es la sencillez del código, que simplifica su escritura y comprensión, pero no es solo eso, también vamos a notar mejoras en el rendimiento.

Código Más Limpio y Legible

Antes de la introducción de DATETRUNC, truncar fechas requería el uso de funciones como DATEADD y DATEDIFF en combinaciones complejas. Con DATETRUNC, el código es mucho más limpio y fácil de entender.

¿Mejor Rendimiento?

La función DATETRUNC, en teoría, está optimizada para el rendimiento, reduciendo la sobrecarga de cómputo comparado con las versiones anteriores que implicaban múltiples ejecuciones de funciónes. Aunque como siempre, sigue siendo mejor no usar funciones.

DATETRUNC-5

En este ejemplo vemos como con la función DATETRUNC el coste de la consulta es un 1% menor pero no se acerca en absoluto a los resultados cuando no usamos funciones de fecha. Es curioso porque Microsoft asegura que ha optimizado el rendimiento pero el comportamiento sigue siendo el mismo. 

El motor de SQL dice: “No tengo ni idea de cuál es la primera fecha que produciría YEAR(2017) y es imposible que pueda adivinarlo por mi mismo. Mejor leeré todas las fechas desde los inicios de los tiempos hasta ahora.” Esto es absurdo, lo sé, pero es así, y es una de las razones por las que siempre se dice que evitemos usar funciones en la cláusula WHERE. Como ves con DATETRUNC en SQL Server 2022 no es diferente.

Conclusión

SQL Server 2022 introdujo innovaciones y mejoras en nuestra capacidad para gestionar y manipular datos de manera eficiente. La función DATETRUNC es una adición bienvenida, simplificando la manipulación de fechas y mejorando la legibilidad y el rendimiento del código. Al empezar a usar esta nueva función, podremos escribir consultas más claras y un poco más eficientes, facilitando nuestro trabajo diario. Sin embargo no es oro todo lo que reluce y, como toda función, debemos evitar su uso en los filtros. 

Si tenéis alguna duda o sugerencia, podéis dejarla en Twitter, por mail o dejarnos un mensaje en los comentarios. Y recuerda que también tenemos un grupo de Telegram y un canal de YouTube a los que te puede unir. ¡Hasta la próxima!

Publicado por Roberto Carrancio en Cloud, Rendimiento, SQL Server, 0 comentarios

SQL vs DAX ¿Quién es más rápido?

El pasado viernes andaba yo absorto en la masterclass de Salvador Ramos en Nasmasdata cuando, de repente, una diapositiva salvaje apareció. Salva nos hablaba de un cálculo de stock acumulado con su fórmula en DAX porque según ponía en SQL era un cálculo imposible. ¿IMPOSIBLE? Eso era un reto para mí, así que, raudo tomé una captura de pantalla y acepté ese reto. No hubo que esperar mucho, hoy sábado, de buena mañana me he sentado delante del ordenador, he creado una tabla con los datos necesarios para la prueba y me he puesto manos a la obra. No sin antes contactar a Salva e informarle de lo que estaba aconteciendo porque sí amigos, Salva sabe de la existencia de este artículo días antes que vosotros, para la próxima que el reto venga de vosotros y estaréis informados antes. 

SQL-vs-DAX_1

Entendiendo el reto en DAX

Lo primero que tenemos que entender es lo que nos propone el reto, la medida DAX que se ve en la imagen es esta:

Por un lado CALCULATE es una función que cambia una expresión en un contexto de filtro modificado. Como parámetros le hemos pasado [Stock Final] que es una medida o una calculada que nos sumariza los movimientos de stock. Para el segundo parámetro hemos pasado la función FILTER con dos parámetros más, el resultado es que filtra la tabla Fecha para incluir solo las filas donde la fecha es menor o igual a la fecha máxima en el contexto actual.

Convirtiendo el DAX a T-SQL

Ahora que ya sabemos lo que tenemos que obtener vamos a ver como debemos hacerlo en SQL Server, a ver si realmente era imposible o no. He de deciros que mi tabla solo tiene dos columnas fecha y stock. Podriamos haber complicado el escenario añadiendo artículos pero para la demo nos vale sin eso, supongamos que tenemos solo uno. Como luego vamos a llevarnos estas tablas a Power BI tal como están en SQL no hay problema, en DAX vamos a jugar en las mismas condiciones.

Para empezar vamos a tener que totalizar por dias para saber cuantos movimientos hemos tenido ese día. Luego tenemos que hacer una suma de los valores desde la primera fecha hasta la fecha actual. Eso lo podremos lograr con una función de ventana. Esta sería la consulta imposible:

Vamos a verla paso a paso. En lo primero que nos tenemos que fijar es en la subconsulta del FROM. Es justo lo que comentábamos antes, la suma de los movimientos de stock agrupados por día. Luego, en la consulta principal, estamos utilizando una función de ventana para calcular el Stock_Acumulado. Esta función de ventana SUM() OVER (ORDER BY Fecha ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) suma los valores de Stock_Final en todas las filas desde el inicio de la tabla (UNBOUNDED PRECEDING) hasta la fila actual (CURRENT ROW), ordenadas por Fecha. Esto da como resultado un total acumulativo de Stock_Final hasta la fecha actual.

SQL-vs-DAX_2

Ya lo tenemos, no era imposible. Sin embargo, a lo que Salva se refería era los inconvenientes de realizar los cálculos en SQL por tiempos. Y realmente este es un pensamiento muy extendido en el sector. DAX es más rápido realizando cálculos que SQL Server. Pero, ¿realmente es cierto? Vamos a verlo.

Comparativas de rendimiento DAX vs SQL

Para que los resultados puedan ser representativos, vamos a hacer las pruebas sobre una tabla con algo más de 1 millón de registros, algo normal en una empresa pequeña. Vamos a analizar dos años de datos de movimientos de stock. Para medir los tiempos de la consulta DAX he sacado la consulta de la tabla y la he llevado a DAX Studio. En SQL vamos a usar las estadísticas de tiempo que podemos sacar con SET STATISTICS TIME ON.

SQL-vs-DAX_3

Como vemos los resultados son demoledores y para nada lo esperado. Analizando 1.010.000 registros repartidos en 1096 fechas distintas SQL Server se ha demorado 85 milisegundos de los cuales 78 ms han sido CPU. En DAX Studio podemos ver que la fórmula DAX para la tabla ha tardado 180 milisegundos, repartidos entre 175 ms del motor de fórmulas (FE) y 5 ms del motor de almacenamiento (SE). 

Complicando el escenario

Vamos a pasar de 1 millón a 15 millones de registros a ver si los resultados son distintos. Todos sabemos que el fuerte de Power BI reside en su motor Vertipaq y su gran capacidad de trabajar con grandes cantidades de datos.

SQL-vs-DAX_4

Ahora sí que vemos la gran diferencia de tiempos de la que todo el mundo habla en DAX y Power BI. Con 15 millones de registros los tiempos en SQL Server se han disparado a 1219 milisegundos de CPU aunque paralelizando la consulta se ha resulto en 186 ms. En DAX tenemos un tiempo total de 193 milisegundos repartidos en 175 ms del motor de fórmulas (FE) y 18 ms del motor de almacenamiento (SE). Aunque los tiempos de DAX son mayores a los de SQL no hay tanta diferencia y teniendo en cuenta el paralelismo de SQL podemos deducir un mayor consumo de recursos si ejecutamos los cálculos en origen.

Mejorando los tiempos de SQL

Ya sabemos el objetivo a batir en DAX 193 ms. Veamos qué podemos hacer en SQL. Para empezar vamos a probar con un índice columnar sobre la tabla, al fin y al cabo los índices columnares son la misma tecnología que el motor vertipaq de Power BI.

SQL-vs-DAX_5

Ahí lo tenemos, ahora sí. Nuestra consulta sobre la tabla con índices columnares ha tardado 155 milisegundos de CPU y solo 56 ms totales al paralelizar. Aun así esto todavía se puede mejorar, ¿recordáis las vistas indexadas? Vamos a probarlo.

SQL-vs-DAX_6

¿Qué os parece el resultado? ¿Os lo esperabais? Con la combinación de índice columnar más vista indexada hemos podido ejecutar la consulta pesada sobre 15 millones de registros en menos de un milisegundo. A mi me ha sorprendido la verdad. No esperaba tanta mejoría.

Es importante destacar que esto es una prueba de concepto en un entorno de laboratorio sin carga de trabajo donde puedo hacer todos los cambios que quiero sobre el SQL sin afectar a ningún otro proceso. Esto es un escenario muy simplificado para la DEMO sin ningún parecido con una base de datos de un ERP de producción. Como siempre digo, primero válida en tus servidores de pruebas y luego, si ves que va bien y no da problemas, piensa en aplicarlo en producción.

Conclusión

SQL sigue más vivo que nunca. Es verdad que DAX es muy potente y seguro que tiene un montón más de optimizaciones de las que yo he sido capaz de aplicar. Os diré que para las pruebas estaba la inteligencia de tiempos desactivada y como dimensión de tiempos estaba usando la plantilla que Salva proporciona gratuitamente en su web que entiendo que es la que usa él. 

Si tenéis alguna duda o sugerencia, podéis dejarla en Twitter, por mail o dejarnos un mensaje en los comentarios. Y recuerda que también tenemos un grupo de Telegram y un canal de YouTube a los que te puede unir. ¡Hasta la próxima!

PD.: Salva, no me importa el resultado de estas pruebas, tu sigues siendo un referente para mi 🙂.

Publicado por Roberto Carrancio en Cloud, Power BI, Rendimiento, SQL Server, 0 comentarios

Anti-Patterns : Nuestro mayor enemigo.

Como DBAs, lo más normal va a ser encontrarnos con consultas que, aunque devuelven el resultado esperado, no están optimizadas y pueden llevar a problemas de rendimiento muy serios. Estos patrones de diseño ineficaces son conocidos como «Query Anti-Patterns» y por muy bien diseñada y optimizada que esté tu base de datos van a dilapidar su rendimiento. Vamos a explorar algunos de los Anti-Patterns más comunes y cómo evitarlos para asegurarnos de que nuestras consultas SQL sean lo más eficientes posible.

Anti-Patterns Comunes y Cómo Evitarlos

La optimización de consultas SQL es una mezcla de arte y ciencia. La habilidad para identificar y corregir anti-patterns en nuestras consultas puede marcar la diferencia entre una base de datos que funciona sin problemas y una que causa dolores de cabeza constantes. Aunque algunos anti-patterns pueden parecer inofensivos a primera vista, su impacto acumulativo, cuando se repiten mucho o se solapan puede ser devastador. En este artículo, vamos a ver varios de estos anti-patterns con ejemplos concretos y soluciones prácticas.

El más común: Select *

Uno de los anti-patterns más comunes y dañinos es el uso de SELECT *. Al seleccionar todas las columnas de una tabla, no solo estamos recuperando datos innecesarios, sino que también podemos estar comprometiendo la seguridad y el rendimiento de nuestra consulta. Este problema se agrava si estamos ante una tabla de un modelo tabular optimizada con índices columnares pues perderemos su gran potencial propio de su diseño, la capacidad de leer solo las columnas necesarias.

Ejemplo:

Solución:

Especificar sólo las columnas necesarias, de esta manera, reducimos la cantidad de datos transferidos y hacemos que nuestra consulta sea más clara y manejable. Además podremos aprovecharnos de índices que cubran completamente nuestras consultas.

Funciones en las Columnas

Usar funciones en las columnas dentro de las cláusulas WHERE es otro anti-pattern que puede degradar significativamente el rendimiento. Las funciones en las columnas evitan que SQL Server use índices, resultando en escaneos de tabla completos. Es lo que se conoce como problemas de sargabilidad de los índices, y consiste en que, al usar un filtro de búsqueda que no se puede aplicar a todos los niveles de la estructura B-tree (árbol invertido), el motor de base de datos tiene que recorrer completamente el nivel hoja buscando coincidencias.

Ejemplo:

Solución:

Reescribir la consulta para evitar la función en la columna. Con esta modificación, permitimos que SQL Server utilice índices sobre OrderDate, mejorando notablemente el rendimiento.

Subconsultas Correlacionadas en el WHERE

Las subconsultas correlacionadas dentro de una cláusula WHERE pueden ser extremadamente costosas, ya que la subconsulta se ejecuta una vez por cada fila en la tabla externa.

Ejemplo:

Solución:

Utilizar un JOIN o CROSS APPLY para evitar la subconsulta correlacionada. Aunque puede haber excepciones en función del tamaño de las tablas, esta aproximación es generalmente más eficiente, ya que la subconsulta se ejecuta una sola vez y los resultados se unen a la tabla principal reduciendo drásticamente el número de lecturas en disco.

Subconsultas en el SELECT

Las subconsultas en la cláusula SELECT pueden causar problemas similares a las subconsultas en WHERE, ya que se ejecutan por cada fila de la tabla principal.

Ejemplo:

Solución:

Usar un JOIN para incluir la información necesaria. De esta forma, la subconsulta se elimina y la consulta puede beneficiarse de una menor cantidad de lecturas.

UNION en Lugar de UNION ALL

El uso de UNION en lugar de UNION ALL puede resultar en un rendimiento deficiente, ya que UNION elimina duplicados, lo cual requiere una operación adicional de ordenación y comparación para lo que es necesario cargar todos los datos en memoria. Es común encontrarse con consultas con UNION por pereza y no escribir los 4 carácteres extra pero, si no es estrictamente necesario nunca es una buena idea.

Ejemplo:

Solución:

Si estamos seguros de que no hay duplicados, usar UNION ALL. De esta manera, evitamos el trabajo adicional de eliminar duplicados y mejoramos la eficiencia de la consulta.

Conversiones Implícitas

Las conversiones implícitas ocurren cuando SQL Server necesita convertir los tipos de datos de una columna o variable para que coincidan. Esto puede tener un impacto negativo en el rendimiento, especialmente cuando involucra columnas indexadas, ya que puede evitar que los índices se utilicen de manera eficiente.

Ejemplo:

En este ejemplo, si OrderID es un entero y estamos comparándolo con una cadena, SQL Server tendrá que convertir OrderID a una cadena para realizar la comparación, lo que puede evitar el uso de índices.

Solución:

Asegurarse de que los tipos de datos coincidan. De esta manera, evitamos la conversión implícita y permitimos que SQL Server utilice los índices de manera eficiente.

Localizando Anti-Patterns con X-Events (ojo, esto ya es muy friki)

Los eventos extendidos son una herramienta muy poderosa en nuestra búsqueda de problemas. Gracias a su capacidad de capturar, en tiempo real, consultas que cumplan unos requisitos establecidos y, a una novedad introducida en SQL Server 2022 como es el evento query_antipattern, nos van a permitir localizar estas consultas mal diseñadas de una manera sencilla. O eso dice la teoría. Os dejo por aquí el script que he usado yo para generar esta sesión de x-events:

Probando los Anti-Patterns X-Events

Ahora que ya hemos visto la teoría vamos a volver al mundo real. Podemos localizar los anti-patterns detectados por este evento extendido si miramos en la DMV sys.dm_xe_map_values que registra los distintos tipos de eventos.

xevents-anti-patterns

Como ves, hay 5 antipatrones, el quinto es el único que coincide con alguno de los que hemos visto nosotros en este artículo. Sobre el resto no hay más documentación, Microsoft ha decidido sacar esta novedad en X-Events pero no lo ha documentado. 

En mis pruebas, he conseguido generar una consulta que active el primero de los tipos de antipatrón, el LargeIn, pero os voy a ser sinceros, no ha sido fácil. Para lograrlo he escrito una consulta con un filtro where CustomerID IN y a continuación le he pasado 2500 parámetros separados por comas. Con menos parámetros no he conseguido hacer saltar la alerta. El antipatrón de conversiones que impiden el Seek sí que es relativamente sencillo verlo y salta ante cualquier consulta con un error de conversión. 

xevents-anti-patterns_2

Sobre el resto no os puedo decir más, llevo más de una semana con este artículo escrito, buscando información y haciendo pruebas pero no lo he conseguido ver. En algún sitio he visto que han conseguido el fallo por un antipatrón LargeNumberOfOrInPredicate con las pruebas que a mi me han dado el LargeIn pero yo no lo he podido reproducir. Igual que ellos no pudieron reproducir el LargeIn. Sobre el resto de tipos de Anti-Patterns no he conseguido más información. No sé qué significa Max en este contexto. En el caso de NonOptimalOrLogic he llegado a pensar que es un problema con las lógicas OR pero no he conseguido reproducirlo ni con 21.500 OR en una misma consulta. Es más, ni con 21.500 OR en una misma consulta mostró ninguno de los otros Anti-Patterns.

Conclusión

Identificar, resolver y evitar estos anti-patterns en nuestras consultas T-SQL puede suponer una mejora significativa en el rendimiento de nuestras bases de datos. Es crucial siempre revisar y optimizar las consultas en ejecución, especialmente en sistemas críticos donde el rendimiento es esencial.Al aplicar buenas prácticas y evitar estos anti-patterns, no solo mejoramos la eficiencia de nuestras consultas, sino que también contribuimos a la estabilidad a largo plazo de nuestras aplicaciones. 

Si tenéis alguna duda o sugerencia, podéis dejarla en Twitter, por mail o dejarnos un mensaje en los comentarios. Y recuerda que también tenemos un grupo de Telegram y un canal de YouTube a los que te puede unir. ¡Hasta la próxima!

Publicado por Roberto Carrancio en Cloud, Rendimiento, SQL Server, 0 comentarios

Detectando BLOQUEOS en SQL Server y Azure SQL

Cuando trabajamos con bases de datos SQL Server, los bloqueos pueden ser una de las características de implementación que más dolores de cabeza nos pueden dar como DBAs. A los usuarios también, por supuesto, pero ellos trasladarán sus quejas a nosotros.

Por esto, en el vídeo de hoy, te enseño a detectar bloqueos en SQL Server o Azure SQL. Gracias a procedimientos integrados de sistema como sp_who o sp_who2 podremos verlo de una forma muy básica. Si queremos más nivel de detalle podremos recurrir a procedimientos de terceros como sp_who3, sp_whoisactive o sp_BlitzWho.

Si queremos detectar un bloqueo de una forma rápida y ligera, los procedimientos de sistema sp_who y sp_who2 son un gran aliado. Sin embargo, la información que nos van a mostrar es más bien justa. Si tenemos ocasión, siempre será recomendable de recurrir a procedimientos más completos como los citados en el vídeo.

También podremos hacer uso del siguiente script que nos muestra los procesos con bloqueos:

Como ves, el script hace uso de las vistas de administración dinámica de sistema sys.dm_exec_request y sys.sysprocesses para localizar los bloqueos. Además de la función sys.dm_exec_sql_text para devolver el texto de la consulta que está ejecutando esa sesión. En determinadas ocasiones, dependiendo del bloqueo, es posible que este script no resuelva debido a la función. En esos casos comenta esa parte del código para por lo menos localizar los bloqueos.

Espero que te haya gustado el video, si es así por favor, deja tu me gusta y suscríbete al canal que nos ayuda mucho. Si tenéis alguna duda o sugerencia, podéis dejarla en Twitter, por mail o dejarnos un mensaje en los comentarios. Y recuerda que también tenemos un grupo de Telegram al que te puede unir. En este grupo estamos creando una comunidad de usuarios y administradores de SQL Server donde cualquiera pueda preguntar sus dudas y compartir sus casos prácticos para que todos seamos mejores profesionales. ¡Hasta la próxima!

Publicado por Roberto Carrancio en Cloud, Rendimiento, SQL Server, Videos, 0 comentarios

Plegado de consultas en Power BI

Si ya has trabajado alguna vez con Power BI, sobre todo si te has interesado por su rendimiento, te sonará el concepto plegado de consultas (query folding en inglés). Este concepto es clave en el rendimiento de power BI y sin embargo a mucha gente se le escapa o no lo comprende muy bien. Hoy, voy a intentar arrojar algo de luz sobre este tema de manera sencilla y para todos los públicos aunque, ya os adelanto que el tema da para mucho y si os interesa al final del artículo os dejo alguna recomendación extra para continuar aprendiendo. 

¿Qué es el plegado de consultas?

Empecemos por el principio, el plegado de consultas, o “Query Folding”, es un proceso por el cual el motor de Power Query (mashup engine) intenta llevar a cabo la mayor cantidad de transformaciones de datos posible en los sistemas de origen origen, en lugar de hacerlo después de que los datos se hayan cargado en la memoria. Esto puede resultar en una mejora significativa del rendimiento de Power BI, especialmente cuando se trabaja con grandes volúmenes de datos.

¿Qué es Power Query?

¡Quieto Roberto! A más de uno le acaba de volar la cabeza con el párrafo anterior. He introducido el concepto Power Query sin explicaros lo que es, perdonadme. Power Query es una característica de Power BI que cumple las funciones de ETL (extraer, transformar y cargar datos). Gracias al motor mashup engine es capaz de extraer datos de varios orígenes, transformar lo que sea necesario y por último cargarlos en un destino. Principalmente vamos a poder encontrar esta función en Power BI, en los flujos de datos de Power BI (dataflows) y en Microsoft Excel 2016 o superiores. Adicionalmente vamos a poder usar Power Query en Excel 2010 y 2013 si descargamos e instalamos manualmente el componente.

¿Cómo funciona el plegado de consultas?

Cuando creamos una consulta con lenguaje M en Power Query, estamos definiendo una serie de pasos para obtener y transformar nuestros datos. Estos pasos pueden incluir filtrado, agrupación, unión de tablas, entre otros. Idealmente, queremos que estos pasos se realicen en el origen de los datos. Esto es lo que se conoce como plegado de consultas y se podrá llevar a cabo en la mayoría de los casos si los orígenes admiten lenguaje SQL y, siempre y cuando, la instrucción M se traduzca en una sola select con funciones que existan en el lenguaje SQL.

El siguiente diagrama de la documentación oficial de microsoft explica el proceso paso a paso:

Diagrama-plegado-consultas
  1. Power Query recibe el script en código M desde el editor avanzado.
  2. El mecanismo de plegado de consultas envía una consulta de metadatos al origen de datos para evaluar sus características.
  3. El mecanismo de plegado de consultas determina qué información extraer del origen de datos y qué conjunto de transformaciones deben producirse dentro del motor de Power Query. 
  4. Power Query consulta el origen de datos mediante una consulta nativa.
  5. El origen de datos devuelve los datos al motor de Power Query.
  6. Una vez que los datos están en Power Query, el motor de transformación de Power Query (también conocido como motor de mashup) realizará las transformaciones que no se pudieron plegar ni descargar en el origen de datos.
  7. Carga en el modelo de Power BI (o en excel) de los datos extraídos y transformados.

¿Por qué es importante?

El plegado de consultas es especialmente útil cuando trabajamos con grandes conjuntos de datos. Al realizar las transformaciones en el origen de los datos, reducimos la cantidad de datos que necesitamos cargar en la memoria, lo que puede resultar en un rendimiento significativamente mejorado. Si por ejemplo solo necesitamos unas pocas filas y columnas de la tabla de origen, gracias al plegado de consultas no vamos a tener que traer todos los datos para luego filtrarlos. Igualmente si, podemos realizar las uniones entre tablas, agregaciones y ordenados en el origen (que está optimizado para ello) es trabajo que le quitamos a nuestro Power BI.

Tiene otras ventajas, como que Power BI optimizará en gran medida las cargas incrementales de los datos cuando las consultas son 100% plegables ya que si no habría que leer todo el origen y cargarlo en memoria para que el mashup engine cribe las filas nuevas de las ya existentes.

¿Cómo saber si se está realizando el plegado de consultas?

Power Query Dataflows proporciona indicadores visuales que nos permiten saber si se está realizando el plegado de consultas. Estos indicadores se encuentran en la ventana de Power Query y nos muestran qué pasos se están plegando a través de iconos. Esto está muy bien resumido en la documentación oficial así que os dejo directamente el extracto.

Plegado-de-consultas

En Power BI Desktop no va a ser tan sencillo verlo como mirar los iconos al lado de los pasos de la transformación, sin embargo, eso no significa que no podamos verlo. Simplemente con hacer clic derecho sobre el paso y verificar si nos está ofreciendo ver la consulta nativa podremos saber si se mantiene o no el plegado de consultas.

Andrés en nuestro grupo de Telegram añade: «Otra de las formas de saber si el plegado se mantiene, es con la función Value.Metadata (tabla). Devuelve información sobre si existe o no el plegado. Del mismo modo, podemos usar una instrucción para mantener el plegado, es con la función Value.NativeQuery() y con el parámetro EnableFolding=true. Esto nos permitirá enviar una consulta directa a SQL Server, mantener el plegado y poder seguir realizando pasos que mantengan el plegado. El problema es que cuando escribes directamente la consulta desde el conector a SQL Server, la consulta ya no seguirá plegando de ahí en adelante. Por suerte, la función Value.NativeQuery(…), si nos permite esto.«

Niveles de plegado de consulta

Como hemos visto a lo largo de este artículo, existen ciertas operaciones de transformación de datos incompatibles con el plegado de consultas. A esto se le llama romper el plegado de consultas y deberemos evitarlo en la medida de lo posible. Aun así, esto no quiere decir que la consulta ya no se vaya a plegar por tener un paso incompatible, la optimización del motor de Power Query sabrá plegar todos los pasos posibles y solo efectuar en el motor de transformaciones lo estrictamente necesario. En este sentido, nos vamos a encontrar con tres niveles de plegado de consultas:

  • Plegado de consultas completo: Todas las transformaciones de consulta se delegan en el origen de datos. El motor de Power Query realiza un procesamiento mínimo y muy eficiente.
  • Plegado parcial de consultas: Una parte de las transformaciones de la consulta, y no todas, se pueden delegar en el origen de datos. En este caso, una parte de las transformaciones las realiza el origen de datos y el resto se producen en el motor de transformaciones de Power Query.
  • Sin plegado de consultas: La consulta no se puede plegar. Normalmente contiene transformaciones que no se pueden traducir al lenguaje de consulta nativo del origen de datos, ya sea porque las transformaciones no son compatibles o porque el conector no admite el plegado de consultas. En este caso, Power Query obtiene los datos sin procesar del origen de datos y utiliza el motor de Power Query para lograr los datos deseados mediante el procesamiento de las transformaciones necesarias a nivel del motor de Power Query.

Conclusión

El plegado de consultas es un concepto complejo pero crucial para el rendimiento en Power BI. Si trabajas a menudo con Power Query dedica tiempo a entender en profundidad esta funcionalidad y así mejorar considerablemente tus resultados. Por mi parte no me queda más que, como os había prometido al inicio, recomendaros el libro “Power BI Dataflows” de Francisco Mullor para convertiros en unos verdaderos maestros de la herramienta. Si solo os interesa este tema que hemos tratado hoy o si queréis usarlo como aproximación al libro, Fran ha publicado el capítulo dedicado al plegado de consultas de manera que está accesible de manera gratuita aquí. También podéis pasar por la academia virtual de Alex Ayala donde encontraréis cursos de Power BI de gran calidad.

Si tenéis alguna duda o sugerencia, podéis dejarla en Twitter, por mail o dejarnos un mensaje en los comentarios. Y recuerda que también tenemos un grupo de Telegram y un canal de YouTube a los que te puede unir. ¡Hasta la próxima!

Publicado por Roberto Carrancio en Power BI, Rendimiento, 0 comentarios