Skip to main content What is Dynamics 365? Guided tours Customer stories Try our products CRM ERP Sales Service Sales Customer Insights Customer Service Contact Center Field Service Supply Chain Management Commerce Finance Project Operations Human Resources Business Central Pricing Business application topics Training & certifications Migrate to the cloud Documentation Events Dynamics 365 Blog Product updates Onboarding and implementation Community Find a partner Software Development Companies Partner resources Microsoft Marketplace Product documentation Technical support On-premises product support Contact us Try for free Sign in
  • 4 min read

Analysis scripts for Performance Analyzer v2.0 Page 9


This is page 9 of 10 of the general performance analysis scripts online for the Performance Analyzer 2.0 tool. See page 1 for the introduction. Use the links in the table below to navigate between pages.

– General analysis
Analyse SQL Configuration Page 1
Analyse SQL Indexes Page 2
Analyse SQL Queries Page 3
Analyse Blocking Page 4
Baseline – benchmark queries Page 5
SSRS Report Analysis Page 6
Query Alerts Page 7
– AX Specific
Analyse AX Configuration Page 8
Analyse AX Indexes Page 9
Analyse AX Queries Page 10
/*********************************************************************
Copy one of the following links and press Ctrl-F and click FIND NEXT
in order to go to that section of the scripts
INDEX_SIZE_BY_CONFIG
INDEX_ACTIVITY_BY_CONFIG_KEY
INDEXES_IN_DB_NOT_IN_AOT
INDEXES_WITH_RECVERSION
TABLES_WITHOUT_UNIQUE_INDEX
********************************************************************/
— ————————————————————–

—   INDEX_SIZE_BY_CONFIG

— List TABLE sizes by AX Configuration Key

—————————————————————-
USE DynamicsPerf
SELECT ISV.DATABASE_NAME,
IDV.CONFIG_KEY_NAME,
SUM(CASE
WHEN ISV.INDEX_ID IN ( 0, 1 ) THEN PAGE_COUNT * 8 / 1024
END)   AS SIZEMB_DATA,
SUM(CASE
WHEN ISV.INDEX_ID > 1 THEN PAGE_COUNT * 8 / 1024
END)   AS SIZEMB_INDEXES,
COUNT(CASE
WHEN ISV.INDEX_ID > 1 THEN ISV.TABLE_NAME
END) AS NO_OF_INDEXES,
MAX(CASE
WHEN ( DATA_COMPRESSION > 0 )
AND ( ISV.INDEX_ID IN ( 0, 1 ) ) THEN ‘Y’
ELSE ‘N’
END)   AS DATA_COMPRESSED,
MAX(CASE
WHEN ( DATA_COMPRESSION > 0 )
AND ( ISV.INDEX_ID > 1 ) THEN ‘Y’
ELSE ‘N’
END)   AS INDEXES_COMPRESSED
FROM   INDEX_STATS_CURR_VW ISV
INNER JOIN AX_INDEX_DETAIL_VW IDV
ON ISV.SERVER_NAME = IDV.SERVER_NAME
AND ISV.DATABASE_NAME = IDV.DATABASE_NAME
AND ISV.TABLE_NAME = IDV.TABLE_NAME
AND ISV.INDEX_NAME = IDV.INDEX_NAME
–WHERE DATABASE_NAME = ‘XXXXXXXXXXXX’
— AND SERVER_NAME = ‘XXXXXXXX’
GROUP  BY ISV.SERVER_NAME,
ISV.DATABASE_NAME,
IDV.CONFIG_KEY_NAME
ORDER  BY 4 DESC
— ————————————————————–

—   INDEX_ACTIVITY_BY_CONFIG_KEY

— List READ/WRITE ratios by AX Configuration Key

—————————————————————-
SELECT ISV.DATABASE_NAME,
IDV.CONFIG_KEY_NAME,
CASE
WHEN ( SUM(USER_UPDATES + USER_SEEKS + USER_SCANS
+ USER_LOOKUPS) = 0 ) THEN NULL
ELSE ( CAST(SUM(USER_SEEKS + USER_SCANS + USER_LOOKUPS) AS DECIMAL) / CAST(SUM(USER_UPDATES + USER_SEEKS + USER_SCANS + USER_LOOKUPS) AS DECIMAL) )
END                                         AS ratioofreads,
CASE
WHEN ( SUM(USER_UPDATES + USER_SEEKS + USER_SCANS
+ USER_LOOKUPS) = 0 ) THEN NULL
ELSE ( CAST(SUM(USER_UPDATES) AS DECIMAL) / CAST(SUM(USER_UPDATES + USER_SEEKS + USER_SCANS + USER_LOOKUPS) AS DECIMAL) )
END                                         AS ratioofwrites,
SUM(USER_SEEKS + USER_SCANS + USER_LOOKUPS) AS totalreadoperations,
SUM(USER_UPDATES)                           AS totalwriteoperations,
SUM(USER_UPDATES + USER_SEEKS + USER_SCANS
+ USER_LOOKUPS)                         AS totaloperations
FROM   INDEX_STATS_CURR_VW ISV
INNER JOIN AX_INDEX_DETAIL_VW IDV
ON ISV.SERVER_NAME = IDV.SERVER_NAME
AND ISV.DATABASE_NAME = IDV.DATABASE_NAME
AND ISV.TABLE_NAME = IDV.TABLE_NAME
AND ISV.INDEX_NAME = IDV.INDEX_NAME
–WHERE DATABASE_NAME = ‘XXXXXXXXXXXX’
— AND SERVER_NAME = ‘XXXXXXXX’
GROUP  BY ISV.SERVER_NAME,
ISV.DATABASE_NAME,
IDV.CONFIG_KEY_NAME
–ORDER BY TotalOperations DESC
–ORDER BY TotalReadOperations DESC
ORDER  BY TotalWriteOperations DESC

—   INDEXES_IN_DB_NOT_IN_AOT

— ————————————————————–
— Find INDEXES that are not defined in the AOT

—  NOTE: Ignore System tables in this list.

— INDEXES should ALWAYS be defined in the AOT as synchronization
—   will remove them

— This also violates Dynamics AX Best Practices to not have an
— index defined in the AOT !!

— It’s ok to add an index for testing purposes on the SQL side
—  as long as you add it to the AOT once you know you are going
—  to keep the index
—————————————————————–
/****************************************************************
NOTE: If no data here, it could be correct OR, it could be
AOTEXPORT hasn’t been run from inside DynamicsAX or
INDEX_STATS data hasn’t collected yet
****************************************************************/
 /********************************************************************
The AX system tables and DEL_ tables will show in this list but are ok
*********************************************************************/
  SELECT *
FROM   INDEX_STATS_CURR_VW I
WHERE  INDEX_DESCRIPTION <> ‘HEAP’
AND INDEX_DESCRIPTION NOT LIKE ‘%FILTERED%’
AND NOT EXISTS (SELECT *
FROM   AX_INDEX_DETAIL_VW A
WHERE  A.SERVER_NAME = I.SERVER_NAME
AND A.DATABASE_NAME = I.DATABASE_NAME
AND A.TABLE_NAME = I.TABLE_NAME
AND A.INDEX_NAME = I.INDEX_NAME)
ORDER  BY SERVER_NAME,
DATABASE_NAME,
TABLE_NAME,
INDEX_NAME

—   INDEXES_WITH_RECVERSION

— ————————————————————–
— Find INDEXES that have RECVERSION in the Key or Included list
—  RECVERSION should NOT be a part of AX Indexes due to the
—  frequency of updates
—————————————————————–
  SELECT *
FROM   INDEX_STATS_CURR_VW I
WHERE  INDEX_KEYS LIKE ‘%RECVERSION%’
OR INCLUDED_COLUMNS LIKE ‘%RECVERSION%’
ORDER  BY SERVER_NAME,
DATABASE_NAME,
TABLE_NAME,
INDEX_NAME

—   TABLES_WITHOUT_UNIQUE_INDEX

— ————————————————————–
— Find tables that don’t have a unique key for AX record caching
— Can’t record cache w/o a unique index on the table
— You must define a unique index and use that filter in X++ code
—————————————————————–
 SELECT DISTINCT TABLE_NAME
FROM   INDEX_STATS_CURR_VW V1
WHERE  NOT EXISTS (SELECT ‘X’
FROM   INDEX_STATS_CURR_VW V2
WHERE  V2.SERVER_NAME = V1.SERVER_NAME
AND V2.DATABASE_NAME = V1.DATABASE_NAME
AND V1.TABLE_NAME = V2.TABLE_NAME
AND V2.INDEX_DESCRIPTION LIKE ‘%UNIQUE%’)
AND EXISTS (SELECT ‘X’
FROM   AX_TABLE_DETAIL AD
WHERE  AD.SERVER_NAME = V1.SERVER_NAME
AND AD.DATABASE_NAME = V1.DATABASE_NAME
AND AD.TABLE_NAME = V1.TABLE_NAME
AND AD.CACHE_LOOKUP IN ( ‘FOUND’, ‘FOUNDANDEMPTY’, ‘NOTINTTS’ ))
— TABLES YOU MIGHT CACHE LATER W/O UNIQUE INDEXES
SELECT DISTINCT TABLE_NAME
FROM   INDEX_STATS_CURR_VW V1
WHERE  NOT EXISTS (SELECT ‘X’
FROM   INDEX_STATS_CURR_VW V2
WHERE  V2.SERVER_NAME = V1.SERVER_NAME
AND V2.DATABASE_NAME = V1.DATABASE_NAME
AND V1.TABLE_NAME = V2.TABLE_NAME
AND V2.INDEX_DESCRIPTION LIKE ‘%UNIQUE%’)
AND EXISTS (SELECT ‘X’
FROM   AX_TABLE_DETAIL AD
WHERE  AD.SERVER_NAME = V1.SERVER_NAME
AND AD.DATABASE_NAME = V1.DATABASE_NAME
AND AD.TABLE_NAME = V1.TABLE_NAME
AND AD.CACHE_LOOKUP IN ( ‘NONE’ ))

Get started with Dynamics 365

Drive more efficiency, reduce costs, and create a hyperconnected business that links people, data, and processes across your organization—enabling every team to quickly adapt and innovate.