indices

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

¿A qué se debe el crecimiento excesivo de bases de datos?

El crecimiento descontrolado de las bases de datos es una preocupación común para los administradores de sistemas y bases de datos. El aumento natural de los datos puede ser una explicación pero, en ocasiones, este crecimiento puede estar influenciado por errores de modelado, configuraciones inadecuadas y prácticas de gestión poco eficaces. En este artículo, abordaremos algunos errores comunes que contribuyen a este problema y veremos soluciones prácticas para tratar de evitarlo.

Crecimiento normal de los datos

Antes de entrar en detalles sobre cómo controlar el crecimiento de nuestros datos tenemos que dejar clara una cosa. Tu base de datos va a crecer, es el comportamiento común. El crecimiento natural y orgánico de las bases de datos es un fenómeno esperado en cualquier sistema en funcionamiento. A medida que se almacenan más datos, ya sea por la expansión de la empresa, el aumento de las operaciones o la recopilación de información de clientes y transacciones, es normal que las bases de datos crezcan. Este crecimiento, aunque esperado, debe ser gestionado adecuadamente para evitar problemas de rendimiento y costes innecesarios.

Crecimiento por errores de modelado de bases de datos

Una de las áreas fundamentales donde se pueden originar problemas de crecimiento en bases de datos es en el diseño y modelado de la propia base de datos. Errores como la falta de normalización adecuada o la sobrecarga de índices pueden llevar a un uso ineficiente del espacio y un crecimiento innecesario de la base de datos.

Falta de normalización adecuada

Una de las causas más frecuentes del crecimiento innecesario de bases de datos que he podido contemplar a lo largo de los años es una falta de normalización adecuada. La normalización ayuda a minimizar la redundancia de datos y garantiza la integridad referencial. Sin embargo, cuando no se aplica correctamente, puede resultar en la duplicación de datos a lo largo de varias tablas, inflando el tamaño total de la base de datos.

Para ponerle solución, es recomendable revisar el diseño de las bases de datos para asegurar que estén normalizadas correctamente. Aunque en algunas situaciones específicas pueda ser necesario que  desnormalicemos los datos para mejorar el rendimiento, sobre todo en entornos analíticos y de BI, esta decisión debemos tomarla con precaución y basándonos en un análisis sólido de las necesidades de la aplicación.

Sobrecarga de índices

Otro de los errores que más se cometen es el uso excesivo de índices. Es tan común ver bases de datos con índices innecesarios o duplicados como bases de datos sin índices. Este es otro problema que puede contribuir al crecimiento de las bases de datos ya que los índices nonclustered son objetos separados de la tabla que requieren su propio almacenamiento duplicando los datos en cada índice que aparezcan. Aunque los índices son fundamentales para acelerar las consultas, mantener demasiados puede llevar a un aumento innecesario en el tamaño de la base de datos, además de afectar el rendimiento durante las operaciones de inserción, actualización y eliminación.

La solución es sencilla, revisar los índices que no se utilizan y eliminarlos, pero a la vez requiere de conocimientos avanzados tanto de administración como del uso de la base de datos para no eliminar un índice que sí sea importante para el rendimiento. Otra buena práctica es usar índices filtrados cuando sea posible ya que pueden proporcionar beneficios de rendimiento específicos sin un aumento significativo en el espacio de almacenamiento.

Crecimiento por configuraciones inadecuadas en SQL Server

Además del diseño de la base de datos, la configuración del servidor SQL también puede influir significativamente en el tamaño y rendimiento de la base de datos. Configuraciones inadecuadas, como el modo de recuperación FULL sin una correcta gestión de los logs de transacciones, o una configuración incorrecta del tamaño del archivo, pueden provocar un crecimiento inesperado y descontrolado.

Modo de recuperación FULL y log de transacciones

El modo de recuperación FULL es esencial para una recuperación completa en caso de desastres, ya que registra todas las transacciones. Sin embargo, si no se gestionan adecuadamente, los logs de transacciones pueden crecer de forma incontrolada, ocupando mucho espacio en disco. Cuando configuras este modo de recuperación tienes que habilitar una buena política de backups con backup log frecuentes o vas a encontrarte con problemas de crecimiento del log descontrolado.

