SQL Server

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

SQL Server sobre VMware vSphere: Buenas prácticas

La virtualización de SQL Server ha sido durante más de una década una de las estrategias más consolidadas en entornos corporativos. VMware vSphere ha jugado un papel central en ese éxito, ofreciendo una plataforma madura, estable y altamente optimizada para ejecutar cargas de trabajo críticas como bases de datos relacionales. Sin embargo, en 2025 la situación es diferente.

Desde que Broadcom cerró la adquisición de VMware a finales de 2023, el panorama ha cambiado. La transición forzada al modelo de suscripción, la retirada de licencias perpetuas y el aumento generalizado de precios han generado un malestar evidente en muchos clientes. Algunas organizaciones han iniciado migraciones hacia Hyper-V, otras han apostado por plataformas cloud y unas pocas han optado incluso por volver al metal físico para sus cargas más exigentes.

Pero en medio de esa reconfiguración estratégica, una cosa sigue siendo cierta: vSphere sigue siendo una de las plataformas más fiables para ejecutar entornos virtualizados críticos como servidores SQL Server, siempre que se configure correctamente. Y eso, precisamente, es lo que nos ocupa en esta guía.

A continuación, abordamos en profundidad las consideraciones técnicas clave para desplegar SQL Server sobre VMware vSphere en 2025, actualizando las recomendaciones oficiales a la realidad operativa actual. Porque más allá de las decisiones de licenciamiento o la política comercial de turno, lo que importa es garantizar que nuestras bases de datos funcionen con previsibilidad, rendimiento y resiliencia.

Antes de empezar, conviene señalar que la mayoría de los fundamentos que vamos a repasar están basados en la guía oficial de VMware publicada en 2019 (Architecting Microsoft SQL Server on vSphere). No obstante, han pasado seis años desde entonces, por lo que además de recuperar los puntos más relevantes, matizaremos aquellos aspectos donde la tecnología, el hardware o las prácticas de operación han evolucionado.

Diseño correcto de la máquina virtual

Uno de los errores más comunes en despliegues SQL Server sobre vSphere es asumir que la virtualización, cómo se puede redimensionar fácilmente, elimina la necesidad de una planificación detallada. Nada más lejos de la realidad. El rendimiento y la estabilidad de SQL Server dependen en gran medida de cómo se diseñe la máquina virtual así que si, podrás cambiarlo luego pero eso no quiere decir que no lo diseñes bien de primeras.

Dimensionamiento inicial (right-sizing)

A diferencia de entornos físicos, en VMware es preferible asignar sólo los recursos que la carga realmente necesita. Asignar más CPU o RAM de la necesaria puede generar efectos negativos: contención, mayor coste de scheduling, uso ineficiente de licencias, o incluso, aunque pueda ser contraintuitivo, peor rendimiento. Una VM con más vCPU de las que necesita puede sufrir más Ready Time, más latencia y menos rendimiento.

Para dimensionar correctamente, conviene recopilar datos de uso real de CPU, memoria y disco mediante DMVs, Performance Monitor o herramientas de observabilidad (SQL Sentry, vRealize Operations). A partir de ahí, se puede asignar el número adecuado de vCPU y memoria, ajustando posteriormente según carga.

Configuración de CPU y NUMA

Núcleos por socket: impacto técnico y de licenciamiento

La edición Standard de SQL Server impone límites que no siempre se respetan al definir una VM: máximo 4 sockets o 24 núcleos. Por tanto, es frecuente encontrar configuraciones ineficientes: por ejemplo, una VM con 8 sockets y 1 core por socket, que solo permite el uso de 4 sockets con un núcleo cada uno, aunque se hayan asignado 8 núcleos.

Lo recomendable es agrupar los núcleos virtuales en menos sockets: por ejemplo, 1 socket con 8 cores, o 2 sockets con 12. Esto permite que SQL Server aproveche todos los recursos asignados sin restricciones de licenciamiento.

Consideraciones NUMA

Cuando una VM supera los recursos de un nodo NUMA físico (CPU o memoria), se producen accesos a memoria remota, lo que introduce latencia física. SQL Server es muy sensible a este comportamiento así que tenlo en cuenta.

VMware detecta la topología NUMA del host y crea configuraciones vNUMA equivalentes, pero esto solo es posible si la VM tiene más de 8 vCPU (configurable). En cualquier caso, es necesario verificar que la asignación real de nodos NUMA es coherente, tanto desde el visor de recursos del host como desde dentro de SQL Server (por ejemplo, con sys.dm_os_memory_nodes).

Asignación y gestión de memoria

Evitar el overcommit de memoria

En entornos VMware es posible sobreasignar memoria física, confiando en mecanismos como ballooning o swapping para equilibrar el uso. Pero esto es completamente desaconsejado para máquinas que ejecutan SQL Server, ya que su gestión interna de memoria (buffer pool, cache) depende de una disponibilidad constante.

La práctica recomendada es reservar memoria para la VM (memory reservation = memory size) y evitar que el host pueda utilizar parte de esa RAM para otros fines. En ESXi modernos, la opción de Transparent Page Sharing (TPS) está deshabilitada por defecto, lo que refuerza la necesidad de no sobrecomprometer recursos.

Configuración dentro de SQL Server

Dentro de la instancia, es imprescindible limitar la memoria máxima (max server memory) para evitar que el sistema operativo se quede sin recursos. Hay que tener un especial cuidado al habilitar lock pages in memory, JAMÁS se debe activar si el balloning está activado para esa VM o puede producir errores. 

Siguiendo con estas configuraciones, el uso de large pages (Trace Flag 834) puede mejorar el rendimiento en sistemas con mucha RAM, pero es muy delicado y requiere pruebas específicas. De todas formas no seré yo quien os recomiende una configuración que ni Microsoft recomienda…

Almacenamiento y controladoras

Cuando se crean discos virtuales (VMDKs) para una VM, VMware permite elegir entre discos de tamaño fijo (thick provisioned) o dinámico (thin provisioned). Aunque el aprovisionamiento dinámico puede ahorrar espacio a corto plazo, introduce fragmentación y penalizaciones de rendimiento a medida que el disco crece.

En entornos SQL Server, donde la carga de I/O es constante y predecible, el uso de discos thin puede generar latencia adicional, sobre todo en sistemas de almacenamiento que no gestionan bien el crecimiento dinámico.

La recomendación es clara, utilizar discos de tamaño preasignado (thick eager zeroed) para todos los VMDKs que manejen datos, logs o TempDB. Este tipo de disco se crea completamente al aprovisionar la VM, evitando operaciones de escritura adicionales durante el uso. Esta práctica garantiza un mejor rendimiento sostenido, especialmente en entornos con IOPS elevados, y reduce el riesgo de fragmentación interna del datastore

Separación de discos y uso de PVSCSI

Una práctica consolidada es separar los distintos tipos de archivos de SQL Server en VMDKs distintos: sistema operativo, base de datos, logs, TempDB. Esto no solo mejora el rendimiento, también facilita la gestión de snapshots, backups y análisis de uso.

En cuanto a la controladora, VMware recomienda usar PVSCSI en lugar de LSI Logic SAS para los discos de datos. PVSCSI ofrece mayor profundidad de cola (hasta 256) y menor uso de CPU. La configuración ideal combina:

  1. LSI Logic SAS solo para la unidad C:\
  2. Varias controladoras PVSCSI adicionales para datos, logs y TempDB, separadas si es posible.

Compatibilidad con NVMe

Aunque los discos NVMe han ganado presencia en datacenters en los últimos años, las recomendaciones no cambian: PVSCSI sigue siendo preferible por compatibilidad, madurez y soporte. Solo si se trabaja directamente con hardware o almacenamiento NVMe puede valorarse otra configuración, siempre tras validación en laboratorio.

Instantáneas (snapshots): limitaciones y riesgos

