IT tutorials
 
Technology
 

Microsoft Dynamic AX 2009 : .Performance (part 6) - Transaction Performance - Caching - Record Caches

10/28/2013 3:47:24 AM
- Free product key for windows 10
- Free Product Key for Microsoft office 365
- Malwarebytes Premium 3.7.1 Serial Keys (LifeTime) 2019

3.3 Caching

The Dynamics AX application runtime supports the enabling of single-record and set-based record caching. You can enable set-based caching in metadata by switching a property on a table definition or writing explicit X++ code, which instantiates a cache. Regardless of how you set up caching, you don’t need to know which caching method is used because the application runtime handles the cache transparently. To optimize the use of the cache, however, you must understand how each caching mechanism works.

3.3.1 Record Caches

You can set up three types of record caching on a table by setting the CacheLookup property on the table definition:

  • Found

  • FoundAndEmpty

  • NotInTTS

One additional value (besides None) is EntireTable, which is a set-based caching option we describe later in this section.

The three record-caching possibilities are fundamentally the same. The differences lie in what is cached and when cached values are flushed. For example, the FoundFoundAndEmpty caches are preserved across transaction boundaries, but a table that uses the NotInTTS cache doesn’t use the cache when first accessed inside a transaction scope—it uses it in consecutive select statements, unless a forupdate keyword is applied to the select statement. The following X++ code example describes when the cache is used inside and outside a transaction scope, when a table uses the NotInTTS caching mechanism, and when the AccountNum field is the primary key. The code comments indicate when the cache is or isn’t used. In the example, it appears that the first two select statements after the ttsbegin command don’t use the cache. The first doesn’t use the cache because it’s the first statement inside the transaction scope; the second doesn’t use the cache because the forupdate keyword is applied to the statement. The use of the forupdate keyword forces the application runtime to look up the record in the database because the previously cached record wasn’t selected with the forupdate keyword applied.

static void NotInTTSCache(Args _args)
{
CustTable custTable;
;
select custTable // Look up in cache. If record
where custTable.AccountNum == '1101'; // does not exist, look up
// in database.
ttsbegin; // Start transaction.

select custTable // Cache is invalid. Look up in
where custTable.AccountNum == '1101'; // database and place in cache.

select forupdate custTable // Look up in database because
where custTable.AccountNum == '1101'; // forupdate keyword is applied.

select custTable // Cache will be used.
where custTable.AccountNum == '1101'; // No lookup in database.

select forupdate custTable // Cache will be used because
where custTable.AccountNum == '1101'; // forupdate keyword was used
// previously.

ttscommit; // End transaction.

select custTable // Cache will be used.
where custTable.AccountNum == '1101';
}



If the table had been set up with Found or FoundAndEmpty caching in the preceding example, the cache would have been used when executing the first selectselect forupdate statement was executed. statement inside the transaction, but not when the first

Note

By default, all Dynamics AX system tables are set up using a Found cache. This cannot be changed.


For all three caching mechanisms, the cache is used only if the select statement contains equal-to (==) predicates in the where clause that exactly match all the fields in the primary index of the table or any one of the unique indexes defined for the table. The PrimaryIndex property on the table must therefore be set correctly on one of the unique indexes used when accessing the cache from application logic. For all other unique indexes, without any additional settings in metadata, the kernel automatically uses the cache, if it is already present. Support for unique-index-based caching is a new feature in Dynamics AX 2009.

The following X++ code examples show when the Dynamics AX application runtime will try to use the cache and when it won’t. The cache is used only in the first select statement; the remaining three statements don’t match the fields in the primary index, so they will all perform lookups in the database.

static void UtilizeCache(Args _args)
{
CustTable custTable;
;
select custTable // Will use cache because only
where custTable.AccountNum == '1101'; // the primary key is used as
// predicate.

select custTable; // Cannot use cache because no
// "where" clause exists.

select custTable // Cannot use cache because
where custTable.AccountNum > '1101'; // equal to (==) is not used.

select custTable // Will not use cache because
where custTable.AccountNum == '1101' // where clause contains more
&& custTable.CustGroup == '20'; // predicates than the primary
// key.
}



Note

The RecId index, which is always unique on a table, can be set as the PrimaryIndex in the table’s properties. You can therefore set up caching using the RecId field.