Como hemos dicho la solución es sencilla en este caso, basta con implementar una estrategia de backups regulares de los logs de transacciones. Esto no solo controla el tamaño del log, sino que también es crucial para la recuperación de datos. Es importante revisar la frecuencia de los backups y ajustar las políticas de recuperación según las necesidades de la organización. Si no es necesario este tipo de copias regulares deberías replantearte el modo de recuperación de tu base de datos.

Configuración inadecuada del tamaño del archivo

Es importante entender la diferencia entre el tamaño del fichero y el tamaño de los datos, ya que esta distinción puede proporcionar una visión más clara sobre cómo se está utilizando el espacio en la base de datos y qué medidas pueden ser necesarias para optimizar su rendimiento y almacenamiento. En SQL Server los archivos de base de datos se dimensionan más allá del tamaño real que tienen ocupado por los datos para que las futuras escrituras sean más rápidas. Este espacio libre en los ficheros es importante, por tanto, para el rendimiento pero hay que saber gestionarlo. Una configuración inicial incorrecta del tamaño de los archivos de datos y logs, junto con opciones de autogrowth mal configuradas, puede resultar en un crecimiento fragmentado y subóptimo de los archivos. Esto puede llevar a un uso ineficiente del espacio en disco y afectar negativamente el rendimiento. 

Para evitar estos problemas debemos configurar adecuadamente el tamaño inicial de los archivos de datos y logs basándonos en las previsiones de crecimiento de la base de datos. Sin embargo, las bases de datos cambian con el tiempo y deberemos ajustar los incrementos de autogrowth para minimizar la fragmentación y asegurar un uso eficiente del espacio en disco.

Crecimiento por errores de aplicación

Los errores en el diseño y configuración no son las únicas fuentes de problemas. Las aplicaciones que interactúan con la base de datos pueden causar un crecimiento descontrolado, especialmente si no gestionan adecuadamente las transacciones o si insertan datos de manera ineficiente. 

Errores de aplicación en la gestión de transacciones

Uno de los errores más comunes que puede llevar al crecimiento descontrolado de los logs de transacciones es el manejo inadecuado de las transacciones por parte de las aplicaciones. Esto incluye transacciones que permanecen abiertas por mucho tiempo o que no se cierran correctamente, lo cual puede causar un aumento innecesario en el tamaño del log.

Debemos revisar y optimizar el código de la aplicación para asegurarnos de que las transacciones se manejen de manera eficiente. Es crucial que las transacciones sean lo más cortas posibles y que se cierren correctamente para evitar el crecimiento innecesario del log. Prestaremos una atención especial a las transacciones de larga duración o aquellas que se producen con demasiada frecuencia.

Errores por insertar datos erróneamente

Otra causa de crecimiento desmedido es la inserción de datos redundantes debido a errores de lógica en la aplicación o a escrituras descontroladas en tablas de log de actividad de las aplicaciones o procesos. Esto puede suceder cuando las aplicaciones insertan datos duplicados debido a fallos en la validación o la falta de controles adecuados para evitar duplicados.

Para evitarlo, deberemos implementar mecanismos de validación en el nivel de la aplicación para prevenir la inserción de datos redundantes. Además, utilizar restricciones de unicidad y primary keys en la base de datos para garantizar la unicidad de los registros. Las tablas de auditoría o de log deberán limpiarse frecuentemente y revisar que la información registrada es útil. Por ejemplo, una buena práctica si un proceso tiene una lógica de reintentos es solo registrar una vez el error y poner una columna con un contador de repeticiones si el error es el mismo en cada reintento.

Evitar el crecimiento con mantenimiento

La gestión y mantenimiento regulares de nuestros datos es fundamental para controlar el tamaño de las bases de datos SQL Server. Esto incluye la limpieza de datos obsoletos y una monitorización constante del rendimiento y el uso del almacenamiento. Sin una gestión adecuada, es fácil que el crecimiento se descontrole, afectando el rendimiento y la eficiencia del sistema.

Limpieza de datos obsoletos

