SQL Server

Aquí encontraras todos nuestros post relacionados con SQL Server desde cero hasta un nivel avanzado. Desde infraestructura hasta modelado de datos.

¿Por qué los linked server rinden tan mal?

Pocas tecnologías han generado tanto rechazo silencioso como los linked servers en SQL Server. Todos los hemos usado alguna vez. Algunos hasta han intentado montar arquitecturas enteras con ellos, como si fueran túneles mágicos entre bases de datos. Y al principio todo parece funcionar… hasta que dejas de hacer pruebas con tablas de 100 filas y llega la realidad con sus millones. Entonces empieza el verdadero drama.

Hoy vamos a entrar al barro y a entender por qué los linked servers rinden tan mal, qué está pasando por debajo y qué alternativas tenemos cuando necesitamos algo que se parezca a un acceso remoto entre instancias. Pero, antes de abrir el quirófano y diseccionar por qué rinden tan mal, conviene repasar qué son exactamente.

¿Qué es un linked server?

Un linked server es una funcionalidad de SQL Server que nos permite acceder a datos almacenados en otro origen, como si fuera parte de nuestra propia instancia. Ese origen puede ser otra instancia de SQL Server, una base de datos Oracle, un Excel, un archivo Access o cualquier cosa que tenga un proveedor OLE DB compatible. Básicamente, nos permite ejecutar consultas distribuidas, mezclando datos de aquí y de allá, sin necesidad de ETL ni procesos intermedios.

Desde el punto de vista del T-SQL, un linked server actúa como un alias remoto: podemos hacer SELECT o incluso INSERT, UPDATE y DELETE sobre objetos que realmente viven en otro servidor. Todo a través de una conexión que, en apariencia, es transparente. Y aquí está el engaño.

Porque aunque la sintaxis parezca sencilla y todo pinte bien en la teoría, por debajo SQL Server tiene que hacer auténticas acrobacias para que eso funcione. Y, como veremos, muchas veces no lo consigue sin romperse una pierna por el camino.

Linked Server o lo que parece una buena idea en realidad es una trampa

El concepto es tentador. Con un linked server podemos conectarnos desde una instancia de SQL Server a otra, e incluso a otros motores de base de datos, como si todo estuviera en la misma base. Basta con un SELECT * FROM [ServidorRemoto].[Base].[Esquema].[Tabla] y listo. Bonito, directo, sin middleware.

Claro, si obviamos que la consulta puede tardar más que una auditoría fiscal y que la mitad de las optimizaciones que teníamos en mente se van por el desagüe.

El optimizador no es adivino

Uno de los mayores problemas de rendimiento viene de cómo SQL Server construye el plan de ejecución cuando hay un linked server de por medio. El optimizador necesita estadísticas para tomar decisiones inteligentes, pero cuando apuntamos a un servidor remoto, las estadísticas simplemente no están ahí. SQL Server no sabe cuántas filas hay, ni cuán selectiva es una condición, ni si merece la pena hacer un join remoto o traerse toda la tabla localmente.

¿Y qué hace cuando no sabe? Apuesta. Y como buen jugador conservador, apuesta mal.

Acaba generando planes de ejecución mediocres, que podrían parecer aceptables en una tabla de juguete, pero que se vuelven un desastre cuando la tabla tiene un volumen real. ¿El resultado? Lecturas innecesarias, joins ejecutados en el servidor equivocado y un tráfico de red digno de una transferencia de backups.

Linked Server PUSH vs PULL

Otro elemento clave es cómo SQL Server decide si “empuja” partes de la consulta al servidor remoto (lo que se conoce como pushing de consultas) o si tira de los datos hacia el local (pulling). Idealmente, querríamos que SQL Server enviase una subconsulta bien formada al servidor remoto, para que allí se ejecute lo que tiene sentido y solo nos devuelva lo necesario. Algo así como el plegado de consultas de Power BI.

Pero no. Muchas veces SQL Server prefiere traerse toda la tabla (sí, toda) al servidor local, y luego aplicar filtros, joins o agregaciones. Porque eso de optimizar entre servidores diferentes le cuesta. Y mucho.

Si alguna vez has hecho un SELECT COUNT(*) contra un linked server y has notado que tarda minutos en devolver un número, ya sabes por qué: se está trayendo todas las filas. A pelo.

El drama del Linked Server Provider

Detrás de cada linked server hay un proveedor OLE DB. Y no todos son iguales. Algunos soportan operaciones remotas de forma más o menos decente. Otros se comportan como si los hubiera programado un becario en prácticas en 1998.

Por ejemplo, el proveedor nativo de SQL Server a SQL Server (SQLNCLI o MSOLEDBSQL) tiene ciertas optimizaciones, pero ni con esas nos salva del todo. Ahora bien, si conectamos a Oracle, MySQL o, que no tengáis que sufrirlo, Access, el comportamiento puede ser completamente errático. Y la culpa, en parte, es del proveedor.

Si el proveedor no soporta pasar consultas completas o no permite ciertas operaciones, SQL Server lo suple como puede: trayendo filas, aplicando funciones en local, y rezando para que la red no esté saturada.

Transacciones distribuidas: el infierno del Linked Server

Si a alguien se te ocurre la brillante idea de meter una transacción que toque un linked server, prepárate. Entramos en terreno de las transacciones distribuidas, y con ello en el mundo de MSDTC (Microsoft Distributed Transaction Coordinator), uno de los servicios más temperamentales de Windows.

¿Funciona? A veces. ¿Es rápido? Ni de lejos. ¿Es seguro? Mejor no responder. Configurar MSDTC entre servidores, sobre todo en entornos con firewalls o clusters, es un vía crucis. Y aunque consigas que funcione, el rendimiento se desploma por la sobrecarga que supone coordinar commit y rollback entre servidores.

JOINs remotos: lo peor que puedes hacer por un Linked Server

Uno de los errores más frecuentes (y más costosos) es hacer joins entre una tabla local y otra remota. En muchos casos, SQL Server se trae la tabla entera del servidor remoto al local y luego hace el join. Si la tabla remota tiene 10 millones de filas y solo necesitábamos 5, mala suerte. Ya es tarde.

El problema se agrava si el join es sobre columnas sin índices en el remoto, o si las condiciones están ocultas tras funciones (como CAST, CONVERT o UPPER). SQL Server no es capaz de generar una consulta remota eficiente y recurre al “me lo traigo todo y ya lo filtro aquí”. Un plan perfecto si tienes acciones del proveedor de ancho de banda.