Los snapshots de vSphere son herramientas útiles para pruebas y cambios puntuales, pero no deben utilizarse como método de backup. En SQL Server, los discos delta que crean los snapshots generan penalizaciones de rendimiento progresivas, especialmente en entornos con alto volumen de escritura.

Es frecuente que un snapshot olvidado de semanas cause degradaciones difíciles de diagnosticar. Si hay que usarlos, deben eliminarse en horas, no días. Y siempre debe preferirse una estrategia de backup basada en herramientas nativas o soluciones de backup empresarial compatibles con SQL Server.

Red y conectividad

SQL Server puede requerir un uso intensivo de red, especialmente en escenarios con alta concurrencia, réplicas, Always On o transacciones distribuidas.

Las interfaces de red deben ser siempre VMXNET3, que ofrecen mejor rendimiento y menor latencia que E1000. Además, se recomienda activar Receive Side Scaling (RSS) tanto en el sistema operativo como en las VMware Tools, para distribuir la carga de red entre múltiples núcleos de CPU.

Si se trabaja con grandes volúmenes de datos entre nodos (como en grupos de disponibilidad o replicaciones), debe garantizarse que la infraestructura física y virtual está optimizada para latencia baja y alto throughput. 

Por ejemplo, es una buena práctica usar una VLAN e interfaz de red (física y virtual) dedicada para la comunicación entre servidores SQL, o para la conexión con los servidores de copias de seguridad.

Configuración de energía

Cuando hablamos de servidores críticos debemos primar el rendimiento a la eficiencia energética y esto implica establecer un plan High Performance en todos los niveles

El plan de energía es una de las configuraciones más olvidadas (si aun en 2025), pero con mayor impacto. Por defecto, ESXi y Windows Server pueden utilizar políticas de ahorro de energía (Balanced), que reducen la frecuencia de CPU o introducen cambios de estado (P-states) perjudiciales para cargas sensibles.

La recomendación es clara: habilitar el modo High Performance en tres capas:

  1. BIOS del host físico.
  2. Política de energía de ESXi.
  3. Plan de energía dentro del sistema operativo invitado.

Esta configuración reduce la latencia de respuesta de la CPU y evita throttling no deseado. En pruebas reales, he notado mejoras de entre el 10 y el 15% en rendimiento solo con una buena configuración de energía.

Disponibilidad y recuperación

Garantizar la disponibilidad de una instancia de SQL Server virtualizada no se limita a activar vSphere HA o a desplegar un grupo de disponibilidad. Exige entender cómo interactúan las funcionalidades de VMware con las tecnologías de alta disponibilidad del propio SQL Server, y decidir cuál debe ser el punto de recuperación (RPO) y el tiempo de recuperación objetivo (RTO) para cada tipo de fallo.

Alta disponibilidad en la capa VMware

VMware proporciona mecanismos propios de alta disponibilidad y movilidad de cargas que pueden complementar (o incluso entrar en conflicto con) las estrategias nativas de SQL Server:

  • vSphere HA permite el reinicio automático de una VM en otro host del clúster cuando se detecta un fallo físico. No ofrece continuidad de servicio inmediata, pero sí reduce el downtime sin intervención manual. Es transparente para el sistema operativo y para SQL Server.
  • vSphere FT (Fault Tolerance) proporciona replicación síncrona a nivel de VM y failover instantáneo sin pérdida de estado. No está soportado para máquinas con más de 8 vCPU (en la mayoría de versiones actuales) y no es compatible con algunos escenarios de licenciamiento de SQL Server. Es útil solo en casos muy concretos y no se recomienda como estrategia principal de HA para SQL.
  • vMotion permite migrar en caliente una VM entre hosts sin apagado, útil para mantenimiento planificado o balanceo. Sin embargo, en cargas intensivas (como operaciones de backup, reindexación o grandes transacciones), la migración puede introducir latencias temporales. Aunque no genera caída del servicio, puede afectar al rendimiento en momentos críticos.
  • DRS (Distributed Resource Scheduler) balancea dinámicamente la carga entre hosts según consumo de recursos. Esto puede provocar movimientos frecuentes de la VM si no se definen reglas adecuadas. 

En entornos con SQL Server, es necesario evaluar cuidadosamente el impacto de vMotion y DRS en instancias críticas. Mover una VM durante una operación intensiva puede degradar el rendimiento o generar latencia adicional. Se recomienda definir reglas de afinidad o exclusión para evitar migraciones no deseadas. 

Consideraciones de diseño

A la hora de planificar una solución de alta disponibilidad para SQL Server sobre VMware, es fundamental definir el tipo de fallo que se quiere cubrir:

  • Fallo físico del host: vSphere HA es suficiente si se acepta un reinicio de VM.
  • Fallo de software en el sistema operativo o SQL Server: requiere HA a nivel de SQL Server (AG, FCI).
  • Fallo del datastore: debe cubrirse mediante almacenamiento redundante (vSAN, replicación SAN/NAS).
  • Fallo completo del datacenter: implica solución de recuperación ante desastres (DR), normalmente con réplicas geográficas y procedimientos definidos de failover manual o automático.

Es importante destacar que las soluciones de VMware y SQL Server no son excluyentes, pero deben coordinarse cuidadosamente para evitar conflictos: por ejemplo, no tendría sentido proteger una FCI solo con vSphere HA, o dejar que DRS migre réplicas sincronizadas entre hosts indiscriminadamente. En casos en los que se implementan soluciones HA de SQL Server se recomienda definir reglas de afinidad y exclusión para que las máquinas implicadas en el HA no compartan host físico.

También hay que considerar el licenciamiento: algunas ediciones de SQL Server requieren licencias activas en todas las réplicas del clúster, incluso si solo una está activa (según el uso que se haga). Además, ciertos entornos requieren asegurar que las réplicas pasivas no procesan cargas activas para beneficiarse de ventajas en licencias de Software Assurance.

Vecinos ruidosos

Uno de los retos más infravalorados en la virtualización de cargas críticas como SQL Server es el efecto de otras VMs compartiendo el mismo host físico, conocidas comúnmente como “noisy neighbors” (vecinos ruidosos).

Una máquina virtual que consume picos de CPU, I/O o memoria puede afectar negativamente a otras VMs en el mismo host, especialmente si no hay control de calidad de servicio (QoS) o reservas definidas. Los síntomas suelen incluir:

  • Latencia intermitente en consultas.
  • Variabilidad en tiempos de respuesta bajo carga constante.
  • Aumento de CPU Ready Time o Co-Stop sin incremento aparente de carga en SQL Server.

Para detectar estos problemas, se requiere visibilidad más allá del sistema operativo invitado. Herramientas como vRealize Operations, SQL Sentry o VMware Aria Operations permiten identificar VMs que saturan recursos compartidos, y correlacionar ese uso con degradaciones de rendimiento en las instancias afectadas.

En este caso las recomendaciones son:

  • Establecer reservas mínimas de recursos para VMs críticas.
  • Aplicar affinity/anti-affinity rules para separar cargas pesadas o sensibles.
  • Evitar que SQL Server comparta host con VMs que realizan tareas de backup, ETL o pruebas automatizadas en horarios críticos.
  • Monitorizar periódicamente la actividad del host para detectar comportamientos anómalos.

En entornos donde se requiere máxima previsibilidad (banca, OLTP de alto rendimiento, entornos de pricing), puede incluso justificarse la dedicación exclusiva de host para una o varias VMs SQL Server.

Versiones de hardware y VMware Tools

Mantener actualizadas tanto la versión de hardware virtual como las VMware Tools es esencial para acceder a nuevas funcionalidades, mejorar el rendimiento y garantizar el soporte oficial.

En 2025, la versión mínima recomendada es hardware version 19 (ESXi 7.0), aunque lo ideal sería estar en versión 20 u 21 si se usa ESXi 8.x. Las VMware Tools deben actualizarse de forma coordinada tras cambios de versión o parches del host.

