Incidencias

El mito de los atajos en bases de datos: por qué no hay recetas mágicas

Pocas cosas me generan más frustración que una presentación titulada “10 trucos infalibles para optimizar tu base de datos en 5 minutos”. No porque no quiera rendimiento (lo quiero, y mucho, como todos), sino porque llevo demasiado tiempo en esto como para creer que la administración de bases de datos funciona a base de fórmulas mágicas o guías milagrosas. Cada entorno tiene sus peculiaridades, sus desastres heredados y sus decisiones cuestionables. Pretender que una receta genérica resuelva un problema específico es como recetar paracetamol para un clúster caído. Puede calmar al usuario, pero no soluciona nada.

Atajos en bases de datos que suenan bien pero no funcionan

He visto más veces de las que me gustaría cómo ciertas “técnicas exprés” se convierten en dogmas. Muchas veces aparecen en foros, otras en conversaciones de pasillo, y a veces incluso las incluye algún artículo con demasiadas estrellitas y poca base técnica. Algunas de estas ocurrencias incluso se disfrazan de buenas prácticas, cuando en realidad son puro maquillaje técnico.

Uno de los clásicos eternos es el de desactivar todos los índices antes de una carga masiva. Suena lógico: menos índices, menos mantenimiento durante la inserción. Y puede tener sentido, pero solo si sabemos lo que estamos haciendo. ¿Qué tipo de índices hay? ¿Son realmente necesarios? ¿Cuál es el coste de reconstruirlos después? Porque de nada sirve ahorrar cinco minutos en la carga si luego pasamos tres horas rehaciendo estructuras en plena ventana de mantenimiento (o peor, fuera de ella).

Otro habitual es el uso de hints a ciegas, como si un INNER HASH JOIN fuera una especie de hechizo arcano que mágicamente convierte cualquier consulta en un rayo de luz. El problema, claro, es que el optimizador tiene más información de la que solemos tener nosotros en tiempo de ejecución. Forzar un plan sin pruebas, sin medir, sin entender por qué el motor decide lo que decide, es jugar a ser adivino con el presupuesto de IOPS de otro.

Y por supuesto, no podía faltar el legendario DBCC SHRINKDATABASE, convertido en herramienta habitual de “mantenimiento” por muchos que aún no se han parado a medir sus consecuencias reales. Fragmentación masiva, crecimiento inmediato posterior, tiempos de espera, y un uso de recursos que no compensa ni en entornos de desarrollo, mucho menos en producción. Apretar y soltar el disco como si fuera un globo no libera espacio: solo complica las cosas.

También me topo, de tanto en tanto, con scripts “mágicos” que prometen optimizar todas las consultas de una base de datos con un solo clic. El solo hecho de que alguien los haya escrito ya es preocupante, pero lo que me quita el sueño es que otros los ejecuten sin pararse a pensar. Optimizar no es lanzar un script genérico; es entender, medir, corregir y validar. Todo lo demás es ruido.

La influencia de las redes sociales y los vídeos cortos

En los últimos años, hemos visto cómo el contenido técnico (especialmente en campos con más tracción como ciberseguridad, desarrollo web o administración de sistemas) ha sido invadido por lo que yo llamo la cultura del vídeo de 30 segundos. Esos fragmentos de sabiduría empaquetada en un reel, un TikTok o un hilo de X (antes Twitter, cuando la gente aún sabía debatir sin stickers), donde se vende una técnica como si fuera una revelación divina.

Y aunque parecía que nuestro sector de las bases de datos estaba a salvo de esa superficialidad, cada vez veo más vídeos y publicaciones que sugieren cosas como “optimiza tu SQL Server con este comando”, “el índice que no conocías y te cambiará la vida”, o directamente “el script definitivo para tunear tu instancia”. La cruda realidad es que si usas un script definitivo sin saber qué hace, probablemente estés abriendo un ticket para mí en dos semanas.

¿Que hay gente compartiendo contenido útil? Por supuesto. Pero también hay mucho perfil que ha aprendido a posicionarse en el algoritmo antes que en el execution plan. Lo importante ya no es si lo que dicen tiene sentido, sino si entra bien en vertical, con una música pegadiza de fondo y subtítulos en negrita.

No tengo nada en contra del formato ágil, yo también consumo contenido rápido, pero sí tengo todo en contra de presentar trucos sin contexto, sin advertencias, y sin reconocer que la base de datos no es un entorno de juguete. Es producción. Y producción no se toca a base de “5 tips en 30 segundos”.

El problema no es solo la desinformación. Es que, al repetirse tanto, estos “atajos mágicos” terminan calando. Y entonces llegan al entorno del cliente, del compañero, o al nuestro, envueltos en frases como “vi a un experto decir que esto mejora el rendimiento” o “lo probé en local y funcionó”. El día que alguien monte un clúster con instrucciones de un TikTok, no quiero estar cerca.

La importancia de entender los fundamentos de SQL Server

Lo que realmente marca la diferencia no son los trucos, sino entender qué está pasando dentro del motor. Cuando dejamos de repetir recetas y empezamos a estudiar el comportamiento real de SQL Server, la administración deja de ser un ejercicio de fe y se convierte en una disciplina técnica seria.

Por ejemplo, saber que SQL Server trabaja internamente con páginas de 8 KB nos hace pensar mejor en los tipos de datos, la compresión, la fragmentación y el diseño de índices. Si no entendemos eso, cualquier optimización será como mover las sillas en el Titanic mientras se hunde, entretenido, pero inútil.

También aprendemos cómo funciona el optimizador de consultas, qué espera encontrar, cómo interpreta las estadísticas, y por qué a veces se equivoca. La cardinalidad, ese concepto que a muchos les suena a magia negra, resulta ser clave para entender por qué una consulta se convierte en un escaneo de tabla de millones de filas o en un plan eficiente con pocos milisegundos de CPU.

