Rendimiento

MERGE en SQL Server: La eterna promesa llena de bugs

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

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

El espejismo de la elegancia

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

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

El historial de errores no es opcional

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

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

Logo SoyDBA

Únete a la newsletter de SoyDBA

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

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

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

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

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

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

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

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

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

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

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

Cuando MERGE falla… ni siquiera sabes por qué

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

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

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

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

Triggers, locking y otras trampas técnicas de MERGE

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

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

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

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

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

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

¿Y entonces qué usamos? Alternativas a MERGE

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

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

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

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

¿Y qué pasa con el rendimiento?

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

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

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

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

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

¿Se puede usar MERGE con garantías?

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

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

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

Conclusión

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

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

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

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

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

¿Cuál es el problema que quieres resolver?

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

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

Cuando dos índices son un problema

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

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

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

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

El optimizador también se equivoca

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

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

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

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

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

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

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

La pregunta de Brent Ozar

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

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

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

Si no mides, no sabes si mejoras o empeoras

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

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

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

Diagnóstico antes de cirugía

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

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

Conclusión

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

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

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

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

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

Novedades sobre el libro

Después de meses de trabajo, revisiones y mucha paciencia, puedo compartir tres novedades clave del libro SQL Server: La NO guía práctica de optimización:

  • El prólogo lo firma Fernando G. Guerrero, pionero en SQL Server y miembro histórico de la comunidad. Además de escribir unas palabras introductorias, ha contribuido en la revisión técnica.

  • Aquí está el índice completo, con los más de 40 capítulos organizados en 7 partes.

  • Y sí: la fecha de lanzamiento ya es oficial. El libro estará disponible a mediados de septiembre. Pronto os diré el día exacto

Índice completo

Parte 1 – Fundamentos del modelo relacional y la arquitectura
Desde la definición de base de datos relacional hasta la estructura física de páginas y archivos. El punto de partida sólido para entender qué hay detrás de cada consulta.

Parte 2 – T-SQL y construcción de consultas eficientes
SELECT, INSERT, UPDATE y DELETE como base, y a partir de ahí subconsultas, CTEs, funciones de ventana, vistas, procedimientos y ejecución de consultas. Todo lo que necesitas para escribir SQL que funcione en producción.

Parte 3 – Transacciones, concurrencia y aislamiento
Propiedades ACID, niveles de aislamiento, bloqueos, deadlocks y el nuevo modelo de bloqueos optimizados. Una sección clave para quien de verdad administre entornos críticos.

Parte 4 – Internals, configuración y mantenimiento
TempDB, almacenamiento, memoria, CPU, cardinalidad, parametrización, índices, estadísticas y particionado. La cocina interna del motor y cómo configurarlo sin hipotecar el rendimiento.

Parte 5 – Backup, recuperación y disponibilidad
Modelos de recuperación, estrategias de backup, restore, Log Shipping, Database Mirroring y Availability Groups. Todo lo que sostiene la continuidad de un entorno SQL Server serio.

Parte 6 – Seguridad y control de acceso
Principales, usuarios, roles, permisos y técnicas avanzadas de seguridad. Desde lo básico hasta RLS, cifrado y enmascaramiento de datos.

Parte 7 – Control, monitorización y diagnóstico
Herramientas internas y externas: Resource Governor, Activity Monitor, DMVs, Profiler, Extended Events, Query Store y PerfMon. Para que no solo administres, sino que entiendas qué ocurre bajo el capó.

Con este índice ya podéis ver que no es un manual de recetas rápidas, sino una guía estructurada de principio a fin para profesionales de SQL Server.

El lanzamiento será a mediados de septiembre y os avisaré en cuanto esté disponible en Amazon.

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

¿Cuál es el coste de no optimizar SQL?

