Incidencias

Especial Halloween. El marrón que todo DBA ha sufrido

¿Qué Halloween da miedo? Será para los que no han tenido que restaurar un backup en producción y estaba corrupto, con el jefe respirándoles en la nuca y un SLA expirando más rápido que el café enfriándose.

Los verdaderos horrores no salen en películas. Se ejecutan en nuestros servidores.

Si el año pasado nos pusimos nostálgicos para hablar del problema de Halloween original, hoy vamos a hablar de jobs fallidos, bloqueos eternos, desarrolladores con acceso a sysadmin, y scripts “probados en otro entorno”. Marrones que un DBA conoce muy bien. Marrones que no se borran con un ROLLBACK.

Definición técnica

MARRÓN (noun)

Término operativo usado en entornos técnicos para describir cualquier tarea, incidente o requerimiento que:

  1. No estaba prevista.
  2. Nadie quiere hacer.
  3. Tiene alta visibilidad y cero documentación.
  4. Requiere acción inmediata (generalmente ayer).
  5. Y suele implicar que el culpable eres tú, aunque no tengas ni idea de qué ha pasado.

Roles asociados:

  • Enmarronador (BrownDispatcher): Individuo que asigna el marrón con una sonrisa, un café en la mano o un “esto es rápido”. Suele tener cargo, pero no responsabilidad.
  • Enmarronado (Browned): Víctima del proceso de asignación. También conocido como “el de SQL” o “el que sabe”. No necesariamente tiene culpa, pero sí marrón.
  • Buscamarrones (BrownFinder): Persona que se ofrece voluntaria “para aprender” o “echar una mano”. A menudo desaparece misteriosamente cuando el marrón explota.
  • Comemarrones (BrownEater): DBA veterano que se ha comido tantos marrones que ya solo le quedan dos emociones: resignación y café.

Importante:

El marrón flotante: la petición que no llega (pero llegará)

Es lunes y alguien menciona “tenemos que mirar lo del rendimiento del ERP” mientras tú estás con otras 40 cosas. Nadie lo documenta, nadie lo asigna, pero ya sabes lo que va a pasar. Lo oyes flotar.

Un día (viernes a última hora, seguro) alguien abre un ticket con prioridad alta y asunto ambiguo: “Problema con SQL”. Ni reproducible, ni claro. Y para cuando llega a ti, ya eres el responsable. Del ERP. Del rendimiento. De todo.

Este marrón huele a cursores usados alegremente por algún genio que ha leído un blog equivocado. Y te va a tocar explicarlo. Otra vez.

El marrón fulminante: el «¿qué ha pasado?» a las 8:00

Son las 7:58. Te conectas. Parece que todo está tranquilo. Hasta que alguien grita por Teams: “¡la base de datos está caída!”

Miras los logs. Alguien reinició el servicio de SQL Server durante la noche. ¿Motivo? “Estaba lento y pensé que eso lo arreglaría, luego el servicio no se paraba y reinicié el servidor”. 

No sabemos qué ha pasado, solo tenemos aplicaciones paradas y usuarios locos por los pasillos.

Y tú, desayunando con una base de datos de 25 Tb en recuperación.

Este es el marrón que se instala sin pedir permiso. Lo único que puedes hacer es ponerte los guantes de forense, y rezar para que pase cuanto antes.

El automarrón: lo hiciste tú, y lo sabes

Hay veces que el marrón no viene de fuera. Te lo cocinas tú solito.

Aceptaste esa migración “sencilla” de SQL Server 2012 a 2022. Te dijeron que solo había que mover “un par de bases”. Ahora estás descubriendo jobs con código T-SQL del pleistoceno, linked servers a dominios que ya no existen, y stored procedures que funcionan por magia negra.

Y todo tiene que estar listo este fin de semana. Por supuesto.

Es el automarrón. Y el problema no es el marrón. Es tu optimismo que te llevó a no mirar dos veces.

El marrón pata negra: ese proyecto que recordarás siempre

Hay marrones, y luego está ese proyecto que te cambió la vida. El que te hizo cuestionarte tus decisiones vitales.

Un data warehouse mal diseñado que hay que “reoptimizar”. Con cientos de tablas de millones de registros sin índices, y vistas anidadas que ya tienen su propio ecosistema. Con consultas que tardan horas y desarrolladores que te juran que “antes iba rápido”.

Es el marrón pata negra. No se arregla. Se sobrevive. Y si logras salir de ahí, probablemente acabarás con un tic nervioso… y un máster en tuning sin quererlo.

El marrón de última hora: el clásico de viernes tarde

Viernes, 14:59. Recoges. Cierra sesión. Y entonces… “oye, una cosilla antes de que te vayas”.

Spoiler: no es una cosilla.

Es un cambio en producción. Un script que nadie ha revisado. Un MERGE que te juran que va bien “porque lo hemos probado en dev”. Unos índices que hay que “crear rapidito” porque el CTO ha leído en LinkedIn que eso mejora el rendimiento.

