<?xml version="1.0" encoding="utf-8"?>
<rss xmlns:atom="https://www.w3.org/2005/Atom" xmlns:sy="https://purl.org/rss/1.0/modules/syndication/" xmlns:dc="https://purl.org/dc/elements/1.1/" xmlns:content="https://purl.org/rss/1.0/modules/content/" xmlns:wfw="https://wellformedweb.org/CommentAPI/" xmlns:slash="https://purl.org/rss/1.0/modules/slash/"
  version="2.0">
  <channel>
    <title>Savio s Blog</title>
    <atom:link
      href="https://docs.microsoft.com/archive/blogs/saviofigueiredo/feed.xml"
      rel="self"
      type="application/rss+xml" />
    <link>https://docs.microsoft.com/archive/blogs/saviofigueiredo/feed.xml</link>
    <description>Just another developer s blog</description>
    <lastBuildDate>Wed, 17 Apr 2019 03:51:53 GMT</lastBuildDate>
    <language>en-US</language>
    <sy:updatePeriod>hourly</sy:updatePeriod>
    <sy:updateFrequency>1</sy:updateFrequency>
    <item>
      <title>Ax 2012 - UnitOfWork - Performance series (Part 5)</title>
      <link>https://docs.microsoft.com/archive/blogs/saviofigueiredo/ax-2012-unitofwork-performance-series-part-5</link>
      <pubDate>Tue, 28 Jan 2014 18:06:00 GMT</pubDate>
      <dc:creator><![CDATA[Sávio Mendes de Figueiredo]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/saviofigueiredo/2014/01/28/ax-2012-unitofwork-performance-series-part-5/</guid>
      <description><![CDATA[Introduction
&nbsp;
The&nbsp;past posts (post 1, post 2, post 3, post 4) about...]]></description>
      <content:encoded><![CDATA[<p><span style="color: #0000ff; font-size: medium;">Introduction</span></p>
<p>&nbsp;</p>
<p><span style="color: #000000; font-size: small;">The&nbsp;past posts (<a href="https://blogs.msdn.com/b/saviofigueiredo/archive/2013/10/29/ax-2012-recordinsertlist-performance-series-part-1.aspx">post 1</a>, <a href="https://blogs.msdn.com/b/saviofigueiredo/archive/2013/10/29/ax-2012-recordinsertlist-performance-series-part-2.aspx">post 2</a>, <a href="https://blogs.msdn.com/b/saviofigueiredo/archive/2013/10/30/ax-2012-recordinsertlist-performance-series-part-3.aspx">post 3</a>, <a href="https://blogs.msdn.com/b/saviofigueiredo/archive/2013/11/08/ax-2012-recordinsertlist-performance-series-part-4.aspx">post 4</a>) about performance&nbsp;focused on <a href="https://msdn.microsoft.com/en-us/library/recordsortedlist.aspx">RecordInsertList</a> class. This class is very usefull to boost performance, but there are some situations when records have relationships, where this class&nbsp;may not fit very well. For example, imagine that you have two tables: ParentFoo and ChildFoo. Suppose that ChildFoo has a field called ParentFooRecId (I guess I don t need to explain what this field is for :p ).&nbsp;Notice that in this scenario, you will be unable to use the <a href="https://msdn.microsoft.com/en-us/library/recordsortedlist.aspx">RecordInsertList</a>, because this&nbsp;<a href="https://msdn.microsoft.com/en-us/library/recordsortedlist.aspx">RecordInsertList</a> can just hold elements of one type. Besides&nbsp;in order to insert the&nbsp;ChildFoo&nbsp;records, you must have the ParentFoo record id.</span></p>
<p>&nbsp;</p>
<p><span style="font-size: small;"><span style="color: #0000ff; font-size: medium;">Unit of Work</span></span></p>
<p><span style="font-size: small;">This pattern maintains a list of objects affected by a business transaction and coordinates the writing out of changes and the resolution of concurrency problems. </span><span style="font-size: small;">(<a href="https://martinfowler.com/eaaCatalog/unitOfWork.html">Martin Fowler blog</a>) </span><span style="font-size: small;">A simple definition of Work means performing some task.&nbsp; From a software application perspective Work is nothing but inserting, updating, and deleting data. For instance let&rsquo;s say you have an application which maintains customer data into a database. </span><span style="font-size: small;">So when you add, update, or delete a customer record on the database it&rsquo;s one unit. In simple words the equation is. 1 customer CRUD = 1 unit of work (<a href="https://www.codeproject.com/Articles/581487/Unit-of-Work-Design-Pattern">Article from codeproject</a>)</span></p>
<p><span style="font-size: small;">While using applications, we are doing a lot of database operations behind the scenes: inserting new elements, deleting and updating existing ones. It may be expensive to perform a datatabase call </span><span style="font-size: small;">for each of the changes required. In order to reduce this overhead, we can use Unit of Work pattern. The pattern is quite simple, somehow it will keep track of the changes that are being made and </span><span style="font-size: small;">at some point, all the changes will be made at once at the database.</span></p>
<p><span style="font-size: small;">Accordingly to <a href="https://msdn.microsoft.com/en-us/magazine/dd882510.aspx">MSDN magazine</a>, the Unit of Work responsabilities are: </span></p>
<ul>
<li><span style="font-size: small;">Manage transactions. </span></li>
<li><span style="font-size: small;">Order the database inserts, deletes, and updates.</span></li>
<li><span style="font-size: small;">Prevent duplicate updates. Inside a single usage of a Unit of Work object, different parts of the code may mark the same Invoice object as changed, but the Unit of Work class will only issue a single UPDATE command to the database.</span></li>
</ul>
<p><span style="font-size: small;">Back to dynamics AX world, there are some points that you must keep in mind</span></p>
<ul>
<li><span style="font-size: small;">Server tier is required</span></li>
<li><span style="font-size: small;">Requires optimistic concurrency</span></li>
<li><span style="font-size: small;">Database transaction is implicit and automatic</span></li>
<li><span style="font-size: small;">Does not bypass record level security</span></li>
<li><span style="font-size: small;">Does not support temporary tables</span></li>
</ul>
<p><span style="font-size: small;">You can find another post about employing UnitOfWork in Ax at <a href="https://daxmusings.codecrib.com/2011/07/ax-2012-recids-and-unitofwork-foreign.html">daxmusings blog</a></span></p>
<p>&nbsp;</p>
<p><span style="font-size: small;"><span style="color: #0000ff; font-size: medium;">Example</span></span></p>
<p><span style="font-size: small;">Lets create a table called FooParent which just has three fields: ParentId, Name&nbsp;and Description. Then, lets create another table called FooChild that contains&nbsp;four fields: ChildId, Name, Description and FooParent. Please, see the below picture.</span></p>
<p><span style="font-size: small;"><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/61/95/4786.FooParent.PNG" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-61-95/4786.FooParent.PNG"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/61/95/4786.FooParent.PNG" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-61-95/4786.FooParent.PNG" alt="" width="191" height="193" border="0" /></a></span></p>
<p>&nbsp;</p>
<p><span style="font-size: small;"><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/61/95/7485.FooChild.PNG" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-61-95/7485.FooChild.PNG"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/61/95/7485.FooChild.PNG" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-61-95/7485.FooChild.PNG" alt="" width="245" height="223" border="0" /></a></span></p>
<p>&nbsp;<span style="font-size: small;">Notice that a <a href="https://msdn.microsoft.com/en-us/library/aa556809.aspx">relation</a> has been created at the FooChild table. This <a href="https://msdn.microsoft.com/en-us/library/aa556809.aspx">relation</a> is mandatory in order to use the Unit of Work pattern. Now it is time to test two different approaches: calling many insert statements through a loop versus using Unit Of Work pattern to control the insertion</span></p>
<p><span style="font-size: small;">So, lets write&nbsp;a method at a class that will insert 10k record of FooParent and 10 records of FooChild though a naive loop.</span></p>
<p>&nbsp;</p>
<pre class="brush: c#;wrap-lines:false;">public class FooController
{
}

public static server void insertThroughManyInsertCalls()
{
    FooChild  child;
    FooParent parent;
    int i;
    
    for (i = 0; i &lt; 10000; ++i)
    {
        parent.ParentId = int2str(i);
        parent.Name = 'Any name for parent' + int2str(i);
        parent.Description = 'Any description for parent' + int2str(i);
        parent.insert();
        
        child.ChildId = int2str(i);
        child.Name = 'Any name for child' + int2str(i);
        child.Description = 'Any description for child' + int2str(i);
        child.FooParent = parent.RecId;
        child.insert();
    }
}
</pre>
<p><span style="font-size: small;">And lets write a job that call this method.</span></p>
<p>&nbsp;</p>
<pre class="brush: c#;wrap-lines:false;">static void ManyInsertCalls(Args _args)
{
    FooController::insertThroughManyInsertCalls();
}
</pre>
<p><span style="font-size: small;">&nbsp;And what is going on if we look at trace parser???</span></p>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/61/95/6153.TraceParserManyInsertCalls.PNG" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-61-95/6153.TraceParserManyInsertCalls.PNG"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/61/95/6153.TraceParserManyInsertCalls.PNG" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-61-95/6153.TraceParserManyInsertCalls.PNG" alt="" border="0" /></a></p>
<p>&nbsp;&nbsp;<span style="font-size: small;">Well, 20k database calls and almost 5 seconds to execute them seems like a big waste. Lets rewrite the code using Unit of work pattern.</span></p>
<p>&nbsp;</p>
<pre class="brush: c#;wrap-lines:false;">public static server void insertWithUnitOfWork()
{
    FooChild   child;
    FooParent  parent;

    // Instantiating the UnitOfWork.
    // Notice that this method runs on server
    UnitofWork unitOfWork = new unitOfWork();
    int i;

    for (i = 0; i &lt; 10000; ++i)
    {
        parent.ParentId = int2str(i);
        parent.Name = 'Any name for parent' + int2str(i);
        parent.Description = 'Any description for parent' + int2str(i);

        child.ChildId = int2str(i);
        child.Name = 'Any name for child' + int2str(i);
        child.Description = 'Any description for child' + int2str(i);

        // You will just be able to call this method if there is a relation
        // called FooParent at FooChild table
        child.FooParent(parent);

        // Marking these buffers to be inserted by UnitOfWork
        // The buffers are not being inserted at the database right now.
        unitOfWork.insertonSaveChanges(parent);
        unitOfWork.insertonSaveChanges(child);
    }

    // Finally, asking UnitOfWork to insert the records at the database.
    unitOfWork.saveChanges();
}
</pre>
<p><span style="font-size: small;">&nbsp;I don t believe this piece of code has worked, what is trace parser saying?</span></p>
<p>&nbsp;&nbsp;<a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/61/95/4135.TraceParserUnitOfWork.PNG" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-61-95/4135.TraceParserUnitOfWork.PNG"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/61/95/4135.TraceParserUnitOfWork.PNG" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-61-95/4135.TraceParserUnitOfWork.PNG" alt="" border="0" /></a></p>
<p><span style="color: #000000; font-size: small;">Indeed the magic happened!!!</span></p>
<p><span style="color: #000000; font-size: small;">Although the number of insert calls remain 20k, the time fall down from 5 seconds to 1.5 seconds. Now we are more than 3 times faster than the na&iuml;ve approach that calls the insert statement 20k times through a loop.</span></p>
<p><span style="color: #000000; font-size: small;">If we look at trace parser, we can see that UnitOfWork insert statements are faster than calling the insert many times.</span></p>
<p>&nbsp;<a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/61/95/4278.InsertStatementsComparison.PNG" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-61-95/4278.InsertStatementsComparison.PNG"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/61/95/4278.InsertStatementsComparison.PNG" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-61-95/4278.InsertStatementsComparison.PNG" alt="" border="0" /></a></p>
<p><span style="color: #000000; font-size: small;"><span style="color: #0000ff; font-size: large;">Summary</span></span></p>
<p><span style="font-size: small;">This post has briefly explained a very simple usage of <a href="https://msdn.microsoft.com/en-us/library/gg846338.aspx">UnitOfWork</a> pattern in Ax 2012. This pattern may be very useful and safe to be employed in many situations. We have a meaningful performance improvement without hurting good principles.</span></p>
<p><span style="font-size: small;">Feel free to download and test the project that is attached to this post.</span></p>
<p><span style="font-size: small;">Finally, remember that:</span></p>
<ol>
<li><span style="font-size: small;"><a href="https://msdn.microsoft.com/en-us/library/gg846338.aspx">UnitOfWork</a> must run on the server tie</span></li>
<li><span style="font-size: small;">The child must have a relation explicity defined in AOT to the parent</span></li>
<li><span style="font-size: small;">No record will be inserted into the database until the <a href="https://msdn.microsoft.com/en-us/library/unitofwork.savechanges.aspx">saveChanges</a> method is called.</span></li>
<li><span style="font-size: small;">You can enjoy the methods: <a href="https://msdn.microsoft.com/en-us/library/unitofwork.insertonsavechanges.aspx">insertOnSaveChanges</a>, <a href="https://msdn.microsoft.com/en-us/library/unitofwork.deleteonsavechanges.aspx">deleteOnSaveChanges</a>, <a href="https://msdn.microsoft.com/en-us/library/unitofwork.updateonsavechanges.aspx">updateOnSaveChanges</a>, <a href="https://msdn.microsoft.com/en-us/library/unitofwork.savechanges.aspx">saveChanges</a></span></li>
</ol>
<p>&nbsp;</p>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Components.PostAttachments/00/10/49/51/63/UnitOfWork.xpo" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-components-postattachments/00-10-49-51-63/UnitOfWork.xpo">UnitOfWork.xpo</a></p>]]></content:encoded>
    </item>
    <item>
      <title>Ax 2012 - RecordInsertList - Performance series (Part 4)</title>
      <link>https://docs.microsoft.com/archive/blogs/saviofigueiredo/ax-2012-recordinsertlist-performance-series-part-4</link>
      <pubDate>Fri, 08 Nov 2013 14:13:00 GMT</pubDate>
      <dc:creator><![CDATA[Sávio Mendes de Figueiredo]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/saviofigueiredo/2013/11/08/ax-2012-recordinsertlist-performance-series-part-4/</guid>
      <description><![CDATA[Introduction
&nbsp;
So far, during my previous&nbsp;posts (post 1, post 2, post 3), we realized...]]></description>
      <content:encoded><![CDATA[<p><span style="color: #0000ff; font-size: medium;">Introduction</span></p>
<p>&nbsp;</p>
<p><span style="color: #000000; font-size: small;">So far, during my previous&nbsp;posts (<a href="https://blogs.msdn.com/b/saviofigueiredo/archive/2013/10/29/ax-2012-recordinsertlist-performance-series-part-1.aspx">post 1</a>, <a href="https://blogs.msdn.com/b/saviofigueiredo/archive/2013/10/29/ax-2012-recordinsertlist-performance-series-part-2.aspx">post 2</a>, <a href="https://blogs.msdn.com/b/saviofigueiredo/archive/2013/10/30/ax-2012-recordinsertlist-performance-series-part-3.aspx">post 3</a>), we realized how to use <a href="https://msdn.microsoft.com/en-us/library/recordsortedlist.aspx">RecordInsertList</a> with regular and temporary tables on Ax. Before covering a new theme on performance, I would just like to highlight the behavior of the <a href="https://msdn.microsoft.com/en-us/library/recordinsertlist.add.aspx">add</a> and <a href="https://msdn.microsoft.com/en-us/library/recordinsertlist.insertdatabase.aspx">insertDatabase</a> methods.</span></p>
<p><span style="color: #000000; font-size: small;">I suppose that you would not think that some calls to the <a href="https://msdn.microsoft.com/en-us/library/recordinsertlist.add.aspx">add</a> method do execute insert transactions on the database. The call to <a href="https://msdn.microsoft.com/en-us/library/recordinsertlist.insertdatabase.aspx">insertDatabase</a> assures that all the buffers added to the list will be inserted, so, it will probably execute a bunch of other insert statements in order to have all the buffers inside <a href="https://www.microsoft.com/sqlserver/pt/br/default.aspx">SQL Server</a>, as promissed by the API.</span></p>
<p><span style="color: #000000; font-size: small;">Depending on the feature you are implementing,&nbsp;you may want&nbsp;to use <a href="https://msdn.microsoft.com/en-us/library/aa609617.aspx">ttsBegin</a> and <a href="https://msdn.microsoft.com/en-us/library/aa609617.aspx">ttsCommit </a>to avoid that in case of exceptions or any unexpected problem, that some records will be inserted while others not.</span></p>
<p><span style="color: #000000; font-size: small;">Behind the scenes, the <a href="https://msdn.microsoft.com/en-us/library/recordinsertlist.add.aspx">add</a> method execute the bulk insert as soon as the number of records being hold by the list achieves a specific value. The math to calculate this value will depend on the server buffer size that has been configured at Dynamics Ax Server Configuration and on the size of the buffer records themselves.</span></p>
<p><br /><span style="color: #000000; font-size: small;"><span style="color: #0000ff; font-size: large;">Example</span>&nbsp;</span></p>
<p><span style="font-size: small;">Before you call me a liar, lets see a practical example using ours MyInvoice table (sorry for not choosing Foo table). In the below code, you can see that I have added 10k buffers to the list, but insertDatabase method has not been called. Then, a&nbsp;select count is executed&nbsp;against the table and the result is printed at infolog. Surprisingly, infolog shows that 9940 records exist in the database. These records&nbsp;have been&nbsp;successfully inserted by the <a href="https://msdn.microsoft.com/en-us/library/recordinsertlist.add.aspx">add</a> method.</span></p>
<p>&nbsp;</p>
<pre class="brush: c#;wrap-lines:false;">static void callingAddManyTimesWillInsertSomeRecords(Args _args)
{
    int              i;
    MyInvoice        myInvoiceRecord, insertedRecords;

    RecordInsertList invoicesToBeInserted = new RecordInsertList(tableNum(MyInvoice));

    delete_from insertedRecords;
    
    for (i = 0; i &lt; 10000; ++i)
    {
        myInvoiceRecord.InvoiceAmount = (i + 1) * 100;
        myInvoiceRecord.CurrencyCode = 'REA';
        myInvoiceRecord.Qty = (i + 1) * 10;
        myInvoiceRecord.InvoiceId = int2str(i + 1);

        invoicesToBeInserted.add(myInvoiceRecord);
    }

    select count(RecId) from insertedRecords;
    
    info(strFmt('Although insertDatabase method has not been called, there are %1 registers in db', 
                insertedRecords.RecId));
}
</pre>
<p>&nbsp;</p>
<p>&nbsp;<a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/61/95/0027.infologAddMethodCalledManyTimes.PNG" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-61-95/0027.infologAddMethodCalledManyTimes.PNG"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/61/95/0027.infologAddMethodCalledManyTimes.PNG" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-61-95/0027.infologAddMethodCalledManyTimes.PNG" alt="" border="0" /></a></p>
<p>&nbsp;</p>
<p><span style="color: #000000; font-size: small;">Is add method inserting the register at the database for every call? If you have read my previous posts, you know the answer for sure. Anyway, lets run a small job that will reveal the answers for those who haven t.</span></p>
<p><span style="color: #000000; font-size: small;">The below job is really straightforward, it instantiates the list of RecordInsertList, adds a single buffer to the list and prints at infolog the number of records that have been inserted into the database.</span></p>
<p><span style="font-size: small;">As you can see, no record has been inserted by a single call to add.</span></p>
<p>&nbsp;</p>
<pre class="brush: c#;wrap-lines:false;">static void callingAddJustOnce(Args _args)
{
    MyInvoice        myInvoiceRecord, insertedRecords;

    RecordInsertList invoicesToBeInserted = new RecordInsertList(tableNum(MyInvoice));

    delete_from insertedRecords;

    myInvoiceRecord.InvoiceAmount = 100;
    myInvoiceRecord.CurrencyCode = 'REA';
    myInvoiceRecord.Qty = 10;
    myInvoiceRecord.InvoiceId = '1';

    invoicesToBeInserted.add(myInvoiceRecord);

    select count(RecId) from insertedRecords;

    info('Probably, no record has been inserted by add since it has just been called once');
    info(strFmt('Number of records inserted is %1', insertedRecords.RecId));
}
</pre>
<p>&nbsp;<a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/61/95/5126.addMethodCalledJustOnceDoesNotInsert.PNG" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-61-95/5126.addMethodCalledJustOnceDoesNotInsert.PNG"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/61/95/5126.addMethodCalledJustOnceDoesNotInsert.PNG" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-61-95/5126.addMethodCalledJustOnceDoesNotInsert.PNG" alt="" border="0" /></a></p>
<p>&nbsp;</p>
<p><span style="color: #000000; font-size: small;"><span style="color: #0000ff; font-size: large;">Summary</span></span></p>
<p><span style="font-size: small;">&nbsp;This post finishes my navigation through <a href="https://msdn.microsoft.com/en-us/library/recordinsertlist.aspx">RecordInsertList</a> class with a performance perspective for now. I tried to explain that <a href="https://msdn.microsoft.com/en-us/library/recordinsertlist.add.aspx">add</a> method will insert the records in to the database, so, for some features you may want to use <a href="https://msdn.microsoft.com/en-us/library/aa609617.aspx">ttsBegin</a> and <a href="https://msdn.microsoft.com/en-us/library/aa609617.aspx">ttsCommit</a> to avoid partial insertions of the set of buffers that must be persisted. My first example called add method many times without a call to <a href="https://msdn.microsoft.com/en-us/library/recordinsertlist.insertdatabase.aspx">insertDatabase</a> and it showed that some records were indeed inserted. My next example called the add method just once it demonstrated that the record was not into db, since add method does not use a record by record insertion approach. This kind of approach would not provide a fast performance.</span></p>
<p><span style="font-size: small;">Please, feel free to download and test the project that is attached to this post.</span></p>
<p><span style="font-size: small;">On my<a href="https://blogs.msdn.com/b/saviofigueiredo/archive/2014/01/29/ax-2012-unitofwork-performance-series-part-5.aspx"> next post</a>, I will explore the <a href="https://msdn.microsoft.com/en-us/library/unitofwork.aspx">UnitOfWork</a> pattern and how to use it in Ax. Ax 2012 does support this pattern.</span></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Components.PostAttachments/00/10/46/52/97/PrivateProject_RecordInsertList_AddMethod.xpo" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-components-postattachments/00-10-46-52-97/PrivateProject_5F00_RecordInsertList_5F00_AddMethod.xpo">PrivateProject_RecordInsertList_AddMethod.xpo</a></p>]]></content:encoded>
    </item>
    <item>
      <title>Ax 2012 - RecordInsertList - Performance series (Part 3)</title>
      <link>https://docs.microsoft.com/archive/blogs/saviofigueiredo/ax-2012-recordinsertlist-performance-series-part-3</link>
      <pubDate>Wed, 30 Oct 2013 06:19:00 GMT</pubDate>
      <dc:creator><![CDATA[Sávio Mendes de Figueiredo]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/saviofigueiredo/2013/10/30/ax-2012-recordinsertlist-performance-series-part-3/</guid>
      <description><![CDATA[Introduction
In my previous post we analyzed the behavior of RecordInsertList when the insert...]]></description>
      <content:encoded><![CDATA[<p><span style="color: #0000ff; font-size: medium;">Introduction</span></p>
<p><span style="color: #000000; font-size: small;">In my previous <a href="https://blogs.msdn.com/b/saviofigueiredo/archive/2013/10/29/ax-2012-recordinsertlist-performance-series-part-2.aspx">post</a> we analyzed the behavior of <a href="https://msdn.microsoft.com/en-us/library/recordinsertlist.aspx">RecordInsertList</a> when the insert method has been overriden. Now, lets play with <a href="https://msdn.microsoft.com/en-us/library/recordinsertlist.aspx">RecordInsertList</a> against a&nbsp;<a href="https://msdn.microsoft.com/en-us/library/gg845661.aspx">TempDb</a> table. Is that possible? </span></p>
<p><span style="color: #000000; font-size: small;">I want to show that there are performance benefits of using <a href="https://msdn.microsoft.com/en-us/library/recordinsertlist.aspx">RecordInsertList</a> to make bulk insertions at a&nbsp;<a href="https://msdn.microsoft.com/en-us/library/gg845661.aspx">TempDb</a> table, although it is not so fast as&nbsp;<a href="https://msdn.microsoft.com/en-us/library/gg863308.aspx">regular</a> tables. You must pay attention to the fact that we can not use the <a href="https://msdn.microsoft.com/en-us/library/recordinsertlist.aspx">RecordInsertList</a> with a <a href="https://msdn.microsoft.com/en-us/library/gg845661.aspx">TempDb</a> on the cliente tier. It is really dangerous to do that because the code is going to compile, but users will get a really ugly and deceiving&nbsp;runtime exception</span></p>
<p><span style="color: #000000; font-size: small;">I will let temporary tables explanation for a future post, so, right now I will just assume that you have some basic understanding on this theme.</span></p>
<p><br /><span style="color: #0000ff; font-size: medium;">Example</span></p>
<p><span style="font-size: small;">Lets see some&nbsp;X++&nbsp;code. In the below example, I am trying to instantiate a collection of MyInvoiceTmp.&nbsp;This code compiles without problems, but, unfortunatelly,&nbsp;if we try to execute it,&nbsp;a runtime exception will be&nbsp;thrown&nbsp;because&nbsp;TmpDbs cannot be used with <a href="https://msdn.microsoft.com/en-us/library/recordinsertlist.aspx">RecordInsertList</a>&nbsp;on the&nbsp;client tier. The infolog message says that we cannot just use them together, but, in fact we can and there are performance benefits if we do so.</span></p>
<p><span style="font-size: small;">So, first of all, I have&nbsp;created a table called MyInvoiceTmp with 4 fields and I&nbsp;set its TableType as TempDb on AOT.</span></p>
<p><span style="font-size: small;"><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/61/95/3857.TempTableAot.PNG" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-61-95/3857.TempTableAot.PNG"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/61/95/3857.TempTableAot.PNG" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-61-95/3857.TempTableAot.PNG" alt="" border="0" /></a></span></p>
<p>&nbsp;&nbsp;</p>
<p><span style="font-size: small;">Then, I wrote some code to use it. Notice that I had to pass the <a href="https://msdn.microsoft.com/en-us/library/gg845661.aspx">TempDb</a> buffer as parameter to the <a href="https://msdn.microsoft.com/en-us/library/recordinsertlist.new.aspx">constructor</a> of the <a href="https://msdn.microsoft.com/en-us/library/recordinsertlist.aspx">RecordInsertList.</a> Since that buffer is not the first <a href="https://msdn.microsoft.com/en-us/library/recordinsertlist.new.aspx">constructor</a> parameter, I also had to pass some boolean parameters before the buffer.</span></p>
<p>&nbsp;</p>
<pre class="brush: c#;wrap-lines:false;">static void testAddInsertsRecordsIntoDbOnTheClient(Args _args)
{
    MyInvoiceTmp        tempRecord;
    
    // This code compiles, but it generates a runtime
    // exception with a misleading message saying
    // that tempDb can not be used together with
    // RecordInsertList
    RecordInsertList    invoicesToBeInserted = new RecordInsertList(tableNum(MyInvoiceTmp), // table id
                                                                    false, // skip insert
                                                                    false, // skip database log
                                                                    false, // skip events
                                                                    false, // skip aos validation
                                                                    false, // skip RLS validation
                                                                    tempRecord); // buffer where records will be inserted
}
</pre>
<p>&nbsp;</p>
<p><span style="font-size: small;">And when we try to run this code, we get an error.</span></p>
<p>&nbsp;<a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/61/95/4812.infologErrorInstantiatingTempTableRecordInsertList.PNG" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-61-95/4812.infologErrorInstantiatingTempTableRecordInsertList.PNG"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/61/95/4812.infologErrorInstantiatingTempTableRecordInsertList.PNG" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-61-95/4812.infologErrorInstantiatingTempTableRecordInsertList.PNG" alt="" border="0" /></a></p>
<p><span style="font-size: small;">&nbsp;Although the message says we can t use temporary tables for such operations, indeed we can. We just need to be careful because the code must be executed on the server.</span></p>
<p><span style="font-size: small;">&nbsp;The below implementation demonstrates how to use <a href="https://msdn.microsoft.com/en-us/library/recordinsertlist.aspx">RecordInsertList</a>&nbsp;together with <a href="https://msdn.microsoft.com/en-us/library/gg845661.aspx">TempDb</a> tables. I would like to highlight the "server" mark on the method declaration, which enforces that the method must be executed on the server tie. So, I have created a job which calls a static method.</span></p>
<p><span style="font-size: small;">&nbsp;&nbsp;Here is the job:</span></p>
<pre class="brush: c#;wrap-lines:false;">static void insertRecordSetListTempTbOnServer(Args _args)
{
    MyInvoiceTmp::testInsertOnServerForTempTable();
}
</pre>
<p><span style="font-size: small;">&nbsp;And here is the static method:</span></p>
<p>&nbsp;</p>
<pre class="brush: c#;wrap-lines:false;">public static server void testInsertOnServerForTempTable()
{
    int              i;
    MyInvoiceTmp        myInvoiceRecord;
    int              startTime, endTime;

    RecordInsertList    invoicesToBeInserted = new RecordInsertList(tableNum(MyInvoiceTmp), // table id
                                                                    false, // skip insert
                                                                    false, // skip database log
                                                                    false, // skip events
                                                                    false, // skip aos validation
                                                                    false, // skip RLS validation
                                                                    myInvoiceRecord); // buffer where records will be inserted

    startTime = WinAPI::getTickCount();

    for (i = 0; i &lt; 10000; ++i)
    {
        // Initializing the buffer with dummy values
        myInvoiceRecord.InvoiceAmount = (i + 1) * 100;
        myInvoiceRecord.CurrencyCode = 'REA';
        myInvoiceRecord.Qty = (i + 1) * 10;
        myInvoiceRecord.InvoiceId = int2str(i + 1);

        // Instead of inserting the record into the database, we will add
        // it to the RecordInsertList array
        invoicesToBeInserted.add(myInvoiceRecord);
    }

    invoicesToBeInserted.insertDatabase();

    endTime = WinAPI::getTickCount();

    info(strFmt('It took %1 miliseconds to insert 10k registers with a RecordInsertList approach at a temptbl',
                endTime - startTime));
}
</pre>
<p><span style="font-size: small;">Instead of getting an ugly infolog error message, we can see that the method was executed in about 2.4 seconds. This is better than running over a loop of insertions record by record, but it is not as good as the result for a regular table.</span></p>
<p>&nbsp;</p>
<p>&nbsp;<a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/61/95/1488.InsertTempTableServer.PNG" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-61-95/1488.InsertTempTableServer.PNG"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/61/95/1488.InsertTempTableServer.PNG" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-61-95/1488.InsertTempTableServer.PNG" alt="" border="0" /></a></p>
<p>&nbsp;<span style="font-size: small;">So far, we have seen that there are performance benefits for using <a href="https://msdn.microsoft.com/en-us/library/recordinsertlist.aspx">RecordInsertList</a>, even with a <a href="https://msdn.microsoft.com/en-us/library/gg845661.aspx">TempDb</a>. But looking at this number at infolog can be tricky, because the number depends on what processes are running right now on my machine.</span></p>
<p><span style="font-size: small;">We must have&nbsp;a second opinion What is happening behind the scenes? What does <a href="https://blogs.msdn.com/b/axperf/archive/2011/08/15/walk-through-major-features-of-microsoft-dynamics-ax-2012.aspx">Trace Parser</a> say about this?</span></p>
<p>&nbsp;</p>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/61/95/1134.TraceParserTempDbInsert.PNG" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-61-95/1134.TraceParserTempDbInsert.PNG"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/61/95/1134.TraceParserTempDbInsert.PNG" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-61-95/1134.TraceParserTempDbInsert.PNG" alt="" border="0" /></a></p>
<p><span style="font-size: small;">Accordingly to <a href="https://blogs.msdn.com/b/axperf/archive/2011/08/15/walk-through-major-features-of-microsoft-dynamics-ax-2012.aspx">Trace Parser</a>, we have done 10k inserts. How can this be better than just doing a record-by-record insert through a loop? Why has the time at infolog been better?</span></p>
<p><span style="font-size: small;">If we play a bit more with the results at <a href="https://blogs.msdn.com/b/axperf/archive/2011/08/15/walk-through-major-features-of-microsoft-dynamics-ax-2012.aspx">Trace Parser</a>, we can see that everytime we called the add method, <a href="https://msdn.microsoft.com/en-us/library/recordinsertlist.aspx">RecordInsertList</a> added the buffer at a list. And when this list achieves a specific size, the <a href="https://msdn.microsoft.com/en-us/library/recordinsertlist.aspx">RecordInsertList</a> inserts all the records that are in this list at&nbsp;<a href="https://www.microsoft.com/sqlserver/pt/br/default.aspx">SQL Server</a>.</span></p>
<p><span style="font-size: small;">The below picture shows that when the <a href="https://msdn.microsoft.com/en-us/library/recordinsertlist.add.aspx">add</a> method is called around 71 times, it inserts all the records being hold by its collection at sql server. So, the records are not inserted just when we call the <a href="https://msdn.microsoft.com/en-us/library/recordinsertlist.insertdatabase.aspx">insertDatabase</a> method. Better than that, they are not inserted using a record by record approach.</span></p>
<p><span style="font-size: small;">Due to this fact, you are probably going to reach better results using the <a href="https://msdn.microsoft.com/en-us/library/recordinsertlist.aspx">RecordInsertList</a> with a <a href="https://msdn.microsoft.com/en-us/library/gg845661.aspx">TempDb</a> than calling the <a href="https://msdn.microsoft.com/en-us/library/aa856945.aspx">insert</a> method inside a loop.</span></p>
<p>&nbsp;</p>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/61/95/3364.TraceParserGroupedAdds.PNG" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-61-95/3364.TraceParserGroupedAdds.PNG"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/61/95/3364.TraceParserGroupedAdds.PNG" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-61-95/3364.TraceParserGroupedAdds.PNG" alt="" border="0" /></a></p>
<p>&nbsp;</p>
<p>&nbsp;<span style="color: #0000ff; font-size: large;">Summary</span></p>
<p><span style="color: #000000; font-size: small;">Throughout this post we&nbsp;saw&nbsp;an example about how to use <a href="https://msdn.microsoft.com/en-us/library/gg845661.aspx">TempDb</a> and <a href="https://msdn.microsoft.com/en-us/library/recordinsertlist.aspx">RecordInsertList</a> together. We have realized that, currently, such mix can just be made on the server tier and that there are advantages from performance side. </span></p>
<p><span style="color: #000000; font-size: small;">The attached xpo contains a project that will allow you to play with the example shown in this post.</span></p>
<p><span style="color: #000000; font-size: small;">My next post on the performance series will continue to&nbsp;analyze the <a href="https://msdn.microsoft.com/en-us/library/recordinsertlist.aspx">RecordInsertList</a> class. I will show what is happening everytime we call the <a href="https://msdn.microsoft.com/en-us/library/recordinsertlist.add.aspx">add</a> method and what happens when we call the <a href="https://msdn.microsoft.com/en-us/library/recordinsertlist.insertdatabase.aspx">insertDatabase</a> method.</span></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Components.PostAttachments/00/10/46/17/65/PrivateProject_RecordInsertListWithTempDB.xpo" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-components-postattachments/00-10-46-17-65/PrivateProject_5F00_RecordInsertListWithTempDB.xpo">PrivateProject_RecordInsertListWithTempDB.xpo</a></p>]]></content:encoded>
    </item>
    <item>
      <title>Ax 2012 - RecordInsertList - Performance series (Part 1)</title>
      <link>https://docs.microsoft.com/archive/blogs/saviofigueiredo/ax-2012-recordinsertlist-performance-series-part-1</link>
      <pubDate>Tue, 29 Oct 2013 15:24:00 GMT</pubDate>
      <dc:creator><![CDATA[Sávio Mendes de Figueiredo]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/saviofigueiredo/2013/10/29/ax-2012-recordinsertlist-performance-series-part-1/</guid>
      <description><![CDATA[Introduction
&nbsp;
From MSDN:
This class allows you to insert more than one record into the...]]></description>
      <content:encoded><![CDATA[<p><span style="color: #0000ff; font-size: large;">Introduction</span></p>
<p>&nbsp;</p>
<p><em>From MSDN:</em></p>
<p><em>This class allows you to insert more than one record into the database at a time, which reduces communication between the application and the database.</em></p>
<p><em>Records are inserted only when the kernel finds the time appropriate, but they are inserted no later than the call to the <span class="code">insertDatabase</span>. <span class="code">add</span> and <span class="code">insertDatabase </span>methods. The <span class="code">RecordInsertList.add</span> and <span class="code">RecordInsertList.insertDatabase</span> methods return the accumulated number of records that are currently inserted, which allows you to keep track of when the records are actually inserted.</em></p>
<p><em>The array insert operation automatically falls back to classic record-by-record inserts when non-SQL based tables are used (for example, temporary tables), or when the <span class="code">insert</span> method on the table is overridden (unless it is explicitly discarded).</em></p>
<p><em><span class="code">RecordInsertList</span> is similar to <span class="code"><a href="https://msdn.microsoft.com/en-us/library/recordsortedlist.aspx">RecordSortedList</a></span>, but it has built-in client/server support (it automatically packs data from one tier to another when needed), and it lacks the sort order features that are available in <span class="code"><a href="https://msdn.microsoft.com/en-us/library/recordsortedlist.aspx">RecordSortedList</a></span>.</em></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p><span style="font-size: small;">&nbsp;<em>In my words:</em></span></p>
<p><span style="font-size: small;">The <a href="https://msdn.microsoft.com/en-us/library/recordinsertlist.aspx">RecordInsertList</a> class supports inserting many records of a given type into the database at once, avoiding the overhead that could happen if we have a loop that inserts a single record per iteration.</span></p>
<p><span style="font-size: small;">When the &nbsp;<a href="https://msdn.microsoft.com/en-us/library/recordinsertlist.insertdatabase.aspx">insertDatabase</a> method is called, Dynamics Ax Runtime packs the buffers to be inserted and send them to <a href="https://www.microsoft.com/sqlserver/pt/br/default.aspx">SQL Server</a>. At <a href="https://www.microsoft.com/sqlserver/pt/br/default.aspx">SQL Server</a>, the package is extracted and SQL Server will insert them record by record. Since many buffers are being packed together, we save a lot of round trips from AOS to <a href="https://www.microsoft.com/sqlserver/pt/br/default.aspx">SQL Server</a>. The number of packages will be calculated accordingly to the size and quantity of the records to be inserted and to <a href="https://technet.microsoft.com/en-us/library/aa569635.aspx">Ax server buffer size</a>. If the <a href="https://msdn.microsoft.com/en-us/library/aa856945.aspx">insert</a> or the <span class="docEmphasis"><a href="https://msdn.microsoft.com/en-us/library/aa625830.aspx">aosValidateInsert</a> methods are overriden at the table, then, <a href="https://msdn.microsoft.com/en-us/library/recordinsertlist.insertdatabase.aspx">insertDatabase</a> will execute the "record by record" insert. The package approach will also not be employed if the table has a <a href="https://msdn.microsoft.com/en-us/library/aa874816.aspx">container</a> field or a <a href="https://msdn.microsoft.com/en-us/library/aa577032.aspx">memo</a> field. Nevertheless, during the instantiation of the <a href="https://msdn.microsoft.com/en-us/library/recordinsertlist.aspx">RecordInsertList,</a> either the <a href="https://msdn.microsoft.com/en-us/library/aa856945.aspx">insert</a> and the <span class="docEmphasis"><a href="https://msdn.microsoft.com/en-us/library/aa625830.aspx">aosValidateInsert</a> can be skipped. Please, be very careful when skipping these methods.</span></span></span></p>
<p>&nbsp;</p>
<p><span style="font-size: small;">The usage is pretty straight forward. First of all, you need to instantiate the a <a href="https://msdn.microsoft.com/en-us/library/recordinsertlist.aspx">RecordInsertList</a> specifying the table id of the table where the records will be inserted. Then, add the buffers at the list using the <a href="https://msdn.microsoft.com/en-us/library/recordinsertlist.add.aspx">add</a> method. Finally, call the <a href="https://msdn.microsoft.com/en-us/library/recordinsertlist.insertdatabase.aspx">insertDatabase</a> method in order to insert all the records at once.</span></p>
<p><span style="color: #0000ff; font-size: large;">Example</span></p>
<p><span style="font-size: small;">Suppose that we have a table called MyInvoice with 4 fields: CurrencyCode, InvoiceAmount, Qty and InvoiceId. Given to a requirement, we need to insert 10k registers into the database.&nbsp;Inserting thousands of registers into the database during the daily activities of ours customers may be painfull since they need to share server resources with tens, may be hundreds, of other users.</span></p>
<p>&nbsp;&nbsp;<a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/61/95/3771.Aot.PNG" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-61-95/3771.Aot.PNG"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/61/95/3771.Aot.PNG" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-61-95/3771.Aot.PNG" alt="" width="234" height="254" border="0" /></a></p>
<p>&nbsp;</p>
<p><span style="color: #0000ff; font-size: medium;">Slow mode</span></p>
<p><span style="font-size: small;">&nbsp;We could add 10k records into this table through the below loop. The insert statement is being called at the end of each iteration. This is really expensive!!!</span></p>
<p>&nbsp;</p>
<pre class="brush: c#;wrap-lines:false;">static void insertIntoMyInvoiceThroughLoop(Args _args)
{
    int       i;
    MyInvoice myInvoiceRecord;
    int       startTime, endTime;

    startTime = WinAPI::getTickCount();

    for (i = 0; i &lt; 10000; ++i)
    {
        // Initializing the buffer with dummy values
        myInvoiceRecord.InvoiceAmount = (i + 1) * 100;
        myInvoiceRecord.CurrencyCode = 'REA';
        myInvoiceRecord.Qty = (i + 1) * 10;
        myInvoiceRecord.InvoiceId = int2str(i + 1);

        // Record by record insert operation
        myInvoiceRecord.insert();
    }

    endTime = WinAPI::getTickCount();

    info(strFmt('It took %1 miliseconds to insert 10k registers with a record-per-record insert approach', 
                endTime - startTime));
}
</pre>
<p>&nbsp;</p>
<p><span style="font-size: small;">After running this job on my test machine for a couple of times, the time spent was around&nbsp;5 seconds, as you can see on the infolog window below.</span></p>
<p>&nbsp;<a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/61/95/1727.infolog10kRegistersLoopRecordPerRecordInsert.PNG" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-61-95/1727.infolog10kRegistersLoopRecordPerRecordInsert.PNG"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/61/95/1727.infolog10kRegistersLoopRecordPerRecordInsert.PNG" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-61-95/1727.infolog10kRegistersLoopRecordPerRecordInsert.PNG" alt="" width="449" height="256" border="0" /></a></p>
<p><span style="font-size: small;">We should also take a look at <a href="https://blogs.msdn.com/b/axperf/archive/2011/08/15/walk-through-major-features-of-microsoft-dynamics-ax-2012.aspx">Trace Parser</a> in order to&nbsp;realize what is going on behind the scenes. Notice that the insert statement has been executed 10k times and the job spent almost 3 seconds just with these statements. <a href="https://blogs.msdn.com/b/axperf/archive/2011/08/15/walk-through-major-features-of-microsoft-dynamics-ax-2012.aspx">Trace Parser</a> is a powerful tool that makes very easy for developers to assess performance and to find bottlenecks. For the sake of simplicity, I will not give any details about <a href="https://blogs.msdn.com/b/axperf/archive/2011/08/15/walk-through-major-features-of-microsoft-dynamics-ax-2012.aspx">Trace Parser</a> in this post.</span></p>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/61/95/8272.TraceParserAnalysis.png" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-61-95/8272.TraceParserAnalysis.png"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/61/95/8272.TraceParserAnalysis.png" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-61-95/8272.TraceParserAnalysis.png" alt="" border="0" /></a></p>
<p>&nbsp;</p>
<p><span style="color: #0000ff; font-size: medium;">Fast mode</span></p>
<p><span style="font-size: small;">&nbsp;If you are not comfortable with such amount of time, we could enjoy <a href="https://msdn.microsoft.com/en-us/library/recordinsertlist.aspx">RecordInsertList</a>. At the end of each iteration, the buffers are just added to the collection. Finally, when all the buffers have been added to the collection, the <a href="https://msdn.microsoft.com/en-us/library/recordinsertlist.insertdatabase.aspx">insertDatabase</a> method is called. The below job shows the usage.</span></p>
<p>&nbsp;</p>
<pre class="brush: c#;wrap-lines:false;">static void insertIntoMyInvoiceByRecordInsertList(Args _args)
{
    int              i;
    MyInvoice        myInvoiceRecord;
    int              startTime, endTime;
    
    // This collection will store the records that must be inserted into the database
    RecordInsertList invoicesToBeInserted = new RecordInsertList(tableNum(MyInvoice));

    startTime = WinAPI::getTickCount();

    for (i = 0; i &lt; 10000; ++i)
    {
        // Initializing the buffer with dummy values
        myInvoiceRecord.InvoiceAmount = (i + 1) * 100;
        myInvoiceRecord.CurrencyCode = 'REA';
        myInvoiceRecord.Qty = (i + 1) * 10;
        myInvoiceRecord.InvoiceId = int2str(i + 1);

        // Instead of inserting the record into the database, we will add
        // it to the RecordInsertList array
        invoicesToBeInserted.add(myInvoiceRecord);
    }

    // After fulfilling the array with the elements to be inserted, we are
    // read to execute the insert operation
    invoicesToBeInserted.insertDatabase();
    
    endTime = WinAPI::getTickCount();

    info(strFmt('It took %1 miliseconds to insert 10k registers with a RecordInsertList approach', 
                endTime - startTime));
}
</pre>
<p><span style="font-size: small;">&nbsp;Now, infolog presents a pretty better value.</span></p>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/61/95/2117.infolog10kRegistersLoopRecordInsertList.PNG" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-61-95/2117.infolog10kRegistersLoopRecordInsertList.PNG"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/61/95/2117.infolog10kRegistersLoopRecordInsertList.PNG" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-61-95/2117.infolog10kRegistersLoopRecordInsertList.PNG" alt="" width="384" height="236" border="0" /></a></p>
<p><span style="font-size: small;">Again, it worths analyzing <a href="https://blogs.msdn.com/b/axperf/archive/2011/08/15/walk-through-major-features-of-microsoft-dynamics-ax-2012.aspx">Trace Parser</a> results. The insert statement was executed just 141 times and the job spent 297 miliseconds to insert the 10k registers into the database.</span></p>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/61/95/3731.TraceParserAnalysisRecordInsertList.png" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-61-95/3731.TraceParserAnalysisRecordInsertList.png"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/61/95/3731.TraceParserAnalysisRecordInsertList.png" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-61-95/3731.TraceParserAnalysisRecordInsertList.png" alt="" border="0" /></a></p>
<p>&nbsp;</p>
<p><span style="color: #0000ff; font-size: large;">What happens when the insertDatabase inserts a register that causes a failure?&nbsp;</span></p>
<p><span style="color: #000000; font-size: small;">&nbsp;If some of the insert statements fail, we have no clue about which insert statements were correctly executed. </span></p>
<p><span style="color: #000000; font-size: small;">For example, I have inserted a register with the invoiceId equals to '100'. So,&nbsp;one of the&nbsp;insert statements must fail because it will also try to insert a record with the '100' value for this field. </span></p>
<p><span style="color: #000000; font-size: small;">An infolog error message will popup to inform about the problem and if query the db, some of the records were indeed inserted.</span></p>
<p>&nbsp;</p>
<pre class="brush: c#;wrap-lines:false;">static void insertByRecordInsertListWithFailures(Args _args)
{
    int              i;
    MyInvoice        myInvoiceRecord;
    
    // This collection will store the records that must be inserted into the database
    RecordInsertList invoicesToBeInserted = new RecordInsertList(tableNum(MyInvoice));

    // this record will cause a failure due to a dupplicated invoiceid. This field must be unique
    myInvoiceRecord.InvoiceId = '100';
    myInvoiceRecord.InvoiceAmount = 0;
    myInvoiceRecord.Qty = 0;
    myInvoiceRecord.CurrencyCode = 'REA';
    myInvoiceRecord.doInsert();
    
    for (i = 0; i &lt; 10000; ++i)
    {
        // Initializing the buffer with dummy values
        myInvoiceRecord.InvoiceAmount = (i + 1) * 100;
        myInvoiceRecord.CurrencyCode = 'REA';
        myInvoiceRecord.Qty = (i + 1) * 10;
        myInvoiceRecord.InvoiceId = int2str(i + 1);

        // Instead of inserting the record into the database, we will add
        // it to the RecordInsertList array
        invoicesToBeInserted.add(myInvoiceRecord);
    }

    invoicesToBeInserted.insertDatabase();
}
</pre>
<p>&nbsp;<a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/61/95/1830.infologErrorMessage.PNG" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-61-95/1830.infologErrorMessage.PNG"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/61/95/1830.infologErrorMessage.PNG" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-61-95/1830.infologErrorMessage.PNG" alt="" width="527" height="259" border="0" /></a></p>
<p>&nbsp;</p>
<p><span style="font-size: small;">Sql server shows that 71 registers have been inserted by the insertDatabase method, plus the one insert that we did at the beginning of the method</span></p>
<p>&nbsp;</p>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/61/95/5164.SqlResultForFailure.PNG" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-61-95/5164.SqlResultForFailure.PNG"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/61/95/5164.SqlResultForFailure.PNG" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-61-95/5164.SqlResultForFailure.PNG" alt="" width="197" height="150" border="0" /></a></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p><span style="color: #0000ff; font-size: large;">Summary</span></p>
<p><span style="font-size: small;">This post demonstrated how to boost bulk insert operations through <a href="https://msdn.microsoft.com/en-us/library/recordinsertlist.aspx">RecordInsertList</a> class. Avoid doing adopting an insert per iteration approach. Besides improving the performance, the usage of this helper&nbsp;class will not scratch good OO design. Be aware about the behavior when a failure occurs.</span></p>
<p><span style="font-size: small;">The attached xpo&nbsp;Project contains the code of this post.</span></p>
<p><span style="font-size: small;">My next <a href="https://blogs.msdn.com/b/saviofigueiredo/archive/2013/10/29/ax-2012-recordinsertlist-performance-series-part-2.aspx">post </a>of the Ax Performance&nbsp;series will highlight the scenario&nbsp;where&nbsp;the&nbsp;insert method has been overriden and we&nbsp;try to use the RecordInsertList.&nbsp;</span></p>
<p>&nbsp;</p>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Components.PostAttachments/00/10/46/15/51/PrivateProject_RecordInsertList.xpo" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-components-postattachments/00-10-46-15-51/PrivateProject_5F00_RecordInsertList.xpo">PrivateProject_RecordInsertList.xpo</a></p>]]></content:encoded>
    </item>
    <item>
      <title>Ax 2012 - RecordInsertList - Performance series (Part 2)</title>
      <link>https://docs.microsoft.com/archive/blogs/saviofigueiredo/ax-2012-recordinsertlist-performance-series-part-2</link>
      <pubDate>Tue, 29 Oct 2013 09:14:00 GMT</pubDate>
      <dc:creator><![CDATA[Sávio Mendes de Figueiredo]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/saviofigueiredo/2013/10/29/ax-2012-recordinsertlist-performance-series-part-2/</guid>
      <description><![CDATA[Introduction
In my previous post of this series, I highlighted that we can use RecordInsertList in...]]></description>
      <content:encoded><![CDATA[<p><span style="color: #3366ff; font-size: large;">Introduction</span></p>
<p><span style="color: #000000; font-size: small;">In my previous <a href="https://blogs.msdn.com/b/saviofigueiredo/archive/2013/10/29/ax-2012-recordinsertlist-performance-series-part-1.aspx">post</a> of this series, I highlighted that we can use <a href="https://msdn.microsoft.com/en-us/library/recordinsertlist.aspx">RecordInsertList</a> in order to execute bulk insert operations and that executing a single insert per iteration is extremelly expensive and should be avoided. </span></p>
<p><span style="color: #000000; font-size: small;"><span style="color: #3366ff; font-size: large;"><span style="color: #000000; font-size: small;"><span style="color: #000000; font-size: small;">Now, lets take a look at a particular scenario where we try to use the <a href="https://msdn.microsoft.com/en-us/library/recordinsertlist.aspx">RecordInsertList</a> helper class to improve the performance, but the <a href="https://msdn.microsoft.com/en-us/library/aa856945.aspx">insert</a> method of the table has been overriden.</span></span></span></span></p>
<p><span style="color: #000000; font-size: small;"><span style="color: #3366ff; font-size: large;">Example</span></span></p>
<p><span style="font-size: small;">In this example I am using a table called MyInvoiceInsertOverriden which has some fields and that has overriden the "<a href="https://msdn.microsoft.com/en-us/library/aa856945.aspx">insert</a>" method. Just because this method has been overriden, we will not enjoy the full&nbsp;benefits&nbsp;from <a href="https://msdn.microsoft.com/en-us/library/recordinsertlist.aspx">RecordInsertList</a> helper class. Below, you can see both the AOT node for this table and the insert method that has been implemented.</span></p>
<p><br /><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/61/95/8867.AotTableWithOverridenInsert.PNG" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-61-95/8867.AotTableWithOverridenInsert.PNG"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/61/95/8867.AotTableWithOverridenInsert.PNG" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-61-95/8867.AotTableWithOverridenInsert.PNG" alt="" width="179" height="260" border="0" /></a></p>
<p>&nbsp;</p>
<pre class="brush: c#;wrap-lines:false;">public void insert()
{
    // Dummy code
    this.InvoiceId += '0';
    
    super();
}
</pre>
<p><span style="font-size: small;">So, lets employ the <a href="https://msdn.microsoft.com/en-us/library/recordinsertlist.aspx">RecordInsertList</a> approach again.&nbsp;Will the "record by record" insert call&nbsp;from the AOS side be avoided?</span>&nbsp;Will Dynamics AX send a small amount of packages to <a href="https://www.microsoft.com/sqlserver/pt/br/default.aspx">SQL Server</a>?</p>
<pre class="brush: c#;wrap-lines:false;">static void insertIntoMyInvOverridenByRecordInsLst(Args _args)
{
    int                             i;
    MyInvoiceInsertOverriden        myInvoiceRecord;
    int                             startTime, endTime;

    // This collection will store the records that must be inserted into the database
    RecordInsertList                invoicesToBeInserted = new RecordInsertList(tableNum(MyInvoiceInsertOverriden));

    startTime = WinAPI::getTickCount();

    for (i = 0; i &lt; 10000; ++i)
    {
        // Initializing the buffer with dummy values
        myInvoiceRecord.InvoiceAmount = (i + 1) * 100;
        myInvoiceRecord.CurrencyCode = 'REA';
        myInvoiceRecord.Qty = (i + 1) * 10;
        myInvoiceRecord.InvoiceId = int2str(i + 1);

        // Instead of inserting the record into the database, we will add
        // it to the RecordInsertList array
        invoicesToBeInserted.add(myInvoiceRecord);
    }

    // After fulfilling the array with the elements to be inserted, we are
    // read to execute the insert operation
    invoicesToBeInserted.insertDatabase();

    endTime = WinAPI::getTickCount();

    info(strFmt('It took %1 miliseconds to insert 10k registers with a RecordInsertList approach with overriden insert',
                endTime - startTime));
}
</pre>
<p><span style="font-size: small;">Now, lets see how many insert&nbsp;SQL statements have been executed through <a href="https://blogs.msdn.com/b/axperf/archive/2011/08/15/walk-through-major-features-of-microsoft-dynamics-ax-2012.aspx">Trace Parser</a>.</span></p>
<p>&nbsp;<a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/61/95/2110.TraceParserInsertOverriden.PNG" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-61-95/2110.TraceParserInsertOverriden.PNG"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/61/95/2110.TraceParserInsertOverriden.PNG" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-61-95/2110.TraceParserInsertOverriden.PNG" alt="" border="0" /></a></p>
<p>&nbsp;<span style="font-size: small;">Wait!!! What is going on??? 10k insert statements!!!</span></p>
<p><span style="font-size: small;">Unfortunatelly, Ax has executed one call to <a href="https://www.microsoft.com/sqlserver/pt/br/default.aspx">SQL Server</a> per insert statement. This situation happened because we have overriden the insert method at the table.</span></p>
<p><span style="font-size: small;">The constructor of <a href="https://msdn.microsoft.com/en-us/library/recordinsertlist.aspx">RecordInsertList</a> allows skipping the insert method call, by passing true to the second parameter, BUT I STRONGLY recommend you to do not try this because the insert method will not be executed. Since there is an insert method, it probably contains&nbsp;important instructions.</span></p>
<p><span style="font-size: small;">Anyway, lets try skipping this method and lets make sure that we will not execute 10k insert statements from AOS side.</span></p>
<p>&nbsp;</p>
<pre class="brush: c#;wrap-lines:false;">static void insertIntoMyInvOverridenSkipInsert(Args _args)
{
    int                             i;
    MyInvoiceInsertOverriden        myInvoiceRecord;
    int                             startTime, endTime;

    // Notice that the second parameter is being passed as true to inform that 
    // the insert method must be skipped
    RecordInsertList invoicesToBeInserted = new RecordInsertList(tableNum(MyInvoiceInsertOverriden), true);

    startTime = WinAPI::getTickCount();

    for (i = 0; i &lt; 10000; ++i)
    {
        myInvoiceRecord.InvoiceAmount = (i + 1) * 100;
        myInvoiceRecord.CurrencyCode = 'REA';
        myInvoiceRecord.Qty = (i + 1) * 10;
        myInvoiceRecord.InvoiceId = int2str(i + 1);

        invoicesToBeInserted.add(myInvoiceRecord);
    }

    invoicesToBeInserted.insertDatabase();
}
</pre>
<p><span style="font-size: small;">&nbsp;This time, if we look at <a href="https://blogs.msdn.com/b/axperf/archive/2011/08/15/walk-through-major-features-of-microsoft-dynamics-ax-2012.aspx">Trace Parser</a> results, just 141 insert statements have been executed from the AOS side. Please, keep in mind that the insert overriden method has not been executed and this skipping may be extremelly dangerous for the consistency of yours data.</span></p>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/61/95/1325.TraceParserSkipInsert.PNG" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-61-95/1325.TraceParserSkipInsert.PNG"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/61/95/1325.TraceParserSkipInsert.PNG" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-61-95/1325.TraceParserSkipInsert.PNG" alt="" border="0" /></a></p>
<p>&nbsp;</p>
<p>&nbsp;<span style="color: #000000; font-size: small;"><span style="color: #3366ff; font-size: large;">Summary</span></span></p>
<p><span style="font-size: small;">While programming with a performance focus, you should always measure your implementation performance because some assumptions may be wrong.</span></p>
<p><span style="font-size: small;">Although sometimes we have the means to overcome a performance downgrade, we must do the trade off analysis.</span></p>
<p><span style="font-size: small;">In some situations <a href="https://msdn.microsoft.com/en-us/library/recordinsertlist.aspx">RecordInsertList</a> will not provide all the performance benefits that we would expect. For sure, you could by-pass these situations by writing some&nbsp;code, but the damage can be huge.</span></p>
<p><span style="font-size: small;">The attached file contains the code of this post.</span></p>
<p><span style="font-size: small;">My next post will cover how to use <a href="https://msdn.microsoft.com/en-us/library/recordinsertlist.aspx">RecordInsertList</a> with <a href="https://msdn.microsoft.com/en-us/library/gg863308.aspx">temporary tables</a>.</span></p>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Components.PostAttachments/00/10/46/14/36/PrivateProject_RecordInsertList.xpo" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-components-postattachments/00-10-46-14-36/PrivateProject_5F00_RecordInsertList.xpo">PrivateProject_RecordInsertList.xpo</a></p>]]></content:encoded>
    </item>
  </channel>
</rss>