Monitorización y observabilidad

Las métricas estándar de vSphere no siempre ofrecen suficiente visibilidad sobre los cuellos de botella que afectan a SQL Server. Por ello, se recomienda utilizar herramientas especializadas que permitan analizar desde la capa de hipervisor hasta el motor de base de datos:

  • SQL Sentry (SolarWinds): ofrece no solo métricas de SQL Server sino también propias del entorno virtual.
  • vRealize Operations: para el análisis de capacidad, planificación y rendimiento.
  • Perfmon + DMVs: exclusivo para el análisis desde dentro de la VM.

Indicadores como CPU Ready Time, Co-Stop, latencia de I/O, uso de memoria o crecimiento de snapshots deben estar controlados de forma continua.

Conclusión

La virtualización de SQL Server sobre VMware sigue siendo, en 2025, una estrategia plenamente válida para cargas de misión crítica. Pero su éxito depende de un diseño cuidadoso, de un conocimiento profundo del comportamiento del motor SQL y de una integración adecuada con las funcionalidades del hipervisor.

Los errores más comunes (malas configuraciones NUMA, exceso de vCPU, uso de snapshots como backup, planes de energía inadecuados) pueden evitarse si se siguen las prácticas que hemos repasado. Esta guía pretende servir como base técnica de referencia para garantizar que cada instancia virtualizada de SQL Server funcione con la previsibilidad, rendimiento y fiabilidad que un entorno de producción exige.

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

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

Nueva caché de seguridad en SQL Server 2025

Llevamos ya tiempo con la preview de SQL Server 2025 probando todas las novedades. La lista es larga y, a veces, cuesta distinguir entre lo realmente útil y lo puramente decorativo. Entre tanto brillo marketiniano, hay una mejora de la que no se ha hablado, que muchos pasarán por alto sin comprender las implicaciones, pero que a mi me ha hecho sonreír y decir: “Ya era hora”. Os hablo de la nueva capacidad de invalidar cachés de seguridad de forma específica por inicio de sesión en SQL Server 2025. Y sí, es tan buena como suena.

¿Qué es esto de la caché de seguridad?

Antes de meternos en harina, conviene recordar qué es exactamente esa “caché de seguridad” que ahora Microsoft ha afinado. Cuando un usuario se conecta a SQL Server, el motor evalúa qué permisos tiene para acceder a objetos, ejecutar procedimientos, ver datos… ya sabéis, lo básico para evitar que todo sea un buffet libre de SELECT * FROM SensitiveTable.

Como no somos tontos (y SQL Server tampoco), esta validación no se repite cada vez que alguien lanza una consulta. Sería un suicidio en términos de rendimiento. En su lugar, SQL Server guarda esa información en memoria (en la famosa security cache) y la reutiliza mientras no haya cambios que invaliden su contenido.

¿El problema? Hasta ahora era muy sensible. Si cambiabas cualquier permiso de cualquier usuario (cambio de permisos, modificación de roles, o revocar un acceso), se eliminaban todas las entradas DE TODOS LOS USUARIOS. Esto, por supuesto, tiene efectos inmediatos en el rendimiento de cualquier sesión abierta, aunque no tuviera nada que ver con el cambio.

Vamos, que tirábamos la caché como quien reinicia un servidor por si acaso: por pura desesperación.

SQL Server 2025 trae cordura: invalidación específica por login

Con la llegada de SQL Server 2025, se acabó el “todo o nada”. Ahora, cuando se invalidan entradas de la caché de seguridad debido a un cambio en los permisos, el sistema es lo bastante listo como para borrar solo las entradas correspondientes al login afectado. El resto permanece intacto.

Esto supone una mejora directa en varios frentes. Para empezar, reduce el impacto de cualquier cambio de seguridad. No hay invalidaciones masivas innecesarias, no se resienten las sesiones de otros usuarios, y la CPU no se dispara validando de nuevo cientos o miles de entradas de permisos para conexiones que no han cambiado ni una coma de sus privilegios.

¿Por qué esto importa? Rendimiento, escalabilidad y menos sustos

Puede parecer que un cambio de estas características no tiene mucha importancia, y así es entornos con pocos usuarios y permisos bastante genericos. Pero cuando el volumen de usuarios y la granularidad de los permisos son considerables, la diferencia entre invalidar toda la caché de seguridad y hacerlo de forma selectiva puede marcar la diferencia. En entornos con cientos o miles de sesiones concurrentes, la diferencia es tan evidente como entre ejecutar SELECT con un índice… o sin él.

Antes, un cambio puntual en los permisos podía convertirse en una mini tormenta de validaciones. La CPU subía, la latencia aumentaba, y tú te encontrabas explicando por qué un GRANT a las 9:30 había dejado la aplicación más lenta que un Access con macros durante unos minutos. Todo eso queda en el pasado con esta nueva implementación.

Ahora, si revocas un permiso a un usuario que ya estaba conectado, SQL Server se limita a eliminar sus entradas específicas de la caché. El resto de usuarios ni se enteran. Y tú tampoco tendrás que revisar gráficos de rendimiento preguntándote qué demonios ha pasado.

Cambios de roles, miembros de grupos y lo que siempre duele

Uno de los escenarios donde esto brilla especialmente es cuando se hace una modificación en roles o membresías de grupos. Añadir o quitar a alguien de un db_datareader, por ejemplo, solía ser sinónimo de purgar toda la caché de seguridad.

Con SQL Server 2025, eso se acabó. La limpieza de la caché se ciñe a ese login concreto, incluso si el cambio afecta a una membresía en roles de servidor o roles personalizados. Menos interrupciones, menos recompilaciones internas, y más estabilidad.

Que sí, que aún quedan muchos elementos que provocan recompilaciones y limpiezas de caché que no siempre tienen sentido, pero al menos aquí han puesto orden en una de las áreas más olvidadas por el motor en versiones anteriores.

¿Cómo saber si está funcionando?

No hay un nuevo DMV mágico que diga “estás disfrutando de la nueva caché de seguridad personalizada”, pero si monitorizas el uso de CPU y el acceso concurrente durante cambios de permisos, deberías notar una mejora clara. Sobre todo en sistemas con mucha actividad concurrente y una gestión de seguridad activa.

Y si eso no te vale y quieres verlo con tus propios ojos siempre nos quedarán los eventos extendidos, esa magnífica herramienta que lo captura todo. Puedes crear una sesión que capture los nuevos eventos “login_token_cache_hit” que se producen cuando el token de la caché de seguridad sigue activo y el evento “login_token_cache_miss” que es cuando el token de la caché no es válido y hay que generar una nueva entrada.

Demo caché de seguridad 

Vamos a comprobar que esto realmente funciona. Para ello tenemos nuestros logins con ID 267 y 268 y vamos a crear una sesión de xEvents que capture los eventos que hemos comentado antes:

Lo primero que vamos a hacer es borrar la caché de seguridad:

Como hemos borrado la caché, estas dos primeras entradas generan un evento “login_token_cache_miss”, no existe registro en la caché. 

Pero, si volvemos a conectarnos veremos ya los hit, es decir ha utilizado el token existente en caché

Ahora vamos a cambiar los permisos de uno de los logins

Y al volver a conectar veremos solo uno de los dos logins tiene el miss y el otro mantiene su token válido (evento hit). Además veís en la captura que yo he añadido tambien los eventos “security_cache_login_timestamp_increment” a mi captura de eventos, que me indica cuando se ha producido un cambio de permisos.

¿Qué implicaciones tiene para nosotros como DBAs?

Básicamente, nos devuelve un poco de control. Ahora podemos aplicar cambios de seguridad sin tener miedo a provocar un alud de recompilaciones y penalizaciones de rendimiento. Se acabó el tener que programar revocaciones de permisos fuera del horario laboral o acompañarlas de una explicación de daños colaterales.

