Roberto Carrancio

Mi nombre es Roberto Carrancio y soy un DBA de SQL server con más de 10 años de experiencia en el sector. Soy el creador del blog soydba.es donde intento publicar varios artículos a la semana (de lunes a viernes que los fines de semana me gusta estar con mi gente y disfrutar de mi moto) Espero que disfrutes leyendo este blog tanto como yo disfruto escribiendo y que te sea de utilidad. Si tienes alguna sugerencia, pregunta o comentario, puedes dejarlo al final de cada entrada o enviarme un correo electrónico. Estaré encantado de leerte y responderte. ¡Gracias por tu visita! Mi principal interés es compartir mi conocimiento sobre bases de datos con todo el que quiera aprenderlo. Me parece un mundo tan apasionante como desconocido. Fuera de lo profesional me encanta la cocina, la moto y disfrutar de tomar una cervecita con amigos.
Mi nombre es Roberto Carrancio y soy un DBA de SQL server con más de 10 años de experiencia en el sector. Soy el creador del blog soydba.es donde intento publicar varios artículos a la semana (de lunes a viernes que los fines de semana me gusta estar con mi gente y disfrutar de mi moto) Espero que disfrutes leyendo este blog tanto como yo disfruto escribiendo y que te sea de utilidad. Si tienes alguna sugerencia, pregunta o comentario, puedes dejarlo al final de cada entrada o enviarme un correo electrónico. Estaré encantado de leerte y responderte. ¡Gracias por tu visita! Mi principal interés es compartir mi conocimiento sobre bases de datos con todo el que quiera aprenderlo. Me parece un mundo tan apasionante como desconocido. Fuera de lo profesional me encanta la cocina, la moto y disfrutar de tomar una cervecita con amigos.

Azure MI Failover Group vs SQL Server Always On

Hablar de alta disponibilidad en entornos SQL Server es como entrar en un congreso de arquitectos y preguntar por el hormigón armado: todo el mundo tiene una opinión, pero no todos entienden lo que hace que no se les caiga el edificio. Desde que apareció Azure SQL Managed Instance, muchos han querido comparar su Failover Group con el clásico y reputado Always On Availability Groups (AO AG) de SQL Server. Spoiler: no son lo mismo. Ni en arquitectura, ni en control, ni en flexibilidad. Y por mucho que Microsoft los presente como soluciones “equivalentes” en diferentes contextos, la verdad está en los detalles. Ahí donde el marketing calla y el diagrama de red grita.

¿Qué es un Failover Group en Azure SQL Managed Instance?

El Failover Group (FOG, para los amigos) en Managed Instance es un servicio de Azure PaaS que nos permite tener una réplica automática en otra región, con conmutación por error (failover) automática o manual. No hay que gestionar clústeres, ni certificados, ni configurar endpoints: todo se cocina dentro de la infraestructura de Azure. ¿Ventajas? Sencillez. ¿Limitaciones? También las hay, pero menos de lo que algunos creen.

El Failover Group actúa a nivel de instancia. Replica automáticamente todas las bases de datos del grupo seleccionado, manteniendo sincronización asincrónica entre regiones. Y aunque históricamente tenía fama de ser unidireccional y sin opciones de lectura secundaria, eso ya no es cierto: podemos habilitar acceso de solo lectura a la réplica secundaria a través del listener. Eso sí, solo una réplica, y nada de topologías a medida. Pero para muchos escenarios de DR, es más que suficiente.

¿Y qué hace SQL Server con su Always On Availability Groups?

Aquí volvemos al SQL Server clásico, el de verdad, el que instalamos en máquinas (físicas o virtuales), con clústeres de Windows, certificados, endpoints, y todo lo que da gusto configurar a las tres de la mañana cuando algo falla. El AO AG es un modelo de alta disponibilidad y recuperación ante desastres (HA/DR) basado en grupos de disponibilidad, con réplicas sincronizadas (para HA) y asincrónicas (para DR). Admite múltiples réplicas, balanceo de lectura, conmutación automática o manual, y una flexibilidad que muchos aún no saben que están mal usando.

¿Requiere trabajo? Mucho. ¿Te da control absoluto? También. Y eso, en infraestructuras exigentes, marca la diferencia entre diseñar alta disponibilidad y simplemente esperar que Azure haga lo suyo.

Diferencias técnicas clave

Aquí es donde empieza lo interesante. El Failover Group en MI está limitado por diseño: solo una réplica secundaria, sincronización asincrónica entre regiones y sin opción a topologías complejas. Pero lo compensa con gestión simplificada, y sí, un listener que permite direccionar tráfico de lectura y escritura de forma bastante transparente. El parámetro ApplicationIntent=ReadOnly funciona como esperamos, siempre que tengamos configurado el grupo correctamente.

AO AG, por su parte, permite hasta ocho réplicas, elegir sincronización o asincronía según la necesidad, distribuir la carga de lectura, gestionar failover policies con precisión quirúrgica y hasta usar clusterless AGs para entornos que no necesitan HA pero sí replicación. También nos permite ajustar los parámetros internos de cada réplica, implementar scripts personalizados ante fallos y mantener una visibilidad completa del estado del clúster.

La diferencia crítica sigue siendo el acceso al entorno. En SQL Server AO AG tienes control del sistema operativo, del almacenamiento, de la red y del motor de base de datos en sí. En Managed Instance estás dentro de una caja cerrada: puedes administrar lo que te dejan, y cuando algo se rompe, dependes completamente del soporte de Azure. Que sí, son majos. Pero a veces el SLA no consuela cuando tienes al CTO respirando en la nuca.

Ventajas y limitaciones prácticas

El Failover Group de Azure Managed Instance es ideal para quienes quieren alta disponibilidad sin complicaciones, sin pelearse con Windows Server Failover Clustering, sin pensar en discos compartidos ni quorum. Y con la posibilidad de lectura secundaria, gana puntos en escenarios de DR que también exigen analítica o reporting en caliente.