Las bases de datos tienden a acumular datos obsoletos o redundantes que ya no son útiles para la operación actual, contribuyendo al crecimiento desmedido. Esto es especialmente problemático en sistemas que carecen de políticas de limpieza o archivado de datos. Establecer procedimientos regulares de limpieza para eliminar registros obsoletos y/o implementar políticas de retención de datos y archivado que permitan gestionar los datos históricos de manera eficiente, liberará espacio en nuestras bases de datos más activas.

Monitorización y mantenimiento

Para terminar con este artículo, y aunque esto no es un error como tal no quería dejar de comentar que la falta de monitorización y mantenimiento adecuado puede permitir que problemas de crecimiento pasen desapercibidos. Esto incluye no solo el seguimiento del tamaño de los datos y logs, sino también la identificación de problemas de rendimiento que pueden indicar un uso ineficiente de recursos. Utilizar herramientas de monitorización propias o de terceros y establecer alertas ante crecimientos inusuales de bases de datos y logs puede evitarnos el problema de que el servidor termine quedándose sin espacio y deje de admitir nuevas transacciones. 

Conclusión

El crecimiento excesivo de las bases de datos SQL Server a menudo se debe a una combinación de errores de modelado, configuraciones inadecuadas y prácticas de gestión insuficientes. Abordar estos problemas con soluciones prácticas, como la normalización adecuada, la gestión eficiente de índices, y la implementación de políticas de mantenimiento y backups, puede ayudar a controlar el tamaño de la base de datos y asegurar un rendimiento óptimo. Con un enfoque proactivo en estas áreas, seremos capaces de manejar el crecimiento de las bases de datos de manera más efectiva y evitar problemas futuros relacionados con el almacenamiento y el rendimiento.

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, SQL Server, 1 comentario

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

Detectando fragmentación de índices en SQL Server y Azure

Volvemos a la carga con un artículo sobre índices de esos que tanto nos gustan. Esta vez vamos a hablar de un tema muy importante y es detectar qué índices están más fragmentados y cómo solucionarlo. A menudo vemos que una mala gestión de los planes de mantenimiento provocan una degradación del rendimiento de las consultas y eso, gran parte de las veces es debido a un problema de fragmentación de índices o falta de mantenimiento de las estadísticas. Hoy vamos a centrarnos en el primero de estos aspectos.

¿Cómo detectar fragmentación en los índices?

Para ver la fragmentación de un índice en concreto podemos hacerlo desde el entorno gráfico de nuestro SSMS, haciendo click derecho sobre el objeto y mirando sus propiedades. Sin embargo, esto no es práctico cuando tenemos cientos de índices en nuestra base de datos y queremos saber de un vistazo cuales son los más fragmentados y cuanto. Para ello, usaremos una consulta sobre la función de sistema sys.dm_db_index_physical_stats

Otra de las cosas que debemos tener en cuenta es el tamaño de nuestra tabla, con menos de 1000 páginas, el motor de base de datos directamente ignorará los índices nonclustered y, en el caso de los clustered, tampoco vamos a notar diferencia.

Con esto en mente vamos a preparar el script. 

Revisemos el script, por un lado podemos ver que a la función para ver las estadísticas de los índices le estamos pasando el id de la base de datos actual para que se ejecute en ese contexto. Esto es para evitar que se ejecute por todas las bases de datos y podamos tener un problema de rendimiento con esta consulta. Por otro lado vemos que solo afecta a tablas y vistas de usuario que tengan un índice clustered, el tipo de índice 0 está excluido de los filtros. Las tablas HEAP (sin índice clustered) necesitan otro tipo de tratamiento. Podemos ver también el filtro para solo mostrar índices con más de 1000 páginas y el de fragmentación superior al 5%, que suele considerarse el umbral de fragmentación aceptable.

Solucionar fragmentación de índices

Ahora que sabemos cuales son los índices más fragmentados debemos actuar y solucionar el problema. Sabemos que tenemos a nuestra disposición dos alternativas: reorganizar o reconstruir. Para elegir entre una opción u otra tenemos varios factores a tener en cuenta.