También nos da más seguridad en entornos de desarrollo y pruebas. Podemos simular escenarios de cambios de permisos sin el temor a que medio entorno colapse por culpa de una caché global destruida innecesariamente.

Eso sí, no todo es perfecto. La documentación oficial todavía no entra en muchos detalles sobre cómo se comporta esta nueva caché con escenarios complejos de impersonación (EXECUTE AS), certificados o permisos a nivel de esquema. Habrá que investigar (y ya lo haré en otro artículo si me lo pedís) si este comportamiento selectivo se extiende también a esos casos.

Conclusión

La invalidación selectiva de la caché de seguridad en SQL Server 2025 es una mejora tan lógica que sorprende que no estuviera ya implementada hace años. Pero aquí está, y funciona como debe. Nos da más precisión, menos impacto colateral y permite cambios de seguridad sin temor a convertir el servidor en una verbena de validaciones.

Como siempre, no es magia. Si haces cambios absurdos o con prisas, te seguirás metiendo en líos. Pero al menos, ahora, el motor te lo pone un poco menos difícil. Y eso, en este mundo de permisos, roles y DBA que no duermen, ya es bastante.

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

El hardware se abarata, el licenciamiento de SQL Server no

Hace poco me compré un portátil nuevo. Un equipo serio, de esos con más núcleos que sentido común y potencia suficiente para levantar sin despeinarse un entorno de desarrollo completo con SQL Server, BI y lo que se le ponga por delante. Vamos, lo que necesito para las demos en los eventos. Precio: unos 2000€. Hasta aquí, todo bien.

Pero al mirar los procesadores disponibles (Ryzen con 16 o 24 núcleos, Intel con 20 y más RAM que la que tenía tu último servidor físico en producción) no pude evitar pensar: si alguien quiere usar esto para algo serio, ¿cómo lo licencia?

Y ahí es donde empieza el problema. Porque el precio del hierro ha bajado, pero el coste del licenciamiento de SQL Server sigue atascado en 2012. O antes.

El espejismo de la democratización

Nos han vendido la moto de que la informática se ha democratizado, que cualquiera puede montar un sistema potente por poco dinero, que digitalizarse es barato. Y en parte es verdad… hasta que levantas la alfombra del licenciamiento.

Cualquier pyme, autónomo o pequeño despacho que hoy quiera informatizar su gestión (pongamos que por exigencias tan poco opcionales como VERIFACTU) probablemente lo hará con lo que tiene a mano: un PC sobremesa moderno, o a lo sumo una torre decente con componentes actuales. Las pequeñas empresas no tienen presupuesto para servidores.

El problema es que hoy incluso un sobremesa “modesto” puede tener un procesador de 16 núcleos físicos y 128 GB de RAM por menos de 1500€. Y en ese momento SQL Server te sonríe… con su sonrisa de tiburón.

SQL Server Standard: paga por core, sufre por diseño

Si quieres usar SQL Server Standard en producción, aunque sea solo para almacenar facturas y cuatro tablas más, y te vas al modelo de licenciamiento por núcleo, prepárate: cada core te cuesta unos 2000 dólares. Sí, da igual que tu software solo use un hilo. Pagas por el número de núcleos visibles al sistema operativo, no por el uso real.

Y aquí viene lo bueno: en un PC moderno que no sea una patata, lo normal es que haya 12, 16 o 24 núcleos físicos (con el doble de vCores). Haz números. Eso son 24.000, 32.000, 48.000 o más euros solo en licencias, sin contar soporte, copias, backups, ni nada más.

Lo que iba a ser una digitalización económica se convierte en un agujero financiero. Y claro, muchos acaban optando por soluciones “temporalmente tolerables” como usar la versión Express… hasta que chocan de frente con sus limitaciones.

Express Edition: demasiado limitada para tomársela en serio

Sí, SQL Server Express es gratuita. Pero su techo de 10 GB por base de datos, 1 GB de RAM utilizable por instancia y uso de un único core lógico la hacen útil para pruebas, no para operar un negocio que mínimamente se tome en serio sus datos.

¿Que quieres hacer informes? Prepárate para sufrir. ¿Que tienes un CRM o un ERP que genera logs o almacena históricos? En dos años estarás exportando datos a Excel para aligerar. ¿Que necesitas rendimiento? Olvídalo.

La Express está bien para entornos de aprendizaje o microproyectos. Pero no está pensada para escenarios empresariales reales, por pequeños que sean.

La trampa del licenciamiento Server + CALs

Aquí algunos intentan una vía alternativa: el modelo de licenciamiento Server + CALs. Y sí, puede ser más asequible si solo tienes unos pocos usuarios y no quieres pagar por cada core.

Pero Microsoft te pone dos límites claros con SQL Server Standard bajo este modelo:

  • Máximo 24 núcleos virtuales visibles.
  • Máximo 128 GB de RAM utilizables.

Y aquí volvemos al drama. Porque un PC de 2025, sin ser nada del otro mundo, puede traer más de 12 núcleos físicos que son 24 virtuales (vCores) fácilmente. Y cuando eso pasa, no puedes usar Server + CALs legalmente. Te obligan a licenciar por core, aunque no necesites ni el 10% de los recursos. Maravilloso, ¿verdad?

Y no, no puedes decir “bueno, entonces limito el uso de cores desde el BIOS o desde el sistema operativo”. Eso no es legalmente vinculante para Microsoft. Si la CPU física tiene 32 núcleos, los vas a pagar todos. Así funciona el modelo de licencias.

En la nube también duele: SQL Server frente a PostgreSQL

Alguien podría pensar: “Vale, el licenciamiento físico es duro, pero si me voy al cloud me quito ese problema de encima, ¿no?”. Bueno… no exactamente. En la nube sigue siendo caro, y en algunos casos, directamente ridículo.

Vamos con cifras reales y actuales, para no caer en sensaciones vagas:

En Azure, una base de datos SQL con 8 vCores cuesta unos 893 dólares al mes. En el mismo entorno, una base de datos administrada de PostgreSQL con 8 vCores cuesta 123 dólares al mes. No es una diferencia. Es un abismo. Con lo que pagas por SQL puedes montar 7 PostgreSQL distintos y aún te sobra para un par de backups con redundancia geográfica.

Y si nos vamos a AWS, el panorama no mejora. Una instancia RDS de SQL Server con 16 vCores y 64 GB de RAM (db.m5.4xlarge) cuesta alrededor de 7.100 dólares mensuales. Sí, has leído bien: más de siete mil dólares al mes. Mientras tanto, la misma configuración con PostgreSQL cuesta 2.423 dólares mensuales. Casi tres veces menos.

Lo importante aquí no es solo el número. Es lo que implica: SQL Server no escala bien en costes. A mayor capacidad, mayor diferencia, y no precisamente a favor. PostgreSQL, en cambio, mantiene un coste racional y predecible, lo que lo hace mucho más viable en entornos que necesiten crecer sin hipotecarse.

Esto deja muy claro por qué tantos arquitectos de datos y CTOs están migrando workloads al open source. No porque les guste complicarse la vida, sino porque el presupuesto manda. Cuando el coste de mantener una base de datos supera al de todo el resto de la arquitectura, hay un problema, y no es técnico.

¿Qué opciones de licenciamiento tiene una pyme? Pocas, y ninguna es buena

Después de todo lo dicho, lo razonable es preguntarse: “¿Qué hago si necesito SQL Server, tengo un hardware moderno y no quiero fundirme el presupuesto en licencias?”

Pues no tienes muchas alternativas, realmente no hay una opción buena, solo algunas menos malas.

Primera opción de licenciamiento: SQL Express