AO AG, por su parte, permite arquitecturas híbridas, complejas y a medida. Pero requiere un nivel de experiencia y de mantenimiento que no todos los equipos pueden asumir. No es para todos, pero en manos expertas es una bestia formidable. Eso sí, como toda bestia, necesita cuidado constante y algo de cariño (o miedo). Cuidado con meterte en esta solución tan compleja si tu equipo no está preparado o tendrás el caldo de cultivo perfecto para un problema grave.

¿Qué debemos elegir para nuestro entorno?

La decisión real no es entre Failover Group y Always On, sino entre PaaS y IaaS (o on-premises). Si tu equipo no puede o no quiere gestionar infraestructura, el Failover Group en Azure MI es una solución más que decente. Pero si necesitas múltiples réplicas, balanceo de lectura avanzado, configuración personalizada o integración con entornos complejos… entonces AO AG sigue siendo la referencia.

También hay que mirar la criticidad del sistema. ¿Puedes tolerar unos minutos de pérdida de servicio mientras Azure detecta y conmuta? ¿O necesitas failover inmediato y con cero pérdida de datos? El RPO y RTO no son iguales, y en algunos casos eso marca la diferencia entre continuidad del negocio y justificación al comité de crisis.

Los precios de ambas soluciones también son decisivos, en Azure Managed Instance tienes que pagar todos los meses depende del tamaño de tu servidor y eso a la larga puede salir caro. Always On, por su parte, no se queda corto ya que vas a necesitar licencias SQL Server Enterprise y, eso no es barato precisamente.

Casos reales y decisiones que duelen

Recientemente, en un proyecto de consultoría, el cliente tenía que mover un entorno crítico de Always On a Azure MI. Las restricciones del Failover Group se hicieron evidentes al tercer día, cuando se dieron cuenta de que no podían controlar la latencia ni ajustar parámetros finos de sincronización. ¿Solución? Replantear parte de la arquitectura y asumir limitaciones. ¿Resultado? Un entorno funcional, sí, pero menos flexible. Y con la sensación de haber pasado de un Fórmula 1 a un coche automático: cómodo, sí. Pero que no te deja cambiar de marcha cuando más lo necesitas.

Conclusión

Failover Group en Azure MI no es el sucesor espiritual de Always On. Es una solución distinta, pensada para escenarios distintos. Si necesitas control, flexibilidad y múltiples réplicas, Always On sigue siendo el rey. Si priorizas simplicidad y mantenimiento mínimo, Failover Group cumple su papel. Y ahora, con acceso de lectura en la réplica secundaria, es más potente de lo que muchos creen.

Pero no confundamos comodidad con equivalencia. Porque cuando llegue el fallo, lo que importa no es la tecnología, sino cómo responde. Y en ese momento, más vale haber elegido bien. ¿Quieres alta disponibilidad sin sustos? Elige con cabeza, no con prisas. Porque lo único peor que una base de datos caída… es una mal diseñada que no sabe caer.

Publicado por Roberto Carrancio en Alta Disponibilidad, Cloud, SQL Server, 0 comentarios

SQL contra el Apocalipsis Mutante (Parte 3): El último asalto

Las noches son cada vez más largas. Los refugios que siguen en pie son fortalezas solitarias rodeadas de silencio y muerte. Pero los supervivientes que completaron las dos primeras partes de esta serie son distintos: dominan SELECTs afilados, JOINs letales y cálculos capaces de prever el caos. Han llegado hasta aquí por méritos propios.

Si acabas de llegar: detente. Aquí no hay atajos. Vuelve al primer capítulo y luego al segundo capítulo para convertirte en un verdadero experto en análisis de datos para sobrevivir al apocalipsis.

Hoy cruzaremos la última frontera: funciones de ventana, CTEs, ROLLUP y CUBE. Con estas habilidades, no solo resistirás: podrás planificar la evacuación, anticiparte a cada ataque y construir un futuro para los últimos humanos.

SurvivalDB: el campo de batalla definitivo

Nuestra base de datos SurvivalDB ha sido nuestro campo de entrenamiento y nuestra línea de defensa y en este último asalto no iba a ser menos. Sus tablas ya te son conocidas: RefugeSupplies, SurvivorStats, MutantSightings y EvacuationRoutes. Hoy, sacaremos todo el jugo posible de sus datos.

Ejercicios: la misión final para salvar a la humanidad

Después de una semana de resistencia, los refugios que aún aguantan necesitan más que coraje: requieren análisis avanzados para planificar el contragolpe o la evacuación definitiva. Hoy vamos a cruzar la última frontera de SQL: funciones de ventana que muestran lo que sucede a tu alrededor, CTEs que revelan rutas de huida imposibles y agregaciones que transforman el caos en información estratégica.

Cada consulta que planteamos a continuación no es sólo un ejercicio: es un paso esencial para decidir si la humanidad logra resistir un día más… o se convierte en recuerdo. Afilad vuestro teclado: el futuro se escribe en T-SQL.

Ejercicio 1: Prioriza refugios con funciones de ventana

Necesitamos saber el orden de prioridad para reforzar refugios: los que más armas tengan irán al final; primero hay que ayudar a los peores armados.

Tu misión: mostrar la información de los refugios con una columna WeaponsRank que indique la posición de cada refugio en el ranking por número de armas. 

Pista: cuando la prioridad depende del orden, las funciones de ventana son tu aliado.

Ejercicio 2: Compara infectados con LAG y LEAD

El Consejo de la Resistencia necesita saber si las infecciones están empeorando refugio a refugio. Comparar cada refugio con el anterior y el siguiente permitirá identificar focos crecientes.

Tu misión: mostrar RefugeID e Infected para cada refugio además de PrevInfected y NextInfected con los valores del refugio anterior y siguiente respectivamente.

Pista: dos funciones en la misma cláusula OVER te darán el pasado y el futuro.

Ejercicio 3: Totaliza avistamientos con ROLLUP

