Forum Discussion

Syndicate_Admin's avatar
Syndicate_Admin
Icon for Administrator rankAdministrator
10 months ago

Complexity RLS - ¡Ayuda, por favor!

¡Hola a todos, buenas noches! Necesito ayuda.

Recientemente, un usuario se puso en contacto diciendo que no podía usar uno de nuestros informes de Power BI. Al principio, me pareció extraño porque él era el único que reportaba problemas — todos los demás siempre han usado el informe normalmente. Es un informe limpio y bien optimizado siguiendo las mejores prácticas, así que no tenía sentido que solo él estuviera experimentando una lentitud tan extrema.

Hice una videollamada con él y confirmé el problema: el informe era prácticamente inutilizable, nada cargaba — y de nuevo, esto solo le pasaba a él. Aún peor, su lentitud consumía una enorme parte de mi capacidad de Fabric (estoy usando Embedded).

Empecé a investigar y descubrí que el problema estaba relacionado con los roles de RLS a los que se le asigna. Es gerente, así que pertenece a 25 roles diferentes en RLS, cada uno relacionado con un centro de costes. Actualmente, todos estos roles comparten la misma particularidad: cada norma RLS contiene dos códigos de centro de costes (uno antiguo y otro nuevo debido a una incorporación reciente). Por ejemplo:

  • Regla 1: Código 1 Antiguo O Código 1 Nuevo
  • … y así sucesivamente, hasta la regla 25.

Tras profundizar, noté que usar la sala de operaciones dentro de RLS perjudica significativamente el rendimiento — y parece que esto es exactamente lo que está rompiendo el informe para este usuario en concreto.

Probé a reemplazar OR por IN, pero el rendimiento era exactamente el mismo, sin ninguna mejora.

Mi pregunta es: ¿cómo puedo solucionar esto?

Pensé en cambiar a RLS dinámico usando USERNAME(). Sin embargo, surgieron dos problemas:

  1. Mantenimiento manual: Tendría que añadir y quitar constantemente a personas de esta mesa. Y se convertiría en una mesa enorme, ya que tenemos casi 1.000 empleados.
  2. Flexibilidad limitada: este enfoque funciona bien si solo necesito filtrar por centro de costes. Pero si necesito ocultar información de otra tabla (como "sección"), no creo que eso lo solucione (al menos hasta donde tengo entendido).

Preguntas:

  • ¿Alguien se ha enfrentado a algo similar?
  • ¿Existe una forma más eficiente de manejar varios roles complejos de RLS?
  • ¿Existe algún enfoque de modelado que evite esta caída de rendimiento, especialmente cuando un usuario pertenece a muchos roles RLS?

Cualquier ayuda será muy apreciada. ¡Gracias!