Y sí, los bloqueos no son enemigos a eliminar. Son síntomas, advertencias, mecanismos de protección. Una transacción larga puede ser más dañina que cien bloqueos bien gestionados. Aprender a leer deadlock graphs, entender niveles de aislamiento y diseñar correctamente el acceso concurrente es mucho más útil que cualquier script que prometa “evitar bloqueos automáticamente”.

Tampoco podemos olvidarnos de las estadísticas. Ejecutar UPDATE STATISTICS porque lo leímos en una lista de tareas semanales es mejor que nada, pero muy lejos de una estrategia de mantenimiento inteligente. Entender cuándo se actualizan, cómo afectan a los planes de ejecución y qué impacto tienen en entornos con muchas escrituras es parte del trabajo que no puede automatizarse con un clic.

Logo SoyDBA

Únete a la newsletter de SoyDBA

Regístrate gratis para no perderte ninguna novedad. Te avisaré de noticias y eventos importantes

¡No hacemos spam! Lee nuestra política de privacidad para obtener más información.

Conocimiento frente a atajos: la diferencia entre arreglar y entender

Aquí es donde la cosa se pone seria. Porque cualquiera puede buscar un error en Google, copiar el primer bloque de código que encuentra y cruzar los dedos. Pero entender el origen del problema, anticipar sus consecuencias y aplicar una solución sostenible y perdurable requiere tiempo, conocimiento y experiencia. Y eso no se compra ni se descarga.

Cuando tengo que elegir entre arreglar algo deprisa o entender por qué está roto, prefiero lo segundo. Porque arreglar sin comprender es pan para hoy y desastre para mañana. Ya nos conocemos ese guion: parche rápido, alivio temporal, y dentro de una semana… el mismo problema, pero más grande.

Los atajos, en general, no resuelven nada. Solo tapan síntomas. Como esa costumbre de algunos de hacer REBUILD INDEX sin mirar estadísticas de fragmentación, sin diferenciar índices columnstore y sin medir el impacto real en el rendimiento. Más mantenimiento no siempre es mejor mantenimiento. A veces es solo ruido.

Conclusión

Si algo tengo claro después de más de una década en esto es que los milagros no existen en administración de bases de datos. Hay herramientas útiles, sí. Hay buenas prácticas, también. Pero no hay soluciones universales. Y cada vez que alguien actúa como si las hubiera, lo único que consigue es complicar aún más el trabajo de quienes venimos detrás a recoger los pedazos.

SQL Server no premia al que improvisa, sino al que entiende. No necesitamos más scripts mágicos, necesitamos más análisis, más diagnóstico, más contexto. Y sobre todo, más respeto por el conocimiento técnico. Porque al final, el rendimiento real no llega por hacer más clics, sino por hacer las preguntas correctas y saber interpretar las respuestas.

Así que, si alguien te promete un truco definitivo para que tu base de datos vuele, recuerda: también hay quien promete que los cursores funcionan bien. No les creas.

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

¿Es PLE un buen indicador de rendimiento de SQL Server?

Durante años, el Page Life Expectancy (PLE) ha sido una de esas métricas que aparecen en los scripts de monitorización como si fueran mantras sagrados. Una de esas columnas que se miran con recelo, que hacen saltar alertas y que, para algunos, justifican peticiones de más memoria RAM con la ligereza con la que se pide café. Pero como todo en SQL Server, nada es tan sencillo como parece y el PLE, aunque útil, tiene trampa.

¿Qué demonios es el PLE?

El PLE representa cuántos segundos, de media, una página de datos puede permanecer en el buffer pool antes de ser desalojada. Es decir, mide cuánto tiempo vive la información en memoria antes de que SQL Server tenga que expulsarla para hacer sitio a otra. Técnicamente, es un contador de rendimiento (sys.dm_os_performance_counters) que se encuentra dentro de Buffer Manager.

Cuando este valor es alto, respiramos tranquilos: significa que las páginas permanecen en memoria lo suficiente, probablemente porque tenemos un buffer pool holgado y un acceso a disco relajado. Cuando cae en picado, suele ser síntoma de presión de memoria o de lecturas físicas excesivas, muchas veces provocadas por planes de ejecución poco afortunados.

Ahora bien, el número mágico de 300 segundos (5 minutos) que algunos siguen usando como umbral es tan fiable como usar una brújula en mitad de un campo magnético. Ese valor tenía sentido… cuando los servidores venían con 4 GB de RAM. Hoy, con instancias que superan los 512 GB, seguir usando el mismo umbral es como usar una regla de colegio para medir una autopista.

Valores PLE deseables: ¿hay alguno?

Aquí viene la gran pregunta que a su vez es el gran problema del PLE: su valor es absolutamente relativo. Depende del tamaño del buffer pool, del patrón de carga de trabajo, de los tipos de queries que se estén ejecutando, y de si el sistema ha tenido un pico puntual de actividad.

Una instancia con 256 GB de RAM debería tener un PLE mucho más alto que una con 16 GB. ¿Cuánto más? No hay una cifra mágica, pero una orientación razonable sería multiplicar los segundos base (300 en los viejos tiempos) por un factor en relación al tamaño del buffer pool. O mejor aún, establecer una línea base propia de nuestra carga habitual y monitorizar desviaciones.

Porque eso es lo que importa: no tanto si el PLE es 2.000 o 20.000, sino si ha caído bruscamente respecto a lo normal. Un descenso repentino suele estar vinculado a algo que no encaja: una query que hace lecturas absurdas, un mantenimiento mal planteado, o simplemente un usuario que ha decidido escanear toda la tabla de movimientos de 200 millones de registros “por si acaso”.

El PLE no es una medida mágica

Muchos lo tratan como si fuera el santo grial de la salud del servidor, pero en realidad el PLE no mide nada en términos de experiencia de usuario. Es un indicador indirecto de presión de memoria, no una medida de rendimiento ni de latencia. Puede estar alto mientras el sistema responde lento, o estar bajo y aun así tener una experiencia fluida si las queries están bien cacheadas.