Y tú, con el abrigo puesto, ejecutando con miedo un script que viene de un Excel. Bienvenido al marrón invocado. No saldrás antes de las 21:00. Si sales.

El marrón mutante: el que cambia cada día

Te asignan un problema de rendimiento. Miras. Optimización sencilla. Pones un índice. Va mejor.

Pero luego cambia el plan de ejecución. Luego te enteras de que han cambiado el MAXDOP sin avisarte. Luego la tabla crece un 300% de un día para otro. Y el problema vuelve. Peor.

El marrón mutante nunca termina. Hoy es CPU, mañana IO, pasado bloqueos. Intentas aplicar parches, pero no hay final. Es como dar soporte a una base que se autodestruye a diario y se recompone… peor.

Vives en un entorno hostil.

El marrón sonda: el disfrazado de consulta inocente

“Una duda rápida sobre un procedimiento que tarda un poco…”

Error. Ya estás dentro.

Empieza como una duda. Luego te piden revisar el plan. Luego optimizar. Luego reescribir. Luego hacer un informe. Luego… estás haciendo tú todo.

Los marrones sonda son los peores porque son invisibles. Te atrapan por empatía. No porque puedas decir que no, sino porque ya estás en medio. Y claro, ya que estás…

El pressing brown: presión en estéreo

Cliente cabreado. Jefe nervioso. Equipo de desarrollo esperando. Todos preguntan. Todos presionan.

Y tú, el DBA, recibiendo por todos lados. Con logs, sin contexto, y con el “esto no puede estar fallando, si no hemos tocado nada” como único diagnóstico.

Es el pressing brown. Nadie lo admite, pero todos lo han hecho: tirar el marrón al de bases porque “seguro que es algo del SQL”.

Y a ti te toca arreglarlo. Sin información. Sin culpa. Sin gloria.

El brown shower: todo cae a la vez

Backup corrupto. Alerta de disco. AG desincronizada. Login bloqueado. Limpieza de datos que ha borrado datos de más (a quien se le ocurre poner las FK con borrado en cascada…). El entorno ha dicho basta. Y todo a la vez.

Eso no es un marrón. Es un brown shower.

Cuando pasa, no arreglas. Contienes. Priorizas, sobrevives, y rezas porque el clúster no decida reiniciarse. Y si alguien pregunta cómo va todo, solo di: “controlado”, mientras lloras por dentro.

Conclusión: el terror real se ejecuta en SQL

Que sí, que Halloween da miedo. Pero no tanto como ejecutar un DELETE sin WHERE en la base de producción, o que el backup del FULL no incluya las bases más críticas.

Nosotros no necesitamos sustos. Ya los trae el trabajo.

Y recuerda: si un jefe te dice “es una tarea rápida”, asegúrate de tener a mano tu última copia del CV actualizado. Y una linterna. Porque se viene noche larga.

Feliz Halloween, compañeros de marrones. Que los browners pasen de largo… o al menos os pillen con un buen plan de contingencia.

Publicado por Roberto Carrancio en Otros, 0 comentarios

Cuando un LEFT JOIN se convierte en INNER. SQL Server Basics

Lo has visto. Lo has sufrido. Y si aún no te ha pasado, enhorabuena, pero no te relajes, tu día llegará. Me refiero al clásico caso del LEFT JOIN que acaba comportándose como un INNER JOIN porque alguien decidió, en un momento de inspiración, colocar un filtro donde no debía. Y claro, la consulta no devuelve lo que se espera, o peor: devuelve justo lo que se espera, pero está mal.

Hoy vamos a hablar de un problema que se cuela en muchos desarrollos y auditorías de código: el efecto de los filtros en un LEFT JOIN, y cómo una mala ubicación puede cambiar radicalmente el comportamiento de tu consulta. Así que prepara café, que vienen curvas.

El LEFT JOIN que no era

Un LEFT JOIN debería, en teoría, devolver todos los registros de la tabla izquierda, aunque no haya coincidencia en la tabla derecha. Hasta aquí, todo bien. Pero esto solo se cumple si no saboteas la lógica desde el WHERE.

Veamos un ejemplo simple pero revelador:

A simple vista parece correcto. Queremos todos los clientes y, si tienen facturas a partir de 2025, las mostramos. Pero no. Lo que acaba devolviendo esta consulta es únicamente aquellos clientes que tienen facturas desde 2025. ¿Y los que no tienen ninguna factura? Fuera del resultado. Despedidos.

¿Por qué? Porque estás aplicando un filtro sobre una columna de la tabla derecha (Facturas) después del JOIN, pero en el WHERE, que se evalúa después del JOIN, cuando los NULL ya están presentes. Y claro, NULL >= ‘2025-01-01’ es FALSE. El motor hace su trabajo, y tú te quedas sin clientes sin facturas.

