cloud

Funciones inline en SQL Server.

Si vienes del artículo anterior sobre procedimientos almacenados vs funciones, ya sabes que no todas las funciones son iguales ni todas son igual de bienvenidas en producción. Hoy vamos a entrar en el terreno de las que sí merecen un sitio en entornos serios, las funciones inline con valores de tabla, o inline TVF.

Porque sí, en SQL Server también hay funciones que se comportan bien, no matan el rendimiento y hasta pueden ser aliadas del optimizador. Eso sí, como siempre en SQL Server, hay letra pequeña. Y no es precisamente corta.

¿Qué es exactamente una función inline?

Una función inline con valores de tabla es un objeto de base de datos que devuelve una tabla como resultado, definida a partir de una única instrucción SELECT. La sintaxis es clara: no hay BEGIN…END, no hay tablas variables intermedias ni lógica procedural. Solo una expresión SELECT que define el resultado.

Un ejemplo básico:

La clave aquí está en el hecho de que la función no tiene cuerpo procedural. El RETURN devuelve directamente el SELECT, sin necesidad de declarar una variable tipo tabla ni usar bloques de control. Y eso le encanta al optimizador de consultas.

¿Por qué son tan diferentes del resto?

La principal ventaja de las funciones inline es que se expanden dentro del plan de ejecución de la consulta que las llama. Es decir, se comportan como si hubieras escrito el SELECT directamente en la consulta. Esto permite al optimizador generar un único plan coherente, hacer estimaciones de cardinalidad más precisas y aplicar filtros, joins o incluso reescrituras sin perder información.

No hay saltos de contexto, no hay opacidad. Todo se ve. Todo se puede optimizar. Todo fluye.

Esto contrasta brutalmente con las funciones escalares o las funciones con valores de tabla multisentencia, donde el optimizador pierde visibilidad, rompe el plan y acaba tirando de valores fijos o estimaciones aleatorias dignas de una quiniela.

En resumen, si necesitas encapsular lógica reutilizable que devuelve datos en forma de tabla y quieres mantener el rendimiento, la inline TVF es tu opción.

Buenas prácticas: lo que conviene hacer

Usar funciones inline no solo es una cuestión de sintaxis correcta. También hay que saber cómo diseñarlas para que sean eficientes, reutilizables y mantenibles. Aquí van algunas prácticas que realmente marcan la diferencia:

Primero, mantén la lógica centrada en una única operación clara. Si necesitas múltiples pasos, joins complejos, condiciones opcionales o lógica condicional, es probable que estés forzando demasiado el diseño y que deberías estar en un procedimiento o en una vista indexada (si tienes valor para ello).

Segundo, evita usar funciones inline como simples extractores de columnas. Si solo encapsulas un SELECT de una tabla sin añadir valor, estás generando una capa innecesaria que complica los planes y aporta poco. Úsalas cuando encapsules lógica real: filtrados, joins relevantes, condiciones específicas.

Tercero, documenta los parámetros con claridad. SQL Server no impone muchas restricciones, pero el que venga detrás (que probablemente seas tú dentro de seis meses) agradecerá saber qué espera exactamente cada parámetro y cómo afecta al resultado.

Por último, cuidado con los TOP y los ORDER BY. En funciones inline, el ORDER BY solo es válido dentro de un TOP… pero eso no significa que respete el orden en la consulta final. El optimizador puede decidir hacer lo que le venga en gana si no hay ORDER BY explícito en la consulta externa. Que no te sorprenda.

Casos de uso donde brillan

Hay escenarios donde una función inline brilla con luz propia. Uno de los más frecuentes: filtros complejos reutilizables. Supón que tienes una lógica de negocio que define qué pedidos se consideran “activos”, basada en múltiples condiciones, fechas, flags y columnas calculadas. Puedes encapsular esa lógica en una función inline y usarla como si fuera una subconsulta parametrizada.

Otro caso clásico: reportes o dashboards parametrizados. Si usas Power BI o cualquier herramienta de reporting que genere consultas dinámicas, puedes exponer funciones inline como “vistas parametrizadas” que reducen la complejidad del modelo y mejoran el mantenimiento.

Y por supuesto, también son útiles en procesos ETL que necesitan aplicar filtros reutilizables en múltiples pasos sin replicar lógica por todas partes.

Lo que NO debes hacer (aunque la tentación sea fuerte)

El hecho de que las funciones inline se comporten tan bien no significa que sean inmunes al mal diseño. De hecho, hay errores recurrentes que siguen apareciendo incluso entre DBAs con experiencia.

Uno muy común es usar funciones inline con un JOIN interno a una tabla de millones de filas sin tener en cuenta filtros exteriores. Como la función se expande, esa tabla puede aparecer en cada ejecución de forma inesperada y generar planes desastrosos.