Esta es la más obvia, SQL Express es gratis, sí, pero está muy limitada. Para empresas pequeñas con muy pocos datos puede ser una opción pero siempre con la vista puesta en sus límites. No solo hablo del hardware, que ya impone unos límites considerables (solo usa 4 vCores, 1 Gb de RAM y las bases de datos no pueden superar los 10Gb), sino que le faltan muchas características como el agente de SQL Server, SSIS, SSAS, etc… 

Aunque también es cierto que seguramente no necesites las aplicaciones de ETL o analítica y que la limitación del agente la puedas salvar ejecutando SQLCMD con tareas programadas en el programador de tareas de windows.

Segunda opción de licenciamiento : Licencias Server + CAL

La segunda opción es licenciar tu SQL Server Standard por Server + CALs… si puedes. Esto solo aplica a SQL Server Standard y si tienes un número limitado de usuarios bien controlado. Y no se aplica a entornos públicos, web apps o APIs abiertas. Si tu escenario es cerrado y sabes exactamente cuántos usuarios acceden, podría salirte más barato, unos 900€ la licencia del servidor SQL Server. Pero cuidado, porque CALs también cuestan y hay que contarlas bien, cada usuario que se conecte necesitará su CAL de aproximadamente 200€.
Pero recuerda, esta opción solo es posible si tu máquina tiene menos de 24 vCores. Y si te preguntas si puedes crear una máquina virtual con menos vCores para ahorrar dinero tengo una mala noticia, no es tan sencillo.
Para el licenciamiento de máquinas virtuales Microsoft exige licenciar todos los vCores de la máquina física así que estaríamos en las mismas. Por suerte hay un clavo ardiendo al que puedes agarrarte, es posible licenciar solo los vCores de la máquina virtual si, y solo si, contratas Software Assurance (SA). Este servicio es una suscripción de pago anual que te da derecho, además de a pagar solo por los vCores de la VM, a actualizaciones de versiones de SQL Server. Lo malo es que aquí no podemos hablar de precios, Microsoft no los comparte y tendrás que negociarlos con tu partner de licencias (suele costar anualmente entre un 20 y un 30% del coste de las licencias).

Tercera opción de licenciamiento: Cloud y pago por uso

Ya hemos visto que el coste de la nube no es barato, aun así, el pago mes a mes puede ser más fácil de asumir que el desembolso total de las licencias de una sola vez. Además, si tienes pocos requisitos de recursos, en Azure hay bases de datos sin servidor desde 5€/mes, con unos recursos muuuuy limitados, claro.

 Quedaría otra opción, abandonar SQL Server y mirar a la competencia pero eso ya no es tan sencillo, al menos para proyectos o desarrollos existentes. Oracle no es una opción, su coste por licencia es también por core y cuesta más del doble que SQL Server, pero no es la única alternativa.

PostgreSQL, MariaDB, o incluso SQLite: la fuga silenciosa

Cada vez más desarrolladores están abandonando SQL Server. No porque no funcione bien (que lo hace maravillosamente bien), ni porque no tenga features potentes (que las tiene geniales). Sino porque ya no es viable para ciertos escenarios.

PostgreSQL y MariaDB no imponen estas barreras. No cobran por core. Tampoco limitan la RAM. No te obligan a licenciar el procesador entero si solo usas dos hilos. Y, sinceramente, para el 80% de los casos de uso en empresas pequeñas, hacen el trabajo igual.

Eso si, que PostgreSQL o MariaDB no cobren por licencias no significa que sea gratis.

Porque cuando eliges PostgreSQL o MariaDB, te llevas el motor, pero no el soporte. Ni la monitorización. Ni el clúster. Tampoco la estrategia de backups. Ni la restauración en caliente. Todo eso hay que construirlo, mantenerlo… o pagarlo a una tercera empresa que lo haga.

Y aquí es donde muchas veces la factura no es tan diferente a SQL Server. Solo que el dinero no se va a Microsoft, sino a consultoras especializadas, soporte de terceros o a una inversión de tiempo interno brutal que acaba saliendo más cara de lo previsto.

También hay que reconocerlo, PostgreSQL tiene una curva de aprendizaje considerable, sobre todo si vienes de SQL Server. Lo que antes resolvías con Management Studio ahora implica línea de comandos, pg_dump, systemd, y a menudo, búsqueda en foros. Y que no te dé por hacer un clúster HA sin una herramienta externa, porque ahí es donde empiezas a pagar con sangre o con suscripciones.

Así que sí, hay motivos para migrar. Pero que no te vendan que todo es gratis. Porque no lo es. Y a veces, cuando te das cuenta, ya estás hasta el cuello de migración, y ni puedes volver atrás ni puedes pagar el camino nuevo.

Conclusión

La paradoja sigue ahí. El hardware moderno ha democratizado el acceso a CPUs potentes, pero SQL Server sigue licenciado como si cada core fuese un diamante. El resultado: una tecnología excelente, pero cada vez más difícil de justificar fuera de entornos que puedan asumir ese coste sin pestañear.

Las PYMEs, los autónomos y cualquier organización que pretenda informatizarse en serio sin vaciar su cuenta bancaria se topan con un muro invisible: el licenciamiento. Un muro que no distingue entre portátil, sobremesa o servidor, y que tampoco afloja si te mudas a la nube.

Y sí, SQL Server 2025 está en puertas, con la Release Candidate ya disponible. Pero no parece que el modelo de licencias vaya a cambiar. Ojalá me equivoque y Microsoft suba ese límite absurdo de 24 vCores para el Server + CAL. Pero no creo.

Mientras tanto, PostgreSQL y compañía siguen ganando terreno. No por ideología, sino por supervivencia económica.

Y si esto te parece exagerado, revisa tu próxima factura de Azure o AWS. O tu presupuesto para licencias on-prem. Verás que la exageración no está en el artículo. Está en el modelo.

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

OPTIMIZED SP_EXECUTESQL: Novedad de SQL Server 2025

Con la llegada de SQL Server 2025, Microsoft introducirá una serie de mejoras orientadas a optimizar el rendimiento del motor. Una de ellas es la nueva configuración OPTIMIZED_SP_EXECUTESQL, pensada específicamente para entornos que hacen uso intensivo de SQL dinámico a través de sp_executesql. En este artículo profundizo en su funcionamiento, cómo activarla, qué impacto tiene en la caché de planes y cómo se comporta bajo carga concurrente.

Contexto: el problema con sp_executesql y el plan cache

Cuando ejecutamos consultas dinámicas con sp_executesql, especialmente en entornos con alta concurrencia, SQL Server puede compilar múltiples planes para lo que, conceptualmente, es la misma consulta. Aunque el texto del lote (batch text) sea idéntico y se usen parámetros, el compilador no siempre consigue identificarlo como la misma ejecución, lo que termina generando entradas repetidas en la plan cache.

Esto da lugar a varios problemas conocidos:

  • Bloat en la plan cache, con decenas o cientos de planes similares almacenados.
  • Consumo innecesario de CPU por compilaciones redundantes.
  • Contención en la compilación, cuando múltiples sesiones intentan compilar la misma consulta al mismo tiempo.

Con OPTIMIZED_SP_EXECUTESQL, SQL Server introduce un nuevo mecanismo para mitigar estos efectos.

¿Qué es OPTIMIZED SP_EXECUTESQL?

Se trata de una configuración a nivel de base de datos que se encuentra desactivada por defecto y que puede activarse mediante ALTER DATABASE SCOPED CONFIGURATION. Su objetivo principal es optimizar la forma en que SQL Server gestiona la compilación y almacenamiento en caché de planes asociados a ejecuciones de sp_executesql.

Cuando se activa esta opción, el comportamiento cambia significativamente:

  • La primera ejecución de un lote dinámico mediante sp_executesql compila el plan normalmente.
  • Otras sesiones concurrentes que ejecutan el mismo lote esperan a que finalice la compilación.
  • Una vez compilado, todas las sesiones reutilizan el mismo plan, del mismo modo que lo harían si fuera un procedimiento almacenado.