¿Dónde va el filtro entonces?

En el ON. Sí, ese que muchos usan como si fuera una casilla para emparejar claves primarias con foráneas y poco más. Pero el ON tiene un papel más interesante aquí, si metes el filtro ahí, estarás condicionando el JOIN, no el resultado final.

Así que la versión correcta sería:

Ahora sí, todos los clientes aparecen. Los que tienen facturas desde 2025 las verán en su fila. Los que no, tendrán NULL en FacturaID. Tal y como un LEFT JOIN debe comportarse.

¿Y si necesito más filtros?

Buena pregunta. No es raro que quieras filtrar también por condiciones de la tabla izquierda. ¿Qué pasa entonces? Pues ahí sí puedes usar el WHERE, con criterio.

Por ejemplo:

Esto funciona como debe. El filtro en Clientes actúa después del JOIN, pero como no anula la lógica del LEFT, todo sigue su curso. Los clientes activos salen todos, tengan o no facturas desde 2025. Así sí.

¿Y si necesito filtrar por una columna de la derecha, pero sólo cuando no sea NULL?

Aquí empieza el juego sucio. Lo que quieres, probablemente, es quedarte con clientes que tengan facturas desde 2025, pero también mostrar los que no tienen ninguna factura. En ese caso, tienes que pensar en lógica condicional.

Una forma válida sería:

Esto ya es más decente. Estás diciendo: «dame los clientes que tienen facturas desde 2025, o los que no tienen ninguna factura». Y eso se respeta.

Pero seamos sinceros, si tienes que hacer esto a menudo, algo en tu modelo de consultas no huele bien. O tu reporting, o tu forma de pensar los datos. En esos casos, es mejor plantearte si necesitas un LEFT JOIN, unas vacaciones o modificar la lógica entera de la consulta.

No es un detalle menor

Aquí no estamos hablando de una microoptimización ni de una virguería SQL. Estamos hablando de lógica rota. El tipo de error que pasa todos los entornos, llega a producción, y luego nadie entiende por qué los informes no cuadran con la realidad.

Y lo peor, es un error silencioso. No da fallo. No lanza excepciones. Simplemente te da datos incorrectos con cara de datos correctos. Lo cual, en nuestro mundo, es el infierno.

En auditorías de rendimiento y revisiones de lógica de negocio, me encuentro este patrón con una frecuencia desesperante. Muchas veces me dicen: «Pero es que es un LEFT JOIN, ¿por qué no salen todos?». Y la respuesta es casi siempre la misma: porque tú mismo has convertido ese LEFT en un INNER, sin darte cuenta.

¿Qué pasa con los ORMs?

Sí, los ORMs. Esos grandes generadores de consultas elegantes como un campo minado. Hay ORMs que optimizan mal los JOIN, o que aplican los filtros fuera del ON por defecto. Y luego te toca a ti arreglar el entuerto porque el modelo “no da para más”.

Así que si estás usando Entity Framework, Hibernate o cualquier ORM moderno, revísalo tú a mano. No confíes en que el generador de consultas haya entendido tus intenciones como tú las entiendes.

Y ya que estamos, un apunte sobre MERGE

Sí, ya sé que esto va de LEFT JOIN, pero la confusión entre el WHERE y el ON en MERGE también merece un recordatorio. Porque ahí también es fácil liarla. En un MERGE, el ON es la condición de emparejamiento, no de filtrado. Si lo usas mal, puedes terminar haciendo UPDATE a registros que no deberías tocar, o insertando cosas que ni sabías que existían.

Lo dejo ahí, pero si te interesa, en el blog ya hablé en profundidad sobre los problemas de MERGE.

Conclusión

Si vas a usar un LEFT JOIN, asegúrate de entender cómo funciona y dónde colocar los filtros. No es un tema de estilo, es un tema de lógica. Un WHERE mal puesto no solo degrada el rendimiento: rompe la semántica de tu consulta.

Así que la próxima vez que revises una query con LEFT JOIN, pregúntate si realmente está haciendo lo que debería. Y si no, ya sabes dónde mirar primero: el WHERE. Porque sí, puedes hacer un LEFT JOIN que se comporte como un INNER, y también puedes correr con los cordones desatados. Ambas cosas acaban mal.

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, 3 comentarios

Canalizaciones por nombre (Named Pipes) en SQL Server

Durante años, las canalizaciones por nombre (Named Pipes) han sido uno de esos protocolos de red que viven en las sombras de TCP/IP. Están ahí, aparecen en las configuraciones del SQL Server Configuration Manager, y de vez en cuando algún alma valiente pregunta si debería activarlas “por si acaso”. Y no, por si acaso no es un argumento válido en administración de sistemas, y mucho menos en bases de datos. Vamos a analizar qué son exactamente, cómo funcionan y en qué escenarios podrían tener sentido… si es que alguno queda en 2025.