¿Hay alguna solución?

Sí, pero no mágica. La primera es no usar linked servers para consultas complejas o de alto volumen. Son útiles para tareas administrativas, sincronizaciones puntuales o lecturas ligeras. Pero si necesitas integrar datos entre sistemas, mejor piensa en otras alternativas.

Replicación, ETL, servicios web o incluso bases de datos distribuidas con lógica de federación (sí, esas cosas raras de Azure SQL) pueden ser opciones más razonables. También puedes optar por staging: traer datos relevantes a una tabla temporal o staging local antes de hacer las operaciones serias.

Otra alternativa, cuando no hay más remedio, es escribir consultas distribuidas con OPENQUERY. Esto obliga a que la consulta se ejecute remotamente, evitando que SQL Server decida hacer el pull de datos. No es bonito, pero al menos sabes lo que estás haciendo.

Y, por supuesto, nunca, nunca asumas que lo que funcionó en desarrollo (con 1.000 filas) escalará igual en producción (con 100 millones). No con linked servers. No hoy. No nunca.

Conclusión

Los linked servers tienen su lugar, pero no es en el rendimiento. Son una herramienta más, no la solución universal. Cuando los usamos sin entender sus limitaciones, el castigo no tarda en llegar. Lo hemos visto demasiadas veces: servidores que colapsan, redes saturadas, y consultas que mueren de inanición esperando datos que jamás deberían haber salido del servidor remoto.

¿Se pueden usar? Claro. Pero como todo en SQL Server, con cabeza, y sabiendo que a veces es mejor copiar datos que pretendiendo unir mundos que no están hechos para unirse en tiempo real.

Porque sí, puedes hacer joins entre servidores remotos, pero también puedes correr descalzo por un campo de cactus y ninguna de las dos opciones es recomendable

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

Azure Arc para SQL Server

Desde hace años, en cada evento, webinar o presentación de infraestructura de Microsoft se repite como un mantra: el futuro es híbrido. Y aunque muchos se limitan a asentir mientras piensan en cómo sobrevivir al próximo reinicio inesperado del servidor de producción, lo cierto es que algo de razón tienen. Especialmente cuando aparece una herramienta que, por una vez, parece estar pensada para los que aún tenemos servidores físicos, clústeres que no caben en una suscripción y dolores de cabeza por políticas de compliance que cambian más que los nombres de productos en Microsoft. Hablemos claro: Azure Arc para SQL Server on-premises no es la panacea, pero sí un paso sensato hacia un control centralizado sin obligarnos a renunciar al datacenter de toda la vida.

¿Qué demonios es Azure Arc (y por qué debería importarnos)?

Empecemos por el principio, ¿qué es Azure Arc? En resumen es la forma en que Microsoft intenta convencernos de que Azure no es solo «la nube», sino «la plataforma de gestión» para todos nuestros recursos, estén donde estén. Y eso incluye nuestros SQL Server instalados con sudor y lágrimas en máquinas físicas, clústeres locales o VM que jamás verán una IP pública.

Azure Arc extiende la gestión de Azure a recursos externos como servidores, Kubernetes, y por supuesto, SQL Server. Pero aquí viene la parte jugosa: Azure Arc para SQL Server no instala una nueva base de datos ni te obliga a migrar nada. Lo que hace es registrar tu instancia on-premises en Azure, otorgándole una especie de identidad en el portal.

Una vez enlazada, puedes aplicar políticas, ver inventario, tener visibilidad de cumplimiento de licencias (sí, esa parte duele), activar extensiones como Defender for SQL o habilitar seguimiento de seguridad desde el Azure Security Center. Todo sin tocar la base de datos. Bueno, casi.

Cómo funciona realmente Azure Arc (no la versión edulcorada del marketing)

Cuando conectamos una instancia de SQL Server a Azure Arc, lo que instalamos es un agente: el Azure Connected Machine Agent, junto con una extensión específica para SQL. Este agente se comunica con Azure a través de HTTPS, informa de configuraciones, recopila datos de diagnóstico y permite acciones remotas de configuración.

Para que funcione, necesitas tener SQL Server 2012 o superior, y una conexión de red desde el servidor hacia Internet (no hace falta conexión entrante, lo cual es un alivio). Lo ideal es tener SQL autenticado con Active Directory para poder controlar mejor el acceso, pero se puede hacer también con SQL Auth si quieres vivir al límite.

Una vez conectado, la instancia aparece en el portal de Azure como un recurso más. Desde ahí podemos aplicar políticas, revisar vulnerabilidades de seguridad, controlar el uso de features según la edición (lo cual es útil para evitar sorpresas desagradables con licencias), monitorizar comportamiento con Azure Monitor o, incluso, balancear nuestro Always On. Todo ello sin abrir el Management Studio… aunque claro, a veces sigue siendo necesario.

Casos reales donde Azure Arc tiene sentido (y donde no)

Supongamos que gestionamos un parque de 40 servidores SQL distribuidos entre varios centros de datos. Algunos son máquinas virtuales, otros físicos con clústeres Always On que llevan más tiempo activos que algunos desarrolladores del equipo. Sin Azure Arc, revisar políticas, aplicar auditorías o simplemente saber qué versión exacta está instalada en cada nodo puede convertirse en una gymkhana de RDPs.

Con Azure Arc, podemos tener una visión centralizada de todas las instancias, aplicar políticas uniformes, activar auditorías y obtener insights de seguridad con Defender sin tener que desplegar scripts o agentes por separado. Además, podemos detectar desviaciones de configuración o uso de features que podrían tener impacto en licencias.

Pero no todo es oro. Azure Arc no es una herramienta de administración del motor de SQL. No vas a hacer restores desde el portal ni crear índices con drag & drop. Tampoco es un sustituto de tus herramientas de backup, ni tiene visibilidad real sobre el rendimiento más allá de lo que Azure Monitor pueda recoger (que no es poco, pero tampoco es SentryOne).

Y lo más importante: si no tienes una estrategia clara de seguridad, gestión de red y control de agentes, puedes acabar con más puntos de fallo que beneficios. Porque, no nos olvidemos, instalar agentes y abrir tráfico a Internet en servidores productivos sin pensar en segmentación ni proxies es una receta para el desastre.

El control de licencias en Azure ARC: la parte que nadie quiere mirar

