This is on Dynamics AX 2012 R2, on SQL 2012 SP2.
The below query is executing every 5 minutes, and from the looks of it, returns the security/permissions for Management Reporter. The issue with the query is that it has a 25 sec execution time.
select T.USERKEY, T.NAME, T.ALIAS, T.DOMAIN, T.SECURITYID, MAX(T.GENERALLEDGERROLETYPE) GENERALLEDGERROLETYPE, T.COMPANYKEY, T.ISENABLED from ( select UI.RECID USERKEY, UI.NAME, UI.NETWORKALIAS ALIAS, UI.NETWORKDOMAIN DOMAIN, SID SECURITYID, CASE st.AOTNAME WHEN 'SysSecSecurityMaintain' THEN 5 WHEN 'LedgerBalanceSheetDimMaintain' THEN 4 WHEN 'LedgerFinancialJournalReportBGenerate' THEN 3 WHEN 'LedgerBalanceSheetDimPrintGenerate' THEN 3 WHEN 'LedgerViewFinancialStatement' THEN 2 END GENERALLEDGERROLETYPE, l.RECID COMPANYKEY, UI.ENABLE ISENABLED from [MicrosoftDynamicsAX]..USERINFO UI inner join [MicrosoftDynamicsAX]..SECURITYUSERROLE sur on UI.ID = sur.USER_ and UI.PARTITION = sur.PARTITION inner join [MicrosoftDynamicsAX_Model]..SECURITYROLE sr on sur.SECURITYROLE = sr.RECID and (GETUTCDATE() between sur.VALIDFROM and sur.VALIDTO OR (sur.VALIDFROM = '1/1/1900' and sur.VALIDTO = '1/1/1900')) inner join [MicrosoftDynamicsAX]..SECURITYUSERROLECONDITION c on c.SECURITYUSERROLE = sur.RECID and c.PARTITION = sur.PARTITION inner join (SELECT T1.SECURITYTASK AS SECURITYTASK ,T2.SECURITYROLE AS SECURITYROLE FROM [MicrosoftDynamicsAX_Model]..SECURITYROLETASKGRANT T1 CROSS JOIN [MicrosoftDynamicsAX_Model]..SECURITYROLEEXPLODEDGRAPH T2 WHERE (T1.SECURITYROLE = T2.SECURITYSUBROLE) GROUP BY T1.SECURITYTASK ,T2.SECURITYROLE) v on v.SECURITYROLE = sr.RECID inner join [MicrosoftDynamicsAX_Model]..SECURITYTASKEXPLODEDGRAPH g on g.SECURITYTASK = v.SECURITYTASK inner join [MicrosoftDynamicsAX_Model]..SECURITYTASK st on g.SECURITYSUBTASK = st.RECID inner join (Select l.RECID, l.PARTITION, CI.DATAAREA from [MicrosoftDynamicsAX]..LEDGER l inner hash join [MicrosoftDynamicsAX]..DIRPARTYTABLE CI on CI.PARTITION = l.PARTITION and l.PRIMARYFORLEGALENTITY = CI.RECID) l on UI.PARTITION = l.PARTITION and l.DATAAREA = c.DATAAREA Where UI.EXTERNALUSER = 0 AND UI.[SID] != '' AND UI.[ACCOUNTTYPE] = 0 AND sur.ASSIGNMENTSTATUS = 1 AND st.AOTNAME in ( 'SysSecSecurityMaintain', 'LedgerBalanceSheetDimMaintain', 'LedgerFinancialJournalReportBGenerate', 'LedgerBalanceSheetDimPrintGenerate', 'LedgerViewFinancialStatement') union all -- get users and their assigned tasks for all companies where the task hasn't been constrained to a company select UI.RECID USERKEY, UI.NAME, UI.NETWORKALIAS ALIAS, UI.NETWORKDOMAIN DOMAIN, SID SECURITYID, CASE st.AOTNAME WHEN 'SysSecSecurityMaintain' THEN 5 WHEN 'LedgerBalanceSheetDimMaintain' THEN 4 WHEN 'LedgerFinancialJournalReportBGenerate' THEN 3 WHEN 'LedgerBalanceSheetDimPrintGenerate' THEN 3 WHEN 'LedgerViewFinancialStatement' THEN 2 END GENERALLEDGERROLETYPE, l.RECID COMPANYKEY, UI.ENABLE ISENABLED from [MicrosoftDynamicsAX]..USERINFO UI inner join [MicrosoftDynamicsAX]..SECURITYUSERROLE sur on UI.ID = sur.USER_ and UI.PARTITION = sur.PARTITION inner join [MicrosoftDynamicsAX_Model]..SECURITYROLE sr on sur.SECURITYROLE = sr.RECID and (GETUTCDATE() between sur.VALIDFROM and sur.VALIDTO OR (sur.VALIDFROM = '1/1/1900' and sur.VALIDTO = '1/1/1900')) inner join (SELECT T1.SECURITYTASK AS SECURITYTASK ,T2.SECURITYROLE AS SECURITYROLE FROM [MicrosoftDynamicsAX_Model]..SECURITYROLETASKGRANT T1 CROSS JOIN [MicrosoftDynamicsAX_Model]..SECURITYROLEEXPLODEDGRAPH T2 WHERE (T1.SECURITYROLE = T2.SECURITYSUBROLE) GROUP BY T1.SECURITYTASK ,T2.SECURITYROLE) v on v.SECURITYROLE = sr.RECID inner join [MicrosoftDynamicsAX_Model]..SECURITYTASKEXPLODEDGRAPH g on g.SECURITYTASK = v.SECURITYTASK inner join [MicrosoftDynamicsAX_Model]..SECURITYTASK st on g.SECURITYSUBTASK = st.RECID inner join (Select l.RECID, l.PARTITION from [MicrosoftDynamicsAX]..LEDGER l inner hash join [MicrosoftDynamicsAX]..DIRPARTYTABLE CI on CI.PARTITION = l.PARTITION and l.PRIMARYFORLEGALENTITY = CI.RECID) l on UI.PARTITION = l.PARTITION Where UI.EXTERNALUSER = 0 AND UI.[SID] != '' AND UI.[ACCOUNTTYPE] = 0 AND sur.ASSIGNMENTSTATUS = 1 AND st.AOTNAME in ( 'LedgerBalanceSheetDimMaintain', 'LedgerFinancialJournalReportBGenerate', 'LedgerBalanceSheetDimPrintGenerate', 'LedgerViewFinancialStatement', 'SysSecSecurityMaintain') and not exists (select 1 from SECURITYUSERROLECONDITION c where c.SECURITYUSERROLE = sur.RECID and c.PARTITION = sur.PARTITION) union all -- get all administrators for all companies where the admin's aren't limited to specific companies select UI.RECID, UI.NAME, UI.NETWORKALIAS, UI.NETWORKDOMAIN, SID, 5 RoleType, l.RECID, UI.ENABLE ISENABLED from [MicrosoftDynamicsAX]..USERINFO UI inner join [MicrosoftDynamicsAX]..SECURITYUSERROLE sur on UI.ID = sur.USER_ and UI.PARTITION = sur.PARTITION inner join [MicrosoftDynamicsAX_Model]..SECURITYROLE sr on sr.RECID = sur.SECURITYROLE and (GETUTCDATE() between sur.VALIDFROM and sur.VALIDTO OR (sur.VALIDFROM = '1/1/1900' and sur.VALIDTO = '1/1/1900')) inner join (Select l.RECID, l.PARTITION from [MicrosoftDynamicsAX]..LEDGER l inner hash join [MicrosoftDynamicsAX]..DIRPARTYTABLE CI on CI.PARTITION = l.PARTITION and l.PRIMARYFORLEGALENTITY = CI.RECID) l on UI.PARTITION = l.PARTITION where UI.EXTERNALUSER = 0 AND UI.[SID] != '' AND UI.[ACCOUNTTYPE] = 0 AND sur.ASSIGNMENTSTATUS = 1 AND AOTNAME in ('SysSecSecurityAdministrator') ) T Group by T.USERKEY, T.NAME, T.ALIAS, T.DOMAIN, T.SECURITYID, T.COMPANYKEY, T.ISENABLED order by T.COMPANYKEY
I've narrowed the issue down to the middle query of the three, and specifically, the actual statement:
inner join (Select l.RECID, l.PARTITION from [MicrosoftDynamicsAX]..LEDGER l inner hash join [MicrosoftDynamicsAX]..DIRPARTYTABLE CI on CI.PARTITION = l.PARTITION and l.PRIMARYFORLEGALENTITY = CI.RECID) l on UI.PARTITION = l.PARTITION
If I remove the "hash" hint, the whole query completes in sub second. I can't see where I can modify the query, thus are there any options to improving this?
What I've done already:
- Index maintenance runs on all user databases weekly, and stats updated daily
- Ran AxUtil Optimize tool
- Manually updated stats