¿Qué demonios son las canalizaciones por nombre?

Antes de decidir si las activamos o las dejamos durmiendo el sueño de los justos, conviene entender qué son. Las canalizaciones con nombre son un mecanismo de comunicación interprocesos (IPC) heredado del glorioso mundo de Windows NT. Permiten que dos procesos, incluso en máquinas diferentes, se comuniquen a través de una ruta virtual. En SQL Server, representan uno de los protocolos disponibles para aceptar conexiones de cliente.

Mientras que TCP/IP utiliza direcciones IP y puertos, Named Pipes utiliza una sintaxis como \\.\pipe\sql\query, y en red sería algo tipo \\Servidor\pipe\sql\query. Esta vía de comunicación puede ser más rápida en entornos muy controlados y locales (léase: conexión directa entre un cliente y un servidor dentro de la misma LAN y sin cuellos de botella), pero en la práctica actual… hay que hilar muy fino para justificar su uso.

TCP/IP vs Canalizaciones por nombre: ¿por qué seguimos hablando de esto?

La realidad es que TCP/IP es el protocolo estándar y recomendado para conexiones SQL Server, tanto en producción como en desarrollo. Es más robusto, más flexible, y más preparado para escenarios reales con múltiples capas de red, firewalls, balanceadores, NATs y demás fauna moderna.

Entonces, ¿por qué SQL Server sigue ofreciendo Named Pipes como opción? Por compatibilidad. Porque aún hay sistemas legacy que las usan. Y porque a Microsoft le cuesta soltar lastre tanto como a cualquiera que aún mantiene SQL Server 2008 en alguna esquina de su datacenter “temporal”.

Hay entornos donde, por motivos históricos o arquitecturas muy específicas, se configuraron conexiones a SQL Server utilizando Named Pipes. En esos casos, sí, deshabilitarlas podría romper algo. Pero esa es la excepción, no la norma.

¿Cuándo tienen sentido las Named Pipes?

Vale, no todo es blanco o negro. Hay escenarios, pocos pero existentes, donde las canalizaciones por nombre pueden tener cierta ventaja:

  • Conexiones locales (cliente y servidor en la misma máquina): En algunos benchmarks internos de Microsoft (de hace más de una década nada menos), se observó que el rendimiento de Named Pipes en conexiones locales era ligeramente superior al de TCP/IP. Pero, francamente, si ese es tu cuello de botella, tienes problemas mayores.
  • Autenticación integrada en entornos Windows puros: Las canalizaciones por nombre pueden simplificar ciertos escenarios de autenticación integrada en entornos totalmente controlados por Active Directory. Pero otra vez: TCP/IP también lo hace sin problemas.
  • Entornos legacy que no quieres (o puedes) tocar: Si tienes una aplicación que explícitamente se conecta usando np: o configuraciones hardcoded de canalizaciones con nombre, y no puedes modificarla… entonces no queda otra que habilitarlas.
  • Solución de problemas puntuales: En algunos casos, cuando el acceso por TCP/IP falla misteriosamente (DNS, puertos bloqueados, fuegos en el CPD…), usar Named Pipes puede servir para diagnosticar si SQL Server sigue vivo y coleando.

Pero si tu escenario no cae en alguno de estos puntos, las Named Pipes sobran.

Cómo funcionan realmente las canalizaciones por nombre

Cuando habilitas Named Pipes en SQL Server, el motor escucha en una canalización concreta: \\.\pipe\sql\query por defecto. El cliente debe conectarse utilizando ese nombre. Lo que muchos no saben es que esto no solo requiere que el cliente conozca la sintaxis, sino también que la resolución de nombres esté bien configurada (en red), y que no haya firewalls bloqueando el tráfico correspondiente.

Además, en entornos remotos, el protocolo puede comportarse de forma bastante torpe: mayor latencia en la negociación, más complejidad en el tráfico de red, y más exposición a errores difíciles de diagnosticar. Si te suena a dolor de cabeza… es porque lo es.

¿Qué pasa si dejo las canalizaciones por nombre activadas “por si acaso”?

Esto es como dejar todas las ventanas de casa abiertas por si te olvidas las llaves. En teoría podría ayudarte, pero en la práctica te estás exponiendo innecesariamente. Habilitar las canalizaciones por nombre sin necesitarlas abre un vector de ataque innecesario (sí, también hablamos de superficie de ataque), complica el troubleshooting de conexiones, y puede provocar que clientes mal configurados intenten conectar usando este protocolo en lugar de TCP/IP.

Por si fuera poco, cuando están activadas, SQL Server puede priorizarlas en la cadena de protocolos, lo que lleva a situaciones surrealistas como que un cliente tarde más de la cuenta en conectarse porque está intentando usar Named Pipes antes que TCP/IP.

Lo peor de todo es que, en redes modernas, usar Named Pipes puede ralentizar la conexión en lugar de mejorarla. Así que eso de activarlas para “ganar velocidad” es un mito que ya deberíamos haber dejado atrás con el disquete.

¿Y si las necesito, cómo las activo (o desactivo)?

Si a pesar de todo necesitas activar Named Pipes, el proceso es sencillo, pero no inmediato. Desde SQL Server Configuration Manager, accede al protocolo correspondiente bajo SQL Server Network Configuration, y ahí puedes habilitarlas o deshabilitarlas. Necesitarás reiniciar el servicio SQL Server para que los cambios tengan efecto.

Además, si vas a usarlas, asegúrate de configurar también correctamente la cadena de conexión en el cliente, usando el prefijo np: para forzar que se utilicen Named Pipes.

Y, por supuesto, monitoriza. No asumas que todo va mejor solo porque te conectaste. Comprueba latencias, errores, y la experiencia real del usuario. Porque los milagros no vienen de las canalizaciones.

¿Qué protocolo prioriza SQL Server?

El orden de los protocolos es importante. SQL Server Native Client (o el driver OLE DB / ODBC que uses) sigue un orden al intentar conectar, salvo que lo fuerces. Ese orden se define también en SQL Server Configuration Manager, y puedes modificarlo.

Si dejas Named Pipes activado y en primer lugar, el cliente intentará primero por ahí antes de probar TCP/IP. Si Named Pipes no está disponible o hay problemas de red, el tiempo de espera puede incrementarse de forma absurda. ¿Te suenan esas conexiones que tardan 20 segundos solo en conectar? Pues eso.

Conclusión

Las canalizaciones por nombre son como el fax, aún existen, aún funcionan, y hay quien defiende que tienen utilidad. Pero en la mayoría de escenarios modernos con SQL Server, no hay ninguna razón técnica sólida para tenerlas activadas si no se están usando.

No aportan ventaja real frente a TCP/IP, complican el diagnóstico, abren superficie de ataque, y pueden ralentizar la conexión. Si tu entorno las requiere, adelante, pero hazlo con conocimiento de causa. Si no sabes para qué las necesitas, es que no las necesitas.

Apaga las Named Pipes, reinicia tu SQL Server y duerme tranquilo sabiendo que has reducido complejidad innecesaria.

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

El libro de SQL Server que estabas esperando

Después de más de una década trabajando con SQL Server y ahora compartiendo contenido en SoyDBA, estoy escribiendo un libro pensado para profesionales que quieren ir más allá de la documentación oficial. Un libro técnico y muy didáctico.

Más de 40 capítulos en 7 partes, desde los fundamentos del modelo relacional hasta las herramientas de diagnóstico más avanzadas. Un recorrido completo, pensado para DBAs, analistas y desarrolladores que quieren entender cómo funciona SQL Server de verdad.

Portada Libro

El prólogo lo firma Fernando G. Guerrero, pionero y referente en nuestra comunidad. La contraportada, Juanjo Luna, MVP de Access y más apasionado de SQL de lo que quiere reconocer. Os dejo aquí el texto de la contraportada:

Si quieres conseguirlo corre a Amazón.

El libro está disponible en Amazon en formato papel y Kindle en todo el mundo.

Mantente al día de las novedades con mi newsletter gratuita

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.

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

MERGE en SQL Server: La eterna promesa llena de bugs

Durante años, MERGE ha sido esa promesa elegante que parecía resolver de un plumazo todo lo que nos complica la vida a los que escribimos consultas T-SQL: una única instrucción que unifica INSERT, UPDATE y DELETE. Menos código, más claridad, mejor rendimiento. El sueño húmedo de cualquier desarrollador… hasta que lo llevas a producción y te explota en la cara.

Sí, yo también quise creer. Pero tras ver más de un sistema roto por culpa de un MERGE traicionero, aprendí la lección. Y como este blog va de compartir experiencia real, no fantasías, vamos a desmontar con datos, técnica y un poco de sarcasmo, por qué MERGE es, en muchos entornos, un unicornio lleno de bugs.

El espejismo de la elegancia

La idea es sencilla y tentadora: haces una sola declaración, defines condiciones de coincidencia entre origen y destino, y luego eliges qué hacer si hay match o no. Todo en un solo bloque. Nada de IF EXISTS, nada de UPDATE por un lado e INSERT por otro. Un único statement, limpio y compacto.

El problema es que SQL Server no es un laboratorio teórico. Es un entorno donde las condiciones cambian, los bloqueos existen, los triggers hacen su trabajo (o no), y las consultas compiten por recursos. Y ahí, la belleza del MERGE se convierte en un infierno difícil de depurar.

El historial de errores no es opcional

Vamos con lo feo. Microsoft lleva más de una década acumulando errores abiertos relacionados con MERGE. Aquí no estamos hablando de edge cases oscuros, sino de fallos que afectan a la integridad de los datos.