Por un lado tenemos el modo de operación de estas instrucciones, reorganizar siempre es una operación online lo que significa que solo generará sobre nuestro índice un intento de bloqueo compartido. El índice se podrá seguir leyendo durante la reordenación sin causar bloqueos. En cuanto a la reconstrucción, solo es online si se lo especificamos manualmente y eso solo es posible en ediciones Enterprise de SQL Server o en las bases de datos o instancias gestionadas de Azure. Si la reconstrucción es offline se generará un bloqueo exclusivo sobre el índice.

Por otro lado, la reconstrucción es más eficiente que la reorganización para porcentajes elevados de fragmentación y eso deberemos tenerlo también muy en cuenta.

¿Debería reorganizar o reconstruir mis índices con mucha fragmentación?

Esto no es una ciencia exacta y es un tema sobre el que hay muchas opiniones discordantes. Normalmente se habla de reorganizar los índices con una fragmentación superior al 5 o 10% y menor al 15 o 30%. Como veis es una horquilla muy amplia y para atinar tenemos que pensar en las las implicaciones de estas operaciones que ya hemos visto antes. Yo os voy a contar cómo lo hago yo pero esto es totalmente personal y deberás adaptarlo a cada caso.

Escenario 1: Mantenimiento programado

En este primer escenario estamos hablando de un mantenimiento programado dentro de una ventana de mantenimiento en la que no hay interferencia con otros procesos. Este caso es el más sencillo porque no tenemos que pensar en no entorpecer a nadie. En estos casos yo pongo el umbral para empezar a actuar en un 5%. Si estamos hablando de una edición Standard de SQL Server reorganizaré los índices con una fragmentación entre un 5 y un 20% y reconstruiré los de mayor fragmentación. Para ediciones Enterprise o Azure reduciré esa horquilla para reorganizar entre un 5 y un 15% y haré reorganizaciones online a partir del 15%.

Escenario 2: Problema puntual de rendimiento

En este escenario estamos hablando de un momento de carga de trabajo elevada en el que hemos recibido o detectado una incidencia por problemas de rendimiento. Tenemos que actuar rápido para solventar la situación pero entorpeciendo lo menos posible a los procesos de negocio que ya de partida tienen un rendimiento mermado. En estos casos pongo el umbral para empezar a actuar en fragmentaciones por encima del 10% en vez del 5. A partir de ahí, si tenemos la suerte de contar con una edición Enterprise, o estamos en Azure, no hay más problema, reconstruiremos con las mismas condiciones que en el escenario anterior, a partir del 15%. Para una edición Standard, donde si vamos a generar bloqueos si reconstruimos, intentaremos reorganizar hasta el 30% de fragmentación.

Solucionar estadísticas desactualizadas

Las estadísticas son clave para SQL Server. Como ya hemos comentado en este blog muchas veces, unas estadísticas desfasadas pueden tener el mismo impacto negativo o peor que un índice fragmentado. Por este motivo, es importante tenerlas en cuenta a la hora de realizar nuestros mantenimientos o enfrentar una incidencia por degradación de rendimiento. Una reconstrucción de índices siempre actualizará las estadísticas asociadas a ese índice pero en el caso de las reorganizaciones deberemos hacerlo manualmente. Tenemos que contar también con que una actualización de estadísticas es más ligera y rápida que un mantenimiento de índices por lo que, en caso de una degradación de rendimiento de una consulta puntual, yo siempre actualizo las estadísticas de las tablas involucradas como primera medida.

Conclusión

Ante un problema de rendimiento, tenemos que verificar el estado de nuestros índices y estadísticas. Además, consultar su nivel de fragmentación será clave a la hora de decidir si vamos a reorganizarlo o reconstruirlo y, todo esto, siempre sin dejar de lado las estadísticas. Tened en cuenta que por mucho que tengamos implementada una solución de mantenimiento de índices y estadísticas nunca vamos a estar 100% seguros de que no va a haber una variación tal de datos que nos va a generar fragmentación o a dejar desfasadas nuestras estadísticas. Es importante que mantengamos una monitorización y vigilancia continua para garantizar el mejor desempeño de nuestros SQL Server.

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 LinkedIn y un canal de YouTube a los que te puede unir. ¡Hasta la próxima!

Publicado por Roberto Carrancio en Cloud, Índices, Rendimiento, SQL Server, 1 comentario

Configurar planes de mantenimiento en SQL Server y Azure