Además, el PLE es un promedio a nivel de NUMA node, lo que significa que puede estar sesgado si tenemos un servidor con múltiples nodos y la presión se concentra solo en uno de ellos. SQL Server calcula un PLE por cada nodo NUMA, pero los scripts que aglutinan el valor total no siempre lo desglosan correctamente. De ahí que convenga analizarlo por nodo para tener una visión clara.

Y por si fuera poco, el PLE se resetea con cada reinicio de la instancia. Así que no, si ves un valor bajo justo después de un restart, no es el fin del mundo: es simplemente lo que hay.

Detractores: con razón, no por moda

Los que critican el PLE no lo hacen por capricho. Lo hacen porque, en muchos entornos, mirar el PLE sin contexto lleva a diagnósticos erróneos y decisiones equivocadas. Se han visto DBAs pidiendo 128 GB de RAM más “porque el PLE está bajo”, sin pararse a mirar que el problema era una consulta sin WHERE que se colaba a producción cada viernes a las 15:00.

El PLE tampoco distingue entre lecturas necesarias y lecturas absurdas. Si haces un SELECT * de una tabla de logs históricos porque alguien quiere exportarla a Excel “por si acaso”, el PLE caerá en picado igual que si tuvieras una mala estrategia de índices. Así que usarlo como medida absoluta de salud es, como poco, ingenuo.

Alternativas: mirar más allá del PLE

Si queremos una visión más rica, hay vida más allá del PLE. Podemos observar métricas como el Buffer Cache Hit Ratio, aunque también con cautela, porque este valor suele estar cerca del 100% en casi todas las instancias modernas y no siempre significa lo que creemos. Lo que realmente nos interesa es entender qué queries están provocando lecturas físicas excesivas.

Aquí entra en juego la DMV sys.dm_exec_query_stats, que combinado con sys.dm_exec_sql_text y sys.dm_exec_query_plan, nos puede dar visibilidad sobre qué consultas están provocando lecturas físicas o lógicas desproporcionadas. También podemos revisar el sys.dm_io_virtual_file_stats para analizar el I/O por base de datos y archivo. 

Y si lo que nos interesa es el uso de memoria, el sys.dm_os_memory_clerks y el sys.dm_os_buffer_descriptors ofrecen información mucho más granular sobre cómo SQL Server está usando realmente la RAM.

Además, a partir de SQL server 2025 tendremos la nueva DMV sys.dm_os_memory_health_history pero eso da para otro artículo.

En resumen: el PLE puede servirnos como un primer vistazo, como ese canario en la mina que nos avisa de que algo pasa. Pero confiar ciegamente en él es como juzgar un libro por el grosor del lomo.

Monitorizar el PLE: ¿sí o no?

Entonces, ¿monitorizamos el PLE o no? Esta es una de esas preguntas que genera debates infinitos y respuestas del tipo “depende”. Yo voy a ser neutral, no voy a entrar en la trinchera de los que lo consideran inútil ni en la de los que lo elevan al nivel de oráculo. Lo que sí diré es que monitorizar el PLE puede tener sentido si sabemos lo que estamos mirando y no nos dejamos llevar por interpretaciones simplistas.

Si tenemos una línea base sólida, si entendemos la arquitectura NUMA de nuestra instancia y si usamos el PLE como un indicador más dentro de un conjunto más amplio de métricas, entonces puede ser útil. Pero si lo usamos como termómetro único del rendimiento, vamos a acabar medicando al paciente por fiebre sin saber que tiene apendicitis.

Conclusión

El Page Life Expectancy no está muerto, pero tampoco es un mesías. Es una métrica con contexto, con historia y con limitaciones. Sirve para levantar sospechas, no para dictar sentencias. Hay que leerlo con ojo clínico, entender lo que implica y, sobre todo, combinarlo con otras métricas más modernas y más específicas.

Como siempre, no hay atajos. Lo que hay es análisis, observación y un poco de sentido común. Que no es mucho pedir… salvo que creas que SELECT * sigue siendo buena idea.

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

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

10 cosas que debe tener tu DRP de SQL Server

Un buen Plan de Recuperación ante Desastres (DRP) en SQL Server no se improvisa con prisas ni se resuelve con un backup semanal en una carpeta compartida. Quien piense lo contrario probablemente también crea que los backups verificados se restauran solos por arte de magia. Aquí venimos a poner orden. Vamos a repasar diez elementos que deben estar presentes en cualquier DRP decente, serio y pensado por alguien que sabe lo que significa tener producción caída más de 15 minutos.

DRP Check 1: Inventario de instancias y bases de datos críticas

Antes de correr a hacer backups como si el mundo se acabara, hace falta saber qué estamos protegiendo. Un DRP sin inventario es como un GPS sin destino. Documentar todas las instancias SQL Server, su versión, configuración, bases de datos alojadas, y cuál de ellas es crítica es el primer paso. Sin eso, el resto del plan será un ejercicio de fe.

Esto incluye nombres, versiones, configuración regional, nivel de compatibilidad, y por supuesto, si estamos hablando de SQL Server On-Prem, en Azure, en máquinas virtuales o en una mezcla caótica digna de una pesadilla DevOps.

DRP Check 2. Estrategia de copias de seguridad (real y testada)

Esto no va de tener un script que haga BACKUP DATABASE, sino de tener un plan de backups bien definido, ajustado al SLA del negocio y validado con restauraciones periódicas. Porque sí, hacer backups sin probar restores es como llenar el depósito del coche sin saber si tienes motor.

Y recuerda debes incluir backups completos, diferenciales y de logs si la base está en FULL.

DRP Check 3. Plan de restauración documentado (y probado, otra vez)

Vale, ya tenemos backups. ¿Y ahora qué? Un DRP sin un procedimiento claro de restauración es solo un acto de fe. Hay que documentar cómo restaurar cada tipo de backup, en qué orden, en qué entorno, y cuánto tiempo se estima que llevará. No valen suposiciones.

