I have created a dashboard on my Power BI Desktop which has Row level security implemented at the Database level.
When I try to access this dashboard as the Service account, the dashboard loads without any delays. But if I try to load it as any other user, it takes atleast 10-13 minutes to load it. Can someone please let me know what might be wrong?
I have tried reading the logs, but except for not being able to delete the expired logs, I do not really see an error. If someone can help,I would happily share the logs too privately?
Yes, I have checked on the DB side, but the queries are pretty fast(0-7 secs), plus there are just about 300,000 rows that are being fetched. The server has 128GB RAM and 16 core processor so I believe it's not an infrastructure issue too. The server just runs the SQL Server and the Power BI Report Server. Just FYI, I am using SQL Server 2016, Power BI Report Server August 2018 and we are not using SSAS, but a direct query.
With my service account, the dashboard loads instantly but not with the user account. Any help?
Below is the function I am using to implement the RLS.
CREATE FUNCTION [dbo].[func_PLAN_KEY_FILTER] ( @PLAN_KEY AS nvarchar(10) ) RETURNS TABLE WITH SCHEMABINDING AS RETURN SELECT 1 AS AccessRight WHERE @PLAN_KEY in (select a.PLAN_KEY from dbo.PROGRAMMES a inner join dbo.SECURITY_GROUP b on (a.GROUP_NAME = b.GROUP_NAME and b.LOGIN_NAME=system_user)) or system_user = 'ServerName\ServiceAcctname' ; GO
Do you believe any problem with the function? I think the service account bypasses the subquery.
So you're running two different queries (or query plans at least), one for regular users, one for the system account.
I would attach a profiler trace to the SQL backend and then run my front end as the service account and again as an end user (test user) and see what the differenece is in response time. If its fast as the system user then that suggests its not a rendering problem/issue but a data query issue. So assuming its slow when a user identity is passed in you could look at optimising the SQL
Looking at your function there are a couple of options.
You could create an index on your SECURITY_GROUP table that is keyed on the LOGIN_NAME and includes the GROUP_NAME, ideally you could cluster the table on those two columns but that may have issues if you have dupliacte rows. You may also need an index on your PROGRAMMES table on the GROUP_NAME including the PLAN_KEY. This would leave your function unchanged.
The other is to expand the whole thing. So turn your JOIN into an indexed VIEW (SCHEM_BINDING will be required) and then index the view on LOGIN_NAME and PLAN_KEY. You can then query the view using an EXISTS test which will be quicker. Something like
RETURN SELECT 1 AS AccessRight
WHERE EXISTS(SELECT 1
WHERE ( PLAN_KEY = @PLAN_KEY
AND LOGIN_NAME = system_user )
OR ( system_user = 'ServerName\ServiceAcctname' )
Do you have the same number of records in the table UAT and PROD?
If you are getting dupicate records this gives rise to two options. If there shoudln't be duplicate records then you have an issue upstream. If you are expecting duplcate records (this could be entirely fine of course) just create a regular NON CLUSTERED NON UNIQUE index on the columns instead. that way the duplicates won't matter.