Hola a todos y bienvenidos a este nuevo formato de Video Blog que espero que os guste y que podamos ver por aquí más a menudo. Hoy vamos a ver un caso práctico sobre como configurar planes de mantenimiento en nuestro SQL Server o instancia administrada en Azure gracias a los script de Ola Hallengren. En todo este tiempo como DBA (más de 10 años) os aseguro que más del 90% de las incidencias por supuestos problemas de rendimiento a las que me he enfrentado eran siempre por lo mismo, una falta de mantenimiento correcto. Por esto es importante programar tareas de reconstrucción de índices y mantenimiento de estadísticas. Y ya de paso, aprovechamos y configuramos las copias de seguridad y comprobaciones de integridad que también nos ofrece esta solución gratuita. Pocas veces vas a encontrar más por menos.

Guía de capítulos

  • 00:00 Introducción
  • 00:39 Descarga
  • 01:20 Instalación
  • 05:42 Backups
  • 10:15 Integrity Check
  • 11:42 Index Optimize
  • 13:13 Limpieza
  • 13:54 Log de procesos

Configurar planes de mantenimiento

Como podemos ver en el vídeo para descargar los scripts de mantenimiento solo deberemos acudir a la web de Ola Hallengren y descargar el script que se llama «MaintenanceSolution.sql». Con el script ya abierto en nuestro SSMS podremos configurar la base de datos donde se van a crear los scripts y una serie de configuraciones importantes para los jobs.

Una vez instalada la solución de planes de mantenimiento vamos a poder configurar en los distintos jobs las tareas de copias de seguridad, supervisión de la integridad y reconstrucción y actualización de índices y estadísticas para las bases de datos de sistema y de usuario. También es importante que configuremos los trabajos que incluyen las tareas de mantenimiento para no encontrarnos con incidencias de espacio en disco en un futuro.

Esta solución, además, tiene la ventaja de dejar un log bastante completo en una tabla llamada CommandLog que estará en la misma base de datos que hayamos creado los procedimientos almacenados de mantenimiento. En esta tabla podremos encontrar todo el historia de ejecuciones de todos los comandos con su detalle, horas de inicio y de fin y, por supuesto, si ha dado un error veremos el por qué.

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

Claves Foráneas (FK): Trucos, Ventajas e Inconvenientes

En las bases de datos, las claves foráneas (FK) son una herramienta esencial para mantener la integridad referencial entre las tablas. Sin embargo, su uso puede tener tanto ventajas como desventajas, especialmente en términos de rendimiento y consumo de CPU. Tanto es así que por ejemplo MySQL por defecto renuncia a la integridad referencial en pro de la velocidad. Otros SGBD relacionales como SQL Server, PostgreSQL u Oracle sí que tratan las FK como una restricción. Comprender este comportamiento es clave para entender el comportamiento de nuestras bases de datos. Pero, veámoslo con detenimiento.

¿Qué son y cómo funcionan las FK?

Como hemos adelantado en la introducción, las claves foráneas son una forma de garantizar la integridad referencial en nuestras bases de datos. Cuando definimos una FK, estamos creando una relación entre dos tablas, donde una tabla tiene una columna o un conjunto de columnas que hacen referencia a una clave primaria en otra tabla. De esta manera no podremos crear en nuestra tabla destino registros con un valor que no exista previamente en la tabla de referencia.

Pensad en un modelo normalizado donde tenemos una tabla de cabeceras de facturas y en otra tabla las líneas de esas facturas. Una FK entre las tablas nos permitirá no poder tener en la tabla de líneas ningún registro que pertenezca a una factura inexistente. Esto tiene más implicaciones, como por ejemplo que en la tabla de facturas no podamos editar o borrar un dato si tiene líneas asociadas que, de otra manera, quedarían huérfanas. 

Actualización y Borrado en Cascada

Las claves foráneas en SQL Server y otros sistemas permiten configurar acciones de actualización y borrado en cascada. Esto significa que cuando se actualiza o se elimina un registro en la tabla principal, SQL Server automáticamente actualizará o eliminará los registros correspondientes en las tablas relacionadas.