¿Se han probado esas restauraciones en un entorno aislado? ¿Se ha medido el tiempo real? ¿Se ha verificado que la aplicación vuelve a levantar sin errores? Si la respuesta es no, el DRP es papel mojado.

DRP Check 4. Topología de alta disponibilidad y replicación

La disponibilidad no es solo cosa del DRP, pero forma parte de él. Un clúster de Always On, una replicación transaccional o un Log Shipping bien montado pueden ser la diferencia entre una caída de horas y una recuperación en minutos.

Aquí hay que documentar cómo están montadas esas soluciones, cómo se comportan ante fallos y, lo más importante, cómo se revierte o se conmutan sin pérdida de datos. Porque el botón “Failover” no es magia, y conviene saber qué pasa antes de pulsarlo.

DRP Check 5. Matriz de responsabilidad (quién hace qué y cuándo)

En medio del caos no hay tiempo para preguntar «¿quién se encarga de esto?». Un DRP debe tener definidos claramente los roles: quién inicia el protocolo, quién comunica a negocio, quién ejecuta los scripts, quién valida y quién da el OK final.

Y no, no vale con poner “El DBA” para todo. Porque el DBA también duerme (al menos en teoría) y puede que no esté disponible a las 3:00 de la mañana un festivo. Así que planifica relevos, turnos y contactos de emergencia. Y por supuesto, guarda esa información fuera del entorno afectado.

DRP Check 6. Procedimiento para activar el DRP

No todo fallo es un desastre. Un plan serio define umbrales: ¿cuándo se considera que hay que activar el DRP? ¿Cuánto tiempo puede estar caída una instancia sin que salten las alarmas? ¿Hay una ventana para intentos de recuperación antes de iniciar failover?

Este punto es crítico. Muchos planes fallan porque nadie sabe cuándo hay que usarlos. Y cuando se deciden, ya es tarde y el daño está hecho. Un buen DRP se activa con decisión, no con debates.

DRP Check 7. Infraestructura de recuperación (y entorno preconfigurado)

Recuperar una base de datos en un entorno que no existe es una broma de mal gusto. El DRP debe incluir un entorno de recuperación configurado con antelación: máquinas, redes, almacenamiento, seguridad… todo listo para levantar una instancia funcional.

Si estás en Azure o AWS, tener imágenes de máquinas o plantillas ARM listas para desplegar reduce el tiempo de recuperación drásticamente. Si estás en On-Prem, tener máquinas físicas o virtuales reservadas para contingencias no es un lujo, es prevención.

DRP Check 8. Automatismos y scripts listos para ejecutar

En medio del desastre, lo último que queremos es escribir scripts a mano o copiar/pegar desde un correo de 2017. El DRP debe contener los scripts ya preparados para tareas como restaurar backups, reconfigurar logins, recrear jobs, reiniciar endpoints y comprobar integridad.

Cuanto más automático esté todo, menos errores y más rapidez. Pero cuidado: automatizar sin entender es un atajo al desastre. Automatización sí, pero documentada, validada y revisada.

DRP Check 9. Validación post-recuperación

El DR no termina cuando el servidor levanta. Termina cuando la aplicación vuelve a funcionar, los usuarios acceden y nadie grita por Teams. El plan debe incluir validaciones técnicas (integridad, acceso, jobs funcionando, monitoreo operativo) y funcionales (consultas clave, flujos de negocio).

Aquí es donde muchos se relajan demasiado pronto. Recuperar una base sin comprobar que los índices no están corruptos o que el SQL Agent arranca, es como arreglar un coche y no probar que arranca. Todo debe quedar verificado y documentado.

DRP Check 10. Revisión y simulacros regulares

Por último, un DRP no es un PDF que se guarda en una carpeta y se olvida. Es un documento vivo que hay que revisar y probar. Idealmente, al menos una vez al año (y si el entorno cambia, con cada cambio relevante).

Los simulacros revelan errores, tiempos reales, dependencias ocultas y, sobre todo, preparan al equipo. No hay vergüenza en fallar en un simulacro. La vergüenza viene cuando el desastre es real y nadie sabe ni por dónde empezar. Y sí, si nunca has hecho un simulacro y crees que todo va a salir bien, te deseo la mejor de las suertes. La vas a necesitar.

Conclusión

Un DRP de SQL Server no es un archivo bonito con diagramas de PowerPoint. Es una estrategia detallada, técnica y validada que te permite dormir un poco más tranquilo (solo un poco). Tiene que estar alineado con el negocio, ejecutado por profesionales y probado con rigor.

Dejarlo para otro día es como ignorar un CHECKDB con errores porque “no ha fallado nada todavía”. Lo sabes tú, lo sabemos todos: el desastre no avisa. Pero sí se entrena. Así que más vale tener el plan listo y no necesitarlo, que necesitarlo y tener que improvisar.

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

 

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

Técnicas de Recuperación ante Desastres (DR) en Always On (AG)

Cuando hablamos de alta disponibilidad en SQL Server, hay un elefante en la sala que muchos prefieren ignorar: la recuperación ante desastres (DR) no es lo mismo que la alta disponibilidad. Y sí, podemos tener un Always On Availability Group en producción, funcionando como un reloj suizo, con réplicas síncronas, listeners con balanceadores bonitos y monitorización con colores llamativos y alertas inmediatas… pero si mañana se prende fuego el CPD o se rompe el clúster de Windows, más nos vale tener algo más que buenas intenciones.

Always On no evita el 100% de los desastres

Empecemos por desmontar un mito recurrente: “Tengo Always On, no necesito backups”. Esta frase existe. La hemos oído. Nos ha dolido. Tener un Availability Group distribuido con tres réplicas no es un sustituto de una estrategia de backup coherente. Es como decir que no hace falta cinturón de seguridad porque llevas airbag. A nivel técnico, los AG están pensados para disponibilidad, no para recuperación. Y desde luego, no protegen contra errores humanos, corrupción lógica ni DROP DATABASE ejecutados por ese usuario avanzado al que le dieron permisos “para que pueda trabajar tranquilo”.