Una de las funcionalidades más interesantes (y más ignoradas) de Azure Arc para SQL Server es el control de licencias. Cuando registramos una instancia, podemos indicar si está licenciada por núcleo o por servidor + CAL. Esto, combinado con el escaneo de features activas, nos permite detectar incoherencias: como esa instancia Standard Edition que «accidentalmente» tiene particionamiento activo (Si, cuando el particionamiento era exclusivo de Enterprise en SQL 2012 esto se podía conseguir). Este control es especialmente útil en entornos con auditorías frecuentes o donde se aplican acuerdos Enterprise Agreement.

¿Y la seguridad? ¿Me estoy exponiendo a algo?

Buena pregunta. Azure Arc requiere ciertos permisos en el servidor, y abre un canal de comunicación constante con Azure. Esto plantea varias consideraciones. Primero, necesitas validar que el tráfico esté cifrado, que el agente esté actualizado, y que el acceso al servidor esté controlado. Segundo, si vas a permitir que ciertas acciones se realicen desde el portal (como cambiar configuraciones o aplicar actualizaciones), más vale que tengas RBAC bien definido en Azure.

La buena noticia es que puedes integrar todo con Azure Policy, Defender, y Log Analytics. La mala es que si no lo haces bien, estarás delegando más poder del que quieres. Y ya sabemos cómo acaba eso.
Azure Arc es gratis… hasta que abres Log Analytics

Una de las verdades menos comentadas de Azure Arc es que registrar tu instancia de SQL Server no cuesta nada. Literalmente: añadir un servidor, instalar el agente de Connected Machine y habilitar la extensión de SQL puede hacerse sin pasar por caja. Microsoft lo promueve como “coste cero” porque, en efecto, el recurso en sí no genera facturación directa.

Pero, siempre hay un pero, en cuanto queremos algo más que ver el nombre del servidor en el portal, empezamos a tirar de servicios que sí cuestan dinero. El más obvio es Log Analytics, que es el backend de todo lo que huela a monitorización seria en Azure. Activar monitorización de rendimiento, auditoría, logs extendidos, o integrar con Defender for SQL pasa irremediablemente por conectar a Log Analytics.

Y aquí viene el truco de magia inverso: el volumen de datos ingeridos, el tipo de consultas (KQL, por supuesto), y el tiempo de retención, todo suma en la factura. No es que Log Analytics sea especialmente caro, pero si estás monitorizando muchas instancias, con métricas detalladas y sin control de retención, la broma puede escalar.

Para tenerlo claro, Azure Arc proporciona el marco, pero no la observabilidad avanzada. Esa vive en Log Analytics, que sí factura. Y lo hace por cada giga ingerido. Si además activas Defender, tienes otro coste adicional por nodo protegido.

¿Merece la pena? 

Esta es la pregunta clave que debes hacerte, si tu entorno tiene requisitos serios de auditoría, cumplimiento, o simplemente quieres centralizar trazabilidad sin herramientas externas, probablemente sí. Pero conviene dimensionarlo bien, ajustar las retenciones, y entender qué datos necesitas realmente antes de abrir el grifo

Este modelo freemium no es nuevo, pero conviene recordarlo: Azure Arc para SQL Server es gratis solo si lo usas como un cartel informativo. Si quieres que hable, escuches y analices, tendrás que pasar por caja.

Conclusión

Azure Arc para SQL Server on-premises es una de esas herramientas que, bien usada, puede marcar una diferencia seria en entornos complejos. Centralizar visibilidad, aplicar políticas, y tener un inventario completo con insights de seguridad no es poca cosa. Pero, como siempre, depende de cómo se implemente.

Si ya tienes una infraestructura ordenada, con buenas prácticas de seguridad, y buscas unificar la gestión sin perder el control, Arc es una opción potente. Si tu entorno es un castillo de naipes sostenido por scripts heredados y manuales en PDF de 2009, lo mejor es empezar por ahí antes de añadir más complejidad.

Porque sí, el futuro puede ser híbrido. Pero nosotros queremos que lo sea con cabeza, no con más capas de problemas. Azure Arc no es magia, pero tampoco es humo. Y eso, hoy en día, ya es mucho decir.

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

Gestión del cambio sin dolor (o al menos con ibuprofeno)

Llevamos varias semanas dedicando los viernes a hablar de metodología, hemos visto Six Sigma, ITIL, Agile, Lean y hasta procesos DevOps. Hoy no vamos a hablar de ningún procedimiento en concreto sino de buenas prácticas generales a la hora de gestionar un cambio. En resumen, hacer las cosas con sentido común.

Decir “vamos a cambiar algo en producción” nunca debería sonar como “crucemos los dedos y a ver qué pasa”. Y sin embargo, más veces de las que nos gusta admitir, ese es exactamente el procedimiento. Porque claro, todo empieza con buena intención: una mejora de rendimiento, una corrección pequeña, “solo un índice” (maldita frase). Pero luego llega el drama, el monitor rojo, el jefe preguntando y el log lleno de errores que no deberían estar ahí.

En este artículo vamos a hablar de cómo gestionar el cambio en sistemas de bases de datos sin que acabe en desastre. O al menos, sin que tengamos que tomar antiinflamatorios a puñados. Porque cambiar en producción es inevitable. Lo que no debería serlo es sufrir cada vez como si estuviéramos lanzando un cohete a Marte con una escoba.

Antes del cambio: sospecha, planifica y valida

La gestión del cambio empieza mucho antes del cambio. Empieza con la duda. Si alguien te dice que es un cambio trivial, deberías activar inmediatamente el protocolo de escepticismo técnico. Los “solo era un índice” son los nuevos “yo controlo”.

Antes de tocar nada, necesitamos entender qué cambia, por qué y qué puede romperse. Parece obvio, pero demasiadas veces se ejecuta sin tener esto claro. Haz preguntas. ¿A qué objetos afecta? ¿Qué procesos dependen de esto? ¿Qué pasa si el cambio no se aplica bien? ¿Hay rollback?

Una vez identificados los riesgos, toca planificar. Y eso incluye mucho más que escribir el script. Hay que definir ventanas, implicar a los equipos afectados, coordinar timings y sobre todo, preparar el entorno. Tener backups recientes, estadísticas actualizadas, y entornos de prueba que sean de verdad representativos (no una base de 50 MB donde todo va rápido porque no hay nada).

En este paso, valida todo lo que puedas antes del cambio. Ensaya el script. Simula el rollback. Comprueba el rendimiento. Documenta las dependencias. Y si no tienes claro cómo validar algo, ya tienes un indicio de que el cambio es más peligroso de lo que parecía.

Durante el cambio: foco, trazabilidad y sangre fría