La principal ventaja de la actualización y borrado en cascada es que simplifica la gestión de las bases de datos. No necesitamos escribir código adicional para manejar estas operaciones, ya que SQL Server se encarga de ello por nosotros. Esto puede ahorrar tiempo y reducir la posibilidad de errores.Sin embargo, la actualización y borrado en cascada también tienen sus inconvenientes. Si no se utilizan correctamente, pueden llevar a la eliminación inadvertida de datos. Por lo tanto, es importante utilizar estas características con cuidado y entender completamente sus implicaciones antes de implementarlas.

En resumen, la actualización y borrado en cascada son herramientas poderosas que pueden simplificar la gestión de nuestras bases de datos. Sin embargo, como con cualquier herramienta, deben utilizarse con cuidado y con un entendimiento completo de sus ventajas e inconvenientes.

Ventajas de las FK

Las FK proporcionan varias ventajas. La más importante, como ya hemos visto, es la garantía de la integridad referencial. Esto significa que no podemos tener datos huérfanos en nuestra base de datos. Además, las FK pueden ayudar a mejorar la legibilidad y la organización de nuestra base de datos. Además tienen otra gran ventaja que a menudo pasamos por alto y no es otra que facilitarnos la comprensión del modelo de datos.

Mantenimiento de la Integridad referencial

Las FK garantizan que los datos en las tablas relacionadas siempre sean consistentes. Esto es crucial para evitar anomalías de datos y garantizar la precisión de los resultados de las consultas.

Comprensión del modelo de datos

Las FK simplifican el proceso de entender el modelo de datos, sobre todo cuando nos enfrentamos a él por primera vez y no hay documentación. Al proporcionar conexiones claras entre las tablas es sencillo entender esas relaciones para cualquiera que lo sepa leer.

Inconvenientes de las FK

A pesar de sus ventajas, las FK, como todo, también tienen sus inconvenientes. Como hemos mencionado, pueden afectar al rendimiento y al consumo de CPU y disco. Además, pueden complicar las operaciones de inserción, actualización y eliminación, ya que requieren comprobaciones adicionales.

Rendimiento

El uso de FK puede tener un impacto significativo en el rendimiento y el consumo de CPU y el disco duro de nuestra base de datos. Cuando se inserta, actualiza o elimina un registro en una tabla que tiene una FK, SQL Server debe realizar comprobaciones adicionales en todas las tablas referenciadas para mantener la integridad referencial. Esto puede aumentar el tiempo de ejecución de estas operaciones y, por lo tanto, el consumo de CPU y disco. Personalmente he llegado a operaciones tan simples como un DELETE por la PK de una tabla que, debido a las FK, obliga a SQL Server a leer más de 50 tablas. Tenemos que tener cuidado con esto sobre todo a medida que el modelo de datos crece y las relaciones entre las tablas se complican.

Además, las verificaciones de integridad referencial requieren un procesamiento adicional, lo que puede aumentar el consumo de CPU además del disco duro. En sistemas con una gran cantidad de transacciones, esto puede ser un problema. Recuerda mantener siempre una buena monitorización sobre el rendimiento de tu modelo de datos.

Complejidad de las operaciones de escritura

No solo nos vamos a encontrar con degradaciones en el rendimiento de SQL Server sino que, para nosotros como DBAs y para los administradores de los datos también se va a añadir una capa de complejidad a la hora de trabajar con los datos. Son escenarios muy comunes para un DBA el de restaurar solo los datos de una tabla de la copia de seguridad o el de copiar datos entre distintos entornos. En estos casos, por ejemplo, tendremos que tener muy claro el orden de las inserciones y deberemos hacerlo de manera secuencial para evitar errores. O eso o deshabilitamos temporalmente las FK pero en este caso deberemos validarlas otra vez al activarlas y en tablas grandes eso es inviable. 

Indexar para evitar los inconvenientes de las FK

Como hemos podido ver, el hecho de tener FKs en nuestra base de datos va a añadir una lógica adicional a las transacciones de escritura lo que va a provocar un mayor consumo de recursos y por tanto un peor rendimiento de nuestro SQL Server. En este sentido, el indexado de los campos de las claves foráneas es una práctica esencial que puede mejorar significativamente el rendimiento de nuestras bases de datos. Crear índices para esos campos referenciados por una clave foránea permitirá, que a la hora de actualizar o borrar un registro en la tabla principal, SQL Server pueda usarlos para verificar rápidamente la integridad referencial sin tener que leer completamente la tabla.