La mayoría de las empresas que trabajan con SQL Server no tienen ni la más remota idea de lo que les cuesta no optimizar sus consultas. Y no, no hablo de la típica pérdida de rendimiento que molesta al usuario de vez en cuando. Hablo de dinero. Del que se escapa cada mes por la rendija del servidor porque nadie se molestó en revisar ese SELECT con JOIN cruzado que parece escrito por un algoritmo con ganas de venganza.

Pero vamos por partes. Porque el drama tiene capítulos, y todos salen caros.

Hardware: más coste para hacer lo mismo (o menos)

Cuando una consulta no está optimizada, lo primero que pide el sistema es más CPU. Más RAM. Más disco. Y como somos humanos, y a veces un poco vagos, el primer impulso es escalar verticalmente: poner más hierro. Total, si ya funciona mal, con más recursos irá mejor, ¿no?

Pues sí. Durante un rato. Luego viene otra consulta igual de mala y vuelta a empezar. El patrón es de sobra conocido: base de datos lenta, compras hardware, mejora temporal, vuelve la lentitud, compras más hardware… y cuando te das cuenta, estás alimentando un monstruo que vive de cores, GB y licencias.

Y aquí entra la broma que siempre duele: SQL Server se licencia por core. Así que cada vez que decides “arreglar” un problema de rendimiento añadiendo CPU, estás aceptando voluntariamente pagar más en licencias, que no son baratas. Es como combatir la sed bebiendo agua salada: parece que ayuda, pero en realidad te estás hundiendo más.

Logo SoyDBA

Únete a la newsletter de SoyDBA

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

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

El coste real en la nube: «elástico», sí, pero hacia arriba

Muchos creen que al migrar a la nube el problema desaparece. Que Azure SQL, AWS RDS o cualquier plataforma PaaS mágica va a solucionar lo que tu SELECT * no quiso arreglar. Y no, no es así.

En la nube todo se factura. Cada milisegundo de CPU, cada MB de RAM, cada GB de almacenamiento y cada IO de disco. Una consulta ineficiente en Azure no solo es lenta: es cara. Muy cara. Porque, a diferencia de tu servidor físico en el CPD, aquí no tienes un coste hundido. Aquí cada operación se convierte en un apunte contable. Y si te pasas, la factura no perdona.

He visto clientes triplicar su consumo mensual de Azure SQL sin añadir ni un solo usuario más. ¿La causa? Un informe mal diseñado, una vista que arrastra medio millón de registros y un desarrollador con más entusiasmo que criterio.

Una historia real de coste en azure

Y luego están los casos como este. Años atrás, un cliente me llamó porque su Azure SQL Managed Instance con 8 cores (unos 1.355€ al mes) tenía la CPU por encima del 90% casi todo el día, con picos constantes al 100% que parecían avisos de incendio. Lo más grave no era eso, sino que ya habían asumido que la única salida era duplicar recursos y pasar a 16 cores, lo que dispararía la factura a 2.700€/mes. Antes de firmar el salto, decidieron llamarme. Por suerte.

Lo que me encontré era un festival del despropósito. Ni un solo índice clustered, todos los índices nonclustered eran de una sola columna y, por supuesto, sin INCLUDE. Mirando el uso, el 95% de esos índices no se usaban. Y claro, la DMV de índices faltantes parecía la lista de tareas de un becario sin supervisión: infinita, desordenada y sin lógica.

Con un par de días de trabajo serio (revisión de patrones de consulta y una política de indexación con sentido común) no solo evitamos el escalado, sino que redujimos la instancia a 4 cores. El resultado fue sorprendente, CPU estable al 30% incluso en horas pico. Lo que se dice, respirar. Pero además, más de 25.000€ al año de ahorro respecto a la solución que estaban a punto de contratar.

El coste del “Pero si se lanza una vez al año…”

Ya que me he puesto en plan cuentacuentos, déjame contarte otra de esas anécdotas que se graban a fuego.