El momento del cambio no es para improvisar. Es para ejecutar con precisión quirúrgica. Nada de “ah, ya que estamos, meto esto también”. No. Eso no es una ventana de mantenimiento, eso es un ataque a la estabilidad del sistema.

Durante el cambio hay que asegurarse de que todo esté monitorizado. Logs activos, ejecución paso a paso si procede, y alguien siguiendo cada resultado. Si algo tarda más de lo esperado, se para, se revisa y se decide. No se reza, no se ignora. Se actúa.

La trazabilidad es crítica. Ejecuta los scripts con logging detallado. Si algo falla, hay que saber exactamente en qué punto estábamos. Nada de copiar/pegar desde un bloc de notas con modificaciones “on the fly”. Si hay que adaptar algo, se documenta, se explica y se versiona. Lo contrario es una receta para la amnesia operativa.

Y sobre todo, mantén la sangre fría. No importa lo mucho que presionen. Si algo no va bien, se detiene y se evalúa. Porque más vale un rollback a tiempo que una explicación al día siguiente con café y cara de insomnio.

Después del cambio: valida, comunica y documenta (sin convertirte en notario)

Una vez aplicado el cambio, viene la parte que más se salta: la validación post-despliegue. Porque claro, como no ha explotado nada, parece que ya hemos terminado. Error. Muchas veces, los efectos secundarios no se notan hasta que los jobs nocturnos empiezan a gritar.

Valida el sistema. Comprueba rendimiento, bloqueos, integridad. Ejecuta consultas clave. Mira los logs. Pregunta a los usuarios si todo responde como debería. Y si algo parece raro, investígalo. Porque si lo dejas pasar, mañana puede ser peor.

Después viene la documentación. No, no hace falta escribir una novela. Pero sí registrar qué cambió, por qué, cómo, cuándo, quién lo aprobó y qué efectos tuvo. ¿Es burocrático? Sí. ¿Es útil cuando en seis meses alguien pregunta qué demonios pasó ese día? También.

Y sobre todo, hazlo accesible. Nada de carpetas perdidas con nombres tipo “scripts_nuevos_OK_def_3_final.sql”. Usa sistemas de control de cambios, añade comentarios claros y deja constancia de las lecciones aprendidas. Documentar no es ser notario. Es dejar herramientas para no tropezar dos veces con el mismo script.

Y, por cierto, si todo fue bien… agradece al equipo, recoge feedback y ajusta el proceso. La gestión del cambio no es un evento. Es una práctica continua.

Cómo sobrevivir al “pero si solo era un índice”

La frase maldita. Todos la hemos oído. Y todos hemos visto lo que puede hacer un índice mal colocado: planes de ejecución destrozados, consultas que pasaban en milisegundos ahora eternas, deadlocks nuevos como setas. Porque no, un índice no es “solo” un índice. Es una reescritura de cómo el motor piensa. Y el motor, cuando se confunde, no avisa: simplemente arrastra al sistema al abismo.

¿Cómo se sobrevive a esto? Primero, aprendiendo a no confiar en los cambios “pequeños”. Segundo, aplicando buenas prácticas: revisando planes de ejecución, analizando estadísticas, usando INCLUDE, cuidando el orden de las columnas y verificando los efectos reales. Tercero, no dejando que nadie toque índices en producción sin una revisión decente. Da igual si es el desarrollador senior o el jefe de arquitectura. Todos cometemos errores.

Y por último, con monitorización y rollback. Si tras aplicar un índice todo empieza a ir peor, hay que poder volver atrás rápido. No hay gloria en mantener cambios dañinos solo porque “ya están puestos”. El ego no arregla el rendimiento.

Conclusión

Gestionar el cambio en producción no debería ser una ruleta rusa disfrazada de mejora. Exige preparación, criterio y procesos claros. Antes del cambio, duda y planifica. Durante el cambio, ejecuta con precisión. Después del cambio, valida y aprende.

Y si algo falla, no escondas el error. Documenta, comparte y ajusta. Porque los sistemas viven de la mejora continua, no del miedo al cambio. Eso sí: hagamos las cosas con cabeza. Con backups, con monitorización, y con la certeza de que cada “pequeño cambio” puede tener un impacto brutal.

Cambiar no tiene que doler. Pero si duele, al menos que haya ibuprofeno… y logs detallados.

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

¿Qué es CLR y por qué deberías limitar su uso?

Hay tecnologías en SQL Server que parecen diseñadas por y para gente que odia SQL. Una de ellas es CLR (Common Language Runtime). Si alguna vez has pensado “¿y si meto C# dentro de una base de datos?”, enhorabuena: acabas de invocar al diablo del rendimiento. Pero, como todo en este mundo, si se usa con criterio y sentido común (sí, eso que tan poca gente aplica), puede aportar soluciones que de otro modo serían infernales de implementar en T-SQL.

¿Qué demonios es CLR y por qué está dentro de SQL Server?

CLR es un motor de ejecución de .NET. Desde SQL Server 2005 tenemos la opción de crear procedimientos almacenados, funciones, triggers y tipos definidos por el usuario usando lenguajes .NET como C# o VB.NET. Esto permite extender la funcionalidad de T-SQL cuando éste se queda corto. Y sí, hay que reconocerlo, T-SQL se queda corto en ciertas áreas, como el procesamiento intensivo de texto, operaciones matemáticas complejas o manipulación avanzada de estructuras de datos.

Ahora bien, que algo se pueda hacer no significa que deba hacerse. De hecho, habilitar CLR en una instancia es como abrir una puerta lateral en un castillo: puede estar bien si sabes quién entra y sale, pero si la dejas abierta, prepárate para las sorpresas.

Activar CLR: el primer pecado

Por defecto, CLR viene deshabilitado. Hay que habilitarlo explícitamente:

Hasta aquí todo bien. Pero luego llega la decisión importante: ¿qué nivel de seguridad vamos a aplicar? Aquí es donde muchos pecan por ignorancia o por prisa. SQL Server permite establecer niveles de seguridad en los ensamblados: SAFE, EXTERNAL_ACCESS y UNSAFE.

  • SAFE es la opción por defecto y la más limitada. Permite usar solo código seguro dentro del sandbox de SQL Server. Vamos, que no puedes acceder al sistema de archivos ni hacer llamadas a red.
  • EXTERNAL_ACCESS permite acceso al sistema, como archivos o recursos de red. Requiere permisos adicionales en la base de datos y en el servidor.
  • UNSAFE es exactamente lo que parece: la carta blanca para que alguien con tiempo libre y ganas de destruir te monte un agujero de seguridad monumental. Desde abrir un puerto TCP hasta modificar binarios en disco. Y si el servidor ejecuta SQL Server con permisos de sistema, el daño potencial es ilimitado.