Conclusión

Las claves foráneas son una herramienta poderosa en SQL Server pero también es un arma de doble filo. Aunque pueden tener un impacto en el rendimiento y el consumo de CPU, los beneficios que aportan en términos de integridad referencial suelen superar estos costes. Como siempre, la clave está en entender cómo funcionan y usarlas de manera inteligente. Recuerda, cada base de datos es un mundo y lo que funciona en uno puede no funcionar en otro. Por lo tanto, siempre es recomendable probar y monitorizar el rendimiento antes de implementar cualquier cambio a gran escala.

Como siempre, te animo a experimentar con estas técnicas y a explorar todas las posibilidades que ofrecen. 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 LinkedIn y un canal de YouTube a los que te puede unir. ¡Hasta la próxima!

Publicado por Roberto Carrancio en Rendimiento, SQL Server, 1 comentario

Impacto en el rendimiento de índices FullText

Llevamos los dos últimos artículos hablando de los índices de texto completo (FullText) en SQL Server. Hemos aprendido lo qué son y cómo se administran, sin embargo hay un tema, quizá lo más importante, que habíamos dejado para el final. Y no es otro que su uso y el impacto en el rendimiento. ¿Realmente merece la pena este tipo de índices? Vamos a descubrirlo juntos.

Cláusulas específicas para buscar en índices FullText

Normalmente cuando tenemos que buscar texto dentro de una columna en SQL usamos la cláusula LIKE y nos apoyamos en el carácter % que hace de comodín. Sin embargo, cuando hemos añadido una columna a un índice FullText se nos habilitan otras opciones de búsqueda como son CONTAINS, FREETEXT, CONTAINSTABLE y FREETEXTTABLE. Aunque todas son cláusulas para filtrar por texto tienen algunas diferencias que debemos conocer.

CONTAINS: La Precisión

CONTAINS es una cláusula que permite realizar búsquedas de texto completo en columnas de tipo char, varchar o text dentro de SQL Server. Esta cláusula es especialmente poderosa por su capacidad de buscar palabras o frases específicas, e incluso formas de una palabra, dentro de un texto. Por ejemplo, si queremos encontrar todos los registros que contengan la palabra «optimización», CONTAINS nos facilitará esta tarea con gran precisión.

FREETEXT: La Relevancia 

Por otro lado, FREETEXT es menos estricta que CONTAINS y se utiliza para buscar términos que sean «similares» o relacionados con el texto de la consulta, sin necesidad de que sean exactos. Es decir, FREETEXT no solo nos va a devolver los campos que contengan esa palabra sino también los que contengan algún sinonimo.  Esto es ideal para cuando la intención es más importante que la coincidencia literal, permitiendo una búsqueda más «libre» y basada en la relevancia.

CONTAINSTABLE: Resultados Ordenados

CONTAINSTABLE es una función que extiende las capacidades de CONTAINS, devolviendo una tabla de resultados con las filas que coinciden con la búsqueda, junto con un rango de relevancia, conocido como «rank». Esto permite no solo encontrar las coincidencias, sino también ordenarlas por su relevancia, facilitando la identificación de los resultados más pertinentes.

FREETEXTTABLE: Mayor Flexibilidad en la Búsqueda

Similar a CONTAINSTABLE, FREETEXTTABLE aplica los principios de FREETEXT a una tabla de resultados clasificables. Esta función es crucial cuando buscamos entender el contexto general de los términos de una búsqueda dentro de un conjunto de datos, proporcionándonos una clasificación que nos ayuda a discernir la importancia relativa de cada registro encontrado.

Sintaxis y ejemplos de la búsqueda de texto