Otro clásico, parámetros mal definidos o con valores opcionales que no se gestionan bien. SQL Server no permite parámetros opcionales en funciones, así que muchos intentan simularlo con NULL y condiciones tipo (@Param IS NULL OR Columna = @Param). Esto degrada los planes de ejecución, impide la indexación eficaz y rompe la estimación de cardinalidad. Una joya.

Y uno más, pensar que por ser una función inline, siempre va a ir rápido. Si la lógica interna es compleja, hace joins mal indexados o usa filtros poco selectivos, el plan puede seguir siendo un desastre. El que se vea no significa que sea bueno.

Comparación real: subconsulta vs función inline

Para los escépticos, vamos con un ejemplo sencillo.

Subconsulta tradicional

Esto se puede convertir en una función inline así:

Y luego usarla así:

¿La diferencia? En un entorno donde se reutiliza la lógica o se combina con otras condiciones, encapsularla en una función inline puede mejorar la legibilidad y el mantenimiento. Y con OUTER APPLY, se comporta como una subconsulta correlacionada, pero con visibilidad total en el plan.

Eso sí, no uses CROSS APPLY si no estás 100% seguro de que todas las combinaciones producirán resultado. Te lo recordarás a las 3 de la mañana.

Conclusión

Las funciones inline son una de esas herramientas que, bien usadas, te hacen la vida más fácil y el código más limpio. Mal usadas, solo complican las cosas sin aportar rendimiento ni claridad. No son la solución a todo, pero en el conjunto correcto de circunstancias, pueden sustituir a vistas, subconsultas o incluso procedimientos ligeros con mucha más flexibilidad.

Y sobre todo, te permiten encapsular lógica sin pagar el peaje que sí tienen otras funciones. Como siempre en SQL Server, no es solo cuestión de saber que existen, sino de saber cuándo y cómo usarlas. Porque sí, hay funciones buenas. Solo hay que reconocerlas.

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

Procedimientos almacenados y Funciones. SQL Server Basics

En SQL Server, hay ciertos conceptos que uno se encuentra tarde o temprano, tanto si empieza en el mundo de las bases de datos como si ya lleva un tiempo peleándose con entornos reales. Los procedimientos almacenados y las funciones son dos de ellos. Ambos permiten encapsular lógica en T-SQL, ambos pueden reutilizarse y ambos tienen su lugar. Pero no son lo mismo. Y tratarlos como si lo fueran es una fuente constante de confusión, errores y, en muchos casos, de mal rendimiento.

Este artículo no busca hacer una comparativa teórica más. Aquí vamos a ver en qué se diferencian realmente, cuándo conviene usar uno u otro, qué limitaciones tiene cada uno y qué errores son más comunes al trabajar con ellos. Si estás empezando con SQL Server, esto es una base fundamental. Y si ya llevas tiempo en el oficio, probablemente te encuentres con más de una práctica que conviene revisar.

Entendiendo la diferencia de base

Aunque en la teoría tanto procedimientos como funciones son objetos reutilizables de código T-SQL, en la práctica se comportan de forma muy distinta, sobre todo cuando hablamos de rendimiento, transaccionalidad, side effects y cómo se integran en una consulta.

Un procedimiento almacenado (Stored Procedure) es una secuencia de instrucciones T-SQL que se ejecuta como un bloque, puede devolver conjuntos de resultados, manejar errores, abrir y cerrar transacciones y, en general, actuar con bastante libertad. Como un EXEC.

Una función (Function), por otro lado, devuelve siempre un valor. Puede ser escalar (un solo valor) o con valores de tabla (inline o multisentencia). Se puede usar dentro de consultas como si fuera una expresión más. Y ahí empiezan los problemas.

Procedimientos almacenados: el «hombre para todo» de SQL Server

Los procedimientos almacenados llevan décadas siendo el núcleo de la lógica de negocio en la base de datos. Y aunque ahora todo el mundo quiere microservicios, orquestadores y que “la lógica viva fuera del SQL”, lo cierto es que los procedimientos siguen siendo una herramienta potentísima.

Pueden contener lógica compleja, trabajar con múltiples tablas, ejecutar DML (INSERT, UPDATE, DELETE), manejar cursores (sí, también hay gente que todavía los usa), y lo más importante: pueden tener efectos secundarios. De hecho, están pensados para eso.

Además, permiten declarar variables, manejar errores con TRY…CATCH, lanzar mensajes de error personalizados con RAISERROR o THROW, abrir transacciones, hacer ROLLBACK, hacer COMMIT, y todo esto mientras devuelven múltiples conjuntos de resultados si hace falta. No es elegante, pero es potente. Como un martillo neumático.

Funciones: elegantes, encapsuladas… y peligrosas

Las funciones escalar (Scalar-valued Functions, SVF) son atractivas. Parecen limpias, reusables, encapsulan lógica, se integran perfectamente en consultas… y luego te destruyen el rendimiento. Así, sin más.