Los analistas necesitan saber la actividad mutante diaria y por zona, pero también los totales diarios y el gran total. Esta vista global decidirá si debemos evacuar o resistir.

Tu misión: agrupar avistamientos por fecha y coordenadas (Latitude, Longitude) y usa ROLLUP para incluir los totales parciales y el gran total.

Pista: agrupar con ROLLUP es como un seguro: te dará todos los niveles de resumen.

Ejercicio 4: Construye rutas de evacuación con CTE recursiva

La evacuación debe organizarse como una cadena desde el refugio inicial al último refugio seguro. Cada ruta conecta dos refugios; necesitamos todas las rutas posibles desde el refugio 1 para planificar el éxodo.

Tu misión: crear una CTE recursiva que muestre todas las rutas desde el refugio 1, listando la secuencia completa de refugios visitados como Path.

Pista: una CTE que se llame a sí misma traza caminos que una simple consulta jamás encontraría.

Ejercicio 5: Agrega por combinaciones con CUBE

Para decidir la distribución de suministros y armas, necesitamos un análisis de refugios agrupados por su estado (CRITICAL u OK) y por rango de armas (0-20, 21-50, >50). Los totales por cada combinación y los globales son imprescindibles.

Tu misión: agrupar por ambos criterios y usar CUBE para obtener todos los totales parciales y el gran total, mostrando también el número de refugios (RefugeCount).

Pista: CUBE permite ver cada combinación posible y cada subtotal en una sola consulta.

Consejo final: sobrevivir no es suerte, es optimización

Llegar hasta aquí no ha sido casualidad. Cada consulta ha reforzado tus habilidades y tu refugio. Pero como cualquier buen plan de supervivencia, hay que mantenerlo actualizado: los índices se fragmentan, los datos crecen y las hordas evolucionan. No bajes la guardia.

¿Quieres las respuestas?

El próximo martes tendremos en YouTube un vídeo con las soluciones paso a paso de este y los anteriores capítulos para que compruebes tu progreso y consolides tu aprendizaje. Pero si lo ves sin practicar antes… no esperes sobrevivir mucho tiempo. Trata de resolver estos ejercicios por tu cuenta antes de recurrir al vídeo y deja en comentarios tus respuestas.

El amanecer tras la noche más oscura

Han pasado varios días desde los primeros ataques. Gracias a los análisis, los refugios críticos fueron reforzados, los más armados ayudaron a los demás y las rutas de evacuación se activaron a tiempo. Los mutantes siguen ahí, pero los supervivientes también. Ahora dominan SQL como nadie y han aprendido que los datos, más que las balas, son el arma definitiva.

Mientras el sol asoma sobre un paisaje todavía plagado de ruinas, una última transmisión interfiere la radio de los refugios: un código desconocido que habla de nuevas hordas, más grandes, más rápidas… y de supervivientes que podrían estar organizándose más allá de lo que creíamos posible.

Porque en este apocalipsis, el verdadero final nunca llega. Y cuando vuelva la oscuridad, volveremos con nuevas queries, nuevas estrategias… y la misma sed de seguir vivos.

 

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

SQL contra el Apocalipsis Mutante (Parte 2): Calcula antes de que te devoren

El humo aún se eleva sobre los refugios que visitamos en el primer capítulo. Algunos apenas aguantan con lo puesto; otros se preparan para resistir. Entre tablas, SELECTs y JOINs empezamos a entender quién tenía posibilidades y quién estaba condenado.

Si te acabas de unir a esta misión y todavía no has completado la Parte 1, detente: no hay gloria para los que intentan correr antes de aprender a caminar. Empieza aquí: SQL contra el Apocalipsis Mutante (Parte 1) y vuelve cuando hayas sobrevivido al primer asalto.

Para quienes seguís con nosotros: bienvenidos al siguiente nivel. Hoy dejaremos atrás los SELECT básicos y nos adentraremos en los cálculos, clasificaciones y agrupaciones. Porque en el apocalipsis, no basta con saber quién está mal; hace falta saber cuán mal están, agrupar por gravedad y priorizar qué hacer antes de que el caos sea total.

Recuerda el escenario: SurvivalDB

Trabajamos sobre la base de datos SurvivalDB, con estas tablas clave:

  • RefugeSupplies: inventario de suministros y armas de cada refugio.
  • SurvivorStats: población e infectados.
  • MutantSightings: registros de avistamientos mutantes.
  • EvacuationRoutes: rutas de evacuación posibles entre refugios.

Ejercicios: el análisis que separa la vida de la muerte

Lo fácil ya se ha acabado, hemos sobrevivido al primer dia pero aun queda mucho que hacer. Vamos a incrementar la dificultad y a trabajar con agrupaciones y operaciones matemáticas en SQL Server.

Ejercicio 1: Calcula la tasa de infección

A simple vista, los refugios parecen estar resistiendo, pero las infecciones avanzan como un cáncer. Queremos saber qué porcentaje de cada refugio está infectado, para encontrar los que superen el 5% y actuar antes de que el pánico los destruya por dentro.

Tu misión: calcula la tasa de infección de cada refugio con dos decimales, muestra RefugeID, Population, Infected y InfectionRate, y ordena por mayor porcentaje.

Pista: deberás hacer un cálculo sobre las columnas y filtrar con un porcentaje.

Ejercicio 2: Clasifica refugios según estado crítico

Los datos de suministros muestran diferencias brutales: algunos refugios están bien; otros al borde del abismo. Queremos etiquetar cada refugio como ‘CRITICAL’ u ‘OK’ según si tienen menos de 10 raciones de comida o menos de 50 litros de agua.

Tu misión: muestra RefugeID, FoodRations, WaterLiters y Status (la etiqueta calculada).

Pista: usa una expresión condicional para devolver un texto según la situación.

Ejercicio 3: Cuenta refugios por estado

Ahora que podemos etiquetar cada refugio, necesitamos saber cuántos están en estado ‘CRITICAL’ y cuántos en ‘OK’. Es el primer paso para dimensionar el desastre.