The following X++ code examples show how unique-index caching works in the Dynamics AX application runtime. InventDim in the base application has InventDimId as the primary key and a combination of keys (inventBatchId, wmsLocationId, wmsPalletId, inventSerialId, inventLocationId, configId, inventSizeId, inventColorId, and inventSiteId) as the unique index on the table.

static void UtilizeUniqueIndexCache(Args _args)
{
InventDim InventDim;
;
select inventDim // Will use cache because only
where inventDim.inventDimId == '00000001_082'; // the primary key is used as
// predicate.

select inventDim // Will use cache
where inventDim.inventBatchId == '' // because the column list in
&& inventDim.wmsLocationId == '' // the "where" clause
&& inventDim.wmsPalletId == '' // match that of a unique
&& inventDim.inventSerialId == '' // index for table inventdim
&& inventDim.inventLocationId == '400' // and the key values point to
&& inventDim.ConfigId == '01' // same record as the primary
&& inventDim.inventSizeId == '' // key fetch (inventDimId ==
&& inventDim.inventColorId == '' // '00000001_082').
&& inventDim.inventSiteId == '4'; //

select inventDim // Cannot use cache because
where inventDim.inventLocationId== '400' // where clause does not
&& inventDim.ConfigId == '01' // match the unique key list
&& inventDim.inventSiteId == '4'; // or primary key.
}



The Dynamics AX application runtime ensures that all fields on a record are selected before they are cached. The application runtime therefore always changes a field list to include all fields on the table before submitting the SELECT statement to the database when it can’t find the record in the cache. The following X++ code illustrates this behavior.

static void expandingFieldList(Args _args)
{
CustTable custTable;
;
select creditRating // The field list will be expanded to all fields.
from custTable
where custTable.AccountNum == '1101';
}


If the preceding select statement doesn’t find a record in the cache, it expands the field to contain all fields, not just the creditRating field. This ensures that the fetched record from the database contains values for all fields before it is inserted into the cache. Even though performance when fetching all fields is inferior compared to performance when fetching a few fields, this approach is acceptable because in subsequent use of the cache, the performance gain outweighs the performance loss from populating it.

Tip

You can disregard the use of the cache by calling the disableCache method on the record buffer with a Boolean true parameter. This method forces the application runtime to look up the record in the database, and it also prevents the application runtime from expanding the field list.


The Dynamics AX application runtime creates and uses caches on both the client tier and the server tier. The client-side cache is local to the rich client, and the server-side cache is shared among all connections to the server, including connections coming from rich clients, Web clients, .NET Business Connector, and any another connection.

The cache used depends on which tier the lookup is made from. If the lookup is made on the server tier, the server-side cache is used. If the lookup is executed from the client tier, the client first looks in the client-side cache; if it doesn’t find anything, it makes a lookup in the server-side cache. If there is still no record, a lookup is made in the database. When the database returns the record to the server and on to the client, the record is inserted into both the server-side cache and the client-side cache.

The caches are implemented using AVL trees (which are balanced binary trees), but the trees aren’t allowed to grow indefinitely. The client-side cache can contain a maximum of 100 records for a given table in a given company, and the shared server-side cache can contain a maximum of 2000 records. When a new record is inserted into the cache and the maximum is reached, the application runtime removes approximately 5 to 7 percent of the oldest records by scanning the entire tree.

Note

You can’t change the maximum number of records to be cached in metadata or from the X++ code.


Scenarios that repeat lookups on the same records and expect to find the records in the cache can suffer performance degradation if the cache is continuously full—not only because records won’t be found in the cache because they were removed based on the aging scheme, forcing a lookup in the database, but also because of the constant scanning of the tree to remove the oldest records. The following X++ code shows an example in which all SalesTable records are looped twice, and each loop looks up the associated CustTable record. If this X++ code were executed on the server and the number of CustTable record lookups was more than 2000, the oldest records would be removed from the cache, and the cache wouldn’t contain all CustTable records when the first loop ended. When the code loops through the SalesTable records again, the records might not be in the cache, and the selection of the CustTable record would continue to go to the database to look up the record. The scenario would therefore perform much better with fewer than 2000 records in the database.