El problema es que las SVF tradicionales se evalúan por cada fila de la consulta donde se usan. Y no, no se «inlinean» automáticamente (al menos no hasta SQL Server 2019 con INLINE y aún así, con limitaciones). Esto significa que si tienes una tabla con 10 millones de filas y usas una función escalar en el SELECT, estás ejecutando esa función… 10 millones de veces. Lo que se dice un plan brillante.

¿Y las funciones con valores de tabla? Aquí hay dos tipos: las inline TVF (Returns Table) y las multisentencia (Returns @Table con BEGIN…END). Las inline funcionan como una vista parametrizada, y eso está bien. Se comportan bien con el optimizador. Las multisentencia, en cambio, generan estimaciones de cardinalidad basura y planes horribles, porque el optimizador no tiene ni idea de lo que pasa dentro. Pero tú tampoco, así que estáis empatados.

Principales diferencias técnicas y funcionales

A nivel práctico, aquí van algunas diferencias que conviene no olvidar cuando te enfrentas al dilema función vs procedimiento:

  • Un procedimiento no se puede usar en un SELECT. No devuelve un valor directamente. Se ejecuta con EXEC.
  • Una función no puede tener side effects: no puede modificar datos (excepto si es una CLR, que eso es otra historia). Tampoco puede llamar a procedimientos, usar TRY…CATCH, ni realizar cambios en el estado de la base de datos.
  • Las funciones escalar tradicionales matan el paralelismo de las consultas y generan estimaciones de coste que parecen salidas de un generador aleatorio.
  • Los procedimientos pueden devolver múltiples conjuntos de resultados. Las funciones no.
  • El plan de ejecución de una función escalar no se ve dentro del plan de ejecución de la consulta (hasta SQL Server 2019 sin INLINE). Así que diagnosticar problemas es como hacer cirugía a ciegas.
  • Las funciones inline TVF sí se comportan bien en los planes de ejecución, porque se expanden como si fueran vistas. Y eso las hace usables en entornos serios.

Rendimiento: el gran elefante en la sala

Nadie crea funciones para que vayan lentas, pero casi todas acaban siéndolo. La causa es bien conocida: cada ejecución de una función escalar es un contexto separado. Si haces un SELECT que usa una función escalar sobre una tabla de millones de filas, estás pidiendo al motor que salte de contexto millones de veces. En vez de vectorizar el acceso, va fila a fila. Y sí, esto se nota.

En cambio, un procedimiento bien diseñado que trabaje con conjuntos puede procesar la misma lógica de forma mucho más eficiente. Y, sobre todo, puedes verlo venir en el plan de ejecución. No te lo oculta como si fuera un secreto de Estado.

Desde SQL Server 2019 se introdujo la inlining de funciones escalares (Scalar UDF Inlining) para funciones marcadas como SCHEMABINDING, sin lógica demasiado compleja y sin referencias a objetos no deterministas. Pero si la función tiene más de una variable o usa GETDATE(), ya estás fuera del juego.

Así que sí, puedes confiar en la mejora… pero más te vale leer la letra pequeña.

Casos de uso típicos (sin liarla)

Entonces, ¿cuándo usar uno y cuándo otro? Vamos al grano.

Usa procedimientos almacenados cuando necesitas lógica compleja, efectos secundarios, manejar errores, o quieres ejecutar bloques de operaciones que se comporten como transacciones. Ideal para llamadas desde aplicaciones, cargas ETL, tareas programadas, o cualquier situación donde el código no esté embebido en un SELECT.

Usa funciones inline con valores de tabla cuando necesites lógica reutilizable que se integre en consultas y no afecte negativamente al rendimiento. Si puedes expresarlo como una única SELECT y devolver una tabla sin BEGIN…END, adelante. Son tus amigas.

Evita funciones escalares tradicionales en cualquier sitio donde importe el rendimiento. O al menos, haz pruebas serias antes de meterlas en producción y que te explote todo el lunes por la mañana.

La trampa de la reutilización mal entendida

Una de las razones por las que se abusa de las funciones es el deseo de reutilizar lógica. Loable, pero mal ejecutado. Si una función contiene una consulta pesada que se va a ejecutar por cada fila, lo que tienes no es reutilización, es una trampa mortal.

A veces es mejor duplicar una expresión compleja dentro de dos consultas que encapsularla en una función escalar. Lo segundo parece más limpio, sí. Pero cuando empiecen las quejas de rendimiento, lo primero será más fácil de optimizar.

La clave está en saber cuándo sacrificar limpieza por control. Y no siempre la opción «bonita» es la correcta.

Conclusión

La diferencia entre procedimientos almacenados y funciones no es solo cuestión de sintaxis, sino de mentalidad. Si quieres control, potencia y libertad, usa procedimientos. Si necesitas expresividad dentro de consultas y sabes lo que estás haciendo, usa funciones inline. Pero si tu objetivo es reutilizar lógica sin entender el coste, acabarás con un sistema lento, opaco y lleno de problemas difíciles de rastrear.

Y si aún dudas, recuerda esto: un procedimiento bien hecho es un aliado; una función escalar mal usada es una bomba de relojería con apariencia de buen código. Tú decides qué prefieres tener en tu entorno.

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

