| |

Las 50 Medidas y Patrones DAX que Destruyen el Rendimiento en DirectQuery (y cómo evitarlos)

0
(0)

Cuando trabajas con Power BI en modo DirectQuery, la regla de oro es simple: delegar todo el procesamiento pesado a la base de datos de origen. El motor de Power BI está compuesto por dos piezas fundamentales: el Formula Engine (FE), que procesa la lógica DAX y las orquestaciones complejas, y el Storage Engine (SE), que en DirectQuery traduce las peticiones a consultas SQL nativas (T-SQL, Snowflake SQL, Databricks SQL, etc.).

El gran problema ocurre cuando escribes una fórmula DAX que el Storage Engine no puede traducir a SQL. En ese instante se produce el temido Callback to Engine (Callback al FE).

¿Qué es un Callback y por qué arruina tu reporte?

Un Callback ocurre cuando la base de datos no puede resolver una operación por sí sola. Para no fallar, el Formula Engine de Power BI interviene: ejecuta consultas SQL intermedias para extraer volúmenes masivos de datos sin resumir a la memoria RAM de Power BI y procesa la lógica fila por fila.

Las consecuencias en DirectQuery son devastadoras:

  • Múltiples consultas SQL secuenciales (en lugar de una sola consulta optimizada).
  • Consumo desmedido de memoria y CPU en el servidor o capacidad de Power BI.
  • Tiempos de carga que pasan de milisegundos a decenas de segundos o terminan en un timeout.

Para mantener la velocidad de tu modelo al máximo, hemos recopilado las 50 medidas, patrones y funciones DAX más problemáticas que activan Callbacks en DirectQuery, organizadas por categoría y con sus respectivas soluciones técnicas.

1. Transición de Contexto e Iteradores Pesados

La causa número uno de Callbacks es forzar al motor a evaluar medidas explícitas o explícitas dentro de bucles fila por fila.

1. SUMX llamando a una medida explícita

  • El patrón:SUMX(Ventas, [Ventas Netas])
  • Por qué genera Callback: Llamar a una medida dentro de un iterador activa una Transición de Contexto implícita (CALCULATE) por cada fila de la tabla. El FE no puede traducirlo a un GROUP BY con SUM simple y debe traer todas las filas a memoria.
  • Solución: Expande la lógica directamente en la expresión sin llamar a la medida: SUMX(Ventas, Ventas[Precio] * Ventas[Cantidad]) o utiliza agregaciones nativas como SUM(Ventas[Monto]).

2. AVERAGEX sobre medidas complejas

  • El patrón:AVERAGEX(Cliente, [Margen Ganancia])
  • Por qué genera Callback: Debe calcular la medida [Margen Ganancia] individualmente para cada cliente antes de promediar, ejecutando bucles de evaluación en el FE.
  • Solución: Reescribe usando agregaciones directas a nivel de columna o resuelve el margen en una vista SQL previa.

3. RANKX básico sobre medidas

  • El patrón:RANKX(ALL(Cliente[ClienteID]), [Total Ventas])
  • Por qué genera Callback: Para determinar el rango, el FE debe evaluar [Total Ventas] para cada cliente de la tabla. En SQL esto requeriría una función de ventana DENSE_RANK() OVER(...), pero si la medida contiene lógica compleja, el FE detiene la traducción nativa.
  • Solución: Simplifica la medida evaluada o calcula los rangos directamente en la capa de datos origen.

4. RANKX con múltiples criterios de ordenación

  • El patrón:RANKX(ALL(Productos), [Ventas], [Beneficio], DESC, Dense)
  • Por qué genera Callback: Añadir múltiples expresiones de desempate en RANKX sobrepasa la capacidad de generación de SQL en la mayoría de conectores DirectQuery.
  • Solución: Limita la ordenación a un único valor o precalcula la jerarquía en la base de datos.