Aaron Bertrand ya lo dejó claro hace más de siete años en su artículo «Use Caution with SQL Server’s MERGE Statement«, el operador MERGE acumulaba más de 20 errores críticos documentados en versiones de SQL Server que abarcan más de una década. Algunos tan graves como silenciosos, otros directamente absurdos. Y lo peor no es que existan, sino que muchos siguen sin resolverse a día de hoy después de años. Y cuando una funcionalidad lleva tanto tiempo con bugs abiertos y nadie los cierra, el mensaje es claro: no está pensada para producción. Punto.

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.

Estamos hablando de que MERGE no ejecuta triggers cuando debería, que dispara errores crípticos si hay más de una coincidencia por fila destino, que genera planes de ejecución incoherentes aunque las estadísticas estén actualizadas, o que, simplemente, no hace lo que le has dicho que haga.

Y cuando algo así puede romper datos sin avisar, no estamos ante una cuestión de estilo. Es un riesgo técnico que hay que conocer y evitar como parte del trabajo profesional.

Yo también lo he usado. Pero sabiendo dónde

Ahora bien, no todo es fuego y azufre. Yo mismo he usado MERGE con muy buenos resultados… pero en su contexto natural: procesos ETL para la carga de un Data Warehouse, sin concurrencia, sin triggers, sin usuarios esperando respuesta en tiempo real.

Ahí, MERGE brilla. En rendimiento, no tiene rival. Cuando puedes controlar el entorno y sabes que nadie va a meter la mano mientras el proceso está en marcha, la ganancia es real. Lo he usado para cargas masivas donde la lógica condicional era extensa y mantener la sincronización entre staging y destino requería algo más que un simple UPDATE. Y funcionó. Rápido, claro y sin sorpresas.

Y aun así, no es cómodo de usar

Ahora bien, incluso cuando MERGE funciona bien, escribirlo es otra historia. La sintaxis es tan compleja y poco intuitiva que soy incapaz de redactar una sentencia completa sin tener que abrir la documentación. Y no soy el único. Todos los que conozco, incluyendo perfiles senior, necesitan repasar los detalles o buscar ejemplos antes de atreverse a escribir uno no trivial. Obviamente al que escriba MERGEs a diario esto no le va pasar pero, al común de los mortales, nos cuesta y mucho.

Y no hablo de un MERGE básico, ese entra bien. Pero en cuanto mezclas múltiples condiciones, WHEN MATCHED, WHEN NOT MATCHED BY SOURCE, columnas calculadas, filtros condicionales y OUTPUT, el código se convierte en un monstruo ilegible. 

¿Es un problema grave? No, para eso está la documentación. Pero sí es un obstáculo innecesario. Más aún en un lenguaje como T-SQL, donde solemos priorizar claridad sobre compactación. Y aunque hoy en día las herramientas de IA nos pueden ayudar a escribirlo, mantenerlo sigue siendo responsabilidad nuestra. Y mantener un MERGE denso, con lógica compleja y comportamiento ambiguo, es como desactivar una bomba con guantes de boxeo.

Cuando MERGE falla… ni siquiera sabes por qué

Uno de los problemas más serios de MERGE es que sus errores no siempre son explícitos. En algunas situaciones simplemente no hace nada, o peor: hace algo, pero no lo que esperabas. Y ni el plan de ejecución, ni el @@ROWCOUNT, ni el log de errores te dan pistas.

Por ejemplo, si en el ON de un MERGE hay ambigüedad o más de una fila coincidente por destino, puedes recibir un error como:

The MERGE statement attempted to UPDATE or DELETE the same row more than once.

¿Y sabes qué fila fue? No. ¿Sabes por qué coincidieron dos filas? Tampoco, a menos que te pongas a hacer debugging con CTEs, filtros y OUTPUT hasta encontrarlo. Una joya para los que trabajamos bajo presión.

Triggers, locking y otras trampas técnicas de MERGE

Otra razón para evitar MERGE es su relación tóxica con los triggers. Por ejemplo, si tienes un INSTEAD OF TRIGGER, debe cubrir todas las acciones (INSERT, UPDATE, DELETE) usadas en el MERGE. Si no, obtendrás un error.

Además, dentro de los triggers, @@ROWCOUNT refleja la suma de todas las operaciones ejecutadas por el MERGE, no por separado. Así que no sabes si te han hecho un INSERT, un DELETE o un UPDATE. Y como $action no es accesible en el contexto del trigger… buena suerte.

A esto súmale que, en entornos de concurrencia, MERGE no garantiza aislamiento ni orden de ejecución. Necesitas usar explícitamente HOLDLOCK en la tabla destino para evitar condiciones de carrera, lo cual puede afectar gravemente al rendimiento o incluso provocar deadlocks si no lo haces bien.

Si Microsoft no usa MERGE… tú tampoco deberías