7 Replies

  • @PedroModa , cuando usas más de un rol, se tratan como condiciones de quirófano. Por lo tanto, necesitamos fusionar esos roles en un solo rol. Esto significa que debes combinar las condiciones en un solo rol si quieres que funcionen como condición AND

  • @PedroModa

    Gracias por ponerte en contacto con la comunidad del Foro Microsoft Fabric.

    @amitchandak Muchas gracias por tus aportaciones.

    Espero que la información proporcionada por los usuarios haya sido útil. Si aún tienes preguntas, no dudes en contactar con la comunidad.

  • @PedroModa,

    Espero que hoy ☺️❤️ estés bien

    Así que el problema probablemente sea la naturaleza aditiva del RLS cuando un usuario está asignado a múltiples roles; la pertenencia de tu usuario a 25 roles significa que Power BI debe combinar los filtros de todos ellos, lo que puede afectar gravemente al rendimiento (Las condiciones de OR dentro de cada regla complican aún más la lógica de filtrado)

    ¿Qué deberías hacer para resolvereste problema?... Aquí tienes un enfoque que puedes probar:

    Primer enfoque: (escalabilidad a largo plazo y para grandes organizaciones)

    • Crea una tabla central que enlace a los usuarios con sus centros de costes (puede ser una hoja de Excel, una tabla de base de datos o una lista de SharePoint que importes)

    • Uso un rol en el RLS con:

    [Username] = USERNAME()
    • Relaciona esta tabla con tu modelo de datos (los filtros se propagan automáticamente)

    Segundo enfoque (Solución rápida)

    • Fusiona 25 roles en 1-3 roles más amplios

    • Sustituir múltiples condiciones OR por una sola cláusula IN
    • Reducir la sobrecarga de filtrado aditivo

    Tercer enfoque

    • Combina RLS con filtros a nivel de página
    • Utiliza tablas resumen para obtener opiniones directivas
    • Implementa RLS con moderación

    Enfoque Final (Optimización Técnica)

    • Convertir códigos de texto en IDs enteros
    • Asegurar relaciones de una sola dirección

    • Usa tablas importadas en lugar de consulta directa
    si este post ayuda, agradecería un pulgar arriba y marcáralo como la solución para ayudar a los demás miembros a encontrarla más rápido.
  • @Ahmed-Elfeel

    ¡Muchas gracias! He visto algo de contenido sobre RLS dinámico, pero como nunca he trabajado con él antes, todavía tengo muchas preguntas... Una de ellas es, por ejemplo, si este gestor puede ver 25 centros de costes, ¿debería crear 25 filas en la tabla para este gestor? Por ejemplo:

    [email protected] | Centro de Costes 1

    [email protected] | Centro de Costes 2

    [email protected] | Centro de Costes 3

    ¿Y así sucesivamente?

    Y en casos en los que, por ejemplo, quería "ocultar" la información en una columna de UNA TABLA para esta regla:

    [email protected] | Centro de Costes 2

    la tabla de transacciones, por ejemplo, quiero ocultar la información para el proveedor 3...

    ¿Cómo podría hacerlo? Esto me resulta muy confuso. ¿Debería manejar esto en la propia tabla o debería hacerlo de forma más "detallada" dentro de Power BI?

    • Syndicate_Admin's avatar
      Syndicate_Admin
      Icon for Administrator rankAdministrator

      @PedroModa,

      Así que vamos a hacer preguntas una por 😅❤️ una

      Primera pregunta

      Si este gestor puede ver 25 centros de costes, ¿deberías crear 25 filas en la tabla para este gestor?

      • Así que sí, exactamente crea 25 filas separadas exactamente así:
      NombrePrincipalUsuarioPrincipalCostCenter
      [email protected]CC01
      [email protected]CC02
      [email protected]CC03
      [email protected]hasta alcanzar el máximo (25)

      Segunda pregunta

      ¿Cuál es la regla RLS para esta estructura?

      • Solo una regla sencilla en tu tabla de seguridad:
      [UserPrincipalName] = USERPRINCIPALNAME()

      Tercera pregunta

      ¿Cómo oculto a un proveedor en UNA sola tabla?

      • Así que para esta pregunta hay dos enfoques que podrías probar (los más cómodos para ti)\
      • La primera es añadir columnas de restricción a tu tabla principal de seguridad:
      NombrePrincipalUsuarioPrincipalCostCenterProveedor Restringido
      [email protected]CC02Supplier3

      Y la regla RLS para esto:

      AND(
          [CostCenter] IN VALUES(SecurityTable[CostCenter]),
          NOT([Supplier] IN VALUES(SecurityTable[RestrictedSupplier]))
      )
      • La segunda es crear tablas dedicadas para diferentes tipos de restricciones:
      NombrePrincipalUsuarioPrincipalProveedor Restringido
      [email protected]Supplier3

      Y la regla RLS para esta tabla es:

      // Main cost center access
      [CostCenter] IN VALUES(UserCostCenterAccess[CostCenter])
      
      // Supplier restrictions  
      NOT([Supplier] IN VALUES(UserSupplierRestrictions[RestrictedSupplier]))

      Finalmente

      • Siempre deberías manejar esto en las tablas RLS (no dentro de los gráficos de Power BI ni en DAX complejos).

      si este post ayuda, agradecería un pulgar arriba y marcáralo como la solución para ayudar a los demás miembros a encontrarla más rápido.
  • @Ahmed-Elfeel Muchísimas gracias por tu ayuda, las cosas empiezan a aclararse... ¿podrías ayudarme a pensar en cómo crearía esta regla?

    ¿Cómo crearía este RLS dinámico... La persona solo puede ver estos coli-codcusto (tabla dcentrodecusto (tabla diensao)) [COLI-CODCUSTO] == "1-1.000010" || [COLI-CODCUSTO] == "2-1.000012"

    en la tabla de Dfornecedor, esta regla [CODCFO] <> "0009789"

    en la tabla de dMedContratos (tabla de dimensiones), esta regla [Contrato] == "" (es decir, no quiero que aparezca nada de esta tabla)

    en la tabla fAjusteGerencial (tabla de hechos), esta regla VAR TI = RELATED(dCentrodeCusto[NOME]) IN {"TECNOLOGIA DA INFORMAÇÃO"} VAR ContaValida = NOT ( [Conta] IN { "Salários E Ordenados", "Hora Extra", "Encargos Trabalhistas", "Rescisões E Indenizações", "Prêmios E Bonificações" } ) RETURN (TI & ContaValida)

    en la tabla fBalance (tabla de hechos), esta regla VAR TI = RELACIONADO(dCentrodeCusto[NOME]) EN {"INFORMATION TECHNOLOGY"} VAR ValidAccount = NOT ( RELATED('dC Account'[Cuentas de Gestión]) IN { "Salarios y Salarios", "Horas Extra", "Cargos Laborales", "Despidos y Compensaciones", "Bonificaciones y Bonificaciones" } ) VAR Initial Excharge = NOT ( fBalance Sheet[COMPLEMENT2] = {"JOAO DA SILVA"} ) DECLARACIÓN (IT & & ValidAccount & Initial Gastense)

    en la tabla de fMedidas (tabla de hechos), esta regla [CODCCUSTO] <> "" en la tabla fPartida (tabla de hechos), esta regla [IDPARTIDA] == "195X195X195" (es decir, no quiero que vea nada)

    en la tabla fpitempartida (tabla de hechos), esta regla [CHAPA] == "195X195X195" (es decir, no quiero que vea nada)

    en En la tabla 'ftmovitens' (tabla de hechos), esta regla: 'VAR TI = RELATED(dCentrodeCusto[NOME]) IN {"TECNOLOGIA DA INFORMAÇÃO"} VAR ContaValida = NOT ( RELATED('dC Conta'[Contas Gerenciais]) IN { "Salários E Ordenados", "Hora Extra", "Encargos Trabalhistas", "Rescisões E Indenizações", "Prêmios E Bonificações" } ) RETURN (TI & & ContaValida)' Bonus" } ) RETURN (TI & ContaValida)

    y en la tabla fvalorçado (tabla de hechos), esta regla VAR TI = RELATED(dCentrodeCusto[NOME]) IN {"INFORMATION TECHNOLOGY"} VAR ContaValida = NOT ( [Conta] IN { "Salarios y Sueldos", "Horas Extra", "Cargos Laborales", "Despidos y Compensaciones", "Bonos y Bonificaciones" } ) RETORNO (TI & & ContaValida)

    • Syndicate_Admin's avatar
      Syndicate_Admin
      Icon for Administrator rankAdministrator

      @PedroModa,

      Por supuesto, aquí tienes una solución sencilla y clara paso a paso que puedes hacer:


      El primer paso es crear una tabla de seguridad llamada UserSecurity con todos los permisos de usuario así:

      UserEmailCostCenter
      [email protected]CC01
      [email protected]CC02
      Hasta que llegues al final (25)etcetera

      Segundo Paso es poner reglas RLS para cada tabla

      • dCentrodeCusto (dimensión):
      [COLI-CODCUSTO] IN VALUES(UserSecurity[CostCenter])
      • dProveedor (dimensión):
      NOT([CODCFO] IN VALUES(UserSecurity[RestrictedSupplier]))
      • dMedContratos (ocultar toda la mesa):
      [Contrato] IN {""}  // Or use FALSE() to hide everything
      • Ajuste fgestional (tabla de hechos):
      VAR TI = RELATED(dCentrodeCusto[NOME]) = "TECNOLOGIA DA INFORMACAO"
      VAR ValidAccount = NOT([Conta] IN { 
          "Salários E Ordenados", 
          "Hora Extra", 
          "Encargos Trabalhistas", 
          "Rescisões E Indenizações", 
          "Prêmios E Bonificações" 
      })
      RETURN TI && ValidAccount
      • fBalance (tabla de hechos):
      VAR TI = RELATED(dCentrodeCusto[NOME]) = "INFORMATION TECHNOLOGY"
      VAR ValidAccount = NOT(RELATED('dC Account'[Management Accounts]) IN { 
          "Salaries and Wages", 
          "Overtime", 
          "Labor Charges", 
          "Terminations and Compensation", 
          "Bonuses and Bonuses" 
      })
      VAR InitialExpense = NOT([COMPLEMENT2] = "JOAO DA SILVA")
      RETURN TI && ValidAccount && InitialExpense
      • fPartida and fpitempartida (hide everything):
      FALSE()  // Hides all rows
      • ftmovitens y fvalorcado (Usa la misma lógica que fAjusteGerencial pero adapta los nombres de las columnas)

      El tercer y último paso es añadir esto a la tabla de UserSecurity:

      [UserEmail] = USERPRINCIPALNAME()

      Espero que esto te resulte útil porque ha tardado demasiado y si necesitas ayuda, dímelo y perdón por la demora 🫡❤️