Un día me encontré con un informe, hecho en Tableau (pero eso es lo de menos), que lanzaban una vez al año y que tardaba en completarse… 22 horas. Bueno, yo lo pillé cuando llevaba 22 horas de ejecución en el SQL Server de producción, a saber cuánto más le quedaba. Cuando lo comenté, me dijeron que no pasaba nada, que solo se lanzaba una vez al año y que solían dejarlo corriendo de un día para otro, como quien pone la olla lenta con garbanzos.

Pero yo lo vi claro. La consulta tenía 47 subconsultas en el SELECT. Si, si, CUARENTA Y SIETE. No índices raros, no estructuras marcianas, solo una estructura de consulta absurda.

¿El cambio? Reescribir con LEFT JOIN bien definidos en lugar de esas subconsultas incrustadas. Nada más. Bueno si, una subconsulta que se repetía bastantes veces muy parecida se persistió como temporal al inicio del proceso. De esa manera los datos se leian y filtraban de una tabla grande una sola vez y se quedaban en una tabla pequeña para consultar el resto de las veces. Pero nada más, ni cambiar índices, ni tocar el esquema. Vamos, sin reformar la casa. ¿El resultado? Menos de 20 milisegundos.

Y esto amigos, esto no es una mejora. Eso es pasar de enviar la consulta en burro a ponerle un cohete. Y no exagero.

Porque no todo el coste es culpa del desarrollador

No vamos a demonizar. Todos hemos escrito consultas que después nos dieron vergüenza ajena. Y sí, hay veces que las prisas, las entregas y los deadlines te llevan a empalmar un par de subconsultas “de emergencia” con un UNION sin ALL y a mirar para otro lado.

Pero eso no justifica dejar ese código en producción durante años como si fuera parte del mobiliario. Porque esa consulta, aunque solo se ejecute una vez al día, puede ser la responsable de saturar el servidor, disparar el DTU en Azure o arrastrar a otras aplicaciones con ella.

Aquí entra en juego lo que me gusta llamar “el coste invisible de la desidia técnica”. No se ve, no se presupuesta, pero se paga igual. En horas de soporte, en tiempo perdido, en usuarios frustrados, en reputación quemada.

De 10 minutos a 2 milisegundos (sin efectos especiales)

Otra historia real, por si alguien aún cree que exagero.

Me llama un cliente porque un proceso tarda más de 10 minutos. Revisamos el plan de ejecución y canta como un tenor: falta un índice. Literalmente lo está pidiendo a gritos. Un Clustered Index Scan sobre una tabla de 10 millones de registros con 5 campos varchar(max).

Creamos un índice sencillo sobre los dos campos que busca… y bajamos a 20 segundos. Bien, ¿no?

Pero no me conformé. Me di cuenta de que esos campos varchar(max) apenas se usaban y propuse moverlos a otra tabla. Un cambio mínimo de esquema, sin traumas. El resultado: la consulta se resuelve ahora en 2 milisegundos.

Sí, de más de diez minutos a dos milisegundos. Sin comprar licencias, sin añadir cores, sin tirar la casa por la ventana. Solo sentido común.

Consultas eficientes, bases de datos rentables

Optimizar una consulta no es hacer magia negra ni sacrificar cabras sobre el plan de ejecución. Es técnica, análisis y experiencia. A veces basta con añadir un índice. O con quitar un SELECT * y poner solo las columnas que necesitas. O con evitar ese cursor que llevas arrastrando desde hace 10 años como si fuera un trauma sin resolver.

Una consulta optimizada no sólo corre más rápido. Consume menos CPU. Bloquea menos. Permite que más usuarios trabajen al mismo tiempo. Y, lo más importante, reduce directamente tu coste de infraestructura y licenciamiento.

No es filosofía, son matemáticas puras, si una consulta tarda 500 ms y logra pasar a 50 ms, puedes hacer 10 veces más operaciones con los mismos recursos. ¿Te imaginas que tu equipo hiciera 10 veces más tareas al mismo sueldo? Eso es lo que hace una base de datos bien afinada.

El coste del «si funciona, no lo toques»