Hay una máxima que sigo como DBA, si ni el propio motor de SQL Server usa una funcionalidad para sus operaciones internas, será por algo. ¿O tú irías a comer a un restaurante donde ni el propio chef se come la comida que cocina?  Y adivina qué: Microsoft no utiliza MERGE internamente en sus procesos de sistema. Ningún SP del sistema usa MERGE. Ninguno.

Tampoco verás MERGE en herramientas como Replication, Change Tracking, CDC o Sync Framework. ¿Casualidad? No. Evitan su uso por inestabilidad, falta de garantías y dificultad de mantenimiento.

¿Y entonces qué usamos? Alternativas a MERGE

Lo que propongo no es TRY HARD SQL. Es simple, robusto y ha demostrado funcionar durante décadas:

Sí, son más líneas. No, no es sexy. Pero sabes lo que hace, puedes depurarlo, y es seguro en entornos OLTP. También puedes encapsularlo en un SP, usar OUTPUT para auditar, y meterlo en transacciones controladas. Resultado: código mantenible, auditable y libre de sorpresas.

Otra opción válida en operaciones masivas o ETL es usar UPDATE por separado, seguido de INSERT con NOT EXISTS. Ejemplo clásico:

Más claro, más predecible y con control absoluto de cada paso.

¿Y qué pasa con el rendimiento?

No podemos cerrar el tema sin hablar de la razón por la que muchos defienden MERGE con uñas y dientes: el rendimiento. La posibilidad de hacer INSERT, UPDATE y DELETE en una única operación suena, y es, más eficiente que dividir el trabajo en tres pasos.

Y sí, cuando funciona bien, MERGE puede reducir el número total de lecturas. El optimizador puede acceder a las tablas implicadas una sola vez, generar un plan compacto, y ejecutar todo con menos I/O que si lanzas varias operaciones por separado. Eso, en entornos de grandes volúmenes, marca la diferencia.

Pero, y este «pero» es importante, todo ese rendimiento se evapora en cuanto las condiciones dejan de ser ideales. Si tienes triggers, estadísticas obsoletas, datos duplicados, falta de unicidad, o cualquier mínima sorpresa en los datos, el plan de ejecución puede degradarse. Y si encima falla en mitad del proceso, el coste de arreglarlo supera con creces cualquier ganancia de rendimiento.

La pregunta no es solo “¿es más rápido?”, sino “¿cuánto me cuesta cuando va mal?”. Porque, al menos para mí, un MERGE que tarda 2 segundos pero rompe una fila cada 10.000 es mucho peor que un UPDATE + INSERT de 15 segundos que funciona siempre.

Dicho eso, si lo usas en un proceso ETL bien contenido, con staging controlado, sin usuarios ni competencia por recursos, y puedes probar cada camino lógico… adelante. En esos casos, sí, el rendimiento justifica su uso y, como os decía antes, yo mismo lo he usado.

¿Se puede usar MERGE con garantías?

La respuesta corta es sí, pero sólo bajo ciertas condiciones. Y con cuidado quirúrgico.

  • No debe haber concurrencia. Ni un solo proceso paralelo tocando las mismas filas.
  • Debe usarse HOLDLOCK explícito.
  • Las condiciones del ON deben garantizar unicidad absoluta.
  • Debes probarlo exhaustivamente, incluyendo casos límite y datos duplicados.
  • Y por favor, nada de usarlo con triggers activos. Ahí directamente estás pidiendo un exorcismo.

¿Vale la pena todo ese esfuerzo para no escribir cinco líneas más? En procesos ETL donde los datos son temporales, y el entorno está bien controlado, puede tener sentido. En entornos críticos OLTP… ni loco.

Conclusión

MERGE es eficiente. Compacto. Potente. Y en los entornos correctos, puede ser una joya. Pero en SQL Server, también es frágil, lleno de trampas y muy poco transparente cuando falla. No es cuestión de gustos, es cuestión de riesgos.

Si lo vas a usar, hazlo con pleno conocimiento de sus limitaciones y con un entorno controlado. Y si no puedes controlar todo lo que MERGE necesita para no traicionarte… mejor escribe unas líneas más y duerme tranquilo.

Porque a veces, la mejor optimización es no tener que hacer un análisis de errores.

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

¿Cuál es el problema que quieres resolver?

Si hay una pregunta que debería resonar en la cabeza de todo DBA antes de tocar nada es esta: ¿cuál es el problema que quieres resolver?. Parece de sentido común, pero basta con ver la cantidad de “optimizaciones” fallidas que nos encontramos a diario para entender que muchos prefieren actuar primero y pensar después.

No es cuestión de señalar a los juniors recién llegados. También he visto seniors con experiencia aplicar consejos a ciegas porque lo leyeron en un blog (sí, incluso en este). Optimizar sin tener claro el objetivo es la mejor forma de acabar con más índices de los que puedes contar y un servidor que corre peor que antes.