Tu misión: agrupa por el estado y cuenta el número de refugios en cada grupo como RefugeCount.

Pista: agrupa por la misma lógica que usaste para clasificar.

Ejercicio 4: Analiza actividad reciente de mutantes

Los avistamientos se suceden casi a diario. Necesitamos saber cuántos mutantes se han visto cada día en la última semana para anticipar si la actividad aumenta.

Tu misión: cuenta el número de avistamientos por día, mostrando la fecha (SightingDate como DATE) y el total.

Pista: filtra por fecha reciente, agrupa y cuenta.

Ejercicio 5: Mutantes cerca de refugios críticos

Los refugios en estado crítico son vulnerables. Si además tienen hordas mutantes cerca, la probabilidad de caída es altísima. Queremos combinar los refugios en ‘CRITICAL’ con los avistamientos de los últimos 3 días que estén a menos de 0,5 grados de sus coordenadas.

Tu misión: muestra RefugeID, SightingDate, Latitude, Longitude de los avistamientos cercanos.

Pista: une los datos de refugios críticos con los avistamientos recientes y aplica una condición de proximidad.

Consejo para cuando los mutantes golpeen la puerta

No olvides que los cálculos y agregaciones pueden ser tan peligrosos como un mutante si los usas mal: un mal GROUP BY puede hacer que creas que un refugio está a salvo cuando ya ha caído. Revísalos como revisarías las barricadas de tu refugio.

¿Quieres las respuestas?

Estoy preparando un vídeo en el canal de YouTube donde resolveremos paso a paso estos ejercicios y explicaremos cada detalle para que no sólo los copies, sino que los entiendas. Eso sí, tendrás que esperar a la semana que viene, mientras tanto intenta resolver estos ejercicios por tu cuenta para practicar y deja tus soluciones en comentarios.

Próximamente…

En la próxima entrega, el caos llegará al máximo nivel: funciones de ventana, CTEs y agregaciones avanzadas para planificar la evacuación definitiva. Porque el fin se acerca, y sólo los que dominan SQL hasta el último detalle podrán salir con vida.

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

SQL contra el Apocalipsis Mutante (Parte 1): Aprende SQL y salva el mundo

Las ciudades están en ruinas. Las carreteras, bloqueadas por coches abandonados. El olor a pólvora y carne podrida se mezcla en el aire mientras hordas de mutantes se extienden sin control. Los pocos refugios que aún se mantienen en pie dependen de un único recurso para resistir un día más: los datos de nuestra base de datos SurvivalDB. Y ahí entramos nosotros, con un SQL Server medio polvoriento pero funcionando como un reloj.

En este primer episodio de nuestra serie para aprender a analizar datos en SQL no vas a encontrar dashboards color pastel ni entornos de BI con animaciones, el mundo se acaba y no hay tiempo para eso. Solo tenemos datos crudos, queries eficientes y la urgencia de sobrevivir. Hoy vamos a plantear una serie de ejercicios básicos que te permitirán dominar SELECT, WHERE y JOIN, mientras ayudamos a los últimos supervivientes a organizar sus suministros, identificar amenazas y evitar convertirse en croquetas mutantes.

El escenario: SurvivalDB, el corazón de la resistencia

En nuestro mundo postapocalíptico, la base de datos SurvivalDB es el último bastión de la civilización. Contiene cuatro tablas esenciales que almacenan la información crítica para la resistencia:

  • RefugeSupplies: el inventario de cada refugio, incluyendo comida, agua, armas y ubicación geográfica (latitud y longitud). Saber qué refugio tiene recursos y cuál se muere de hambre es la diferencia entre enviar ayuda o enterrar cadáveres.
  • SurvivorStats: registra la población de cada refugio y el número de infectados. Porque nada genera más pánico que un refugio lleno de supervivientes a punto de convertirse en mutantes.
  • MutantSightings: almacena los avistamientos de hordas de mutantes con fecha y localización. Analizar estos datos permite anticipar ataques y planificar rutas seguras para los supervivientes.
  • EvacuationRoutes: describe las rutas de evacuación posibles entre refugios, indicando desde qué refugio se parte y a cuál se llega. Es vital para planificar la huida cuando la defensa ya no es una opción y sólo queda correr.

Te dejo el script para que crees tú mismo la base de datos, las tablas y los datos que vamos a usar en los ejercicios.

Ejercicios: cada consulta es un capítulo en la lucha por la supervivencia

El destino de los supervivientes depende de cómo consultemos estos datos. Un SELECT rápido puede significar reforzar un refugio a tiempo; un SELECT lento puede significar que ya es demasiado tarde. Comete cualquier error en tus consultas y podrías enviar suministros al refugio equivocado o ignorar un refugio al borde del colapso.

Ejercicio 1: Localiza los refugios al borde del colapso

Tras semanas sin recibir suministros, varios refugios podrían quedarse sin comida ni agua en cualquier momento. Si caen estos refugios, los supervivientes saldrán huyendo y propagarán el caos… o algo peor.

Tu misión: listar los refugios con menos de 10 raciones de comida o menos de 50 litros de agua. Tenemos que conocer el RefugeID, FoodRations y WaterLiters, ordenados de menor a mayor por FoodRations. Al ser el primero este será el único ejercicio con respuesta incluida como ejemplo.

Ejercicio 2: Identifica a los refugios mejor armados

Tras localizar los refugios en situación crítica, el Consejo necesita saber quiénes pueden apoyarlos. Los refugios con más armas son los únicos capaces de enviar ayuda o resistir un asedio prolongado.

Tu misión: mostrar los cinco refugios con mayor número de armas (Weapons), mostrando también RefugeID. Piensa cómo limitar los resultados para centrarte en los más fuertes.

Pista: Ordena tus datos de forma que los primeros sean los más peligrosos… o los más protegidos.

Ejercicio 3: Define la zona caliente del mapa