El resumen es simple: si usas EXTERNAL_ACCESS o UNSAFE y no sabes exactamente lo que estás haciendo, ya puedes ir llamando al responsable de seguridad para una charla “interesante”.

¿Y por qué usar CLR? ¿Realmente aporta algo?

En ocasiones, sí. Hay escenarios donde CLR no solo tiene sentido, sino que puede ser la solución óptima. Por ejemplo:

  • Procesamiento de texto complejo: Las expresiones regulares en T-SQL son una promesa aún. Mientras que estamos empezando a verlas en las previews de Azure SQL y SQL Server 2025, en C# puedes usarlas sin volverte loco. Una función CLR que use Regex.Match puede reemplazar cientos de líneas de T-SQL feo y lento.
  • Cálculos matemáticos avanzados: ¿Has intentado hacer operaciones trigonométricas complejas o cálculos estadísticos avanzados con T-SQL? No, ¿verdad? Pues eso. CLR te permite usar librerías de .NET que hacen esto sin romperte la cabeza. Aunque, pensándolo bien, ¿no preferirías usar python o R para estas cosas?
  • Manejo de estructuras como arrays o diccionarios: Aunque con SQL Server 2022 y sus mejoras en JSON y XML estas necesidades han bajado, aún hay casos donde un buen Dictionary<string, List<int>> en C# resuelve en milisegundos lo que en T-SQL requeriría un máster.
  • Performance en funciones escalares: Una función escalar en T-SQL puede ser un veneno para el rendimiento si se ejecuta por cada fila de una tabla grande. En CLR, ese impacto puede reducirse significativamente.

Eso sí, si el único motivo para usar CLR es que “yo sé C# y no me gusta T-SQL”, lo que necesitas no es un CLR, es un cambio de trabajo.

Cómo crear un ensamblado CLR sin invocar a Satán

Veamos el proceso básico:

Primero escribes el código en C# (en Visual Studio o lo que uses). Luego compilas el ensamblado (DLL) y lo subes a SQL Server con CREATE ASSEMBLY. Por último creas la función o procedimiento que lo expone. Un ejemplo sencillo:

Código C#:

Compilas esto como DLL y lo subes:

Y voilà. Ya puedes usar dbo.ReverseString(‘hola’).

¿Dónde rompe CLR las cosas y por qué?

Ahora hablemos de los pecados originales del CLR. El primero es la dificultad de mantenimiento. El código está fuera del ámbito natural del DBA. Si mañana hay que parchear un bug en ese ensamblado, necesitas recompilar, volver a subirlo y cruzar los dedos para que no tengas dependencias rotas. Además, muchas veces ni siquiera se versionan correctamente. Y sí, lo hemos visto en producción. Más veces de las que nos gustaría.

Segundo, el tema de la seguridad. Un ensamblado con UNSAFE puede hacer cualquier cosa en el sistema operativo. Y cuando decimos cualquier cosa, es cualquier cosa. ¿Quieres que tu base de datos escanee el disco C:? Puedes hacerlo. ¿Deberías hacerlo? No. Nunca.

Tercero, el rendimiento. Aunque en algunos escenarios el CLR escala mejor que T-SQL (especialmente en funciones escalares y algoritmos complejos), introducir CLR sin medir su impacto real es como poner un turbo a un coche sin frenos. Necesitas pruebas serias, monitorización con Extended Events o Profiler, y entender bien los contextos de ejecución y memoria.

CLR y los entornos modernos

¿Sigue teniendo sentido usar CLR en 2025? Depende. SQL Server ha mejorado mucho en áreas como funciones en línea, JSON, XML, y hasta integración con Python y R vía Machine Learning Services. Muchas cosas que antes requerían CLR ahora se pueden hacer dentro del propio SQL Server sin salir del ecosistema T-SQL.

Pero aún hay casos de uso válidos: si necesitas lógica reutilizable, validaciones complejas, o consumir recursos externos con control, puede ser una herramienta útil. Eso sí, no abuses. Lo que empieza como una solución elegante puede acabar como un infierno de dependencias, DLLs perdidas y bugs imposibles de depurar.

Conclusión

El CLR no es el enemigo. El enemigo es usar herramientas que no entendemos solo porque «molan» o porque «así lo hacemos en .NET». SQL Server permite muchas cosas, pero no todas son recomendables. Si vas a meter CLR en tu arquitectura, hazlo con cabeza, documentación, versiones bien gestionadas y, por supuesto, tests.

Y si estás usando funciones CLR porque no sabías cómo hacerlo en T-SQL… mejor sigue leyendo el blog. Tenemos artículos sobre expresiones regulares y otras maravillas menos propensas a prenderle fuego a tu entorno productivo.

Porque sí, puedes meter C# en SQL Server, y también puedes meter un gato en una lavadora. Pero no deberías.

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

LINQ y SQL Server: consulta tú, que ya lloro yo

Si eres developer y trabajas con .NET, lo más probable es que en algún momento hayas caído rendido ante LINQ. Lo entiendo, es tentador cual canto de sirena. Tiene lo suyo: expresividad, fluidez, integración total con C#… es cómodo. Pero si trabajas con SQL Server como motor de datos, más te vale saber qué está haciendo LINQ por detrás. Porque aquí, en las profundidades del motor, no nos tragamos la excusa de «yo sólo puse un .Where()».

Este artículo no es para demonizar LINQ. Es para que entiendas, desde el punto de vista del DBA que va a recibir tus consultas, por qué usar LINQ sin saber cómo funciona es como lanzar T-SQL con los ojos cerrados y esperar que salga rápido. Alerta spoiler: no lo hace.

LINQ: el ORM moderno que no siempre sabe lo que hace

A ti LINQ te permite escribir consultas con tipos, IntelliSense, lambdas y toda la fantasía moderna del desarrollo elegante. A nosotros nos llega una consulta SQL que ha generado un ORM sin ningún sentido del rendimiento, de los índices ni del plan de ejecución.

Tú ves:

Nosotros vemos: joins sin sentido, LEFT OUTER JOIN innecesarios, condiciones que no usan índices, y a veces hasta SELECT TOP 1000000 porque alguien no quería paginar como es debido. Lo que para ti es una consulta sencilla, para nosotros puede ser una fiesta de bloqueos, CPU y discos saturados.