Cuando dos índices son un problema

Hace un tiempo publiqué un artículo en el blog que mostraba un comportamiento extraño en SQL Server: si creas dos índices con los mismos campos pero en orden inverso, el optimizador puede entrar en bucle y empeorar el rendimiento.

No es que uno de los índices fuera inútil, es que la mera coexistencia de ambos confundía al motor. El resultado eran planes de ejecución incoherentes, lecturas disparadas y un servidor que parecía castigar la osadía de haber creado ese segundo índice.

Lo comprobé en mi propio laboratorio y sí, el problema existe en distintas versiones, desde 2014 hasta 2022. No hay explicación oficial, pero el efecto es evidente: un índice que no se usa puede penalizar tanto como uno mal diseñado.

La moraleja es clara: no todo lo que parece buena idea lo es. Crear un índice extra “por probar” puede desatar un problema que no estaba ahí antes.

El optimizador también se equivoca

A ese escenario extraño se suma otro que me he encontrado demasiadas veces: el optimizador sugiriendo crear un índice que ya existe.

¿Cómo puede ser? Muy simple: lo que realmente falla son las estadísticas. Si los datos de distribución están obsoletos, el optimizador cree que no tiene un índice adecuado y recomienda uno nuevo. Y como “buenos DBAs obedientes”, lo creamos. Resultado: en el mejor de los casos acabamos con dos índices redundantes, el motor igual de confundido y el verdadero problema (las estadísticas) intacto. En el peor, con el problema que hemos descrito en el apartado anterior y con las estadísticas aún desactualizadas.

La historia se repite: en vez de preguntarnos qué queremos resolver, nos dejamos llevar por la sugerencia de turno y complicamos aún más el entorno.

Optimizar sin objetivo: el problema más común

Ambos casos ponen de manifiesto lo mismo: aplicar soluciones sin entender el problema real es un deporte de riesgo.

Ya lo comentamos en este otro artículo, los entornos de bases de datos no se arreglan con recetas universales ni con “scripts definitivos” de Internet. Cada entorno es distinto, con sus cargas, sus decisiones históricas y sus miserias. Copiar y pegar soluciones genéricas es más postureo técnico que administración seria.

La optimización sin objetivo es como disparar con los ojos cerrados, con suerte no das en nada, pero la mayor parte del tiempo acabas dañando algo.

La pregunta de Brent Ozar

Aquí entra la insistencia de Brent Ozar en su mantra favorito y que da titulo a este artículo:
¿Cuál es el problema que quieres resolver?

Antes de crear índices, actualizar estadísticas o aplicar hints a lo loco o cambiar configuraciones en el servidor hay que responder a esa pregunta. ¿El problema es el tiempo de respuesta? ¿Consumo excesivo de CPU? ¿Bloqueos? ¿O solo que alguien quiere que una consulta de 3 segundos baje a 0,3 porque sí?

Uno de esos es un problema técnico. El otro es un problema de expectativas. Y mezclar ambos lleva a dedicar horas a optimizar lo que no importa mientras lo urgente sigue sin atenderse.

Si no mides, no sabes si mejoras o empeoras

Aquí está el punto que muchos olvidan, si no sabes que tienes un problema y no mides antes, no puedes saber si lo que hiciste fue una mejora o un desastre.

Un cambio sin línea base no es optimización, es puro azar. Y en producción, jugar al azar es abrir la puerta a que mañana alguien te pregunte por qué el sistema está peor y no tengas respuesta. Sin métricas antes y después, la optimización es indistinguible del postureo.

Y ojo, también tienes que medir cuando todo funciona bien, sin esa linea base es imposible saber si de verdad algo va mal o es solo la sensación de los usuarios. Ya sabemos que adoran decir: “esto ahora va más lento” sin pruebas.

Diagnóstico antes de cirugía

La única forma de trabajar en serio es diagnosticar antes de tocar. Eso implica medir, observar y recopilar evidencia. Query Store, planes de ejecución, Extended Events, DMVs… las herramientas están ahí, pero hay que usarlas con criterio.

El motor se equivoca, los consejos de Internet también, y a veces hasta nuestras “buenas prácticas” son contextuales y no universales. La diferencia entre un DBA que arregla problemas y otro que los multiplica está en hacerse siempre la pregunta incómoda antes de optimizar.

Conclusión

Cambiar configuraciones del servidor, crear índices o aplicar consejos sin diagnosticar el problema real no es optimización, es azar.

SQL Server no premia las soluciones automáticas. Premia el análisis. Y la diferencia entre un DBA que arregla cosas y otro que las rompe está en hacerse siempre esa pregunta incómoda antes de tocar nada: ¿cuál es el problema que quiero resolver?

Si no sabes que tienes un problema y no lo mides antes, no tienes forma de saber si tu cambio fue mejora o desastre. Y en bases de datos, la duda casi siempre juega en tu contra.

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 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