Los exploradores acaban de interceptar señales de radio que indican grandes movimientos de hordas entre las latitudes 39 y 41 y longitudes -75 y -73. Hay que comprobar si los refugios críticos o mejor armados están dentro de esa zona de peligro inminente.

Tu misión: listar los refugios ubicados en ese rango, mostrando RefugeID, Latitude y Longitude.

Pista: Dos coordenadas definen un área. ¿Cómo filtrarías para quedarte solo con los refugios dentro de esa caja imaginaria?

Ejercicio 4: Conoce a los supervivientes que defiendes

La información reunida hasta ahora es valiosa, pero incompleta. Necesitamos saber cuántos habitantes hay en cada refugio para calcular si tienen suficiente comida, agua y armas para sobrevivir. Sin estos datos combinados, cualquier estrategia será un tiro en la oscuridad.

Tu misión: combinar RefugeSupplies y SurvivorStats para mostrar RefugeID, Population, FoodRations y Weapons de cada refugio.

Pista: La información de suministros y la población viven en tablas distintas, pero tienen algo en común: el refugio.

Ejercicio 5: Identifica tragedias inminentes

El análisis anterior revela un peligro alarmante, algunos refugios tienen mucha gente pero apenas armas. Si un mutante llega, la masacre será inmediata y el caos se extenderá a otros refugios.

Tu misión: encontrar los refugios que tienen menos de 5 armas y más de 50 supervivientes. Estas son las prioridades absolutas para enviar refuerzos antes de que el desastre sea irreversible.

Pista: Para detectar refugios sobrepoblados y mal armados, debes comparar datos que no están en la misma tabla. ¿Cómo unirlos y luego aplicar las condiciones?

Consejo de veterano

En producción, la diferencia entre una consulta optimizada y una chapuza es la misma que entre un refugio reforzado y uno que se desmorona al primer ataque. Indexa, revisa planes de ejecución y parametriza: no estamos jugando, estamos sobreviviendo.

¿Quieres las respuestas?

Estoy preparando un vídeo en el canal de YouTube donde resolveremos paso a paso estos ejercicios y explicaremos cada detalle para que no sólo los copies, sino que los entiendas. Eso sí, tendrás que esperar a la semana que viene, mientras tanto intenta resolver estos ejercicios por tu cuenta para practicar y deja en comentarios tus respuestas.

Próximamente…

En el siguiente episodio subiremos la dificultad: cálculos de tasas de infección, clasificaciones y agrupaciones para decidir a quién ayudar primero. Porque en un mundo arrasado por mutantes, saber sumar y agrupar correctamente puede ser lo que te salve.

Publicado por Roberto Carrancio en Cloud, SQL Server, 9 comentarios

Page Split: el invitado indeseado en SQL Server

Hay conceptos en SQL Server que son como ese compañero de trabajo que nadie ha invitado a la reunión pero que aparece, opina y encima se queda a tomar café. Los Page Split son ese compañero. Y lo peor de todo es que, en muchos casos, somos nosotros los que, sin querer, les abrimos la puerta. En este artículo vamos a diseccionar qué son, por qué ocurren, cómo detectarlos y, sobre todo, cómo podemos hacerles la vida difícil para que molesten lo menos posible.

Qué demonios es un Page Split

Cuando hablamos de Page Split en SQL Server nos referimos a un fenómeno que ocurre cuando el motor de base de datos necesita insertar un registro en una página de datos (o de índice) que ya está llena. Como SQL Server trabaja con páginas de 8 KB (sí, esa unidad tan entrañable que nos acompaña desde hace décadas), llega un momento en el que no hay espacio para ese nuevo registro. Entonces, el motor se ve obligado a dividir la página en dos: mueve aproximadamente la mitad de las filas a una nueva página y deja espacio en la original para la nueva inserción. Esto es el famoso Page Split.

Hasta aquí podría parecer un mecanismo inteligente y útil. Y lo es, en teoría. El problema es el impacto que tiene: incremento del número de páginas (y por tanto del tamaño del índice), fragmentación lógica, más operaciones de I/O, y un rendimiento que empieza a cojear como un servidor sin mantenimiento en una década.

Cuándo y por qué ocurre el Page Split

La causa principal de un Page Split es el uso de claves que no son secuenciales en índices clustered o nonclustered. Insertar valores intermedios en el orden lógico del índice fuerza al motor a abrir hueco donde no lo hay. Por ejemplo, si tenemos un índice clustered sobre un campo Nombre y estamos insertando valores aleatorios, SQL Server tendrá que hacer malabarismos para mantener el orden lógico.

Claro, alguno podría pensar: “Esto con un índice clustered en una clave IDENTITY no pasa”. Efectivamente, las claves secuenciales como IDENTITY, NEWSEQUENTIALID() o datetime en inserciones crecientes suelen evitar la mayoría de los Page Split. Pero ojo: incluso con claves secuenciales, si empezamos a hacer updates que ensanchan las filas más de lo que la página puede aguantar, también podemos provocar splits. Porque sí, los Page Split no son sólo cosa de INSERT, también los UPDATE pueden invitar al desastre si agrandan las filas.

Cómo afectan al rendimiento (y al ánimo del DBA)

Los Page Split producen fragmentación interna y externa. Interna porque dejan huecos en las páginas; externa porque el orden lógico del índice ya no se corresponde con el orden físico. Esto se traduce en más lecturas para recuperar los datos, más uso del log de transacciones y, en general, más I/O. Y todos sabemos que el disco es, casi siempre, el cuello de botella por donde mueren los sueños de un servidor bien optimizado.

Por si fuera poco, cada Page Split genera actividad en el log de transacciones: hay que registrar la creación de la nueva página, el movimiento de filas y la actualización de punteros. Si tenemos una base de datos en modo FULL, el crecimiento del log puede ser un espectáculo digno de verse (si uno disfruta con los desastres).

Cómo detectar Page Split