LINQ no es malo. Pero no sabe optimizar. Y su traductor a SQL (ya sea EF, LINQ to SQL o el flavor de turno) sólo tiene una misión: funcionar. No rendir. Eso, amigos, es responsabilidad vuestra.

SQL Server no es una caja negra

Si has trabajado toda tu vida con Entity Framework sin mirar lo que genera por debajo, te estás perdiendo la mitad de la película. Y no la buena. SQL Server es un motor potente, flexible y bastante generoso… pero sólo cuando le das instrucciones claras.

Cuando llega una consulta LINQ traducida automáticamente, SQL Server hace lo que puede. Pero si la estructura de la consulta es compleja, el uso de joins es arbitrario y los filtros se aplican después del .ToList(), entonces no hay milagros. Hay “table scans”, “sort warnings”, “hash matches” no deseados y todo lo que un DBA no quiere ver en el plan de ejecución.

Lo que tú ves como un .Include() para cargar relaciones, nosotros lo vemos como una máquina de hacer JOINs sin control. Y cuando eso se hace en producción con datos reales, hay que estar muy seguro de que se entiende lo que se está mandando.

IEnumerable, IQueryable y el horror que no ves en LINQ

Hay un detalle que seguimos viendo incluso en equipos senior: no distinguir IEnumerable de IQueryable a la hora de consultar.

Cuando usas IQueryable, la consulta se traduce a SQL y se ejecuta en la base de datos. Bien. Pero cuando haces .ToList() antes de aplicar más filtros, estás trayendo todo a memoria y filtrando en .NET. Eso está bien si tienes diez registros. Si tienes diez millones, acabas de llenar el servidor de aplicaciones con datos que no necesitabas.

El ORM no sabe optimizar. Tú sí deberías.

Así que cuando alguien hace esto:

Y luego se pregunta por qué la aplicación va lenta, la respuesta es clara: no es la base de datos, es tu código. LINQ puede ser declarativo, pero no mágico.

Los casos en que LINQ hace llorar al optimizador

¿Sabes lo que pasa cuando encadenas tres .Include()s, haces un .SelectMany() y luego aplicas una condición que sólo puede evaluarse en cliente? Que el SQL resultante se convierte en un engendro. Y a nosotros nos llega una consulta de 150 líneas con subconsultas, columnas que no se usan y JOINs en cascada que anulan los índices.

Esto no es una exageración. Lo he visto con mis propios ojos. Y no una vez. Las herramientas modernas de desarrollo facilitan mucho la creación de consultas… que nadie ha revisado. Y luego cuando llegan las quejas de rendimiento, el culpable nunca es el ORM. Siempre es “la base de datos que no escala”.

No. La base de datos escala. Lo que no escala es traducir expresiones lambda como si fueran instrucciones optimizadas para un motor relacional.

Cómo hacer las paces: consejos para developers (sí, es por vuestro bien)

Lo primero: aprende a ver el SQL que estás generando. EF Core permite interceptar y registrar el SQL generado. Úsalo. Lee ese SQL. Míralo con ojos críticos. Si ves que tiene 10 joins, 30 columnas innecesarias y ninguna cláusula WHERE, no lo envíes a producción. Mándalo al infierno de staging, a ver cuánto tarda.

Segundo: si una consulta es crítica, escribe SQL tú mismo. Usa FromSqlRaw() o, mejor aún,  procedimientos almacenados dentro de SQL Server. No pasa nada. No es “menos elegante”, es más responsable.

Tercero: si tienes dudas, habla con el DBA. No somos ogros. Bueno, algunos sí. Pero en general, preferimos una conversación a tener que cazar queries con el SQL Profiler porque ha saltado una incidencia de rendimiento a las 3 de la mañana.

Cuarto: entiende el modelo de ejecución diferida de LINQ. Y si tienes que filtrar, hazlo antes del .ToList(). Siempre.

Y por último: no abuses del azúcar sintáctico. LINQ puede ser cómodo, pero no sustituye al conocimiento. No saber lo que está pasando en SQL Server es como conducir un coche sin saber si vas en primera o en tercera.

¿Cuándo sí usar LINQ?

LINQ brilla en consultas simples. En operaciones sobre colecciones en memoria. En proyecciones pequeñas y bien definidas. Si tu consulta es trivial y los datos están bien indexados, no hay problema. Pero si estás construyendo un informe complejo, una API con cientos de miles de registros o una consulta crítica para el negocio, deja de lado la comodidad.

Y si usas LINQPad, mejor. Ahí sí puedes ver lo que pasa y ajustar con cabeza. Porque en el fondo, LINQ no es el problema. El problema es no saber cuándo dejar de usarlo.

Conclusión: hay vida más allá de LINQ

No hay escapatoria. Si trabajas en un proyecto con SQL Server, y usas un ORM o LINQ, el rendimiento de tus consultas depende de ti. No vale decir “eso es cosa del DBA” o “es que eso lo hace el ORM solo”. Porque cuando la aplicación se arrastra, da igual de quién sea la culpa: hay que arreglarlo y ni todo el hardware del mundo arregla depende que consultas.

Así que la próxima vez que escribas una consulta LINQ, pregúntate: ¿qué SQL va a salir de aquí? ¿Lo he mirado? ¿Lo he probado con datos reales? ¿Estoy filtrando bien? ¿Estoy trayendo sólo lo que necesito?

Y si no puedes responder a eso con seguridad, tal vez lo mejor sea bajarse al T-SQL y escribir como los mayores.

Porque aquí no se trata de gustos. Se trata de no matar al servidor con buenas intenciones y malas queries.

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

DevOps y SQL Server: amor, odio y pipelines con fugas

El romance entre DevOps y SQL Server es complicado. Como esas parejas que se quieren a gritos, viven juntas, pero uno duerme en el sofá y el otro con el gato. Porque claro, DevOps suena precioso sobre el papel: integración continua, despliegues automáticos, infraestructura como código y todo ese rollo de agilidad infinita. Pero cuando llevamos eso a una base de datos relacional que todavía tiene stored procedures escritos en 2009 por alguien que ya no trabaja en la empresa… el cuento cambia.

Nosotros, los DBAs, vivimos en esa intersección peligrosa entre los mundos del código y los datos. Y cuando alguien decide que ahora todo tiene que ir por pipelines de CI/CD porque “lo ha dicho el consultor de DevOps”, hay que tener cuidado. Porque sí, automatizar es maravilloso. Pero automatizar sin entender es como montar un sistema de riego automático sin comprobar si hay goteras. Spoiler: las hay. Y en producción.