Sargabilidad: el arte de no cabrear al optimizador

En SQL Server hay conceptos que separan al junior entusiasta del profesional que ha pasado noches enteras mirando planes de ejecución con el ceño fruncido. La sargabilidad es uno de ellos. Es esa palabra fea que no encontrarás en la RAE, pero que puede hacer que tus consultas vuelen… o se arrastren como un SELECT * sin índice por una tabla de 500 millones de filas.

Si llevas tiempo escribiendo T-SQL y nunca te has parado a pensar en si tus consultas son sargables o no, probablemente estés dejando rendimiento encima de la mesa. Y si trabajas con datos en serio, sabes que eso es inaceptable.

Qué es la sargabilidad (de verdad)

Sargabilidad viene del acrónimo SARG: Search ARGument-able. Es decir, que el motor de base de datos puede usar un índice para resolver la consulta de forma eficiente, sin escanear toda la tabla como si no hubiera mañana.

En SQL Server, una consulta es sargable cuando el predicado (la condición del WHERE, JOIN, HAVING, etc.) puede aprovechar un índice para filtrar datos directamente, sin tener que procesar fila por fila. En otras palabras: si el optimizador ve que puede usar un índice de forma directa, lo hará. Si no, te prepara un bonito Index Scan o Table Scan con aroma a cuello de botella.

Un ejemplo básico:

  • Sargable
  • No sargable

La diferencia es simple pero letal. En el primer caso, SQL Server puede usar un índice sobre la columna Nombre. En el segundo, como le has puesto una función encima, el optimizador no puede buscar directamente. Tiene que aplicar la función a cada fila y luego comparar. Y claro, eso escala tan bien como un script que hace DELETE sin WHERE.

Las funciones son el enemigo (cuando no sabes usarlas)

El caso anterior ilustra la regla de oro de la sargabilidad: si transformas la columna del predicado, estás condenado a un escaneo. Las funciones como LEFT, SUBSTRING, CONVERT, DATEDIFF, COALESCE o incluso simples operadores matemáticos, rompen la posibilidad de usar índices si se aplican sobre la columna.

Veamos otro clásico:

Esto es tan común como ineficiente. Lo correcto sería:

Y sí, es más feo. Pero el plan de ejecución será infinitamente más feliz. Y tú también, cuando no tengas que explicar por qué la consulta tarda 30 segundos con un índice que, supuestamente, estaba para eso.

ISNULL y COALESCE: los rompeíndices silenciosos

Uno de esos consejos que se repite como mantra en el mundo SQL es: «no uses funciones en columnas si quieres mantener la sargabilidad». Y, como todo buen mantra, es útil… pero no siempre cierto.

Tomemos el caso de ISNULL() y COALESCE(). Ambos permiten sustituir valores nulos por un valor por defecto. A efectos prácticos:

Parecen lo mismo, ¿no? Pero el optimizador de SQL Server no los trata igual. En la demo real que estás viendo, con un índice sobre DisplayName, la diferencia es cristalina.

ISNULL(): sorprendentemente sargable

Cuando usas ISNULL(DisplayName, ») = ‘Juan’, SQL Server aplica un Index Seek sin despeinarse. No le molesta la función. ¿Por qué? Porque el motor puede predecir exactamente lo que hace ISNULL() en este contexto: evalúa la columna, y si es NULL, la reemplaza por ». Como el predicado sigue siendo evaluable con un valor constante, puede derivarlo internamente como un predicado OR:

Y esa es la clave. Porque si escribes ese predicado tú directamente, es igual de eficiente y, de paso, más claro:

Mismo Index Seek. Misma eficiencia. Pero sin necesidad de funciones.

COALESCE(): aquí sí se complica

Ahora bien, si usas COALESCE(DisplayName, ») = ‘Juan’, el plan cambia. SQL Server ya no puede garantizar que la expresión sea determinista y sencilla de evaluar. Más que nada porque podría haber más de dos argumentos o que el orden de evaluación tuviera implicaciones semánticas. El resultado: Index Scan.

Así que no, ISNULL() y COALESCE() no son intercambiables en el WHERE (importante esto) cuando te importa el rendimiento. En teoría devuelven lo mismo, en la práctica afectan al plan de ejecución de formas distintas.

El OR: ese sospechoso habitual

Otro rompe-sargabilidad por excelencia es el OR, que puede obligar a escanear incluso si una de las condiciones sí es sargable. Imagina esto:

A menos que tengas un índice compuesto que cubra ambas columnas, el optimizador suele rendirse y tirar de escaneo. 

Así que ya sabes, si usas con frecuencia este tipo de filtros con OR asegurate de tener un índice compuesto bien creado.

Las columnas calculadas como tabla de salvación

A veces no hay forma humana de evitar una función sobre la columna. En esos casos, una solución decente (aunque no milagrosa) puede ser usar columnas calculadas indexadas. Si sabes que todo el mundo va a seguir escribiendo:

Puedes añadir una columna calculada persistente:

Y ahora sí, el predicado puede ser sargable, porque la función ya se calculó y se indexó. No es magia negra, es simplemente darle al optimizador algo que pueda usar sin pensar.

El caso especial del LIKE

El LIKE también puede ser sargable o no, dependiendo del patrón. Esta es sargable:

Esta no:

Si el comodín está al principio, el índice no sirve. No puede buscar «desde» ningún valor. El patrón tiene que permitir una búsqueda por rango, como ‘Juan%’ o incluso ‘J%’. Todo lo demás se traduce en escaneo.

Aquí no hay mucha escapatoria salvo usar Full-Text Search si de verdad necesitas búsquedas internas. O pensar si realmente necesitas buscar así, que a veces el problema no es técnico sino de requisitos mal planteados.

Cuando CONVERT(DATE, datetime) sí es sargable (sí, lo has leído bien)

Aunque llevamos un buen rato diciendo, con razón, que aplicar funciones sobre columnas rompe la sargabilidad, hay una excepción curiosa (y bastante útil) que merece su propio rincón en este artículo: la conversión de un datetime a DATE usando CONVERT o CAST.

Mira este caso donde CreationDate es un campo DATETIME:

Lo lógico sería pensar: “acabo de meterle una función a la columna del WHERE, esto va directo a un Index Scan, ¿verdad?”. Pues no. SQL Server es capaz de usar un Index Seek, incluso con esa conversión.

¿Por qué? Porque el motor es más listo de lo que a veces creemos. Internamente, evalúa que convertir un datetime a date reduce la precisión pero no cambia la semántica de ordenación, y por tanto puede generar un predicado de rango equivalente: desde 2010-06-05 00:00:00.000 hasta justo antes del 2010-06-06. Si hay un índice sobre la columna CreationDate, lo usa. Sin mirar atrás.

Ahora bien: esto no lo convierte en buena práctica universal.

Porque si haces esto:

El motor no te va a perdonar. Ahí sí hay Index Scan, porque ya estás forzando una conversión de tipo y de formato, y encima con ambigüedad regional. No hay forma de hacer un seek con eso.

Así que, como en todo, hay que ser precisos: CONVERT(DATE, datetime) es una excepción válida a la regla general, y SQL Server lo optimiza sin necesidad de escanear. Pero eso no quiere decir que cualquier CONVERT o CAST sea seguro.

JOINs y sargabilidad: el otro lado del desastre

La sargabilidad no solo importa en los WHERE. También afecta a los JOIN. Si haces cosas como:

Estás rompiendo toda posibilidad de usar un índice sobre B.Codigo. La función LEFT en el lado derecho del JOIN es como ponerle una venda en los ojos al optimizador. Y luego esperar que encuentre el camino solo. Mejor no.

Reescribe la lógica o introduce columnas auxiliares si hace falta, pero no pongas funciones en las condiciones de unión. A menos que tu hobby sea revisar planes de ejecución a las tres de la mañana.

Cómo detectar consultas no sargables

El mejor chivato es el plan de ejecución. Si ves Index Scan o Table Scan donde debería haber un Seek, es que tienes un problema de sargabilidad. También puedes usar las estadísticas de ejecución o SET STATISTICS IO ON para ver si se están leyendo más páginas de las que tocan.

Además, en SQL Server 2019+ puedes usar Intelligent Query Processing que, en algunos casos, mitiga errores de diseño como este… pero no es una excusa para escribir mal. Es un parche, no una solución.

Y si quieres una ayuda más visual, herramientas como SQL Sentry Plan Explorer o el propio SSMS con su plan gráfico te permiten ver rápidamente si estás tirando índices a la basura.

Scan no siempre es sinónimo de error (aunque duela admitirlo)

Otro punto clave: un Index Scan no siempre es el villano. Sí, lo hemos demonizado durante años, pero como todo DBA que ha peleado con planes de ejecución sabe, hay ocasiones en las que el escaneo es simplemente lo más eficiente.

Por ejemplo, si tu predicado devuelve un porcentaje alto de filas (pongamos, más del 25-30% de la tabla), al optimizador le puede salir más a cuenta ir a buscar los datos de una vez que intentar ser selectivo con un Seek y acabar con mil Key Lookup de regalo.

Lo mismo pasa cuando el índice cubre poco y el motor tendría que hacer lookups constantes para recoger el resto de columnas. En ese caso, el coste de los seeks individuales más los lookups supera con creces el coste de un buen escaneo. El optimizador no es tonto: elige lo que más conviene a nivel global de coste estimado.

Y aquí viene lo peligroso: si tu consulta está perfectamente escrita y sargable, pero el plan muestra un Scan, no asumas automáticamente que está mal. Revisa el plan, el número de filas estimadas, y el acceso a columnas. Lo que queremos evitar son los scans necesarios por diseño deficiente, no los que el motor elige porque son lo más razonable.