Así que, antes de emocionarnos con réplicas distribuidas y latencias internacionales, empecemos con lo básico.

Los backups si nos salvan ante desastres

Los backups siguen siendo la base de cualquier estrategia de recuperación ante desastres, incluso (y especialmente) cuando usamos Always On. No hay excusa. Y sí, sabemos que hay quien piensa que como tiene tres réplicas en tres regiones, puede dormir tranquilo. Hasta que se borra un dato en la base de datos primaria, y esa operación se replica con precisión quirúrgica a las secundarias. Una especie de ransomware lento y sin rescate.

En un entorno con AG, es fundamental tener claro dónde y cómo hacemos los backups. Idealmente, deberíamos delegar las copias a las réplicas secundarias para liberar carga de la primaria. SQL Server lo permite desde hace varias versiones, y con una correcta configuración de las preferencias de backup, podemos establecer qué réplica se encargará de cada tipo de backup: full, log o copy-only.

Pero cuidado, porque no todas las réplicas valen para todo. Las copias completas deben realizarse en una réplica con acceso legible a la base de datos, y los logs solo en réplicas sincronizadas que reciban todas las transacciones. Además, asegúrate de que el software de backup (si usas uno) es compatible con AG y respeta las preferencias de backup configuradas en el clúster. Hay soluciones “enterprise” que, sorprendentemente, no lo hacen.

Y por si acaso recuerda: sí, seguimos necesitando restaurar las copias de vez en cuando para comprobar que funcionan. Testear la restauración no es una opción, es parte del proceso. ¿Tienes backups diarios? Genial. ¿Los has restaurado alguna vez? Porque si no lo has hecho, lo que tienes son archivos que ocupan espacio, no un plan de recuperación.

AG distribuidos: la aspiración de los ya experimentados en desastres

Si nos tomamos en serio la continuidad de negocio, y el presupuesto lo permite, debemos hablar de Availability Groups distribuidos. Esto no es simplemente una extensión de AGs tradicionales, sino una arquitectura pensada para verdaderas estrategias de recuperación ante desastres geográficamente dispersas. Aquí no estamos hablando de movernos de Madrid a Barcelona, sino de poder perder el centro de datos entero en Frankfurt y que el negocio siga operando desde Dublín sin sudar tinta.

Un AG distribuido se compone de dos (o más) AG independientes que se sincronizan entre sí mediante un listener y una réplica que actúa como puente. Esto implica una configuración más compleja, pero aporta una flexibilidad enorme. Cada lado del AG distribuido puede tener su propio clúster de Windows, su propio quorum, su propia lógica de failover, y no dependen directamente del otro para estar operativos. Es decir, si se rompe todo el AG primario, el secundario puede levantar cabeza por sí mismo, sin necesidad de consultar a nadie. Autonomía total, como un buen DBA cansado de justificarle al jefe por qué no es culpa suya.

Pero no es magia ni es todo tan bonito. Los AG distribuidos no hacen failover automático. Necesitan intervención manual o scripts muy bien preparados, monitorizados y probados. Y además, la sincronización es asíncrona, por lo que hablamos de cierta pérdida de datos en caso de desastre. Aceptarlo o no dependerá del negocio y de su tolerancia al RPO.

Consideraciones adicionales: DR de verdad

¿Todo configurado, AG distribuido listo, backups funcionando? Perfecto. Ahora hablemos de lo que realmente se rompe cuando todo lo demás funciona: la red y el DNS. Porque puedes tener la mejor estrategia del mundo, pero si el listener de SQL no resuelve correctamente en la región de DR, o si el firewall bloquea el puerto de sincronización, todo tu diseño se convierte en una bonita maqueta de PowerPoint.

La recuperación ante desastres es un proceso que debe contemplar todos los componentes, y eso incluye:

  • Que los clientes puedan conectarse automáticamente al entorno de DR sin intervención manual (o con la mínima posible).
  • Que los certificados estén correctamente instalados en todos los nodos si estamos usando encriptación.
  • Que los endpoints estén accesibles, los firewalls configurados y los balanceadores preparados para redirigir tráfico.
  • Que el almacenamiento de backups esté accesible desde ambos lados del AG (o, al menos, replicado adecuadamente).
  • Y más cosas específicas de tu arquitectura que solo tu sabes…

Un test de DR que no valida los nombres DNS, las ACL de red y la resolución de nombres es como una auditoría de seguridad en la que solo se revisan los colores del logo.

Automatización: scripts o muerte

La recuperación ante desastres no debería depender del pulso de una persona que lleva 20 horas despierto. Por eso, automatizar el proceso de failover y recuperación es obligatorio. No deseable. No recomendable. Obligatorio. Y no, no hablo de automatización genérica. Hablo de scripts personalizados para tu entorno, que validen el estado de las réplicas, que ejecuten el ALTER AVAILABILITY GROUP … FAILOVER cuando toque, y que actualicen rutas, registros DNS o configuraciones post-failover si es necesario.

¿Y la documentación? Sí, también es importante. Porque cuando suena el teléfono a las 4 de la mañana, necesitas saber qué hacer y no improvisar con algo que has visto en Stack Overflow o con lo que te ha dicho Chat GPT.

Conclusión

Always On es una herramienta potentísima para mantener la disponibilidad de nuestras bases de datos, pero no sustituye una estrategia de recuperación ante desastres (DR) bien pensada, bien ejecutada y bien documentada. Los backups siguen siendo sagrados. Los AG distribuidos son una bendición si se usan bien. Y los entornos sin pruebas de restauración o sin scripts de failover son simplemente apuestas disfrazadas de arquitectura.

Que un sistema esté “disponible” no significa que esté “protegido”. Y si no lo tenemos claro antes de la caída, lo aprenderemos después. Y no será barato.

¿Recomendación final? Probemos los escenarios de desastre antes de que lo sean. Porque el caos no avisa, pero nosotros sí podemos estar preparados.

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

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

Usar siempre dbo en SQL Server: ventajas, riesgos y buenas prácticas

Después de analizar cómo funciona la propiedad db_chainig y los riesgos de activar cross db ownership chaining a nivel de instancia, nos queda un tema que está en el centro de todo: el uso del usuario y esquema dbo de forma sistemática. Es una práctica habitual, cómoda y hasta cierto punto tradicional en SQL Server, pero que conviene revisar con detalle cuando hablamos de seguridad, despliegues controlados y gobernanza de datos.

¿Realmente es buena idea que todo pertenezca a dbo? ¿Qué consecuencias tiene a medio y largo plazo? ¿Dónde está el equilibrio entre comodidad y control?

Qué es dbo y por qué se usa tanto

El usuario dbo (database owner) es un usuario especial en cada base de datos de SQL Server. Está vinculado al propietario real de la base de datos y tiene todos los privilegios dentro de ella. Cuando creamos objetos sin especificar un esquema, y el usuario con el que trabajamos está asignado como dbo, los objetos se crean bajo ese esquema por defecto.

Esto significa que en la mayoría de los entornos, a menos que se especifique lo contrario, todos los procedimientos, tablas, vistas y funciones acaban siendo del esquema dbo y perteneciendo al usuario dbo.

Esta práctica tiene una ventaja clara: evita problemas de permisos y simplifica el acceso a los objetos, sobre todo en proyectos donde no se quiere dedicar tiempo a gestionar esquemas ni propietarios. En resume, es una forma de trabajar directa y suele «funcionar a la primera». Pero también tiene implicaciones importantes que no se deben ignorar.

Seguridad: encadenamiento de propietarios dbo y permisos no deseados

Cuando todos los objetos son propiedad de dbo, es muy fácil que se establezcan cadenas de confianza sin querer. Esto es justo lo que habilita la propiedad db_chainig cuando está activa, y lo que se multiplica peligrosamente si además se activa cross db ownership chaining a nivel de instancia.

Al compartir el mismo propietario, los objetos pueden acceder entre sí sin que se comprueben los permisos del usuario que ejecuta la operación. Esto puede ser deseable en ciertos diseños bien controlados, pero también abre la puerta a que procedimientos maliciosos o mal diseñados escapen a la lógica de seguridad prevista, sobre todo cuando hay múltiples bases de datos con el mismo esquema y propietario.

Además, si todos los objetos son de dbo, resulta más difícil aplicar políticas de control por esquema o restringir accesos según áreas funcionales, ya que todo está en el mismo «cajón».

Mantenimiento y legibilidad: lo que hoy parece fácil con dbo, mañana es un dolor

Usar siempre dbo dificulta la organización lógica de los objetos. Cuando una base de datos empieza a crecer, no hay forma rápida de agrupar o identificar objetos por módulo funcional, equipo responsable o ciclo de vida.

Tampoco ayuda en tareas como generar scripts de despliegue por módulos, aplicar permisos diferenciados según esquema, monitorizar la actividad por subsistemas o delegar administración de partes concretas de la base de datos.

Todo eso requiere una separación explícita por esquemas o, al menos, una política clara de nomenclatura y propiedad. Si todo está bajo dbo, estas tareas se convierten en búsquedas manuales y excepciones constantes.

Auditoría y trazabilidad: todos los caminos llevan a dbo

Desde el punto de vista de la auditoría, tener todos los objetos bajo dbo borra cualquier pista sobre quién creó o modificó qué. El seguimiento de cambios se vuelve opaco, y las herramientas de trazado o revisión de permisos no pueden distinguir entre distintos propietarios lógicos. Esto se agrava si además usamos usuarios compartidos o impersonificación (EXECUTE AS), donde es muy difícil reconstruir el contexto original de ejecución.

Cuando una base de datos es pequeña y la usa un solo equipo, esto puede parecer un problema menor. Pero en sistemas colaborativos, auditados o con cumplimiento normativo, no tener separación de propietarios o esquemas puede ser un problema serio.

Despliegue controlado: lo que no se define, se rompe

Si trabajamos con plantillas de despliegue, versionado de bases de datos o pipelines CI/CD, usar siempre dbo limita la capacidad de definir entornos reproducibles y con permisos granulados. No se puede diferenciar entre objetos internos, públicos, temporales o propios de cada equipo.

Además, algunos errores de despliegue tienen que ver precisamente con suposiciones implícitas sobre el esquema o el propietario: si un script no especifica dbo y el usuario por defecto cambia, el objeto puede terminar en otro esquema, provocando errores sutiles y difíciles de detectar.

¿Cuándo sí tiene sentido usar dbo?

No todo es negativo. Hay escenarios donde usar exclusivamente dbo puede ser razonable. Por ejemplo en bases de datos monolíticas mantenidas por un solo equipo, en proyectos personales o experimentales donde no hay requisitos de seguridad ni mantenimiento a largo plazo o en aplicaciones donde toda la lógica de negocio está encapsulada y no se expone acceso directo a las tablas.

En estos casos, usar dbo reduce fricción y permite concentrarse en el desarrollo funcional. Pero, incluso en estos casos, conviene tener claro que estamos asumiendo una simplificación consciente, no una buena práctica general.

Buenas prácticas recomendadas: ¿dbo si o no?

Si queremos mantener un equilibrio entre simplicidad y control, podemos aplicar algunas de estas pautas.