5. CONCATENATEX sobre tablas de alta cardinalidad

  • El patrón:CONCATENATEX(Ventas, Ventas[Codigo], ", ")
  • Por qué genera Callback: La concatenación de cadenas en bucle rara vez se traduce de forma limpia a dialectos SQL (como STRING_AGG o GROUP_CONCAT), forzando al FE a traer las cadenas no agrupadas.
  • Solución: Aplica filtros estrictos para reducir la tabla a pocas filas antes de iterar, o realiza la concatenación en el origen.

6. MINX / MAXX sobre expresiones textuales o condicionales

  • El patrón:MAXX(Pedidos, Pedidos[Estado] & "-" & [MedidaCompleja])
  • Por qué genera Callback: Combinar iteración de texto con evaluación de medidas obliga al FE a parsear valores fila a fila para resolver nulos y ordenamiento de cadenas.
  • Solución: Separa la lógica de texto de la agregación numérica.

7. PRODUCTX o GEOMEANX

  • El patrón:PRODUCTX(Finanzas, 1 + Finanzas[Tasa])
  • Por qué genera Callback: La mayoría de los motores SQL relacionales no poseen una función de agregación nativa para productos multiplicativos o medias geométricas.
  • Solución: Utiliza transformaciones logarítmicas en SQL para convertir productos en sumas: $\exp(\sum \ln(x))$.

2. Abuso de CALCULATE y Filtros Ineficientes

8. CALCULATE dentro de un iterador

  • El patrón:SUMX(Tabla, CALCULATE(SUM(Tabla[Valor])))
  • Por qué genera Callback: Invocar CALCULATE en cada iteración invalida cualquier intento del motor de agrupar la consulta en SQL, generando miles de subconsultas individuales.
  • Solución: Elimina CALCULATE dentro de los iteradores.

9. Filtrar tablas completas con FILTER(Tabla, ...)

  • El patrón:CALCULATE([Ventas], FILTER(Ventas, Ventas[Monto] > 1000))
  • Por qué genera Callback:FILTER es un iterador que escanea toda la tabla Ventas en memoria. Al pasársela completa a CALCULATE, anula el optimizador de consultas de DirectQuery.
  • Solución: Filtra columnas directamente: CALCULATE([Ventas], Ventas[Monto] > 1000).

10. Uso de ALLSELECTED en medidas de porcentaje sobre el total

  • El patrón:DIVIDE([Ventas], CALCULATE([Ventas], ALLSELECTED(Ventas)))
  • Por qué genera Callback:ALLSELECTED necesita mantener y rastrear el contexto visual exacto de la interfaz en la memoria RAM del FE. Traducir este estado dinámico a una cláusula WHERE de SQL es prácticamente imposible para consultas complejas.
  • Solución: Utiliza ALL o ALLEXCEPT sobre columnas explícitas en lugar de ALLSELECTED.

11. Relaciones inactivas mediante USERELATIONSHIP

  • El patrón:CALCULATE([Ventas], USERELATIONSHIP(Ventas[FechaEnvio], Calendario[Fecha]))
  • Por qué genera Callback: Si el modelo físico en la base de datos no soporta fácilmente la reescritura de claves para el JOIN, el FE ejecutará dos consultas separadas y las combinará localmente.
  • Solución: Crea una segunda vista o tabla de dimensión en el origen para evitar activar relaciones dinámicamente.

12. Alteración de filtros con CROSSFILTER

  • El patrón:CALCULATE([Ventas], CROSSFILTER(Cliente[ID], Ventas[ClienteID], Both))
  • Por qué genera Callback: Forzar la bidireccionalidad en tiempo de ejecución satura la lógica del generador SQL de DirectQuery.
  • Solución: Define las relaciones bidireccionales en la base de datos mediante vistas relacionales estructuradas.