Conclusión

La sargabilidad no es un capricho del optimizador ni un tema menor. Es la base sobre la que se construye el rendimiento de cualquier sistema OLTP que merezca la pena. Ignorarla es como ir a una entrevista con el pantalón del pijama: técnicamente puedes, pero no deberías.

Escribir consultas sargables exige disciplina, conocimiento y cierta humildad. Hay que dejar de pensar en lo que «funciona» y empezar a pensar en lo que escala. Y cuando la diferencia entre una consulta sargable y otra que no lo es se mide en millones de lecturas lógicas… no hay excusa.

Así que la próxima vez que te enfrentes a un WHERE, piensa como el optimizador. No le pongas trabas, no le escondas la columna tras una función, y no le pidas milagros con predicados imposibles. Dale lo que necesita. Y si aún así se queja, entonces sí: culpemos al cardinality estimator.

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

¿Junior, Senior o “experto”? El teatrillo de los títulos

Pocas cosas generan más debate en una comunidad técnica que intentar definir qué significa ser junior, senior o experto. Bueno, quizás si un MERGE en producción está justificado… pero eso es otro tema del que ya hablaremos. Hoy vamos a hablar de galones o etiquetas, como queráis llamarlo, de cómo se reparten sin criterio y de por qué seguimos viendo ofertas para “junior con 3 años de experiencia” como si eso tuviera sentido alguno. Y es que para mí no lo tiene.

Junior no es sinónimo de becario

Vamos al grano. Un perfil junior no es alguien que no sepa nada. Es alguien que está empezando, sí, pero con una base ya formada, aunque sea mínima. No es un becario que necesita que le expliquen qué es un JOIN, pero tampoco es alguien que se siente cómodo optimizando una consulta compleja en un entorno con 3.000 conexiones simultáneas.

El problema es que muchas empresas confunden junior con “alguien barato que haga lo que un senior, pero por la mitad del sueldo”. Ahí vienen esas ofertas delirantes que piden de 1 a 3 años de experiencia, conocimiento de media docena de tecnologías, disponibilidad 24/7 y espíritu “proactivo”. Y todo eso, claro, a cambio de un salario que apenas supera al de prácticas. La trampa es evidente: quieren que hagas de todo, cobres poco y no te quejes. Si encima sonríes, mejor.

Pongamos un ejemplo concreto en nuestro terreno. El junior DBA es el encargado de realizar tareas totalmente procedimentadas sin salirse del guión. No se le puede exigir más. Es el que aún lanza un BACKUP DATABASE desde Management Studio, feliz de ver el mensaje de éxito, sin pensar en restaurarlo después para comprobar que realmente sirve. Y cuando falla, su primera reacción es: “pero si la copia terminó sin errores”. Es normal, es parte del camino, pero ahí está la diferencia.

Y ojo, no es que tener 2 o 3 años de experiencia te haga automáticamente senior. Ni mucho menos. Pero llamar junior a alguien que lleva 3 años comiéndose marrones de producción es no entender nada.

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.

Senior no es el junior que lleva más tiempo

La etiqueta de senior se ha convertido en una medalla que muchos se cuelgan demasiado pronto. Como si el calendario fuera el único juez válido. Y no. Ser senior implica haber visto cosas. Muchas cosas. Implica haber roto entornos, haberlos arreglado, haber tomado decisiones técnicas difíciles y haber lidiado con sus consecuencias. Ser capaz de evaluar el coste de una mala decisión antes de que reviente todo un domingo a las 3AM.

Un ejemplo de DBA senior: sabe que hacer un BACKUP no es suficiente, que hay que automatizar la validación de restauraciones, que conviene pensar en RPO y RTO antes de que el CTO lo pregunte, y que poner todos los backups en la misma SAN que la base de datos es tan útil como poner un extintor dentro del fuego. Además, cuando revisa un plan de ejecución, no se queda en el dibujito bonito: entiende qué decisiones está tomando el optimizador y sabe cuándo necesita una intervención manual.

No necesariamente dará la solución más elegante, pero sí una que funcione, que no comprometa la seguridad y que no mate el rendimiento del sistema. Porque un senior de verdad no solo sabe lo que hace, sino por qué lo hace. Y lo más importante: también sabe cuándo no hacerlo.

Las horas que se cuentan (o no se cuentan)

Aquí entra uno de los mitos más persistentes del sector: las dichosas 5.000 horas para ser senior, y las 10.000 para ser experto. Un concepto que hemos heredado casi como dogma y que muchos repiten como si fuera una verdad revelada. La famosa teoría de la práctica deliberada que, si alguna vez tuvo sentido en el contexto del violín o el ajedrez, se ha degenerado por completo en el mundo técnico.

Porque no, no basta con acumular horas para ser mejor. Si tu jornada consiste en encender el PC, abrir Management Studio y hacer lo mismo que hiciste ayer, anteayer y hace dos años, entonces lo que estás sumando no son horas de experiencia, sino horas de repetición. Y eso no te convierte en senior. Te convierte en alguien que sabe repetir procesos.