La primera sería no usar dbo y usar esquemas distintos para separar áreas funcionales, como ventas, compras, auditoria, etc. Especialmente debemos evitar crear objetos como dbo si el usuario final no debe tener control total. En estos casos asignar esquemas a roles o usuarios concretos, y establecer políticas de permisos basadas en ellos es clave. Además, definir el esquema siempre de forma explícita en scripts y objetos programables es imprescindible para que, si un usuario tiene otro esquema por defecto, todo siga funcionando. Por último documenta siempre la política de propiedad y esquema como parte del diseño de cada base de datos.

Con estas simples recomendaciones podrás mantener la claridad y la organización incluso en proyectos con muchos objetos o múltiples desarrolladores.

Conclusión

Usar dbo para todo es cómodo, pero a menudo es una señal de diseño descuidado o sin política de seguridad clara. Aunque puede parecer una solución rápida, a largo plazo complica el mantenimiento, debilita el control de accesos y dificulta la trazabilidad.

En bases de datos pequeñas o entornos cerrados, puede no suponer un problema. Pero si trabajamos en entornos colaborativos, con ciclos de vida largos, requisitos de auditoría o despliegues automatizados, separar esquemas y propietarios deja de ser una opción y se convierte en una necesidad.

No se trata de demonizar dbo, sino de dejar de usarlo como valor por defecto para todo. Definir y respetar una estructura clara es una de las formas más efectivas de asegurar calidad y sostenibilidad en nuestras bases de datos.

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

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

Cross DB Ownership Chaining en SQL Server

En el artículo anterior vimos cómo la propiedad db_chainig permite que el encadenamiento de propietarios funcione entre objetos ubicados en bases de datos distintas, siempre que esta opción esté activada en ambas bases de datos y se cumplan ciertos requisitos. Pero hay un aspecto que no abordamos en profundidad: qué ocurre cuando esta configuración se aplica no solo a nivel de base de datos, sino también a nivel de instancia, utilizando la opción cross db ownership chaining. Este ajuste tiene un comportamiento más agresivo y, en la mayoría de los entornos, representa una mala práctica de seguridad que conviene evitar.

¿Qué hace exactamente cross db ownership chaining?

Mientras que la propiedad db_chainig se puede activar o desactivar de forma individual en cada base de datos, la opción cross db ownership chaining es una configuración de instancia que fuerza la activación del encadenamiento de propietarios entre todas las bases de datos de la instancia, sin posibilidad de excluir ninguna.

Activarla equivale, a efectos prácticos, a establecer db_chainig = ON para todas las bases de datos, aunque no lo hayamos hecho explícitamente. Esto significa que cualquier procedimiento, vista, función u otros objetos en una base de datos que comparta propietario con una tabla en otra podrá acceder a ella sin que el usuario tenga permisos explícitos. Y lo más preocupante: este comportamiento se extiende automáticamente a cualquier base de datos nueva que se cree en la instancia.

Cómo activar y desactivar cross db ownership chaining

Podemos consultar el estado actual de la opción con:

Si devuelve valor 1, la opción está activada. Para desactivarla (que es lo recomendable en la mayoría de casos):

Esta configuración requiere nivel de sysadmin, ya que afecta directamente a la seguridad global del motor.

Implicaciones de seguridad

El principal riesgo de mantener esta opción activa es que se rompen los límites de seguridad entre bases de datos. En lugar de tener compartimentos estancos, con cross db ownership chaining se permite el acceso entre objetos de distintas bases de datos con solo compartir el mismo propietario. Esto debilita el aislamiento lógico que SQL Server garantiza por defecto.

Imaginemos una instancia donde convivieran varias bases de datos de distintos departamentos, proyectos o incluso clientes. Si todas ellas utilizan el esquema y usuario dbo, y se activa cross db ownership chaining, cualquier procedimiento mal diseñado o malicioso podría acceder a tablas fuera de su alcance original sin necesidad de permisos explícitos. Este escenario rompe cualquier principio de defensa en profundidad.

Además, si se utilizan funciones como EXECUTE AS, se complica todavía más el análisis de los permisos efectivos, y pueden aparecer brechas difíciles de detectar hasta que ya es tarde.

¿Hay algún caso donde activarla tenga sentido?

La única situación razonable para activar cross db ownership chaining es en entornos completamente controlados, con una única aplicación propietaria desplegada en la instancia, donde todas las bases de datos forman parte de la misma solución y no hay usuarios externos ni terceros ejecutando código dinámico o creando objetos.

Incluso en ese caso, sigue siendo preferible activar db_chainig solo en las bases de datos que lo necesiten, en lugar de aplicar un cambio de instancia que afectará a todo lo que esté ejecutándose ahora y en el futuro.

También puede tener cierta justificación en entornos de desarrollo o pruebas rápidas, donde se valore más la agilidad que la seguridad. Pero ahí conviene recordar que muchas veces lo que se prueba en desarrollo acaba en producción… y con ello los errores de configuración.

Buenas prácticas y recomendaciones

Para mantener la seguridad y el control en nuestras instancias de SQL Server, las pautas más recomendables respecto a esta configuración son claras: “Mantener cross db ownership chaining desactivado por defecto”. Siempre es más recomendable activar db_chainig solo en las bases de datos que lo requieran y siempre de forma explícita y documentada. En cualquier caso, además te recomiendo evitar el uso masivo del propietario dbo en todas las bases de datos, especialmente en entornos con múltiples aplicaciones o proyectos y revisar regularmente qué bases de datos tienen esta propiedad activada y por qué. Tampoco está de más aplicar control de cambios y auditoría cuando se modifiquen opciones de instancia.

Además, en cualquier revisión de seguridad o auditoría formal, tener esta opción activada puede ser motivo de alerta o incluso de no conformidad con normativas como ISO 27001, PCI-DSS o el Esquema Nacional de Seguridad (ENS).

Conclusión

La opción cross db ownership chaining es uno de esos ajustes que, a simple vista, puede parecer útil para evitar errores de permisos durante el desarrollo, pero que en producción representa una puerta abierta a problemas de seguridad difíciles de rastrear. Es una opción de legado que hoy en día solo deberíamos tocar si entendemos perfectamente sus implicaciones.