Una de las excusas más repetidas cuando se habla de optimizar es: “Pero si ya funciona, ¿para qué meternos ahí?” Pues por eso mismo. Porque ahora va, pero mal. Y cada día que pasa, cada usuario que se conecta, cada nuevo informe que se genera, lo hace un poco peor.

La deuda técnica no caduca. Se acumula. Y cuando salta, no lo hace con un error bonito y fácil de arreglar. Lo hace con un rendimiento desastroso en el peor momento: justo antes del cierre contable, durante el Black Friday o cuando el CEO quiere ver “cómo va todo” desde Power BI (todo casos reales).

Si optimizar parece caro, espera a ver cuánto cuesta no hacerlo.

Formación, experiencia y algo de mala leche

Sí, optimizar lleva tiempo. Requiere saber leer planes de ejecución, entender estadísticas, conocer cómo SQL Server decide qué estrategia usar y cuándo. Pero también requiere actitud. Ganas de escarbar. De no conformarse con que funcione “más o menos”.

Y eso, lamentablemente, no lo da ningún botón mágico ni el asistente del Management Studio. Hay que aprenderlo. O contratar a alguien que lo sepa.

Aquí es donde entra mi parte, claro. No solo como autor de este blog, sino también como consultor. Llevo más de 12 años viendo barbaridades que harían llorar al optimizador de consultas. Y ayudando a equipos a entender por qué sus bases de datos son lentas, y cómo hacer que dejen de serlo sin hipotecar la nube ni sacrificar fines de semana enteros en tareas de mantenimiento que no deberían existir.

Y sí, estoy escribiendo un libro

Mi libro se va a llamar “SQL SERVER: La NO guía práctica de optimización”. Y no será el típico tocho con recetas milagrosas genéricas que nadie es capaz de aplicar en producción. Será un manual honesto, directo y realista. Uno que explica cómo optimizar sin morir en el intento, desde la base y comprendiendo el funcionamiento interno del motor de base de datos. Porque ya tenemos demasiadas presentaciones bonitas que no dicen nada.

Y sí, también haré formación. Y talleres. Y sesiones donde, si hace falta, nos peleamos con los planes de ejecución hasta que canten. Porque se puede. Porque debe hacerse. Y porque seguir pagando licencias por no optimizar… simplemente no tiene sentido.

¿Quieres dejar de pagar por no saber? Hablemos.

Si después de leer esto has pensado en esa consulta que lleva años sin tocar, en ese informe que tarda 12 minutos, o en ese servidor que cada semana pide más cores como si fueran cromos… ya sabes lo que hay.

Puedes seguir ignorándolo, puedes aprender cómo optimizar SQL Server o puedes llamarme y lo miramos juntos.

Tu factura lo va a notar.

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

Page Split: el invitado indeseado en SQL Server

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

Qué demonios es un Page Split

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

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

Cuándo y por qué ocurre el Page Split

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

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

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

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

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

Cómo detectar Page Split

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

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

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

Cómo prevenir los Page Split

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

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

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

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

Casos reales y conclusiones claras

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

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

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

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

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

El problema del Reenvío de punteros en tablas heap

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

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

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

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

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

Cómo se genera un reenvío de punteros

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

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

Impacto en el rendimiento de los reenvíos de punteros

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

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

Cómo detectar el reenvío de punteros

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

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

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

¿Como elimino los reenvíos de punteros?

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

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

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

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

¿Hay situaciones donde el heap tenga sentido?

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

Conclusión

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

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

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

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

SORT_IN_TEMPDB: lo que de verdad hay que saber

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

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

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

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

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

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

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

Para ser claros:

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

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

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

Beneficios reales: cuándo SORT_IN_TEMPDB es útil

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

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

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

Impacto de SORT_IN_TEMPDB en operaciones online y con columnas LOB

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

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

Consideraciones finales y buenas prácticas

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

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

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

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

Conclusión

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

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

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