One problem we encounter almost on a weekly basis is general performance problems. Most performance problems we have seen lately have been related to either inadequate disk configuration or MAPI restrictions. Mike Lee has already explained the bit about Disk issues in his entry, so I am going to tackle the other issue of MAPI restrictions.
Let’s start with the basics. MAPI represents data typically in the form of a table. Everything is a table; there is a table that is presented to the client when it requests a list of providers, a table for folders, folder contents, attachments, etc. Each table is comprised of columns. Each column is a different MAPI property representing things like the sender, subject, and delivery time. Each row represents an individual item, so for a folder contents table, each row would represent messages. Now the client can do some interesting things with the tables, like resort them. The client can seek in the table to a specific row that matches criteria. This operation is referred to as a FindRow(). It can also request that only items fitting a certain criteria be included in the table. An example would be to only include items created on a specific day. This is what is known as a restriction. The resulting folder contents table would only have items in the table that meet the given criteria. Restrictions are used when it is expected the client will be requesting the same representation of data on a frequent basis.
So now you maybe asking, “Why is that so bad?”
Well to understand it we need to take a look at how the Store actually stores the data a MAPI client requests and how it interprets requests such as FindRow and Restrict. Inside the storage schema of the store we have various tables that collectively represent things such as mailboxes, folders, folder contents, and messages. This is what allows the store to do things like Single Instance Storage.
When a client requests a list of the contents of a folder, that request is mapped to a special folder referred to as a MessageFolder Table (MsgFolder for short). Each folder created in the system has a separate message folder table. The purpose of the MsgFolder table is to map a folder to its contents. Keep in mind that for Single Instance Storage we have to allow multiple folders to keep a reference to a single message and multiple messages may appear in any given folders. In the database terminology this is known as a many-to-many relationship which requires an intermediate mapping table, the MsgFolder table (one for each folder).
So to accommodate the client request to only be presented with messages from a specific date range, we could get a reference to the Folder’s MsgFolder table, then selectively remove unwanted rows by traversing the table in memory, but that would be very expensive operation. To handle the expectations of a Restrict call (frequent re-request for the same data) we create a new special folder (and corresponding MsgFolder table) that is referred to as a Restricted Search Folder. This folder is linked back to the original folder and logical relationship exists between these two folders. We place a condition on the search folder such that it should only include items that meet the criteria specified by the restriction. In this search folder, a backlink to the original row in the MsgFolder table exists for each message in the MsgFolder table that meets the criteria of the restriction.
The performance issues that is encountered is the time it takes to manage the update to each of the search folders. When a change takes place on the original folder, the change is compared to each of the restricted search folders associated with the folder in question to determine if they need to be updated as well. This has a bigger impact when a lot of search folders exists for one or many folders. The second issue encountered is the creation of the restricted search folders. The creation of restricted search folder requires a full pass of the original folder to extract individual items that need to be linked into the restricted search folder. If this process occurs as a direct result of an action of the client, the time make experience a hang or receive the Outlook popup box indicating a request is taking a long time process. The time it takes to create the restricted search folder is proportional to the number of items in the regular folder.
In Exchange 5.5 we did not put a limit on the number of the restricted search folders that we would allow, but the default timeout was 8 days. If the restricted search folder was not used in 8 days, it would be removed as a part of background store maintenance. The led to performance problems as lots of restricted search folders could be created all of which would need to be updated every time the original folder had any add/delete/changes/moves.
In Exchange 2000/2003 we put a cap on the maximum number (11) of restricted search folder we would allow on a per folder basis, however the default lifetime was increased from 8 to 40 days.
This has proven to be adequate for most, but from time to time we see the opposite problem occur. If a folder already has 11 restricted search folders associated with it and a new restrict request is made, the list of search folders is FIFO based using the last time the restriction was actually used. So this means the stalest restricted search folder is removed to make room for the new request. As mentioned above, this requires a full pass of the regular MsgFolder table and if done on the “Clients time” the client may perceive a performance issue while the table is being build for the client. So it is possible that on a daily or weekly basis more than 12 restricted search folders are used/created while the limit is 11. Eventually the client hits a restriction request that currently doesn’t have a matching search folder and results in the delete and creation of new restricted search folder on the client’s time.
So how do you identify this situation and what can be done about them?
isinteg -pri|pub -dump -l logfilename
Hope this was helpful!