Vamos a ver cómo podemos integrar nuestro trabajo como DBAs en ese ciclo CI/CD sin que todo explote. O al menos, sin que explote demasiado.

DevOps, el síndrome del pipeline perfecto y la realidad del script roto

Hay que empezar aclarando una cosa: el mundo del desarrollo de software y el de las bases de datos no evolucionan igual. Mientras los desarrolladores compilan, versionan y despliegan sin mirar atrás, nosotros lidiamos con sistemas vivos. La base de datos no se borra y se vuelve a levantar como si fuera un contenedor. Cada ALTER TABLE toca datos reales. Y cada script mal planteado puede dejar un sistema en coma.

El enfoque de Database as Code nos ayuda a acercarnos al modelo DevOps. Usar herramientas como SSDT, Flyway, Liquibase, Redgate SQL Change Automation o, incluso, migraciones de Entity Framework, nos permite tener nuestros objetos versionados, controlar los cambios y desplegar de forma coherente. Hasta aquí, todo bien.

Pero claro, la teoría no menciona qué pasa cuando hay diferencias de collation entre entornos, cuando un índice tarda 45 minutos en crearse o cuando un trigger olvidado lanza una tormenta de inserts en cascada. Eso no lo arregla ningún pipeline.

Por eso, antes de lanzarnos a automatizar, necesitamos tener una estrategia de cambios bien pensada, un control de versiones sólido y, sobre todo, scripts que no se limiten a “funcionar en desarrollo”. El típico CREATE TABLE que nadie probó con un insert de 10 millones de filas no es infraestructura como código: es una amenaza.

Automatización con cabeza: lo que sí y lo que no en DevOps

No todo se debe automatizar. Sí, lo he dicho. Y lo repito. Hay tareas que siguen necesitando supervisión humana porque los datos no perdonan errores.

Automatiza los despliegues de cambios de esquema cuando están bien versionados y han pasado por entornos intermedios. Automatiza los backups, los restores de prueba, las revisiones de espacio en disco y las tareas de mantenimiento. Automatiza las revisiones de cumplimiento de convenciones con linting de scripts. Incluso automatiza los unit tests con tSQLt si tienes valor.

Pero no automatices, por ejemplo, la ejecución de un DROP COLUMN en producción sin que nadie revise qué otras vistas o procedimientos dependían de ella. Tampoco automatices sin revisión los despliegues que incluyen cambios destructivos o transformaciones masivas de datos. Y por supuesto, no pongas en un pipeline un script que actualiza 300 millones de registros en una tabla sin particiones y sin índices adecuados. Eso no es DevOps. Eso es sabotaje con CI/CD.

Porque sí, puedes tener despliegues automáticos cada cinco minutos. Pero si lo que despliegas son bombas lógicas, lo que estás haciendo no es integración continua: es desastre continuo.

DevOps si, pero con backups

Convertir la base de datos en código es un avance necesario. Repositorio Git, revisiones con Pull Requests, validaciones automáticas, historial de cambios… todo eso mejora la calidad y la trazabilidad. Nos permite dormir un poco más tranquilos. Por algo SSMS 21 incorpora soporte Git.

Pero ojo: base de datos como código no significa que los datos también lo sean. Los objetos son versionables. Los datos no lo son. No de la misma forma.

Por eso, ningún pipeline que toque la base de datos debería existir sin un buen backup previo. Y no, no vale con el backup nocturno. Un BACKUP DATABASE justo antes del despliegue, con nombre identificable y retención clara. Si algo va mal, hay que poder volver atrás. Nada de rezar a San Point-in-Time-Restore.

Además, si versionamos la base de datos, también hay que versionar los scripts de recuperación. ¿Qué haces si se despliega una función que rompe una lógica crítica? ¿Esperar a que el desarrollador vuelva de comer? No. Hay que tener plan B. Y plan C.

Roles y responsabilidades: DevOps no sustituye al DBA

En algunos modelos DevOps mal entendidos, parece que el DBA es prescindible. “Ya tenemos pipelines”, dicen. Claro. Y también tienes un coche, pero no han desaparecido los talleres mecánicos porque ahora sabes cambiar una rueda.

El rol del DBA en DevOps es más importante que nunca. Porque ahora, además de saber mantener sistemas estables, necesitamos saber cómo se integran en procesos automáticos, cómo se controlan los cambios, cómo se auditan los scripts y cómo se asegura la integridad del sistema en cada paso.

El DBA no solo ejecuta. Diseña el flujo. Revisa los PR. Define los checks de calidad. Valida la coherencia entre entornos. Y, sobre todo, es quien entiende que los datos no son líneas de código: son el corazón del negocio. Si fallan, no hay rollback que salve la reputación.

¿Y si todo explota igual?

Spoiler: alguna vez explotará. No importa lo bueno que sea tu pipeline. Alguien olvidará algo. Un script fallará. Una tabla no tendrá stats. Un índice nuevo matará el plan de ejecución.

Lo importante es que cuando eso pase, tengas herramientas para detectar, reaccionar y recuperar rápido. Logging detallado. Monitores activos. Backups listos. Versionado claro. Y sobre todo, un equipo que sepa que los despliegues no son cosa del azar, sino de la preparación. Herramientas como la de Four9s (sponsor de nuestros eventos online mensuales) ayudan a monitorizar estos cambios.

Porque en DevOps, como en SQL Server, todo funciona… hasta que no.

Conclusión

Integrar SQL Server en un entorno DevOps no es imposible, pero tampoco es trivial. Exige entender los riesgos, planificar con cabeza y automatizar sin perder el control. Versionamos código, sí. Pero protegemos datos. Y eso no se hace con fe ciega en YAMLs.

No somos un estorbo para la agilidad. Somos los que impedimos que se despliegue una migración irreversible a las 18:00 del viernes. Así que, si vamos a vivir en este nuevo mundo de CI/CD, vivamos con dignidad. Con backups. Con validaciones. Y con esa sospecha saludable de que un script sin revisar es una granada sin anilla.

El amor entre DevOps y SQL Server existe. Pero como todo amor real, necesita trabajo, comunicación y saber cuándo decir: “Esto mejor lo revisamos antes de darle al botón.”

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

¿Qué es xp_cmdshell y por qué deberías limitar su uso?