13. Expresiones OR (||) cruzando múltiples tablas

  • El patrón:CALCULATE([Ventas], Cliente[Pais] = "España" || Producto[Categoria] = "Bicis")
  • Por qué genera Callback: Cláusulas OR entre columnas de distintas tablas dificultan la generación de un JOIN eficiente en SQL, obligando al FE a resolver la intersección.
  • Solución: Divide la medida en dos expresiones simples y súmalas, o reescribe la condición usando UNION o variables.

3. Inteligencia de Tiempo (Time Intelligence)

Las funciones nativas de tiempo en DAX asumen un calendario continuo. Si no se cumplen ciertas condiciones, causan graves problemas en DirectQuery.

14. SAMEPERIODLASTYEAR aplicado sobre la tabla de hechos

  • El patrón:CALCULATE([Ventas], SAMEPERIODLASTYEAR(Ventas[Fecha]))
  • Por qué genera Callback: Evaluar variaciones temporales directamente sobre fechas de transacciones obliga al FE a procesar la continuidad de fechas fila por fila.
  • Solución: Aplica siempre las funciones de tiempo sobre una dimensión Calendario dedicada y marcada como Tabla de Fechas.

15. TOTALYTD con filtros adicionales integrados

  • El patrón:TOTALYTD([Ventas], Calendario[Fecha], Cliente[Region] = "Norte")
  • Por qué genera Callback: Añadir argumentos de filtro dentro de la función de tiempo impide la traducción a funciones de ventana SQL (SUM OVER).
  • Solución: Separa la lógica: CALCULATE(TOTALYTD([Ventas], Calendario[Fecha]), Cliente[Region] = "Norte").

16. DATEADD con vacíos en la dimensión calendario

  • El patrón:CALCULATE([Ventas], DATEADD(Calendario[Fecha], -1, MONTH))(con fechas faltantes)
  • Por qué genera Callback: Si la dimensión calendario no es 100% contigua en la base de datos de origen, el FE intentará rellenar los huecos en memoria antes de aplicar el desplazamiento.
  • Solución: Garatiza la integridad referencial y continuidad absoluta de la tabla de fechas en la base de datos.

17. CLOSINGBALANCEMONTH / CLOSINGBALANCEYEAR

  • El patrón:CLOSINGBALANCEMONTH(SUM(Inventario[Stock]), Calendario[Fecha])
  • Por qué genera Callback: Requieren localizar la última fecha con datos no vacíos, lo que se traduce en un patrón de búsqueda iterativo reincidente.
  • Solución: Reemplaza por un patrón explícito usando CALCULATE y LASTDATE.

18. PARALLELPERIOD con diferentes niveles de granularidad

  • El patrón:CALCULATE([Ventas], PARALLELPERIOD(Calendario[Fecha], -1, YEAR)) en un reporte con nivel de detalle diario.
  • Por qué genera Callback: Las diferencias de granularidad entre la visualización y la consulta generan discrepancias que el FE resuelve procesando conjuntos de datos intermedios.
  • Solución: Alinea la granularidad del cálculo con la de la consulta SQL subyacente.

19. Rangos dinámicos con DATESBETWEEN y MAX()

  • El patrón:CALCULATE([Ventas], DATESBETWEEN(Calendario[Fecha], [FechaInicio], MAX(Calendario[Fecha])))
  • Por qué genera Callback: Calcular los límites de fecha dinámicamente mediante medidas fuerza al FE a determinar los extremos antes de armar la consulta SQL.
  • Solución: Pasa fechas fijas o variables escalares prefijadas a DATESBETWEEN.

4. Manipulación de Cadenas de Texto y Búsquedas

20. SEARCH o FIND con control de errores

  • El patrón:SEARCH("PROMO", Cliente[Notas], 1, 0)
  • Por qué genera Callback: El motor DirectQuery no siempre puede traducir la captura de errores de búsqueda a funciones de posición de texto de SQL (CHARINDEX o POSITION), delegando la intercepción al FE.
  • Solución: Utiliza CONTAINSSTRING o maneja la lógica de texto en la capa SQL.

