web
You’re offline. This is a read only version of the page.
close
Skip to main content
Community site session details

Community site session details

Session Id :
Finance | Project Operations, Human Resources, ...
Suggested answer

When to use inMemory or TmpDB when building reports?

(0) ShareShare
ReportReport
Posted on by 465

Hi,

Does using these tables depend on the number of columns or number of rows?

So i created a tmp table with about 12 fields. But the result of the report might return maybe 100 records.

So should i use inMemory because i'm using 12 columns

Or should i use tmpDB because 100 records might be returned? Or is 100 records considered small and i should still use inMemory

  • Or for example if a report should return all customers in the system (maybe just few fields about the customer) i'm assuiming thr number of customers is very large.. So should we use in this case tmpDb or inMemory
I have the same question (0)
  • Suggested answer
    ergun sahin Profile Picture
    8,824 Moderator on at
    RE: When to use inMemory or TmpDB when building reports?

    community.dynamics.com/.../tempdb-and-in-memory-table-type-in-d365fo

    14-dynamics365.com/.../

  • D365FO user Profile Picture
    465 on at
    RE: When to use inMemory or TmpDB when building reports?

    Hi Ergun,

    Thanks for the article. But based on what i read. Currently my report takes about 7 min to run 87 pages

    I'm using inMemory table any my RDP class extends SSRS base provider

    So in this case would using tmpDB make it faster?

    The article said if more than 1000 records use tmpDB and my number is close.

    Or how can i make it faster?

  • Suggested answer
    nmaenpaa Profile Picture
    101,160 Moderator on at
    RE: When to use inMemory or TmpDB when building reports?

    I think you need to analyze the report execution to find out where the execution time is spent.

    Maybe you knew this already, but you can test tmpDB/InMemory yourself to find out if it helps or not. Please share the results with us!

  • D365FO user Profile Picture
    465 on at
    RE: When to use inMemory or TmpDB when building reports?

    Hi Nikolas,

    How can i analyze the report execution?

    And the report took 7 min for 87 was not in my dev machine, it was in a test environment. So maybe i need to copy the data to my dev machine to switch to tempDB and test. But in general do you know if switching to temp db will make it faster? Also what other things i can enhance to make it faster?

  • Suggested answer
    Sheikh Sohail Profile Picture
    6,125 on at
    RE: When to use inMemory or TmpDB when building reports?

    Hi

    Despite both being temporary type tables.

    TempDB

    You can use TempDB Table the SSRS report with a large amount of data without losing performance.

    TempDB tables can be used in Joins with the other temp table or regular table.

    Memory Table

    Slow performance with the huge number of records.

    couldn't use the inMemory table in the query with a join.

    Hope I addressed your question properly.

  • Suggested answer
    nmaenpaa Profile Picture
    101,160 Moderator on at
    RE: When to use inMemory or TmpDB when building reports?

    There are many ways how you can investigate the performance. I recommend to search the web for finding information about the topic. 

    Anyway just some very first quick things to try.

    1. Comment out the line(s) of code that actually insert in the temp table. Compare execution time to the original code. Now the report will be empty but you will see how much of the time is spent retrieving the data that you will insert to the temp table. 
    2. Change temp table type between TempDB and InMemory
    3. Capture trace to find what in the data retrieval part takes time
    4. Analyze the code that retrieves data befofe inserting into temp table. Perhaps you have nested loops, or you use non-indexed fields as filtering criteria

    Please let us know the results for all four, then we can comment more. Thanks! 

  • D365FO user Profile Picture
    465 on at
    RE: When to use inMemory or TmpDB when building reports?

    Hi Nikolaos,

    So we copied the data from Perf environment to my dev machine. There are 1024 records (82 pages)

    I ran the report and used my mobile stop watch, it took the report to appear  5.16  minutes (i'm using in memory tmp table) I'm not sure how it took more in perf environment, which was about 7.5 minutes).

    Here's my query when I run the report:(please not that the deviceStatus condition is from the query itself. However, for the custAccount and InventLocationId then it's from the contract parameters)

    query: 
    SELECT Table1.Id, Table1.PurchOrderFormNum, Table1.Name, Table1.CustAccount
    , TableX.DeviceId, DeviceStatus, PickupLocationId, PickupDate, ReturnDate, TransId, TableX.ItemId
    ,TableX.DeviceName,
     TableX.dataAreaId, TableX.Id, Qty, TableX.JobSiteId, TableX.ClassId, TableX.ModelId
     ,TableY.JobSiteId
     ,lpa1.Address
     ,lpa2.Address
    FROM Table1
    
    JOIN TableX ON Table1.Id= TableX.Id
    
    full OUTER JOIN  TableY ON TableX.JobSiteId = TableY.JobSiteId
    full OUTER JOIN   LogisticsPostalAddress lpa1 ON TableY.DeliveryPostalAddress = lpa1.RecId
    full OUTER JOIN   LogisticsPostalAddress lpa2 ON Table1.DeliveryPostalAddress = lpa2.RecId
      WHERE ((Table1.CustAccount = N'xxx')) AND ((InventLocationId = N'1111')) AND ((DeviceStatus = 55 OR DeviceStatus = 56 OR DeviceStatus = 40)) 

    Now i'm following your instructions:


    1. I commented out  the insert line of code and it took 15 seconds (1 page, no records)

    Q1: Any problem with this?

    2. I changed to tempDB now (with insert line is not commented out) and it now took using mo mobile stop watch  5.35 minutes which is slower than in memory by 10 seconds

    Q2: btw now the records are 1024 but they might be more, so should I switch to tmpDB anyways, is it considered faster? but how come it was slower than in memory?

    I switched back to in Memory now

    3. you asked me to capture trace 

    I noticed two sessions,

    one session, where it contains my query and  process report
    pastedimage1632853625747v2.png

    and the other session is where the controller of the report took a lot of time

    pastedimage1632853423773v1.png

    Q3: what should i understand from this? i'm new to this

    4. part1: I don't have any indexes in my tmp table. However, i have the following three fields in my contract parameter (ItemId, CustAccount, inventLocationId)


    Q4a: should i add an index to my tmp table? should the index contain the three fields? or should i add 3 indexes for each field. or should i add an index to another table?

    part 2: I don't have nested loops, here's my code. 

    Q4b: any suggestions?

    /// 
    ///     The ReportRDP class is the data provider for the Report report.
    /// 
    [SRSReportParameterAttribute(classstr(ReportContract)), SRSReportQueryAttribute(queryStr(ReportQuery))]
    class ReportRDP extends SRSReportDataProviderBase
    {
        ReportTmp reportTmp;
    
        /// 
        /// Gets an  ReportTmp  record.
        /// 
        /// 
        /// The  ReportTmp  record.
        /// 
        [SrsReportDataSetAttribute(' ReportTmp')]
        public ReportTmp getReportTmp()
        {
            select reportTmp;
            return reportTmp;
        }
    
        /// 
        /// Processes the report business logic.
        /// 
        public void processReport()
        {
            ReportContract contract = this.parmDataContract() as ReportContract;
            Query query = this.parmQuery();
    
            if(contract.parmAccountNum() != null)
            {
                query.dataSourceTable((tablenum(Table1))).addRange(fieldNum(Table1, CustAccount)).value(contract.parmAccountNum());
            }
            if(contract.parmItemId() != null)
            {
                query.dataSourceTable((tablenum(TableX))).addRange(fieldNum(TableX,    ItemId)).value(contract.parmItemId());
            }
            if(contract.parmInventLocation() != null)
            {
                query.dataSourceTable((tablenum(Table1))).addRange(fieldNum(Table1, InventLocationId)).value(contract. parmInventLocation());
            }
    
    
            QueryRun            queryRun = new QueryRun(this.parmQuery());
            while (queryRun.next())
            {
                Table1             table1 = queryRun.get(tableNum(Table1)) as Table1;
                TableX        tableX = queryRun.get(tableNum(TableX)) as TableX;
                LogisticsPostalAddress  logisticsPostalAddress = queryRun.getNo(5);
                TableY           tableY = queryRun.get(tableNum(TableY)) as TableY;
                LogisticsPostalAddress  tableYlogisticsPostalAddress = queryRun.getNo(4);
    
                if(tableX)
                {
    
                    if(tableX.ClassId == '111' && t.ModelIableX == '111-11')
                    {
                        continue;
                    }
    
                    reportTmp.clear();
    
                    reportTmp.CompanyLogo = FormLetter::companyLogo();
    
                    Table2 table2;
                    select table2 where table2.EnumBy == Enum::A && table2.TransId == tableX. TransId;
                    if(table2)
                    {      
                        reportTmp.itemId = tableX.ItemId;
    
                        if(tableX.ItemIdAllocated != null)    
                        {
                            reportTmp.Name = strFmt('%1 %2 %3', Item::find(tableX.temIdAllocated).Name, "As", table2.Name);
                        }
                        else
                        {
                            reportTmp.Name = table2.Name;
                        }
    
                        reportTmp.SalesUnit = table2.SalesUnit;
                        if(table2. ChargesGroupId != null &&  table2. ChargesGroupId == 'KkK')
                        {
                            reportTmp.SalesUnit = table2.SalesUnit   ' ('   table2.ChargesGroupId   ')';
                        }
                        reportTmp.LineAmount          = table2.LineAmount;
                        reportTmp.LineDisc            = table2.LinePercent;
                        reportTmp.SalesPrice          = table2.SalesPrice;
                        reportTmp.CustAccount         = table2.CustAccount;
                        reportTmp.CStatus    = table2.CStatus;
                        reportTmp.DataArea            = tableX.dataAreaId;
                        reportTmp. Id              = tableX. Id;
                        reportTmp.Device          = tableX.DeviceId;
                        reportTmp.DeviceStatus    = tableX.DeviceStatus;
                        reportTmp.PickupDate          = tableX.PickupDate;
                        reportTmp.ReturnDate = tableX.ReturnDate;
                        reportTmp.Qty                 = tableX.Qty;
                        reportTmp.PickupLocationId    = tableX.PickupLocationId;
                        reportTmp.CustName            = table1.Name;
                        if(tableX.JobSiteId != null && tableY && tableY.DeliveryPostalAddress != 0)     
                        {
                            reportTmp.DeliveryAddress     = tableYlogisticsPostalAddress.Address;
                        }
                        else
                        {
                            reportTmp.DeliveryAddress     = logisticsPostalAddress.Address;
                        }
                        reportTmp.PurchaseOrderNumber = table1.PurchOrderFormNum;
    
                        reportTmp.insert();
                    }
                    else
                    {
                        reportTmp.itemId = tableX.ItemId;
                        if(tableX.ItemIdAllocated != null)
                        {
                            reportTmp.Name  = Item::find(tableX.ItemIdAllocated).Name;
                        }
                        else
                        {
                            reportTmp.Name    = tableX.DeviceName;
                        }
                        reportTmp.CustAccount         = table1.CustAccount;
                        reportTmp.DataArea            = tableX.dataAreaId;
                        reportTmp.Id              	=tableX.Id ;
                        reportTmp.Device          = tableX.DeviceId;
                        reportTmp.DeviceStatus    = tableX.DeviceStatus;
                        reportTmp.PickupDate          = tableX.PickupDate;
                        reportTmp.ReturnDate = tableX.ReturnDate;
                        reportTmp.Qty                 = tableX.Qty;
                        reportTmp.PickupLocationId    = tableX.PickupLocationId;
                        reportTmp.CustName            = table1.Name;
                        if(tableX.JobSiteId != null && tableY && tableY.DeliveryPostalAddress != 0)    
                        {
                            reportTmp.DeliveryAddress     = tableYlogisticsPostalAddress.Address;
                        }
                        else
                        {
                            reportTmp.DeliveryAddress     = logisticsPostalAddress.Address;
                        }
                        reportTmp.PurchaseOrderNumber = table1.PurchOrderFormNum;
    
                        reportTmp.insert();
                    }
                }
            }
    
        }
    
    }
    

  • D365FO user Profile Picture
    465 on at
    RE: When to use inMemory or TmpDB when building reports?

    Any idea?

  • Suggested answer
    nmaenpaa Profile Picture
    101,160 Moderator on at
    RE: When to use inMemory or TmpDB when building reports?

    Hi,

    it seems a bit strange why printing a report of 1024 rows takes 5 minutes. But perhaps there' s something special there.

    I ran the report and used my mobile stop watch, it took the report to appear  5.16  minutes (i'm using in memory tmp table) I'm not sure how it took more in perf environment, which was about 7.5 minutes).

    This is most likely because in a dev system there's practically no latency in database calls since you have local SQL Server instead of Azure SQL.

    1. I commented out  the insert line of code and it took 15 seconds (1 page, no records)

    This indicates that the data fetching takes only about 5% of total execution time so no need to do anything there.

    2. I changed to tempDB now (with insert line is not commented out) and it now took using mo mobile stop watch  5.35 minutes which is slower than in memory by 10 seconds

    Seems that also switching between tempDb and inMemory has less than 5% impact.

    About the trace, I recommend to try to dig deeper in the Call tree of the session of your second Trace parser screenshot.

Under review

Thank you for your reply! To ensure a great experience for everyone, your content is awaiting approval by our Community Managers. Please check back later.

Helpful resources

Quick Links

Responsible AI policies

As AI tools become more common, we’re introducing a Responsible AI Use…

Abhilash Warrier – Community Spotlight

We are honored to recognize Abhilash Warrier as our Community Spotlight honoree for…

Leaderboard > Finance | Project Operations, Human Resources, AX, GP, SL

#1
CA Neeraj Kumar Profile Picture

CA Neeraj Kumar 1,964

#2
André Arnaud de Calavon Profile Picture

André Arnaud de Cal... 823 Super User 2025 Season 2

#3
Sohaib Cheema Profile Picture

Sohaib Cheema 564 User Group Leader

Last 30 days Overall leaderboard

Product updates

Dynamics 365 release plans