Hay ciertas funciones en SQL Server que tienen más leyenda que documentación, y una de ellas es xp_cmdshell. Mencionarla en una reunión de seguridad es como decir “TRIGGER” en una daily de DBAs: inmediatamente empiezan los sudores fríos. Pero como buenos profesionales de bases de datos, no podemos permitirnos el lujo de ignorarla. Hay que entender qué hace, cómo se usa (o se abusa), y sobre todo por qué en la mayoría de los casos deberíamos tenerla bien atada, o mejor aún, desactivada.

¿Qué es xp_cmdshell?

Para los recién llegados (o para los que han tenido la suerte de no cruzárselo nunca), xp_cmdshell es un extended stored procedure que permite ejecutar comandos del sistema operativo directamente desde SQL Server. Tal cual. Es decir, desde una sesión de SQL puedes invocar comandos como si estuvieras en la consola de Windows: copiar ficheros, lanzar scripts batch, ejecutar aplicaciones externas… o destruir medio sistema si tienes permisos suficientes y pocas luces.

El siguiente ejemplo es inocente (más o menos), pero ilustra la idea:

SQL ejecuta el comando y te devuelve el resultado como si estuvieras en una consola de MS-DOS de los 90. Y sí, es tan peligroso como suena.

¿Para qué se usa xp_cmdshell legítimamente?

Hay quien justifica su uso con casos reales: automatización de procesos que interactúan con el sistema de archivos, lanzamiento de tareas administrativas, scripts que integran SQL con otros procesos batch o herramientas de terceros. Incluso estos ojos han visto escenarios donde se usaba para invocar clientes FTP y descargar archivos que luego se importaban con BULK INSERT o mover backups entre servidores.

Y aunque todo esto se puede hacer, la pregunta es: ¿debería hacerse así? Spoiler: no. O al menos, no sin un análisis serio de riesgos y alternativas. Porque una cosa es poder, y otra muy distinta es tener criterio.

La seguridad, el verdadero problema de xp_cmdshell

El mayor problema de xp_cmdshell no es su existencia, sino su potencia. Ya sabes, eso de que un gran poder conlleva una gran responsabilidad. Este procedimiento ejecuta los comandos en el contexto de seguridad de la cuenta del servicio de SQL Server, lo que, si no se ha configurado adecuadamente, puede significar ejecutar con privilegios elevados. Y eso convierte cualquier brecha de seguridad en una puerta abierta al sistema operativo, red y mil cosas más.

Por defecto, xp_cmdshell viene desactivada. Microsoft no es tonta, y sabe que dejar esto habilitado por defecto sería como enviar servidores a producción con el firewall desactivado. Pero como casi todo en SQL Server, se puede activar fácilmente:

Y una vez activada, el riesgo está servido. Cualquier usuario que tenga permisos para ejecutarla puede comprometer el servidor. Si encima tiene permisos sysadmin (y aún hay entornos donde todo el mundo es sysadmin «porque así funciona»), la fiesta está asegurada.

¿Se puede usar xp_cmdshell de forma segura?

La teoría dice que sí. Microsoft introdujo ciertas medidas para controlar su uso. Por ejemplo, si el usuario no es sysadmin, se puede configurar una cuenta proxy mediante el procedimiento almacenado sp_xp_cmdshell_proxy_account que limita los permisos con los que se ejecutan los comandos.

Esto permite definir una credencial para que el comando xp_cmdshell se ejecute con los permisos de ese usuario en lugar de usar la cuenta del servicio. Pero seamos serios: ¿cuántas veces se hace esto bien en entornos reales? ¿Cuántas veces se revocan luego los permisos cuando ya no hacen falta? ¿Y cuántos servidores en producción tienen la proxy account configurada pero también usuarios sysadmin “temporales” que llevan ahí desde 2016?

Además, aunque configures la cuenta proxy correctamente, sigue siendo un punto de entrada que puede explotarse si no se audita y controla su uso. El riesgo persiste, solo se disfraza de buena práctica.

Alternativas reales y razonables a xp_cmdshell

Casi todo lo que se hace con xp_cmdshell se puede hacer mejor y con más control desde fuera de SQL Server. Si necesitas mover archivos, usar PowerShell o scripts externos lanzados desde un agente de automatización como SQL Server Agent o un sistema de orquestación decente (¿alguien ha dicho Azure Data Factory?) es mucho más razonable.

Para transferencias FTP o SFTP, hay herramientas modernas que no requieren meter comandos del sistema operativo en medio del motor de base de datos. Y si lo que se busca es coordinación entre procesos, los servicios de Windows, los job schedulers o incluso Integration Services son alternativas mucho más limpias.

SQL Server es un motor de bases de datos, no un sistema operativo ni un centro de comandos. Empezar a usarlo como tal es como usar un bisturí para abrir latas: técnicamente se puede, pero no es lo suyo y probablemente acabes con un desastre.

Auditar, controlar, eliminar

Si estás heredando un sistema y no sabes si xp_cmdshell está activa, revísalo. Yo personalmente es de las primeras cosas que compruebo. Para verlo es tan fácil como ejecutar:

Si el valor de «config_value» es 1, está habilitado. Si no se está utilizando (y muchas veces no lo está, pero nadie se atreve a desactivarla “por si acaso”), desactívalo sin piedad:

Y si alguien protesta, que traiga el caso de uso documentado, el análisis de riesgos y una alternativa propuesta. Si no puede justificarlo, no es necesario. Punto. No admito discusiones.

Además, si en algún entorno necesitas activarlo temporalmente, documenta cuándo y por qué, y asegúrate de desactivarla después. Y lo más importante: registra quién tiene permisos para usarlo, y controla ese acceso como si fuera el código para activar el botón rojo nuclear. Porque en cierto sentido, lo es.

Conclusión

xp_cmdshell es una herramienta poderosa, pero como todas las herramientas poderosas, puede causar más daño que beneficio si se usa mal. No está pensada para ser parte habitual de ningún flujo de trabajo moderno en SQL Server. Su existencia tiene sentido en contextos muy controlados, con auditoría, justificación y planificación. Pero la realidad es que en la mayoría de los entornos en los que aparece, lo hace como un parche rápido, una chapuza heredada o un atajo que algún valiente implementó sin medir consecuencias.

Limitar o eliminar su uso no solo mejora la seguridad del entorno, sino que obliga a buscar soluciones más sostenibles, limpias y profesionales. Porque si nuestra base de datos necesita ejecutar scripts del sistema para funcionar, igual el problema no está en xp_cmdshell, sino en cómo hemos diseñado la arquitectura.

Y si aún piensas que «no pasa nada por tenerla habilitada», revisa tus backups. Puede que los necesites antes de lo que crees, o que alguien los haya borrado desde xp_cmdshell.

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