21. Funciones de Jerarquía Padre-Hijo (PATH, PATHCONTAINS)

  • El patrón:PATH(Empleado[ID], Empleado[JefeID])
  • Por qué genera Callback: Generar cadenas delimitadas por texto para representar jerarquías requiere recursividad, una operación no soportada nativamente por el traducidor estándar de DAX a SQL.
  • Solución: Aplica la técnica de «Aplanado de Jerarquías» (Parent-Child Unflattening) mediante consultas SQL en el origen (ETL).

22. Extracción de subcadenas con MID o SUBSTRING en medidas

  • El patrón:SUMX(Ventas, IF(MID(Ventas[Codigo], 2, 3) = "ABC", Ventas[Monto], 0))
  • Por qué genera Callback: Parsear texto dentro de medidas acumulativas obliga al FE a descargar las cadenas para procesarlas en RAM.
  • Solución: Extrae los caracteres en una columna persistida en la base de datos.

23. LOOKUPVALUE con múltiples condiciones

  • El patrón:LOOKUPVALUE(Precios[Valor], Precios[ID], Ventas[ID], Precios[Fecha], Ventas[Fecha])
  • Por qué genera Callback: Se traduce como un LEFT JOIN complejo con condiciones de búsqueda que, si no garantizan unicidad absoluta, activan verificaciones de seguridad en el FE.
  • Solución: Utiliza relaciones físicas entre las tablas del modelo en lugar de búsquedas virtuales.

24. Concatenación de claves dinámicas al vuelo

  • El patrón:CALCULATE([Ventas], Ventas[RegionID] & "-" & Ventas[Tipo] = "1-A")
  • Por qué genera Callback: Forzar al motor a concatenar dos columnas para filtrar por un resultado compuesto deshabilita el uso de índices en la base de datos de origen.
  • Solución: Crea la columna clave compuesta directamente en la base de datos de origen.

5. Lógica Condicional y Captura de Errores

25. Envolver cálculos con IFERROR o ISERROR

  • El patrón:IFERROR(SUM(Ventas[Monto]) / SUM(Ventas[Unidades]), 0)
  • Por qué genera Callback: Capturar errores obliga al Formula Engine a inspeccionar cada valor individual devuelto por la base de datos para prevenir excepciones de ejecución.
  • Solución: Utiliza la función DIVIDE(SUM(Ventas[Monto]), SUM(Ventas[Unidades]), 0), que está optimizada para evitar callbacks.

26. DIVIDE con expresiones complejas en el argumento alternativo

  • El patrón:DIVIDE([Ventas], [Meta], [MedidaDeRespaldoComplex])
  • Por qué genera Callback: Si el tercer argumento (valor si hay división por cero) contiene una medida compleja, el FE evaluará ambas ramas de forma preventiva.
  • Solución: Pasa constantes simples (como 0 o BLANK()) en el tercer argumento de DIVIDE.

27. SWITCH(TRUE(), ...) con condiciones heterogéneas

  • El patrón:SWITCH(TRUE(), [Ventas] > 1000, "Alto", [Clientes] < 10, "Bajo", "Medio")
  • Por qué genera Callback: Mezclar diferentes medidas y condiciones no homogéneas impide la conversión del SWITCH a una instrucción CASE WHEN limpia en SQL.
  • Solución: Homogeneíza las condiciones o evalúa columnas simples de la misma tabla.

28. Comprobar ISBLANK sobre medidas pesadas

  • El patrón:IF(ISBLANK([MedidaPesada]), 0, [MedidaPesada])
  • Por qué genera Callback: Este patrón calcula la medida dos veces: una para verificar si es nula y otra para devolver el valor, duplicando la carga sobre el FE.
  • Solución: Utiliza variables: VAR v = [MedidaPesada] RETURN IF(ISBLANK(v), 0, v).