static void AgingScheme(Args _args)
{
SalesTable salesTable;
CustTable custTable;
;
while select SalesTable order by custAccount
{
select custTable // Fill up cache.
where custTable.AccountNum == salesTable.CustAccount;
// More code here.
}

while select SalesTable order by custAccount
{
select custTable // Record might not be in cache.
where custTable.AccountNum == salesTable.CustAccount;
// More code here.
}

}


Important

If you test code on small databases, you can’t track repeat lookups only by tracing the number of statements parsed to the database. When you execute such code in a production environment, you can encounter severe performance issues because this scenario doesn’t scale very well.


Before the Dynamics AX application runtime searches for, inserts, updates, or deletes records in the cache, it places a mutually exclusive lock that isn’t released until the operation is complete. This lock means that two processes running on the same server can’t perform insert, update, or delete operations in the cache at the same time; only one process can hold the lock at any given time, and the remaining processes are blocked. Blocking occurs only when the application runtime accesses the server-side cache. So although the caching possibilities the application runtime supports are useful features, you shouldn’t abuse them. If you can reuse a record buffer that is already fetched, you should do so. The following X++ code shows the same record fetched twice. The second fetch uses the cache even though it could have used the first fetched record buffer. When you execute the following X++ code on the server tier, the process might get blocked when the application runtime searches the cache.

static void ReuseRecordBuffer(Args _args)
{
CustTable custTable;
;
select custTable
where custTable.AccountNum == '1101';

// Some more code, which does not change the custTable record.

select custTable // The cache will be used, but
where custTable.AccountNum == '1101'; // blocking might occur.
// Reuse the record buffer
// instead.
}

 
Others
 
- Microsoft Dynamic AX 2009 : .Performance (part 6) - Transaction Performance - Set-Based Data Manipulation Operators - The RecordInsertList and RecordSortedList Classes
- Microsoft Dynamic AX 2009 : .Performance (part 5) - Transaction Performance - Set-Based Data Manipulation Operators - The RecordInsertList and RecordSortedList Classes
- Microsoft Dynamic AX 2009 : .Performance (part 4) - Transaction Performance - Set-Based Data Manipulation Operators - The delete_from Operator
- Microsoft Dynamic AX 2009 : .Performance (part 3) - Transaction Performance - Set-Based Data Manipulation Operators - The update_recordset Operator
- Microsoft Dynamic AX 2009 : .Performance (part 2) - Transaction Performance - Set-Based Data Manipulation Operators - The insert_recordset Operator
- Microsoft Dynamic AX 2009 : .Performance (part 1) - Reducing Round-Trips Between the Client and the Server
- Exchange Server 2010 Quick Start Guide : Configuring Recipients (part 3) - Configuring a Postmaster Address, SSL Certificate , Entering the Product Key
- Exchange Server 2010 Quick Start Guide : Configuring Recipients (part 2) - Creating Distribution Groups, Organizational Health
- Exchange Server 2010 Quick Start Guide : Configuring Recipients (part 1)
- Sharepoint 2010 : Data Access Overview - Performance
 
 
Top 10
 
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Finding containers and lists in Visio (part 2) - Wireframes,Legends
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Finding containers and lists in Visio (part 1) - Swimlanes
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Formatting and sizing lists
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Adding shapes to lists
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Sizing containers
- Microsoft Access 2010 : Control Properties and Why to Use Them (part 3) - The Other Properties of a Control
- Microsoft Access 2010 : Control Properties and Why to Use Them (part 2) - The Data Properties of a Control
- Microsoft Access 2010 : Control Properties and Why to Use Them (part 1) - The Format Properties of a Control
- Microsoft Access 2010 : Form Properties and Why Should You Use Them - Working with the Properties Window
- Microsoft Visio 2013 : Using the Organization Chart Wizard with new data
Technology FAQ
- Is possible to just to use a wireless router to extend wireless access to wireless access points?
- Ruby - Insert Struct to MySql
- how to find my Symantec pcAnywhere serial number
- About direct X / Open GL issue
- How to determine eclipse version?
- What SAN cert Exchange 2010 for UM, OA?
- How do I populate a SQL Express table from Excel file?
- code for express check out with Paypal.
- Problem with Templated User Control
- ShellExecute SW_HIDE
programming4us programming4us