Como sabes, lo que no se mide no se puede optimizar, lo bueno es que detectar los Page Split no es complicado si sabemos dónde mirar. Un sitio clásico es el contador de rendimiento SQLServer:Access Methods – Page Splits/sec. Si ese contador empieza a dar cifras escandalosas, es momento de investigar.

Otra opción es recurrir a las DMV. La vista sys.dm_db_index_physical_stats nos permitirá ver el grado de fragmentación de los índices. Un índice muy fragmentado suele ser un buen candidato a tener Page Split en su historial reciente. Y si queremos verlos en tiempo real, un Extended Event como page_split o sqlserver.page_split, según versión, nos dará información jugosa sobre cuándo y dónde están ocurriendo.

Sí, podemos hacerlo también con Profiler, pero sinceramente, a estas alturas quien siga usando Profiler en producción para esto se merece un Page Split en su jornada laboral.

Cómo prevenir los Page Split

Es mejor prevenir que curar, siempre. La primera y más efectiva estrategia es diseñar bien las claves de los índices. Un índice clustered sobre un campo secuencial es nuestro mejor amigo. Esto evita la mayor parte de los Page Split derivados de inserciones.

Otra técnica clásica es jugar con el FILLFACTOR. Cuando creamos o reconstruimos un índice podemos indicar un valor de Fillfactor que deje un porcentaje de espacio libre en las páginas (por ejemplo, un 90% en vez del 100% por defecto). Esto da margen a que nuevas inserciones se acomoden sin provocar un split inmediato. Claro, no es gratis: el índice ocupará más espacio y necesitaremos más memoria y más I/O. Pero al menos los splits no nos atacarán a traición.

Eso sí, cuidado con el Fillfactor. Poner un Fillfactor bajo indiscriminadamente es como invitar al primo gorron a casa: puede aliviar al principio pero al final nos pasa factura. Hay que medir, probar y ajustar.

Y no olvidemos las operaciones de mantenimiento: reconstruir o reorganizar los índices periódicamente ayuda a reducir la fragmentación causada por los Page Split. Aquí no vamos a descubrir nada nuevo, pero sí recordar lo evidente: el mantenimiento es como lavarse los dientes; si no lo haces, el problema llegará y será feo.

Casos reales y conclusiones claras

En entornos OLTP con claves no secuenciales he llegado a ver índices con más del 70% de fragmentación en menos de una hora de actividad. La consecuencia era un aumento de I/O y un rendimiento que hacía llorar al más curtido. ¿La solución? Cambio de diseño de clave, ajuste del Fillfactor y un plan de mantenimiento digno.

En entornos con cargas masivas de datos desordenados, lo ideal es insertar en tablas heap (sin clustered) y luego aplicar el índice clustered al finalizar, o bien usar particiones y cargas ordenadas. Porque sí, hay vida más allá de pelearse con Page Split en cada carga.

En definitiva, los Page Split son inevitables en determinados escenarios, pero podemos hacer mucho para mantenerlos a raya. El diseño de los índices, el Fillfactor y un mantenimiento adecuado son nuestras principales armas. Y no, el truco no está en hacer rebuilds cada noche a lo loco; está en entender el porqué y el cuándo, y actuar con cabeza.

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, Rendimiento, SQL Server, 0 comentarios

El problema del Reenvío de punteros en tablas heap

Hoy vamos a hablar de un fenómeno tan molesto como habitual en ciertos entornos: el reenvío de punteros en tablas heap de SQL Server. Sí, ese “detalle” que suele pasar desapercibido hasta que un día nuestras consultas empiezan a ir como un carro tirado por burros, y claro, toca ponerse el traje de bombero.

Antes de entrar en harina, pongamos un poco de contexto. Las tablas heap, esas nobles estructuras sin índice clustered, a veces se eligen por necesidad, otras por ignorancia y, en los peores casos, porque alguien tenía prisa por entregar y pensó que ya lo arreglaríamos después.Y claro, luego nunca se arregla. Y mientras tanto, los forwarded records o reenvíos de punteros campan a sus anchas.

¿Qué es un reenvío de punteros y por qué debería importarnos?

Cuando una tabla no tiene índice clustered, SQL Server guarda las filas donde buenamente puede. Sin ese ordenamiento y estructura que un clustered impone, el heap es un campo abierto. Hasta aquí, todo bien. El problema aparece cuando actualizamos una fila y esa nueva versión no cabe en la misma página. ¿Qué hace SQL Server? ¿Mover toda la fila a otra página y actualizar los punteros que la referencian? Ojalá. Lo que hace es dejar un puntero en la ubicación original que apunta a la nueva ubicación de la fila. Ese es el reenvío de puntero: un salto innecesario que se añade al acceso de la fila.

Esto, que puede parecer inofensivo en pequeñas dosis, se convierte en un verdadero problema cuando la tabla crece y las modificaciones son frecuentes. Cada reenvío implica un acceso extra a disco o memoria para encontrar la fila real. Y como bien sabemos, esos accesos extra no son gratuitos: incrementan el tiempo de lectura y degradan el rendimiento de las consultas. Especialmente en esas tablas que alguien decidió consultar con un SELECT * y sin WHERE, porque total, ¿qué podría salir mal?

Cómo se genera un reenvío de punteros

Veámoslo en acción. Tenemos una tabla heap. Insertamos filas. Todo perfecto. Llega el día en que un UPDATE aumenta el tamaño de una fila (añadimos datos a una columna VARCHAR, por ejemplo). La fila ya no cabe en su página. SQL Server mueve la fila a una nueva página y deja un puntero en la posición original apuntando a la nueva ubicación. Algo así como el cartel de nos hemos mudado que ponen algunos negocios en su antiguo local cuando cambian de ubicación. Ahora acceder a esa fila implica primero leer la página con el puntero, luego saltar a la nueva página y leer la fila real. Siguiendo con el ejemplo anterior es como si el GPS te llevase al local antiguo para que vieses el cartel y tuvieses que ir al nuevo.