29. COALESCE con tipos de datos o medidas mixtas

  • El patrón:COALESCE([Ventas], [MetaGlobal], 0)
  • Por qué genera Callback: Si alguna de las expresiones dentro de COALESCE genera un callback por sí misma, toda la función arrastrará al FE el procesamiento del resto de las ramas.
  • Solución: Asegúrate de que todas las expresiones pasadas a COALESCE sean traducibles a SQL simple.

6. Granularidad, Cardinalidad y Conteo Distinto

30. DISTINCTCOUNT sobre columnas calculadas o manipuladas

  • El patrón:DISTINCTCOUNT(FORMAT(Ventas[Fecha], "YYYY-MM"))
  • Por qué genera Callback: Modificar la columna dentro del conteo borra los índices nativos de la base de datos. El motor no puede aplicar COUNT(DISTINCT columna) en SQL.
  • Solución: Aplica DISTINCTCOUNT directamente sobre la columna original sin modificar.

31. COUNTROWS sobre tablas agregadas mediante SUMMARIZE

  • El patrón:COUNTROWS(SUMMARIZE(Ventas, Ventas[ClienteID], "Total", [Ventas]))
  • Por qué genera Callback: Crear una tabla resumida intermedia virtual para luego contar sus filas obliga al FE a materializar dicha tabla en RAM.
  • Solución: Usa DISTINCTCOUNT(Ventas[ClienteID]) o resuelve el resumen en la base de datos.

32. Cálculo de Mediana (MEDIAN / MEDIANX)

  • El patrón:MEDIAN(Ventas[Monto])
  • Por qué genera Callback: El cálculo de la mediana requiere ordenar todo el conjunto de datos y encontrar el elemento central. Muy pocos conectores DirectQuery traducen esto a SQL nativo.
  • Solución: Precalcula percentiles en el motor de datos de origen o utiliza aproximaciones cuando sea posible.

33. Percentiles (PERCENTILE.EXC / PERCENTILE.INC)

  • El patrón:PERCENTILE.INC(Ventas[Monto], 0.95)
  • Por qué genera Callback: Mismo problema que la mediana: los algoritmos estadísticos continuos suelen requerir procesamiento en memoria por parte del FE.
  • Solución: Calcula los percentiles en la capa de datos (ETL) o mediante procedimientos almacenados.

34. Desviación Estándar y Varianza (STDEV.S, VAR.S)

  • El patrón:STDEV.S(Ventas[Monto])
  • Por qué genera Callback: Requieren dos pasadas sobre los datos (calcular la media y luego la suma de las diferencias al cuadrado), lo cual DirectQuery suele dividir entre SQL y FE.
  • Solución: Descompón la fórmula algebraicamente usando sumas y sumas de cuadrados traducibles a SQL.

7. Tablas Virtuales y Relaciones Virtuales

35. Inyección masiva de valores con TREATAS

  • El patrón:CALCULATE([Ventas], TREATAS(ValoresSeleccionados, Tabla[Columna]))
  • Por qué genera Callback:TREATAS traduce los valores virtuales a una cláusula IN (...) en la consulta SQL. Si el número de elementos supera el límite admitido por el motor de base de datos, DirectQuery cae en Callback.
  • Solución: Limita el uso de TREATAS a conjuntos pequeños de datos o usa relaciones físicas.

36. Operaciones de Conjuntos (INTERSECT, EXCEPT)

  • El patrón:COUNTROWS(INTERSECT(VALUES(TablaA[ID]), VALUES(TablaB[ID])))
  • Por qué genera Callback: La comparación de tablas virtuales mediante teoría de conjuntos se procesa casi siempre dentro del Formula Engine.
  • Solución: Realiza las uniones o exclusiones en SQL mediante EXISTS, IN o JOIN.