Requisitos y dependencias

Lo primero, obviamente, es tener SQL Server 2025 y tu base de datos en un nivel de compatibilidad 170. Además, si en tu base de datos tienes activada la opción de actualización automática de estadísticas, Microsoft recomienda habilitar también ASYNC_STATS_UPDATE_WAIT_AT_LOW_PRIORITY (más bien es un requisito pero, ¿has visto qué bien me ha quedado lo de “Microsoft recomienda”?). Esto asegura que el nuevo comportamiento no introduzca contención innecesaria durante las actualizaciones estadísticas, en escenarios de alta concurrencia.

SP_EXECUTESQL

Cómo activarlo

Para habilitar la funcionalidad, puedes ejecutar el siguiente bloque:

Recuerda, necesitas estar en nivel de compatibilidad 170 (SQL Server 2025) para que la opción sea válida.

Puedes comprobar el estado actual de la configuración con:

Demostración práctica

Vamos a ejecutar una serie de pruebas en una base de datos StackOverflow (modo de compatibilidad 170) para observar el impacto real de esta configuración en la plan cache.

Paso 1: Asegurar que la opción está desactivada

Paso 2: Limpiar la caché de planes

Paso 3: Ejecutar carga concurrente

Usaremos SQLQueryStress para lanzar la siguiente consulta, que ejecuta sp_executesql de forma concurrente:

Parámetros en SQLQueryStress:

  • Iteraciones por hilo: 10
  • Número de hilos: 100

Esto generará 1000 ejecuciones concurrentes de la misma consulta dinámica.

Paso 4: Analizar la plan cache

Una vez completadas las ejecuciones, inspeccionamos el número de planes generados:

Resultado esperado (sin optimización): múltiples planes distintos (en pruebas reales, se observan entre 20 y 30 para este escenario), aunque la consulta sea la misma.

Esto evidencia el comportamiento ineficiente por defecto: múltiples planes para la misma carga.

Paso 5: Activar la optimización

Paso 6: Limpiar de nuevo la caché

Paso 7: Ejecutar la misma carga

Volvemos a lanzar los 100 hilos concurrentes con SQLQueryStress, exactamente como antes.

Paso 8: Analizar resultados

Ejecutamos de nuevo la consulta sobre la plan cache:

Resultado esperado (con optimización): una sola entrada en la caché de planes, con una execution_count acumulada de 1000. El compilador ha tratado la consulta dinámica como si fuese un procedimiento almacenado.

Este comportamiento elimina de raíz el bloat en la caché y evita la compilación paralela.

¿Qué hace SQL Server exactamente?

El mecanismo detrás de esta optimización replica el modelo clásico de los procedimientos almacenados:

  1. La primera ejecución de una consulta concreta compila el plan.
  2. El resto de ejecuciones esperan a que ese plan esté disponible.
  3. Una vez compilado, todas las ejecuciones reutilizan ese mismo plan.

Este comportamiento garantiza una mayor eficiencia tanto en uso de CPU como en gestión de memoria. Ya no veremos un plan por cada sesión, sino un único plan compartido y referenciado por todas.

Consideraciones finales

Este cambio solo aplica a sp_executesql. No afecta a EXEC() ni a otros mecanismos de ejecución dinámica.

Las consultas deben ser realmente idénticas (texto y parámetros) para que se detecte la coincidencia.

Si tu aplicación genera SQL dinámico con pequeñas variaciones en los literales o estructura, el beneficio será menor.

La mejora se aprecia especialmente en entornos con alta concurrencia o patrones repetitivos.

Conclusión

OPTIMIZED_SP_EXECUTESQL es una de las mejoras más importantes en la gestión del plan cache que hemos visto en años. Su activación puede suponer una diferencia notable en servidores que sufrían problemas de rendimiento por exceso de compilaciones o saturación de memoria con planes efímeros.

Es una de esas configuraciones que, bien aplicada, no solo mejora el rendimiento, sino que permite aprovechar mejor los recursos existentes. No es una solución mágica, pero sí una herramienta eficaz para un problema conocido.

Si trabajas con aplicaciones que generan SQL dinámico intensivo y tienes pensado actualizar SQL Server 2025 cuando sea estable, este cambio debería estar en tu lista de tareas prioritarias.

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

Sinónimos en SQL Server. SQL Basics

No todos los objetos de SQL Server nacieron para ser usados con confianza ciega. Algunos tienen nombre de perfume barato y generan sensaciones parecidas. Hoy hablamos de los sinónimos, esos alias de objetos que pueden facilitarte la vida o clavarte una estaca en mitad de una migración mal hecha.

Los sinónimos (synonyms, si estás leyendo esto con el Management Studio en inglés) son una característica de SQL Server que permite crear un nombre alternativo para referenciar a un objeto, ya sea una tabla, vista, procedimiento almacenado o función. A primera vista suena bien. Evitas tener que escribir nombres de servidores, bases de datos y esquemas cada vez que llamas a algo remoto. Pero como todo en la vida, cuando lo haces demasiado fácil, el problema aparece justo después.

¿Qué es un sinónimo?

Los sinónimos permiten definir un alias a un objeto que puede estar incluso en otro servidor. Esto puede incluir tablas en bases de datos remotas, procedimientos almacenados en otras instancias, funciones en otro universo, etc.

Por ejemplo, puedes tener un sinónimo así:

Y desde ese momento puedes hacer:

Sin preocuparte de toda la parafernalia de nombres largos y cuatro partes. Es cómodo, sí. Pero también estás metiendo debajo de la alfombra varias capas de dependencia, latencia y seguridad implícita.

¿Por qué usar sinónimos?

Vale, vamos a concederle al sinónimo su minuto de gloria. Hay casos en los que puede tener sentido.

Cuando trabajas con entornos donde los nombres de base de datos o incluso los servidores cambian con frecuencia (hola, entornos de desarrollo y preproducción mal organizados), usar sinónimos permite centralizar esos nombres en un solo punto. En lugar de cambiar 58 procedimientos almacenados, cambias un solo sinónimo. Bravo.

También son útiles cuando accedes a objetos remotos y no quieres estar repitiendo la ruta de cuatro partes cada vez. Si el enlace funciona y las credenciales no han caducado, puede parecer magia.

Y por supuesto, si estás trabajando con múltiples bases de datos y necesitas mantener cierto nivel de encapsulamiento o abstracción (palabra que aquí significa “hacer como que lo que depende de otro servidor no depende de él”), un sinónimo puede ayudarte.

Pero no te emociones.

Los problemas empiezan con la transparencia

El gran problema de los sinónimos es que precisamente no parece que estás accediendo a algo remoto.

Tú haces un SELECT * FROM ProductoExt y ni idea de que en realidad estás yendo a otro servidor, otra base de datos, o peor aún, a un servidor vinculado (linked server) que va a dar más vueltas que un sp_executesql dentro de un cursor.

Esa falta de visibilidad genera problemas muy reales:

  • Latencia inesperada. Estás accediendo a una tabla en otro continente y no lo sabías.
  • Errores de seguridad. ¿Quién tiene permiso en el objeto real? ¿Qué cuenta usa el servidor vinculado? ¿Tienes doble salto Kerberos bien configurado? 
  • Fragmentación lógica. El código parece limpio, pero la traza de dependencias es un infierno.

Y como cereza del pastel: cuando algo falla, el mensaje de error puede ser tan claro como una excepción de .NET lanzada por un junior con prisa.

Rendimiento de los sinónimos

Vamos a dejar esto claro, usar sinónimos no introduce penalización de rendimiento por sí mismo. No hay sobrecarga, ni resolución dinámica, ni instrucciones mágicas de más. Un sinónimo es un alias, y el plan de ejecución generado es exactamente el mismo que si hubieras usado el nombre completo del objeto original.

Entonces, ¿dónde está el problema?

En que el sinónimo oculta la naturaleza del objeto que estás tocando. Puedes estar accediendo a una tabla local… o a una tabla en otro servidor a través de un Linked Server. Y como el nombre del sinónimo no da pistas, el riesgo es que estés haciendo una SELECT * a 10 millones de registros en remoto sin saberlo.

Esa opacidad puede llevar a errores de diseño y análisis, planificas como si accedieras a una tabla local, pero detrás hay un OLEDB pasando datos entre servidores. Y eso sí que es un problema de rendimiento, de los serios.

Además, al estar encapsulado como alias, el sinónimo puede dificultar el análisis del plan de ejecución, sobre todo cuando hay muchos niveles de indirección. No porque el plan sea distinto, sino porque hay que tirar del hilo hasta encontrar el objeto real.

Y no, los sinónimos no hacen caché de nada. Ni de la resolución del nombre, ni del esquema, ni del servidor remoto. Cada vez que los usas, se resuelve el nombre desde cero. Esto normalmente no es un cuello de botella, pero en entornos de alta concurrencia o con muchas referencias cruzadas, puede notarse. Poco, pero lo justo para volverse molesto.

Así que el sinónimo no penaliza, pero tampoco te avisa. Por eso conviene saber muy bien qué estás llamando, de dónde cuelga, y si realmente necesitas ese acceso encapsulado. Porque cuando el rendimiento se resiente, el sinónimo suele ser el último sitio donde alguien mira… y a veces es justo donde empezó el desastre.

¿Y la seguridad? ¿Qué podría salir mal?

En realidad, poco. O al menos, nada distinto a lo que ya puede salir mal sin sinónimos.

Porque, que quede claro por si no lo he dicho suficiente: un sinónimo es solo un alias. No altera cómo funciona la seguridad en SQL Server. Los permisos que necesita un usuario para acceder a un sinónimo son exactamente los mismos que si accediera directamente al objeto original con su nombre completo.

Si no tienes permisos sobre la tabla, vista o procedimiento al que apunta el sinónimo, obtendrás el mismo error que si usaras [Base].[Esquema].[Objeto] a pelo. Y si los tienes, funcionará. Punto.

Lo mismo aplica si el objeto está en otra base de datos: el login debe tener un usuario definido en esa base, con permisos suficientes. Y si el sinónimo apunta a un Linked Server, el control lo marca la configuración del servidor vinculado. Pero eso pasaría exactamente igual si accedieras con nombres de cuatro partes. No hay atajo, ni puerta trasera, ni cambio de contexto.

Lo único que realmente puede salir mal (y lo hace más de lo que parece) es que el objeto original cambie o desaparezca. El sinónimo no se entera de nada. Si el objeto cambia de esquema, se renombra o se elimina, el sinónimo sigue ahí, inerte, esperando a que alguien lo use… y falle. Porque SQL Server no valida los sinónimos en tiempo de creación, ni en tiempo de despliegue. Solo en tiempo de ejecución.

¿Qué objetos pueden tener sinónimos?

Los sinónimos en SQL Server no son tan versátiles como a veces se cree. No puedes crear alias para “lo que te dé la gana”. Están limitados a objetos individuales y concretos. Vamos a dejar esto bien claro para evitar que alguien pierda una hora pegándose con errores de sintaxis absurdos.

Sí puedes crear sinónimos sobre:

  • Tablas (locales o remotas, si usas nombres de cuatro partes correctamente).
  • Vistas.
  • Procedimientos almacenados.
  • Funciones definidas por el usuario (escalares o con valores de tabla).

Siempre que el objeto esté definido en un esquema, sea accedible por nombre completo y tenga una representación clara en la metadata, puedes hacerle un sinónimo.