Pero es que la fiesta no termina ahí. Si la fila se vuelve a actualizar y tampoco cabe en su nueva página, obtenemos un reenvío de un reenvío. ¿Bonito, verdad? Sí, tan bonito como ese fragmento lógico que nadie defragmenta porque “total, no pasa nada”.

Impacto en el rendimiento de los reenvíos de punteros

El impacto de los reenvíos de punteros se manifiesta principalmente en las operaciones de lectura. Cada reenvío supone al menos un salto adicional. Si tenemos un número considerable de ellos, nuestras lecturas se convierten en una gincana de páginas de datos, con sus correspondientes cache misses, latches y demás alegría. Pero no creas que las escrituras están exentas, recuerda que antes de escribir casi siempre lees.

Esto no solo afecta a la velocidad de las consultas. También incrementa el uso de CPU, el tráfico de I/O y la presión sobre el buffer pool. Y aquí viene el detalle que más nos gusta: el optimizador de consultas no tiene en cuenta el coste de los reenvíos al planificar. Así que podemos tener un plan que parecía estupendo sobre el papel y que en ejecución se arrastra como un SELECT con hints absurdos.

Cómo detectar el reenvío de punteros

Detectar reenvíos de punteros no es complicado, pero requiere mirar donde hay que mirar. Podemos usar sys.dm_db_index_physical_stats con la opción DETAILED para analizar las tablas heap y ver el número de forwarded_records. Si este número empieza a crecer, es hora de preocuparse.

Un ejemplo de consulta para los amigos de lo rápido y directo:

Esto nos da una idea de cuántos reenvíos tenemos por tabla. Si ese número no es cero, tenemos trabajo pendiente. Y si el número es alto, es probable que también tengamos un problema de rendimiento.

¿Como elimino los reenvíos de punteros?

La primera solución (y la más eficaz) es: no uses heap salvo que tengas un motivo sólido para hacerlo. Si la tabla tiene lecturas frecuentes y actualizaciones que modifican el tamaño de las filas, un índice clustered es casi siempre mejor elección. Sí, incluso aunque esa tabla sea de staging y “solo esté ahí un ratito”.

Si por algún motivo tenemos que seguir con el heap, toca plan de mantenimiento especial. Por norma general, los planes de mantenimiento de índices no nos van a servir. En su lugar, tenemos que usar el comando ALTER TABLE [NombreTabla] REBUILD que reconstruye el heap y elimina los reenvíos de puntero. Pero claro, eso implica bloqueo de tabla (en algunas versiones de SQL) y no es algo que uno quiera hacer en mitad de un horario productivo.

Otra opción es rediseñar el esquema de la tabla para minimizar las columnas de longitud variable que crecen sin control. Porque claro, si tenemos un VARCHAR(8000) para guardar un número de teléfono “por si acaso”, el problema no es el heap: el problema somos nosotros.

Y por supuesto, monitorizar. Tener un job que periódicamente revise el número de forwarded_records y alerte si se dispara es una medida sencilla que nos puede ahorrar muchas sorpresas.

¿Hay situaciones donde el heap tenga sentido?

Sí, existen. Por ejemplo, en tablas de staging para cargas de datos donde no se hacen actualizaciones y los datos se procesan y eliminan rápidamente. Ahí un heap puede funcionar bien. Pero claro, en cuanto se empieza a hacer algún UPDATE, la decisión de no poner un clustered se vuelve difícil de defender. Y no, el argumento de “es que así insertamos más rápido” no vale si luego el rendimiento de las consultas se va al traste.

Conclusión

El reenvío de punteros es un mecanismo interno de SQL Server para lidiar con el crecimiento de filas en tablas heap. No es un bug, es un diseño consciente. El problema es que suele aparecer porque tomamos decisiones de diseño pobres o porque descuidamos el mantenimiento. Si tenemos un heap, debemos ser conscientes de las implicaciones y monitorizar su estado. Y si vemos reenvíos, actuar antes de que el rendimiento se desplome.

Como siempre, lo más efectivo es evitar el problema desde el principio. Un índice clustered bien elegido elimina de raíz el riesgo de reenvíos. Y si alguien nos insiste en que un heap es la mejor opción para esa tabla con 500 millones de filas y actualizaciones frecuentes, siempre podemos sugerirle que haga las pruebas en producción. Total, ¿qué podría salir mal?

Espero que este artículo te haya resultado útil e interesante. Si tienes alguna duda o comentario, no dudes en contactarnos en Twitter o por mail o dejarnos un mensaje en los comentarios de aquí abajo. Y recuerda que también tenemos un grupo de LinkedIn al que te puedes unir.

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

SORT_IN_TEMPDB: lo que de verdad hay que saber

Entre las opciones que nos ofrece SQL Server a la hora de crear o reconstruir un índice, SORT_IN_TEMPDB es una de esas que suele generar más dudas que certezas. A menudo la encontramos marcada (o desmarcada) en scripts heredados sin que nadie recuerde por qué se tomó esa decisión. Y claro, luego llegan las sorpresas: operaciones que fallan por falta de espacio, tiempos de reconstrucción eternos o índices más fragmentados que la agenda de un comercial. Hoy vamos a poner orden y explicar, con rigor y sin adornos innecesarios, qué hace realmente SORT_IN_TEMPDB, cuándo nos conviene usarlo y cuándo es mejor no tocarlo.

¿Qué es SORT_IN_TEMPDB y cuál es su propósito real?

Cuando creamos o reconstruimos un índice, SQL Server tiene que ordenar los datos para generar la estructura B-Tree. Este proceso de ordenación genera lo que se llaman sort runs, que son fragmentos intermedios de datos ya ordenados que se van almacenando en disco. Por defecto, esos sort runs se guardan en el mismo filegroup de destino del índice, lo que implica que el espacio temporal necesario para la ordenación y el espacio final del índice compiten en el mismo sitio.