37. Agregar columnas calculadas dentro de SUMMARIZE

  • El patrón:SUMMARIZE(Ventas, Cliente[Region], "Total", SUM(Ventas[Monto]))(Anti-patrón conocido)
  • Por qué genera Callback:SUMMARIZE no debe usarse para calcular extensiones de columna. Produce patrones de consulta ambiguos que terminan ejecutándose en el FE.
  • Solución: Utiliza la combinación estandarizada: ADDCOLUMNS(SUMMARIZE(Ventas, Cliente[Region]), "Total", [Ventas]) o SUMMARIZECOLUMNS.

38. ADDCOLUMNS iterando tablas virtuales de alta cardinalidad

  • El patrón:ADDCOLUMNS(ALL(Ventas[TransaccionID]), "Margen", [MedidaMargen])
  • Por qué genera Callback: Evaluar una medida para cada fila de una tabla virtual gigante genera miles de transiciones de contexto en memoria.
  • Solución: Reduce la cardinalidad de la tabla antes de aplicar ADDCOLUMNS.

39. NATURALINNERJOIN / NATURALLEFTOUTERJOIN

  • El patrón:NATURALINNERJOIN(TablaA, TablaB)
  • Por qué genera Callback: Combinar tablas en DAX sin relaciones físicas explícitas en el modelo exige que el FE descargue ambas tablas y haga el JOIN en RAM.
  • Solución: Establece la relación física en el modelo de datos de Power BI.

40. Productos cartesianos con CROSSJOIN o GENERATE

  • El patrón:CROSSJOIN(VALUES(Cliente[Ciudad]), VALUES(Producto[Categoria]))
  • Por qué genera Callback: Generar combinaciones masivas al vuelo agota los recursos del FE si la cardinalidad es media o alta.
  • Solución: Precalcula las combinaciones válidas en la base de datos de origen.

8. Conversión de Tipos y Formatos

41. Usar FORMAT dentro de medidas de agregación

  • El patrón:FORMAT(SUM(Ventas[Monto]), "$#,##0.00")
  • Por qué genera Callback:FORMAT convierte un valor numérico o de fecha en una cadena de texto (String). Esto destruye la capacidad de agregación del motor SQL.
  • Solución: Define el formato de la medida en el panel de Propiedades de la medida en Power BI Desktop, nunca dentro del código DAX.

42. Conversión explícita de tipos con VALUE

  • El patrón:SUMX(Ventas, VALUE(Ventas[CodigoNumText]))
  • Por qué genera Callback: Convertir texto a número sobre la marcha en una medida obliga a procesar cada registro en el FE para manejar posibles errores de conversión.
  • Solución: Cambia el tipo de datos de la columna directamente en la fuente de datos o en Power Query.

43. Integrar tablas estáticas DATATABLE con DirectQuery

  • El patrón:LOOKUPVALUE(TablaEstatica[Valor], TablaEstatica[ID], Ventas[ID])
  • Por qué genera Callback: Las tablas creadas con DATATABLE viven exclusivamente en el FE. Cruzar datos de DirectQuery con tablas internas requiere que el FE realice la fusión localmente.
  • Solución: Inserta las tablas maestras o paramétricas directamente en la base de datos de origen.

44. Uso de EARLIER / EARLIEST

  • El patrón:SUMX(Tabla, IF(Tabla[Valor] > EARLIER(Tabla[Valor]), 1, 0))
  • Por qué genera Callback: Mantiene múltiples contextos de fila anidados simultáneamente en el FE, creando bucles de complejidad $O(n^2)$.
  • Solución: Reemplaza por variables (VAR) o resuelve el cálculo mediante funciones analíticas en SQL.

9. Patrones Avanzados de Semi-Agregación

45. Búsqueda del último estado conocido con LASTNONBLANK

  • El patrón:CALCULATE(SUM(Stock[Cantidad]), LASTNONBLANK(Calendario[Fecha], [TotalStock]))
  • Por qué genera Callback:LASTNONBLANK es un iterador que escanea las fechas hacia atrás, evaluando la expresión en cada paso hasta encontrar un valor no nulo.
  • Solución: Utiliza filtros Top 1 sobre la fecha máxima o resuelve el inventario con tablas de instantáneas (snapshot tables) en el origen.