No puedes crear sinónimos sobre:

  • Tablas temporales (#Local, ##Global).
  • Triggers. (No me preguntéis por qué alguien lo intentaría).
  • Constraints (CHECK, DEFAULT, FOREIGN KEY, etc.).
  • Columnas. Lo de SELECT columna AS alias es otra cosa.
  • Tipos definidos por el usuario (UDT), reglas (RULE), secuencias (SEQUENCE), ni defaults independientes.
  • Funciones del sistema (GETDATE(), ISNULL(), etc.).
  • Objetos CLR o ensamblados .NET.
  • Índices, particiones, estadísticas o cualquier cosa que no sea “llamable” desde T-SQL por sí sola.
  • Bases de datos. No puedes hacer un alias de una base de datos entera. Olvídalo.
  • Esquemas. Tampoco puedes crear un sinónimo para un esquema. Ni para [dbo], ni para ninguno. Si necesitas encapsular el acceso a todos los objetos de un esquema remoto, necesitarás crear un sinónimo por cada objeto. O usar otro enfoque (vistas, procedimientos, sin llorar).

Recuerda: los sinónimos apuntan a objetos, no a contenedores de objetos. Si te estás planteando crear sinónimos para simplificar nombres de base de datos o de esquema, estás intentando que hagan algo para lo que no fueron diseñados. Te toca o escribir más código o usar una capa de abstracción de verdad.

¿Versionado y mantenimiento? 

Cuando usas sinónimos para abstraer el acceso a objetos en otras bases de datos, estás añadiendo una capa más que también necesita mantenimiento. Y como suele pasar, se te va a olvidar.

¿Haces despliegues con DACPACs? ¿Tienes control de versiones? ¿Sabes en qué base de datos está realmente cada sinónimo? ¿Cuándo fue la última vez que hiciste un DROP SYNONYM?

Exacto.

Además, los sinónimos no aparecen claramente en muchas herramientas de análisis de dependencias. Ni en algunos generadores de documentación. Son casi como variables globales: parecen útiles hasta que tu entorno tiene más de dos personas y cinco entornos.

¿Y cómo los controlo?

Si has heredado una base de datos con decenas (o cientos) de sinónimos, lo primero es hacer inventario:

Con eso ya puedes empezar a trazar qué objetos están apuntando a qué lugares. Usa sys.sql_expression_dependencies para ver si están en uso, aunque no siempre captura todo.

Haz pruebas. Valida que cada sinónimo realmente apunte a algo válido. Y luego decide si vale la pena mantenerlo o rediseñar esa parte del acceso.

No olvides que puedes hacer scripts automáticos para regenerarlos si decides mover entornos. Pero asegúrate de que esos scripts están bajo control de versiones, como Dios y el sentido común mandan.

Conclusión

Los sinónimos son ese tipo de herramienta que SQL Server te da con una sonrisa pero sin instrucciones. Te ahorran escritura, sí, pero a cambio te introducen opacidad, dependencias ocultas y posibles dolores de cabeza cuando algo deja de funcionar y nadie recuerda de dónde venía ese nombre tan bonito.

No están prohibidos. Pero tampoco deberían ser tu primera opción. Úsalos con mesura, con documentación, y con una pizca de paranoia técnica. Porque el día que falle un sinónimo en producción, nadie va a buscar el problema en ese alias inofensivo… hasta que ya es demasiado tarde.

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

Database Snapshots en SQL Server: Ni backup, ni milagro, pero muy útil

Llevábamos ya años con el blog y sin hablar de snapshots. Quizá porque es una de esas funcionalidades que están ahí desde hace años (SQL Server 2005, nada menos), pero que siempre han vivido en esa zona gris de lo útil pero olvidado. Como ese índice XML que alguien creó en 2013 y nadie ha tocado desde entonces. Hoy vamos a remediarlo, no para darles bombo, sino para entender realmente qué ofrecen, qué limitaciones arrastran, y sobre todo, cuándo tiene sentido usarlos… y cuándo no.

¿Qué es un Database Snapshot?

Un Database Snapshot es una copia solo lectura de una base de datos en un punto en el tiempo. No es una copia física, ni tampoco un backup, aunque mucha gente los confunda (mal hecho). Es un mecanismo basado en copy-on-write que permite mantener la imagen original de los datos a medida que la base activa cambia.

No crea una copia completa de los datos. En lugar de eso, guarda las páginas modificadas en un archivo sparse, lo que permite “reconstruir” cómo estaban los datos en el momento del snapshot sin necesidad de duplicar todo el almacenamiento.

Importante: el snapshot depende completamente de la base de datos original. Si la base cae, se corrompe o desaparece, el snapshot no vale absolutamente para nada. Cualquier parecido con un backup es pura coincidencia y mala comprensión técnica.

¿Cómo funciona internamente?

El principio es simple, en el momento en que se crea un snapshot, SQL Server marca todas las páginas como estables. A partir de ese instante, cada vez que una página de datos va a ser modificada en la base de datos original, su contenido anterior se copia en el archivo sparse del snapshot. Esto es el famoso copy-on-write.

Por eso, al consultar un snapshot, SQL Server reconstruye cada página accediendo al archivo sparse solo si esa página ha cambiado. Si no, la lee directamente de la base original. Esta eficiencia hace que los snapshots sean rápidos de crear y razonablemente económicos en almacenamiento… al menos al principio.

Ahora bien, si la base de datos se modifica mucho, los archivos sparse pueden crecer de forma nada despreciable. A efectos prácticos, un snapshot puede acabar ocupando casi tanto como la base original si hay suficiente actividad. No es frecuente, pero tampoco impensable.

Sintaxis básica 

Supongamos que tenemos una base de datos llamada MiBase y queremos crear un snapshot. Es así de fácil:

Casos reales de uso

Los snapshots tienen usos muy específicos. Aquí van algunos que sí tienen sentido técnico.

1. Restauración rápida tras una operación peligrosa

Antes de hacer un update masivo, un truncate o cualquier otro acto temerario, puedes crear un snapshot. Si algo sale mal, puedes volver al estado anterior usando un revert.

Eso sí, este RESTORE elimina todos los cambios hechos desde que se creó el snapshot. Nada de granularidad. Esto es todo o nada. 

2. Consultas analíticas en entornos OLTP

A veces necesitas lanzar un informe o validación sin que los datos cambien mientras se ejecuta. Y no, no siempre puedes meter todo en una transacción ni usar niveles de aislamiento elevados sin liarla en el entorno OLTP.

Ahí es donde un snapshot puede tener sentido. El snapshot genera una imagen coherente y estable de los datos en el momento de su creación. Puedes hacer consultas complejas sin riesgo de leer datos a medias ni provocar bloqueos.

Pero que no te vendan la moto, el snapshot no reduce la carga del sistema. Las páginas que no han cambiado desde su creación se siguen leyendo desde la base original. El I/O sigue yendo a los mismos discos. Incluso puedes añadir algo más de carga por el copy-on-write si la base está escribiendo mucho.

¿Quieres estabilidad en tus lecturas? Perfecto.
¿Quieres rendimiento? Haz otra cosa.
Por ejemplo:

Tendrás una lectura coherente, congelada en el tiempo, sin preocuparte de cambios concurrentes. Pero no esperes milagros en los tiempos de respuesta.

3. Comparaciones entre versiones

Ideal si necesitas comparar el estado de los datos antes y después de una carga o transformación. Puedes leer ambos mundos (activo y snapshot) en paralelo, por ejemplo:

O comparar registros concretos, detectar cambios en columnas, o revisar cuántos registros nuevos hay que no existían en el snapshot. Todo sin afectar a la base activa.

4. Testing rápido

En entornos de pruebas donde necesitas una copia coherente y estática para validar un proceso, sin necesidad de clonar toda la base.

Limitaciones que no conviene ignorar

Los snapshots no son mágicos. Y como todo lo que parece demasiado cómodo, tienen letra pequeña. Aquí van algunas verdades que conviene tener presentes:

  • Solo lectura. No se pueden modificar. Olvídate de hacer pruebas de escritura ahí dentro.
  • Vinculación absoluta a la base original. Si la base cae, se va el snapshot con ella. No es replicable, no es portable, y desde luego, no es “seguro”.
  • No puedes hacer backup de un snapshot. Ni exportarlo fácilmente. Vive y muere en el servidor que lo contiene.
  • No están soportados en Azure SQL Database. Aunque sí en SQL Server en Azure VMs. Si estás en PaaS, olvídate.
  • Limitación de cantidad. No hay una cifra oficial, pero no abuses. SQL Server no está pensado para mantener docenas de snapshots activos a la vez.

Y sí, pueden afectar al rendimiento. Pero esto merece su propia sección…

El coste en rendimiento

Una de las mayores falacias con los snapshots es que «como no copian todos los datos, no afectan al rendimiento». Bueno, sí, y los triggers tampoco afectan si no se disparan nunca. Vamos al grano.

El impacto de los snapshots no está en la creación inicial, eso es casi instantáneo, sino en lo que pasa después, en cuanto la base de datos empieza a cambiar. Cada vez que se modifica una página en la base activa, SQL Server tiene que hacer una copia previa en el archivo sparse del snapshot. Esto añade una operación de escritura adicional por cada modificación.

¿Y eso qué implica? Más I/O. Más presión sobre el subsistema de almacenamiento. Y si no tienes discos NVMe, una SAN generosa o un almacenamiento SSD con margen, vas a notarlo. No al minuto uno, pero lo vas a notar.

En sistemas con alta tasa de escritura (bases OLTP vivas, sincronizaciones frecuentes, cargas masivas…), ese copy-on-write puede convertirse en un cuello de botella silencioso. No suele romper el sistema, pero lo frena. Y lo hace justo cuando menos te interesa: en plena operación intensa.

Lecturas extra, carga extra

Otra consecuencia menos obvia, al hacer lecturas desde el snapshot, SQL Server tiene que reconstruir cada página accediendo a dos ubicaciones posibles (la base original o el archivo sparse). Esto añade complejidad interna a la lógica de lectura, aunque el impacto sea menor que en escritura.

¿Quieres pruebas? Basta con monitorizar I/O cuando un snapshot está activo y tu base de datos empieza a recibir carga. Puedes usar sys.dm_io_virtual_file_stats, perfmon o herramientas de terceros como Redgate SQL Monitor. Verás cómo crece la escritura en el archivo sparse, y con ello, la latencia de las operaciones normales.

Y por supuesto, más archivos significa más trabajo para el planificador de I/O de SQL Server. En entornos con varias bases y múltiples snapshots, el impacto se acumula. No es dramático si lo controlas, pero si te dedicas a crear snapshots como quien colecciona Pokémon, vas a pagar el precio.

En resumen: los snapshots no son gratis. Cuestan I/O, y ese coste crece con el tiempo y con la actividad. Por eso no deben dejarse activos más de lo necesario, ni usarse como sistema “por si acaso”. Ese «por si acaso» puede ser el motivo por el que tus discos van al 90% sin razón aparente.

Conclusión

Los Database Snapshots son útiles. Mucho. Pero solo si se usan con cabeza. No sustituyen backups, no mejoran el rendimiento por arte de magia, y desde luego, no están hechos para vivir en producción de forma indefinida. Son un bisturí, no un martillo.

En manos de un DBA que sabe lo que hace, pueden ser la diferencia entre una operación arriesgada y un desastre. Pero mal usados, solo sirven para saturar discos, ralentizar el I/O y dar una falsa sensación de seguridad.

Así que la próxima vez que pienses en crear un snapshot, hazlo sabiendo por qué lo haces, cuánto tiempo lo vas a mantener, y qué coste estás dispuesto a asumir. Y cuando ya no lo necesites… bórralo. Que no eres un coleccionista.

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

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