Si en tu entorno necesitas acceso cruzado entre bases de datos, activa db_chainig solo donde sea estrictamente necesario. Y si lo que quieres es encapsular accesos sin exponer tablas directamente, plantéate usar certificados para firmar procedimientos y mantener un modelo de permisos más seguro y robusto.

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

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

Código dinámico con seguridad en SQL Server

En muchas ocasiones nos enfrentamos a escenarios donde necesitamos construir sentencias SQL de forma dinámica. Ya sea para crear filtros condicionales, construir cláusulas ORDER BY en tiempo de ejecución o ejecutar consultas sobre distintos objetos, la generación de SQL dinámico parece una solución sencilla y flexible. Pero esta potencia viene acompañada de riesgos, especialmente desde el punto de vista de la seguridad.

A lo largo de los años, he visto cómo el uso descuidado del SQL dinámico ha sido uno de los vectores de ataques de inyección SQL (SQLi) más comunes, y aún sigue siéndolo. Por eso, en este artículo vamos a repasar cómo generar SQL dinámico en SQL Server de forma segura, analizando técnicas recomendadas y errores frecuentes, con ejemplos claros y aplicables.

¿Cuándo usamos SQL dinámico?

Los escenarios más frecuentes en los que aparece la necesidad de SQL dinámico suelen estar relacionados con filtros condicionales, búsquedas avanzadas, generación de informes personalizables, lógica multi-tenant o incluso mantenimiento automatizado.

Un ejemplo muy habitual es una búsqueda con varios filtros opcionales. Supongamos una aplicación que consulta una tabla de personas donde el usuario puede buscar por nombre, ciudad y país. Si tratamos de resolver esto con un procedimiento estándar, el número de combinaciones posibles puede crecer exponencialmente. El SQL dinámico permite construir la sentencia ajustada a los filtros que el usuario haya proporcionado.

El problema del SQL Injection

El gran riesgo del SQL dinámico mal implementado es el conocido SQL Injection, una técnica con la que un atacante puede alterar la consulta ejecutada para acceder o modificar datos sin autorización. Esto ocurre cuando concatenamos directamente valores dentro de la cadena SQL. Veamos un ejemplo inseguro:

Si @city proviene de un parámetro externo (una app, una web), el usuario podría inyectar algo como: “Madrid’; DROP TABLE Person.Person;” y provocar un desastre.

Este patrón, por desgracia, sigue viéndose demasiado a menudo en aplicaciones heredadas o mal diseñadas.

Uso seguro de SQL dinámico con sp_executesql

La solución más eficaz ante este problema es usar sp_executesql, que permite construir consultas dinámicas pero separando el código de los datos mediante parámetros tipados. Esto bloquea cualquier intento de inyección porque el valor del parámetro no se interpreta como código. Reescribamos el ejemplo anterior de forma segura:

Aquí, aunque el usuario intentase inyectar código en @city, no lo conseguiría. SQL Server lo tratará como un valor, no como una parte de la instrucción.

Además, esta técnica también permite la reutilización de planes de ejecución, lo que supone una ventaja adicional en términos de rendimiento.

Código dinámico con filtros condicionales

Un paso más allá es cuando necesitamos construir dinámicamente múltiples filtros. En estos casos, lo ideal es ir concatenando las condiciones SQL pero parametrizando todos los valores. Veamos un ejemplo más completo:

De este modo, solo se añaden los filtros que tengan valor, pero todos los valores siguen protegidos mediante parámetros.

Identificadores dinámicos: el caso más delicado

sp_executesql no permite parametrizar nombres de columnas o tablas. Esto es especialmente importante si necesitamos cambiar el objeto sobre el que se ejecuta la consulta. En estos casos debemos concatenar el identificador, pero asegurándonos de que el valor es válido. La función QUOTENAME es clave para evitar inyecciones sobre identificadores ya que introduce el nombre del objeto entre corchetes [].

Aquí estamos asumiendo que el nombre de la tabla ha sido validado previamente. Aún así, QUOTENAME evita que un valor como SalesOrderHeader; DROP TABLE x;– pueda hacer daño. 

En entornos multi-tenant esto es especialmente útil si cada cliente tiene su propia tabla (modelo database-per-tenant) y accedemos a ellas dinámicamente.

Consejos adicionales para SQL dinámico seguro

Cuando usamos SQL dinámico en entornos críticos o expuestos a usuarios externos, es fundamental aplicar otras prácticas complementarias como encapsular en procedimientos almacenados ya que así reducimos la exposición del motor y permitimos auditar más fácilmente. Otra buena práctica es registrar las consultas generadas, esto es especialmente útil para soporte, auditoría y detección de patrones de abuso. Otro paso obligatorio, para mi es evitar privilegios excesivos; el usuario que ejecuta el código dinámico no debe tener más permisos de los necesarios.

Por último, si queremos ir un paso más allá, podemos aplicar SET FMTONLY OFF y otras opciones de seguridad sobre todo si trabajamos con herramientas de terceros. De esta manera podremos asegurarnos de que el motor de base de datos ejecuta todo el bloque tal cual, sin modificar el flujo por culpa del modo de metadatos.

Conclusión

El SQL dinámico en SQL Server puede ser tan útil como peligroso. En nuestras manos está la diferencia entre construir una solución flexible y robusta o abrir una puerta trasera a posibles ataques.

La clave está en nunca concatenar valores directamente y utilizar sp_executesql con parámetros siempre que sea posible. Cuando se trabaja con nombres de objetos, debemos validar y proteger con QUOTENAME. Y si el contexto lo permite, encapsular toda la lógica dentro de procedimientos controlados.

Estas técnicas yo las aplico habitualmente en proyectos reales, y son parte esencial de una arquitectura segura, especialmente en entornos donde la escalabilidad o la “multi-tenencia” requieren cierta flexibilidad a nivel de metadatos. 

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

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