La práctica solo te lleva a la maestría cuando es desafiante, consciente y dirigida a mejorar. Si no hay errores, reflexión y aprendizaje, da igual cuántas horas pongas: seguirás en el mismo punto. He visto gente con 2.000 horas de trabajo real, bien guiado, bien sufrido y bien reflexionado, que vale más que otros con 15.000 horas de pulsar “Next” en el asistente de instalación.

Así que si alguien te dice que ya ha superado las 10.000 horas y por tanto es experto, pregúntale si puede explicarte qué hace exactamente el Cardinality Estimator en SQL Server o cómo se comporta el Query Store bajo una carga de lectura intensiva. Si pone cara de “eso no lo he tocado”, ya tienes la respuesta.

El mito del experto

Y luego están los expertos. Esa palabra maldita que ha perdido su valor en LinkedIn. Todo el mundo es “experto” en algo. Hay quienes se autodefinen expertos en SQL Server por haber creado 4 procedimientos almacenados, un par de vistas y haber leído la documentación de sp_whoisactive.

Aquí conviene diferenciar. Un experto funcional puede ser brillante operando un entorno concreto: conoce de memoria las rutinas de mantenimiento, maneja la seguridad de usuarios sin pestañear, y sabe cómo lidiar con el sistema en el día a día. Pero un experto técnico va un paso más allá: entiende las tripas, cómo funciona realmente el optimizador de consultas, cómo afectan las estadísticas al plan de ejecución, o por qué tu índice columnstore se viene abajo con ese patrón de inserción masiva.

Ambos perfiles son valiosos, pero no son lo mismo. Y lo que más abunda son los que creen que ser expertos funcionales les convierte en gurús universales. Y no es así.

Un experto de verdad también sabe cuándo callarse y escuchar. Porque cuanto más sabes, más consciente eres de lo que te queda por aprender. Así de simple.

¿Y los niveles intermedios?

Esto es algo que muchas organizaciones siguen sin entender. No todo el mundo entra en la categoría binaria de junior o senior. Hay una progresión natural, pero parece que da miedo nombrarla. Habría que hablar más de perfiles middle, semi-senior, advanced junior o como demonios queramos llamarlos, pero con definiciones claras y expectativas razonables.

Piénsalo en términos prácticos: un middle DBA ya ha gestionado despliegues, se ha peleado con deadlocks y sabe cómo monitorizar correctamente el entorno. No es alguien a quien quieras dejar al mando de una arquitectura distribuida en microservicios con réplicas en 4 regiones de Azure, pero tampoco es el novato que lanza un TRUNCATE en producción sin comprobar antes si hay backup.

La falta de estas categorías intermedias genera frustración. Los juniors que progresan se sienten estancados, y los seniors reales se queman porque tienen que apagar fuegos sin ayuda suficiente. Así que sí, necesitamos más niveles, pero sobre todo, más claridad y menos ego en las etiquetas.

La falacia de la experiencia acumulada

Este es otro punto clave. Tener 5 años de experiencia no significa nada si has pasado esos 5 años repitiendo el mismo trabajo que hacías el primer mes. Lo que tienes entonces no son 5 años de experiencia, sino 1 mes de experiencia repetido 60 veces. Y eso, lo siento, no es lo mismo.

La experiencia que cuenta es la que desafía, la que te obliga a aprender algo nuevo, a tomar decisiones, a equivocarte y mejorar. Si tu trabajo durante años ha sido ejecutar tareas repetitivas en una base de datos que ni siquiera entiendes, difícilmente puedes reclamar el título de senior.

Y sí, esto pasa más de lo que creemos. Entornos donde la innovación técnica es nula, donde todo se hace igual “porque siempre ha funcionado”, y donde el único cambio en cinco años ha sido cambiar de proveedor de café. Luego llega alguien con 2 años en un entorno exigente y en 6 meses demuestra más criterio que tú. Duele, pero es real.

Entonces, ¿cómo se pasa de junior a senior, y de senior a experto?

Pasar de junior a senior requiere algo más que cumplir con lo que te encargan durante mucho tiempo. Hacer backups, monitorizar jobs o ejecutar scripts que te da otro está bien, pero no es suficiente. El salto se produce cuando empiezas a cuestionar lo que haces, a entender por qué se hace de una manera y no de otra, y a proponer alternativas. Un junior ejecuta. Un senior piensa y decide. Ese cambio de chip no viene solo con las horas, viene con iniciativa y curiosidad técnica.

Si eres junior, ten iniciativa. Pégate a los senior y a los expertos, y que te expliquen lo que hacen y por qué. Cuando escales una incidencia, pregunta si puedes participar en la solución. No siempre la carga de trabajo lo va a permitir, pero cuando se pueda, la mayoría de los buenos profesionales estarán encantados de explicarte las cosas. Y créeme: no tengas miedo a preguntar. Nadie que merezca la pena tiene miedo a que aprendas y le quites el trabajo. Al contrario: queremos que mejores para que puedas hacer más cosas tú, y nosotros podamos vivir mejor. Porque un equipo fuerte se construye compartiendo, no guardando secretos como si fueran recetas de la abuela.

Luego está el paso de senior a experto. Aquí la cosa se complica, porque ya no se trata solo de resolver problemas en tu día a día, sino de anticiparlos. El experto sabe detectar patrones, entender tendencias y diseñar sistemas para que el fuego no llegue a prenderse. Y, además, sabe explicarlo a otros. Porque si no eres capaz de transmitir tu conocimiento, tu “expertise” se queda en ego. Un verdadero experto enseña, documenta, comparte. Ahí está parte de la diferencia.

¿Y hace falta dar un “extra” fuera del trabajo? Seamos claros: sí. Si te limitas a lo que ves en tu jornada laboral, avanzarás, pero despacio, muy despacio. El que llega más lejos es el que dedica tiempo a seguir estudiando, probando, rompiendo cosas en entornos de pruebas, leyendo papers, explorando novedades y enfrentándose a problemas que quizás no le toquen aún. La gente que crece es la que tiene curiosidad más allá de su checklist diario.

Ojo, tampoco se trata de romantizar las jornadas interminables de autoestudio como si fueran la única vía. No es sano ni sostenible trabajar 8 horas y estudiar otras 8. Pero la realidad es que los mejores profesionales que he conocido no apagaban el ordenador al terminar de trabajar y se olvidaban de todo. Seguían investigando, aunque fuera con un proyecto personal, un curso puntual o trasteando con la última versión de SQL Server en una máquina virtual.

Con todo esto, ¿qué valor tiene realmente una etiqueta?

La respuesta honesta es, depende de quién la use y para qué. Para muchos reclutadores es simplemente un filtro. Algunos managers se lo toman como una excusa para pagar menos. Para los técnicos, un arma de doble filo: puede abrirte puertas o hacer que te pidan milagros.

Pero hay algo que no cambia: los títulos no te salvan cuando el clúster se cae, cuando hay que restaurar un backup sin dormir o cuando el rendimiento se desploma sin motivo aparente. En esos momentos, solo cuenta lo que sabes hacer. Y lo que sabes transmitir.

Porque si algo he aprendido después de más de una década en este mundo, es que el respeto profesional no se gana con etiquetas, sino con hechos. Con decisiones acertadas bajo presión, con humildad para reconocer errores y, sobre todo, con ganas de seguir aprendiendo aunque tengas el CV lleno de palabras bonitas.

Y aquí viene la idea final: ser junior, senior o experto no es un estado fijo. Es un proceso continuo. Hoy puedes ser senior en SQL Server 2019, pero si dejas de aprender, mañana serás el que se quedó atascado en técnicas de hace una década. El mercado no espera a nadie, y el conocimiento tampoco.

Conclusión

Las etiquetas junior, senior y experto seguirán existiendo, pero lo importante es no tomárselas demasiado en serio. Sirven como orientación, sí, pero no son la verdad absoluta. Mucho menos en un sector donde el conocimiento evoluciona a la velocidad del rayo y donde lo que hoy dominas, mañana está obsoleto.

Así que, la próxima vez que alguien te diga que es senior porque ha superado las 5.000 horas, o experto por las 10.000, recuerda que también hay quien cree que el MERGE bien hecho existe. Nosotros no lo hemos visto. Pero tampoco hemos visto unicornios.

Publicado por Roberto Carrancio en Otros, 2 comentarios

El libro de SQL Server que estabas esperando

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

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

Portada Libro

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

Si quieres conseguirlo corre a Amazón.

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

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

Logo SoyDBA

Únete a la newsletter de SoyDBA

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

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

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

MERGE en SQL Server: La eterna promesa llena de bugs

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

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

El espejismo de la elegancia

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

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

El historial de errores no es opcional

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

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

Logo SoyDBA

Únete a la newsletter de SoyDBA

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

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

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

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

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

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

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

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

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

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

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

Cuando MERGE falla… ni siquiera sabes por qué

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

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

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

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

Triggers, locking y otras trampas técnicas de MERGE

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

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

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

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

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

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

¿Y entonces qué usamos? Alternativas a MERGE

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

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

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

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

¿Y qué pasa con el rendimiento?

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

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

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

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

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

¿Se puede usar MERGE con garantías?

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

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

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

Conclusión

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

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

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

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

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

¿Cuál es el problema que quieres resolver?

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

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

Cuando dos índices son un problema

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

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

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

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

El optimizador también se equivoca

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

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

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

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

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

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

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

La pregunta de Brent Ozar

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

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

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

Si no mides, no sabes si mejoras o empeoras

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

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

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

Diagnóstico antes de cirugía

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

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

Conclusión

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

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

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

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

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