Variables DAX (VAR): cuándo aceleran y cuándo matan el rendimiento
En el desarrollo profesional de modelos de datos en Power BI, las variables (VAR) se introducen habitualmente como una herramienta para mejorar la legibilidad del código. Sin embargo, tratarlas simplemente como etiquetas para organizar fórmulas es un error de principiante que puede derivar en problemas de rendimiento severos o, peor aún, en resultados de negocio incorrectos. Como consultor, me encuentro constantemente con medidas que fallan no porque la lógica sea errónea, sino porque el desarrollador no ha entendido cómo y cuándo se evalúa una variable.
Una variable en DAX no funciona como una variable en un lenguaje de programación imperativo como Python o C#. En DAX, una variable es estrictamente una constante local dentro del ámbito de la expresión donde se define. Una vez que se evalúa, su valor queda congelado. Esta característica es su mayor virtud para el rendimiento DAX, pero también su trampa más peligrosa cuando se trabaja con funciones que modifican el contexto de filtro.
Para optimizar modelos complejos en sectores como el retail o la industria, donde manejamos millones de filas, entender la mecánica interna del motor VertiPaq respecto a las variables es obligatorio. No basta con que la medida devuelva el dato; debe hacerlo de la forma más eficiente posible para no saturar los recursos de la capacidad.
El mecanismo de Caching: por qué VAR acelera tus medidas
El principal beneficio de rendimiento de las variables es la eliminación de cálculos redundantes. En DAX, si invocas la misma medida o expresión varias veces dentro de una lógica compleja (por ejemplo, en un IF o un SWITCH), el motor de fórmulas podría verse obligado a reevaluar esa expresión en cada ocasión. Al asignar el resultado de esa expresión a una variable, obligas al motor a calcularlo una sola vez.
Este concepto se conoce como evaluación perezosa (lazy evaluation). La variable no se calcula en el momento en que se define, sino la primera vez que se solicita su valor en la sección RETURN. Una vez calculada, el resultado se almacena en memoria (cacheado) y se reutiliza en todas las menciones posteriores dentro de esa misma ejecución de la medida.
Consideremos el siguiente escenario de cálculo de crecimiento de ventas donde comparamos el importe actual con un objetivo, pero solo si el importe supera un umbral:
Ventas con Alerta =
VAR ImporteVentas = [Ventas Totales] -- Se evalúa una vez
VAR Umbral = 10000
RETURN
IF (
ImporteVentas > Umbral,
(ImporteVentas - Umbral) / Umbral,
0
)En este ejemplo, [Ventas Totales] se calcula una única vez. Si hubiéramos escrito la fórmula repitiendo la medida en cada parte del IF, el motor de fórmulas (Formula Engine) tendría que procesar la misma petición al motor de almacenamiento (Storage Engine) dos veces. En modelos con gran granularidad, este ahorro de ‘callbacks’ es la diferencia entre un informe fluido y uno que desespera al usuario.
El peligro oculto: Evaluación Temprana y pérdida de Contexto
El error más grave que veo en auditorías de proyectos es el uso de variables para almacenar medidas que luego se intentan filtrar mediante un CALCULATE. Para entender esto, debemos recordar los conceptos avanzados de DAX sobre Row Context y Filter Context.
Cuando asignas una medida a una variable, el valor se calcula en el contexto de filtro que existe en el momento de la definición. Si después intentas usar esa variable dentro de un CALCULATE, el nuevo filtro aplicado por CALCULATE no afectará al valor de la variable, porque esta ya es una constante.
Ejemplo de error de lógica
Imagina que quieres calcular las ventas del año anterior. Un desarrollador podría intentar esto:
Ventas Año Anterior ERROR =
VAR VentasActuales = [Ventas Totales]
RETURN
CALCULATE (
VentasActuales, -- ERROR: El valor ya está calculado y no cambiará
SAMEPERIODLASTYEAR('Calendario'[Fecha])
)En este caso, VentasActuales captura el valor de las ventas del periodo actual. El CALCULATE intenta desplazar el tiempo un año atrás, pero al recibir una variable (un valor estático) en lugar de una expresión o medida, el filtro de tiempo no tiene sobre qué actuar. El resultado será idéntico a las ventas actuales, pero con un coste de procesamiento innecesario. Para que el cálculo funcione, debes pasar la medida directamente al CALCULATE, permitiendo que la transición de contexto ocurra correctamente. Este es un caso donde el uso de VAR no solo es inútil, sino que destruye la lógica del informe.
Variables e Iteradores: El impacto en el Row Context
Otro escenario crítico ocurre dentro de funciones iteradoras como SUMX, AVERAGEX o FILTER. Aquí es fundamental entender las interacciones entre el Row Context y el Filter Context.
Si defines una variable fuera de un iterador, su valor es constante para todas las filas que recorra la función. Si la defines dentro, se recalculará para cada fila. La decisión de dónde colocar la VAR determina si el cálculo es escalable o si colapsará el motor de fórmulas.
| Ubicación de VAR | Comportamiento | Impacto en Rendimiento |
|---|---|---|
| Fuera del iterador | Se calcula una vez para todo el objeto visual. | Óptimo. Reduce carga en el motor de almacenamiento. |
| Dentro del iterador | Se calcula por cada fila de la tabla iterada. | Peligroso. Puede generar millones de evaluaciones si la tabla es grande. |
| Medida sin VAR | Invocación directa de la medida (Context Transition). | Variable. Depende de la complejidad de la medida y el volumen de datos. |
Como consultor, mi recomendación es siempre intentar extraer cualquier cálculo que no dependa de la fila actual fuera del iterador. Esto es especialmente relevante cuando trabajamos con funciones de tabla en DAX donde el coste de la materialización puede dispararse.
Medición con Server Timings en DAX Studio
No podemos hablar de rendimiento sin medir. Para validar si una variable está ayudando o perjudicando, usamos los Server Timings de DAX Studio. Al analizar el rastro (trace), debemos fijarnos en dos indicadores:
- FE (Formula Engine): Si el tiempo de FE es muy alto, es probable que estemos realizando demasiadas evaluaciones de variables dentro de iteradores o que no estemos aprovechando el cacheado.
- SE (Storage Engine) y SE Queries: Un número elevado de consultas al Storage Engine suele indicar que el motor no está pudiendo reutilizar resultados previos. Las variables bien utilizadas reducen el número de SE Queries.
En proyectos de gran volumen, como en el sector público o energía, he visto medidas que pasaban de 15 segundos a menos de 100ms simplemente moviendo una expresión de un
IFrepetitivo a una variable bien posicionada.
Errores frecuentes que destruyen el rendimiento
- Encapsular todo en variables por defecto: No todas las medidas necesitan variables. Si una expresión se usa solo una vez y no requiere claridad extra, añadir una
VARsolo añade ruido al plan de ejecución. - Variables para filtrar tablas: Usar
VAR MiTabla = FILTER(...)y luego usarMiTablaen múltiples sitios puede forzar la materialización de una tabla en memoria, consumiendo mucha RAM. A veces es preferible dejar que el motor optimice la consulta de tabla globalmente. - Confundir VAR con parámetros dinámicos: Recuerda que una variable no puede cambiar su valor basándose en una selección de segmentador que ocurra después de que la variable haya sido evaluada en el flujo de la medida.
Resumen de decisiones: ¿VAR o Medida directa?
La elección depende del objetivo. Usa variables para mejorar la legibilidad y para evitar el recalculo de la misma expresión. Evita las variables cuando necesites que una expresión reaccione a cambios de contexto aplicados por un CALCULATE posterior.
Si estás trabajando con modelos complejos, te recomiendo revisar también cómo el rendimiento en DirectQuery se ve afectado de forma mucho más agresiva por estas decisiones, ya que cada reevaluación se traduce en una consulta SQL enviada a la base de datos origen.
Preguntas frecuentes
¿Las variables consumen más memoria que las medidas directas?
Sí, mínimamente, ya que el valor debe almacenarse en la memoria temporal durante la ejecución de la consulta. En modelos con miles de millones de filas, materializar tablas grandes en variables puede agotar la memoria de la capacidad, por lo que debe hacerse con cautela.
¿Puedo usar una variable definida en una medida dentro de otra medida?
No. El ámbito (scope) de una variable es estrictamente local a la medida donde se define. Si necesitas reutilizar esa lógica en varias medidas, lo correcto es crear una medida base y llamarla, o usar una variable en cada una si el rendimiento lo justifica.
¿Es cierto que las variables impiden que DAX optimice el plan de consulta?
En versiones antiguas de Power BI había ciertas limitaciones, pero hoy el motor es extremadamente eficiente. El mayor riesgo no es la falta de optimización del motor, sino el error humano al ‘congelar’ un valor que debería ser dinámico mediante el uso incorrecto de la variable.
Checklist de optimización con variables
- ¿Se evalúa la expresión más de una vez en la medida? Usa
VAR. - ¿La lógica de la variable depende de un
CALCULATEque viene después? No usesVAR. - ¿La variable está dentro de un
SUMXu otro iterador? Asegúrate de que realmente necesite el contexto de fila. - ¿Has comprobado en DAX Studio si el número de SE Queries disminuye al usar la variable?
- ¿El nombre de la variable es descriptivo (ej.
VentasPrevias) en lugar de genérico (ej.V1)?