Ahora que ya sabemos las diferencias entre las distintas búsquedas vamos a ver como se usan en un caso práctico. Para esto vamos a usar la base de datos de ejemplo de Microsoft AdventureWorks. Como ya sabréis (o no, no importa) esta base de datos tiene datos de ejemplo de una tienda de bicicletas. Vamos a buscar, entonces, por la palabra rendimiento en la tabla de descripciones de los productos. Lamentablemente no tenemos una base de datos AdventureWorks con datos en español así que tendremos que buscar en inglés pero es solo por esto. Vosotros tendreis que buscar en el idioma que tengáis vuestros datos y, muy importante, tendréis que haber creado directamente el índice en ese idioma (si no sabéis como se hace os lo conté aquí). 

Vamos a hacer la misma búsqueda con todas las posibles opciones que hemos visto antes:

Podríamos entrar aquí y ahora en todas las opciones avanzadas de filtrado que incluyen cada una de estas opciones frente al tradicional y simple LIKE pero, convertiría este artículo en eterno y tampoco es el objetivo del post. Si queréis profundizar más tenéis la documentación oficial y si queréis que veamos aquí algunos ejemplos podeis pedirmelo y lo haremos. 

Rendimiento en las búsquedas de texto

Vamos ahora a comparar el rendimiento de las consultas anteriores. Para que el ejemplo tenga más relevancia he creado aproximadamente unos 200.000 registros en la tabla en lugar de los menos de 800 que trae cuando restauramos la base de datos. No sufráis por eso que después de eso también he actualizado los índices y estadísticas de la tabla. Esto nos va a permitir verificar mejor las diferencias.

Estos han sido los resultados ejecutando las anteriores consultas:

CláusulaTiempo de CPULecturas lógicasPorcentaje del plan
LIKE781 milisegundos4365 páginas77%
CONTAINS< 1 milisegundo278 páginas5%
FREETEXT< 1 milisegundo278 páginas7%
CONTAINSTABLE< 1 milisegundo278 páginas5%
FREETEXTTABLE< 1 milisegundo278 páginas7%
FullText_Performance1
FullText_Performance2

Las conclusiones son obvias, el mayor consumo de recursos es con Like, cuando no se usa el índice FullText tardando 780 veces más en completar la consulta y leyendo 34 Mb de información (4365 páginas * 8Kb por página / 1024 = 34 Mb) frente a los solo 2 Mb de información que se leen las consultas que sí hacen uso del índice de texto completo. 

Rendimiento en escrituras

Ya hemos hablado en varias ocasiones de esto pero no está de más recordarlo, los índices en SQL “no son gratis” y por no son gratis me refiero a que hay un precio a pagar por toda esta mejora de rendimiento en las lecturas. En concreto el precio a pagar es un gran empeoramiento de las escrituras. Para verificar hasta dónde es negativo este impacto en las escrituras he creado una tabla en mi SQL Server con la misma estructura que con la que estamos haciendo la prueba y con los mismos datos pero sin el índice de texto completo. Si que tiene el resto de los índices que tiene la tabla original (PK + Nonclustered). A continuación he insertado en las dos tablas los mismos 100.000 registros para medir los tiempos. 

FullText_Performance3

Como podéis ver en la imagen, el resultado de la inserción en la tabla sín índice FullText ha tardado 225 milisegundos frente a 1079 milisegundos en la tabla que tiene índice de texto completo. En cuanto a la información que se ha necesitado leer para hacer la inserción encontramos que para insertar en la tabla con FullText hemos tenido que leer 12,6 Gb de información mientras que para la que no tiene ese índice solo hemos tenido que leer 259,2 Mb.

Conclusión

Los índices de texto completo o FullText pueden ser un gran aliado en las consultas de lecturas, no tanto en las escrituras, donde nos pueden llegar a dar verdaderos problemas de rendimiento. Además, al contrario que en los índices normales donde su creación es transparente, para aprovechar la mejora de un índice FullText tendremos que adaptar nuestro código y usar las cláusulas específicas que usarán el índice. 

Espero que esta serie de artículos te haya ayudado a comprender mejor los índices de texto completo y a poder analizar si son o no beneficiosos para tus escenarios de uso actuales y futuros. Como siempre, te animo a experimentar con estas técnicas y a explorar todas las posibilidades que ofrecen. 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 LinkedIn y un canal de YouTube a los que te puede unir. ¡Hasta la próxima!

Publicado por Roberto Carrancio en Índices, Rendimiento, SQL Server, 0 comentarios