Con SORT_IN_TEMPDB ON, lo que hacemos es indicarle al motor que esos sort runs se almacenen en tempdb, mientras que el índice final sigue creándose en el filegroup de destino. Esto no cambia el hecho de que el índice ocupe lo que tenga que ocupar; lo que cambia es dónde se consumen los recursos temporales durante la operación.

El objetivo de esta opción es optimizar el patrón de I/O: si tempdb está en discos diferentes al filegroup de destino, podemos lograr un acceso más secuencial y eficiente, con menos movimientos de cabezales (en discos mecánicos) o menos contención de I/O (en cualquier tipo de almacenamiento). El resultado: potencialmente menos tiempo de creación o reconstrucción del índice. Eso sí, el beneficio depende por completo de cómo tengamos configurado el entorno.

Espacio necesario: no es menos, es más (en el buen sentido)

Uno de los errores más extendidos es pensar que SORT_IN_TEMPDB reduce el espacio requerido para la operación. Nada más lejos de la realidad. Lo que hace es repartir el consumo de espacio entre tempdb y el destino del índice, pero el total de espacio consumido durante el proceso será mayor, porque estamos usando espacio en dos sitios al mismo tiempo.

Para ser claros:

Si SORT_IN_TEMPDB está en OFF (comportamiento por defecto), todo el espacio temporal y el índice final comparten el mismo filegroup. Los sort runs se van liberando conforme se procesan, y sus extents pueden ser reutilizados para el índice final, aunque esto suele provocar que los extents del índice queden menos contiguos.

Si SORT_IN_TEMPDB está en ON, necesitamos suficiente espacio en tempdb para los sort runs y suficiente espacio en el destino para el índice final. La ventaja es que los extents que se asignen al índice final estarán menos fragmentados, porque no se verán afectados por los extents que se van liberando de los sort runs.

Esto implica algo obvio pero que conviene recordar: si no hemos dimensionado tempdb con el espacio suficiente, la operación fallará. Lo mismo si el filegroup destino anda justo de espacio. Ni SORT_IN_TEMPDB ni ningún otro parámetro nos salvará de un error por falta de espacio.

Beneficios reales: cuándo SORT_IN_TEMPDB es útil

El principal beneficio de SORT_IN_TEMPDB es el patrón de I/O más eficiente durante la creación o reconstrucción del índice. Al separar las lecturas de los datos base, las escrituras de los sort runs y las escrituras del índice final en diferentes volúmenes (idealmente), conseguimos que el motor trabaje de forma más ordenada. En discos mecánicos esto significa menos saltos de cabezales; en SSDs o cabinas de almacenamiento, menos contención de I/O.

Además, como hemos comentado antes, usar SORT_IN_TEMPDB mejora la probabilidad de que los extents del índice final sean contiguos, lo que se traduce en un índice más compacto y eficiente en el acceso posterior. Esto es especialmente útil cuando creamos índices grandes, donde la fragmentación inicial puede tener un impacto notable en el rendimiento de las consultas.

Eso sí, el beneficio se da cuando tempdb está en un storage diferente, rápido y bien dimensionado. Si tempdb comparte disco con el resto de bases de datos, o está en un volumen saturado, no sólo no veremos ventaja alguna, sino que podemos incluso empeorar la situación al sumar más carga a un único punto de fallo.

Impacto de SORT_IN_TEMPDB en operaciones online y con columnas LOB

Cuando combinamos SORT_IN_TEMPDB con operaciones online (ONLINE = ON), el consumo de espacio temporal en tempdb puede ser significativo, especialmente si el índice incluye columnas LOB o tenemos activada la opción de compactación de LOB. Aquí el riesgo de quedarnos sin espacio en tempdb es real y hay que tenerlo muy en cuenta. No es raro ver operaciones online que fallan a mitad de proceso por no haber calculado bien este detalle.

Por tanto, si vamos a combinar SORT_IN_TEMPDB con ONLINE, más nos vale monitorizar tempdb y asegurarnos de que tenemos espacio suficiente antes de lanzar el proceso. Y si además lo vamos a hacer en un entorno con mucha carga concurrente, tocará vigilar muy de cerca el uso de I/O y espacio.

Consideraciones finales y buenas prácticas

SORT_IN_TEMPDB es una herramienta muy útil en el arsenal de mantenimiento de índices, pero no es un interruptor mágico que podamos activar sin pensar. Antes de decidir su uso, hay que valorar:

¿Tenemos tempdb en un storage separado y rápido? ¿Hay suficiente espacio disponible en tempdb y en el destino del índice? ¿El índice es lo bastante grande como para que el beneficio compense?

En bases de datos pequeñas o medianas, o en entornos donde tempdb no está optimizado, probablemente no veamos ninguna diferencia perceptible. En cambio, en bases de datos grandes con índices voluminosos y tempdb bien dimensionado, el uso de SORT_IN_TEMPDB puede marcar la diferencia en el tiempo de ejecución y en la calidad del índice generado.

Ah, y no olvidemos un detalle que no por obvio deja de ser importante: SORT_IN_TEMPDB sólo afecta a la operación actual. No hay metadatos que recuerden que un índice se creó o reconstruyó con esta opción. Así que, si queremos un comportamiento consistente, tendremos que especificarlo en cada script donde lo consideremos necesario.

Conclusión

SORT_IN_TEMPDB no es un adorno exótico ni un parámetro para marcar por inercia. Es una opción que, bien usada, nos ayuda a crear y mantener índices más eficientes, más compactos y, potencialmente, más rápido. Pero como todo en SQL Server, depende de que el entorno esté preparado para soportarlo. Porque al final, lo que importa no es el checkbox que marquemos, sino que el índice se construya bien y el servidor no acabe temblando tras la operación. Y eso, amigos, sólo se consigue con planificación, conocimiento y un tempdb en condiciones.

Espero que este artículo te haya resultado útil e interesante. Si tienes alguna duda o comentario, no dudes en contactarnos en Twitter o por mail o dejarnos un mensaje en los comentarios de aquí abajo. Y recuerda que también tenemos un grupo de LinkedIn al que te puedes unir.

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