46. Captura del primer valor con FIRSTNONBLANK

  • El patrón:CALCULATE([Medida], FIRSTNONBLANK(Calendario[Fecha], [Medida]))
  • Por qué genera Callback: Mismo comportamiento iterativo de escaneo secuencial en memoria RAM que LASTNONBLANK.
  • Solución: Reemplaza por patrones explícitos con CALCULATE y MIN.

47. Conversión de divisas dinámica fila a fila

  • El patrón:SUMX(Ventas, Ventas[Monto] * LOOKUPVALUE(Tasas[Factor], Tasas[Fecha], Ventas[Fecha]))
  • Por qué genera Callback: Buscar una tasa de cambio correspondiente a la fecha de cada transacción mediante iteración causa miles de búsquedas individuales en el FE.
  • Solución: Une la tabla de ventas con la tabla de tasas de cambio directamente en la base de datos mediante un LEFT JOIN.

48. Aging dinámico o cálculo de antigüedad de saldos

  • El patrón:SUMX(Facturas, IF(DATEDIFF(Facturas[Fecha], TODAY(), DAY) > 30, Facturas[Monto], 0))
  • Por qué genera Callback: Comparar la fecha actual con la fecha de cada factura dentro de un iterador ejecuta llamadas constantes a funciones de sistema en memoria.
  • Solución: Calcula los días de antigüedad en una vista de la base de datos o crea rangos de antigüedad precalculados.

49. Promedios ponderados con dividendo dinámico

  • El patrón:SUMX(Ventas, Ventas[Monto] * (Ventas[Peso] / CALCULATE(SUM(Ventas[Peso]), ALL(Ventas))))
  • Por qué genera Callback: La transición de contexto obligada dentro del divisor en cada paso de la iteración destruye la vectorización de la consulta.
  • Solución: Calcula el peso total en una variable previa o resuelve la ponderación directamente en la base de datos.

50. Prorrateo dinámico de presupuestos (Disaggregation)

  • El patrón:SUMX(Calendario, [PresupuestoMensual] / COUNTROWS(DATESBETWEEN(...)))
  • Por qué genera Callback: Distribuir una cifra de alto nivel (como un presupuesto mensual) a nivel diario comparando proporciones dentro de un iterador fuerza al FE a procesar toda la matriz de distribución.
  • Solución: Asigna el presupuesto a nivel diario mediante un proceso de ETL previo en la base de datos.

Lista de Verificación: Diagnóstico y Optimización en DirectQuery

Para asegurar que tus fórmulas DAX no generen Callbacks en producción:

  1. Utiliza DAX Studio: Conecta DAX Studio a tu modelo, activa el Server Timings y ejecuta tu medida. Revisa la columna FE Benchmark / Callbacks. Si ves eventos CallbackDataID, tienes código DAX que no se está traduciendo a SQL.
  2. Revisa la consulta SQL generada: Si la consulta enviada a la base de datos contiene cláusulas excesivamente largas o si se ejecutan docenas de consultas SQL pequeñas para una sola visualización, hay un iterador generando callbacks.
  3. Mueve la complejidad al origen: DirectQuery está diseñado para fuentes de datos potentes (Snowflake, SQL Server, Databricks, BigQuery). Todo lo que sea limpiado de texto, jerarquías, conversiones de tipo o acumulados debe resolverse en la capa de datos (SQL/ETL), nunca en DAX.

¿De cuánta utilidad te ha parecido este contenido?

¡Haz clic en una estrella para puntuarlo!

Puntuación media 0 / 5. Recuento de votos: 0

Hasta ahora, ¡no hay votos!. Sé el primero en puntuar este contenido.

Publicaciones Similares

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *