D365 Trace Parser is a powerful tool for analyzing trace files. In my earlier articles, I explained how to capture a trace (D365 Trace – My D365 Journey) and how to load the generated file into D365 Trace Parser (Loading D365 Traces – My D365 Journey). Now that we have the trace file loaded and a session selected, let’s walk through how I analyze it.
There are many approaches to reviewing a trace, but I’ve found this method to be a strong starting point for troubleshooting performance issues. Trace Parser offers several tabs, each providing a different perspective on the data. Below, I’ll go through each tab and highlight how it can help during analysis.
D365 trace parser: Call Stack tab
When I start reviewing a trace, I usually begin with the X++ and SQL tabs to look for any obvious performance problems. If nothing stands out there, I switch over to the Call Stack tab.
The Call Stack tab is especially valuable because it reveals exactly where a process spends its time. By drilling into calls from this view, you can quickly see which methods or queries consume the most time and prioritize your investigation around them. Even when you can’t optimize performance further, the Call Stack provides insight into where time is spent.

To cut down on the noise, I start by clicking the Filter button and setting the Minimum Inclusive Duration field to 20 milliseconds. This step filters out any code execution or queries that run under 20 milliseconds. Most of these are routine system calls with little performance impact, so removing them highlights longer, more meaningful durations. Note that objects with a larger consumption of overall time will be highlighted in shades of red.

The screen capture above shows a great example of when the Call Stack tab becomes especially useful. In this case, I can see that creating seven supplementary sales lines takes between 4–7 seconds per line. By expanding each line creation, I can drill down further and pinpoint exactly where the process spends the most time within each line creation.

To simplify the review process, you can right-click a line and select “Create sub-trace for the node.” This action generates a new trace file within Trace Parser that isolates only the code and SQL for that specific call stack. With the noise removed, reviewing the X++ and SQL tabs becomes much easier, especially when analyzing the performance of a single line creation.
D365 trace parser: X++ tab
The X++ tab in D365 Trace Parser shows how long different code methods take to run. The bottom pane displays the actual code for the method you’ve selected. You can click through the call stack to see the logic behind each method.
To review customized code, load the trace file in an environment where that customization exists. Otherwise, Trace Parser will only show standard methods, hiding the ability to view custom logic that could impact performance.

The three main columns I focus on are:
Total Exclusive – This column measures only the time spent inside the specific method itself. Sorting by this value can highlight methods where code optimizations are possible. When I notice high exclusive duration for a single method, I dig into the method to check for loops, SQL queries, or costly operations.
Count – I usually start by sorting this column to spot unusually high counts of X++ method calls. While it’s normal for system calls to appear frequently, seeing custom or unexpected methods with high counts could point to a poorly written loop or incorrect logic.
Total Inclusive – This column shows the total time spent within a method plus any methods it calls. Since inclusive timing provides a broader picture, I often rely on the Call Stack tab for a clearer breakdown of method stacks.
Other useful functionality

Another helpful feature in the X++ tab is the Name filter field. You can use an asterisk (*) as a wildcard. For example, in the screenshot above, the filter limits the view to methods containing the text “sys.”
In practice, I often filter by the prefix used for customized code. Since performance issues usually stem from customizations, this approach lets me quickly narrow down the methods most likely to cause problems. From there, I can review the code behind each custom method. This serves as a secondary code review and confirms whether the logic is efficient.

Lastly, you can also use Trace Parser to help debug errors. All errors surface through the Info.Add class/method, and by locating this method in the trace, you can review the call stack that generated each Infolog message. This makes it much easier to trace an error back to the exact process or code path that triggered it.
For a deeper dive into how Info statements and the Infolog work, I recommend Peter Ramer’s article: D365 Infolog Messages – Dynamics 365 Musings.
D365 trace parser: SQL tab
The SQL tab displays all the SQL query statements generated during the captured process. If you enabled the “Capture SQL parameters” option when taking the trace, this tab will also show the parameters passed into each statement.
These parameters are especially useful for diagnosing unexpected behavior. For example, you might notice a query executing with a blank value in a field that should always contain data. This is an indication that something in the code is triggering the query incorrectly. Spotting details like this can save a lot of time when tracking down the root cause of performance issues.

Similar to the X++ tab, the SQL tab has a Call Stack section that displays the code responsible for generating each SQL query. This view helps you connect queries directly back to the methods that triggered them.
Note: In the screenshot above, one query took 36 seconds to execute, while the next longest query ran in just 22 milliseconds per call. That kind of gap clearly points to the slow query as a potential root cause of slowness.
The three main columns I focus on are:
- Count – Shows how many times a query was executed. A high count can indicate a potential loop problem. For example, I once saw hundreds of calls to the
findmethod on the warehouse table, even though fewer than 25 warehouses existed. That pointed to either a poorly written loop or a missed caching opportunity. - Inclusive Total – Displays the total time spent for all executions of a query. A high value isn’t always a red flag. Sometimes the query legitimately needs to run many times, but it does highlight where most of the time in a process is spent. Note that queries against a temp table may not be able to be aggregated, due to the unique identifier of the temp table object.
- Inclusive Average – Shows the average execution time for a single run of the query. This column is often more useful for spotting performance issues. If a query is called only once, like a form’s
executeQuery, a long runtime might be acceptable. Still, I usually review the top queries by average duration to check for missing indexes or potential optimizations.
Other useful functionality

You can right-click any query and select “Jump to Non-Aggregate View.” This option shows the raw, non-aggregated details behind the query so you can examine each execution individually. The same action also works on methods in the X++ tab, giving you a more detailed view of specific method calls.

From the Non-Aggregate View, you can see each individual execution of a query. This view is especially useful because it exposes the parameters used in each call. I’ve often noticed cases where the first execution of a query runs very slowly, while all subsequent executions are much faster. That difference can point to either specific parameters that make the initial call more expensive or caching that speeds up the later runs.
Additional ways to use the SQL tab to debug a process:
Sort by Statement Type – Sorting on the Name column groups queries by type (e.g., SELECT, INSERT, UPDATE). This makes it easier to see which tables are being read from, inserted into, or modified during the process.
Name Filter – Lets you search for queries using keywords. I often use this when debugging a process to quickly locate a specific query and then trace it back to its call stack.
D365 trace parser: Timeline and Overview tabs
The final two tabs in Trace Parser are Timeline and Overview. I don’t use these tabs often, but it’s worth noting their purpose:

The Timeline tab lists all events from the trace file in the order they were captured. While this can provide a sequential view of activity, I personally don’t find it very useful. The Call Stack tab provides a clearer picture of the sequence of events and how time is actually being spent, making it a more effective tool for performance analysis.

The Overview tab highlights the top five methods or queries that contribute the most to overall time within the trace. While this summary can be helpful at a glance, you can’t drill down into the methods directly from this tab. Because of that limitation, I generally find the X++ and SQL tabs far more useful for deeper analysis.
That said, I occasionally use the Overview tab as a quick sanity check. It helps confirm I’ve selected the correct session before diving into detailed tabs.
Conclusion
D365 Trace Parser is a powerful tool for reviewing trace files and understanding performance bottlenecks. Traces provide the clearest way to see exactly where time is spent within a specific process. With them, you can measure how much time individual code methods and SQL queries consume. This helps identify which areas deserve deeper investigation.
Each tab in Trace Parser offers unique benefits:
- Call Stack gives the clearest picture of where a process spends its time.
- X++ highlights code performance and potential issues in customizations.
- SQL helps uncover slow or repeated queries that may require optimization.
- Timeline and Overview provide high-level perspectives, though they are often less useful than the detailed tabs.
By combining insights across these views, you can troubleshoot performance issues more efficiently and focus on the changes that will have the biggest impact.
