Chapter 5: Improving Application PerformanceCHAPTER 5: IMPROVING APPLICATIONPERFORMANCEObjectives                The objec...
SQL Server Installation and Optimization for Microsoft Dynamics®NAV 2009Optimizing C/AL Code                  There are se...
Chapter 5: Improving Application Performance      A heap can be considered as an unordered table or a collection of unorde...
SQL Server Installation and Optimization for Microsoft Dynamics®NAV 2009                   C/AL Code                    SQ...
Chapter 5: Improving Application Performance      Instead of re-reading the data, Microsoft Dynamics NAV can immediately  ...
SQL Server Installation and Optimization for Microsoft Dynamics®NAV 2009                  BLOBs                  BLOBs can...
Chapter 5: Improving Application Performance      Change Filtered Values      In the following example, a field used to fi...
SQL Server Installation and Optimization for Microsoft Dynamics®NAV 2009                  Initially, the record set is ret...
Chapter 5: Improving Application Performance      By changing the key field, you disturb the current sorting and at the sa...
SQL Server Installation and Optimization for Microsoft Dynamics®NAV 2009SIFT                  SIFT was originally implemen...
Chapter 5: Improving Application Performance      If developers disable the SIFT table by clearing the MaintainSIFTIndex c...
SQL Server Installation and Optimization for Microsoft Dynamics®NAV 2009                  To keep the SIFT tables from gro...
Chapter 5: Improving Application Performance      After the indexed view has been created, the contents of the view are ma...
SQL Server Installation and Optimization for Microsoft Dynamics®NAV 2009                  There are different possibilitie...
Chapter 5: Improving Application Performance                You do not have to maintain a SIFT key for a total that is onl...
SQL Server Installation and Optimization for Microsoft Dynamics®NAV 2009                  Cursors                  Because...
Chapter 5: Improving Application Performance      When executed, the first code sample will be translated into an SQL stat...
SQL Server Installation and Optimization for Microsoft Dynamics®NAV 2009                  WARNING: If using a REPEAT/UNTIL...
Chapter 5: Improving Application Performance      From previous paragraphs, you know that FIND will generate a cursor in c...
SQL Server Installation and Optimization for Microsoft Dynamics®NAV 2009                  The variations of the FINDSET in...
Chapter 5: Improving Application Performance                GLEntry."Credit Amount" := 0;              END ELSE BEGIN     ...
SQL Server Installation and Optimization for Microsoft Dynamics®NAV 2009                  Like FINDSET(TRUE), the command ...
Chapter 5: Improving Application Performance                    IF SalesLine.Type = SalesLine.Type::Item THEN             ...
SQL Server Installation and Optimization for Microsoft Dynamics®NAV 2009                  table, there are several keys th...
Chapter 5: Improving Application Performance      Classic Database Server will search through the index branches and retri...
SQL Server Installation and Optimization for Microsoft Dynamics®NAV 2009                  The decision whether to use few ...
Chapter 5: Improving Application Performance      MaintainSQLIndex Property      This property determines whether a SQL Se...
SQL Server Installation and Optimization for Microsoft Dynamics®NAV 2009                  MaintainSIFTIndex               ...
Chapter 5: Improving Application Performance      Key groups can be maintained in the Database Key Groups window. To open ...
SQL Server Installation and Optimization for Microsoft Dynamics®NAV 2009Locks, Blocks and Deadlocks                  When ...
Chapter 5: Improving Application Performance       User A                 User B            Comment       Cust.Blocked := ...
SQL Server Installation and Optimization for Microsoft Dynamics®NAV 2009                  For example, consider a case in ...
Chapter 5: Improving Application Performance                Although locking and blocking are necessary to support concurr...
SQL Server Installation and Optimization for Microsoft Dynamics®NAV 2009                  Parameter Sniffing              ...
Chapter 5: Improving Application Performance      Adding the 1048576 value to the Diagnostics column of the row in      nd...
Na2009 enus sql_05
Na2009 enus sql_05
Na2009 enus sql_05
Na2009 enus sql_05
Na2009 enus sql_05
Na2009 enus sql_05
Na2009 enus sql_05
Na2009 enus sql_05
Na2009 enus sql_05
Na2009 enus sql_05
Na2009 enus sql_05
Na2009 enus sql_05
Na2009 enus sql_05
Na2009 enus sql_05
Na2009 enus sql_05
Na2009 enus sql_05
Na2009 enus sql_05
Na2009 enus sql_05
Na2009 enus sql_05
Na2009 enus sql_05
Na2009 enus sql_05
Na2009 enus sql_05
Na2009 enus sql_05
Na2009 enus sql_05
Na2009 enus sql_05
Na2009 enus sql_05
Na2009 enus sql_05
Na2009 enus sql_05
Na2009 enus sql_05
Na2009 enus sql_05
Na2009 enus sql_05
Na2009 enus sql_05
Na2009 enus sql_05
Na2009 enus sql_05
Na2009 enus sql_05
Na2009 enus sql_05
Na2009 enus sql_05
Na2009 enus sql_05
Na2009 enus sql_05
Upcoming SlideShare
Loading in...5
×

Na2009 enus sql_05

749

Published on

Published in: Technology
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total Views
749
On Slideshare
0
From Embeds
0
Number of Embeds
0
Actions
Shares
0
Downloads
22
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

Na2009 enus sql_05

  1. 1. Chapter 5: Improving Application PerformanceCHAPTER 5: IMPROVING APPLICATIONPERFORMANCEObjectives The objectives are: • Write optimized C/AL code. • Optimize Sum Index Field Technology (SIFT) tables. • Optimize cursors by using the right C/AL code statements. • Optimize key design and usage in Microsoft Dynamics® NAV. • Avoid locks and deadlocks. • Troubleshoot performance issues related to the graphical user interface. • Setup index hinting. • Optimize data entry using the Bulk Insert feature. • Use some tips and tricks that are useful when optimizing Microsoft Dynamics NAV on Microsoft® SQL Server®.Introduction This chapter describes how to solve and avoid performance issues by optimizing C/AL code and indexes. Microsoft Official Training Materials for Microsoft Dynamics ® 5-1 Your use of this content is subject to your current services agreement
  2. 2. SQL Server Installation and Optimization for Microsoft Dynamics®NAV 2009Optimizing C/AL Code There are several areas where developers need to focus when optimizing Microsoft Dynamics NAV applications. These areas are as follows, in order of importance (based on the processing costs): • SIFT • Keys and Indexes • Cursors • Locks • Suboptimum Code • Graphical User Interface (GUI) This lesson contains general guidelines for writing C/AL code. It explains which areas to pay extra attention to. Keys Keys define the order in which data is stored in your tables. Logically, records are stored sequentially in ascending order, sorted by the clustered index. Physically, records can be sorted on disk in a different order. You can speed up searches in tables by defining several keys which sort information in different ways. Defining keys is one thing; using the correct keys is also very important for performance. When writing code or creating reports, you must use the appropriate keys to get maximum performance. If you do not specify an adequate key, Microsoft SQL Server will try to find the best index. When a key is created in Microsoft Dynamics NAV, an index is created for that key in the corresponding SQL Server table. By default, a primary key is translated into the clustered unique index and secondary keys become non- clustered unique indexes. The only time when data in a table in SQL Server is stored in a sorted manner is when there is a clustered index defined in the table. The data is then stored sorted according to the fields in the clustered index. The primary key does not always provide the best sorting order for records. A typical example is a ledger entry table. The primary key of a ledger entry table is a single field, Entry No. However, most queries on ledger entry tables use fields other than the primary key, such as Posting Date, No. or Status. Data manipulation and retrieval on these tables can be optimized by physically storing the records in the order in which they are often queried. The physical storage order of records is determined by the clustered index. By default, if you do not specify a clustered index, the primary key will be used as clustered index. To select a key as clustered index, you can set the Clustered property of a key to Yes. You can have only one clustered index per table. Tables without clustered indexes are called "heaps."5-2 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement
  3. 3. Chapter 5: Improving Application Performance A heap can be considered as an unordered table or a collection of unordered data pages. This means that rows will be inserted into the heap anywhere there is space. As data is fragmented, retrieving data from a heap causes many data page reads. Often this results in reading the complete table. For this reason, heaps are to be avoided. Indexes that are only designed for sorting purposes can create overhead during insert, update, delete statements on SQL Server. That is why sometimes we recommend not to maintain these indexes on SQL Server. On the other hand, Microsoft Dynamics NAV will request a dynamic cursor most of the time and, in general, it is a good idea that an index fits both the order by and the where clause. Cursors When writing code to retrieve or browse through record sets in Microsoft Dynamics NAV, you can use a number of instructions. Retrieving data can be done for different reasons, such as you want to modify the data, or you just want to check whether records exist that meet specific criteria (without doing anything with the records). In SQL Server Option, each FIND instruction will be translated into one or more SQL statement that read data a particular way (using a specific cursor and isolation level). Very often, performance issues are caused by improper use of FIND statements, causing wrong cursors and isolation levels to be used. As a result of this, data is returned but not used, or data is returned as read-only when it must be modified. Using the correct FIND statement improves data retrieval and processing. Locks There are additional considerations to make when working with Microsoft Dynamics NAV on SQL Server. Microsoft Dynamics NAV is designed to read without locks and locks only if it is necessary, following optimistic concurrency recommendations. If records are to be modified, that intent should be indicated to the Database Management System (DBMS) (use explicit locking), so that the data is read properly. Implicit Locking The following table demonstrates implicit locking. The C/AL code is mapped to the equivalent action on SQL Server: C/AL Code SQL Server Cust.FIND(-); SELECT * FROM Customer WITH (READUNCOMMITTED) (the retrieved record timestamp = TS1) Cust.Name := John Doe; Microsoft Official Training Materials for Microsoft Dynamics ® 5-3Your use of this content is subject to your current services agreement
  4. 4. SQL Server Installation and Optimization for Microsoft Dynamics®NAV 2009 C/AL Code SQL Server Cust.MODIFY; SELECT * FROM Customer WITH (UPDLOCK, REPEATABLEREAD) (the retrieved record timestamp = TS2) performs the update UPDATE Customer SET Name = John Doe WITH (REPEATABLEREAD) WHERE TimeStamp <= TS1 The reason for such a complex execution is that: • The data is read with the READUNCOMMITED isolation level, but because users will update it, they need to ensure that they read committed data and issue an update lock on it to prevent other users from updating the same records. • The data is originally read uncommitted. Users need to lock the record and ensure that they update the record with an original timestamp. If somebody else changes the record, that person receives the following error message: "Another user has modified the record since users retrieved from the database." Explicit Locking If developers indicate that their intention is to modify the record by using explicit locking, they can eliminate the unacceptable behavior completely, as shown in the following table: C/AL Code SQL Server Cust.LOCKTABLE; Indicates intention of modification. Cust.FIND(-); SELECT * FROM Customer WITH (UPDLOCK) (the retrieved record timestamp = TS1) Cust.Name := John Doe; Cust.MODIFY; UPDATE Customer SET Name = John Doe WITH (REPEATABLEREAD) (the retrieved record timestamp is guaranteed to be TS1)5-4 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement
  5. 5. Chapter 5: Improving Application Performance Instead of re-reading the data, Microsoft Dynamics NAV can immediately proceed to issue an UPDATE statement. This behavior explains the many occurrences of the following piece of code in the standard application: IF Rec.RECORDLEVELLOCKING THEN Rec.LOCKTABLE; The LOCKTABLE instruction is used to read the data with the correct isolation level. On SQL Server, LOCKTABLE will not lock any records. It will change the way records are accessed. The RECORDLEVELLOCKING function returns true if the code is being executed on SQL Server, otherwise it returns false. Suboptimum Code Taking performance into consideration often influences programming decisions. Often, users pay a high price in terms of performance because the code is not optimized. For example, if developers do not use explicit locking, or if they program bad loops and provoke problems with NEXT. Therefore, developers must review their code and check for the presence of performance degrading statements or scenarios, such as the following: • Read the same table multiple times. • Use COUNT to check whether records exist that meet specific criteria. • Use MARKEDONLY instead of pushing records to a temporary table and read them from there. • Use WHILE FIND to browse through a record set. (The WHILE FIND always looks for the first or last record in a set and therefore automatically disables the read ahead mechanism). • Use IF NOT INSERT THEN MODIFY. Additionally, there are features in the application that require special attention. For example, the advanced dimensions functionality can be cost demanding when you use a lot of dimensions and have analysis views updated automatically on posting. Other functionalities that require attention to are as follows: • Automatic Cost Posting, Automatic Cost Adjustment, Expected Cost Posting to G/L • Discount Posting ="All Discounts" • Credit Warnings ="Both Warnings" • Stockout Warnings Users should review the application setup for the performance aspect and make corrective actions possible. Microsoft Official Training Materials for Microsoft Dynamics ® 5-5Your use of this content is subject to your current services agreement
  6. 6. SQL Server Installation and Optimization for Microsoft Dynamics®NAV 2009 BLOBs BLOBs can also cause performance issues because they are stored in a specific way in the SQL Server database. First of all, BLOB fields in Microsoft Dynamics NAV have a compressed property, which indicates whether the data will be saved compressed. By default, the property is set to True, which means that Microsoft Dynamics NAV will use a special algorithm to compact the BLOB data. However, SQL Server does not know this algorithm and needs additional operations to handle the data. Secondly, as Microsoft Dynamics NAV always generates SELECT * FROM queries, all data from a table is returned, including BLOB fields. As the BLOB is stored separately from the other table columns, SQL Server needs extra operations (page reads and CPU power) to collect the BLOB data. (Because a BLOB can take up to 2 GB, BLOBs are often spread over several pages.) However, the BLOB data is not relevant for many transactions and processes (such as item lookups, order posting, and item journal posting). Nevertheless, the BLOB data is always read. When using BLOBs, we recommend that you: • Set the Compressed property on BLOB fields to False. As a consequence, SQL Server needs less operations to retrieve the BLOB data. • Keep BLOBs away from transactions and processes, by storing the BLOB data in separate tables. You do not have to delete or disable the BLOB field; not using the field will already do this. Problems with NEXT In some cases, the NEXT command causes the biggest performance problem in Microsoft Dynamics NAV. The problem is that NEXT uses a cursor, and you cannot change the isolation level in the middle of the data retrieval. This means that data has to be retrieved again, using a new SELECT statement. This imposes a serious performance penalty in SQL Server and, in some cases, leads to very lengthy execution. Typical scenarios where NEXT causes problems are as follows: • The filtering of a record set is changed • The sorting of a record set is changed • A key value is changed • The isolation level is changed • NEXT is called in the middle of nowhere (on a record that is retrieved using GET or another way) • NEXT in combination with FINDFIRST or FINDLAST The following examples show some of the scenarios listed here.5-6 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement
  7. 7. Chapter 5: Improving Application Performance Change Filtered Values In the following example, a field used to filter a table is assigned a new value in the record set. SETRANGE(FieldA, Value); FIND(-); REPEAT ... FieldA := NewValue; ... MODIFY; ... UNTIL NEXT = 0; By changing the filtered field, the record will be moved outside the current record set. When calling the NEXT instruction, Microsoft Dynamics NAV needs to execute extra queries to detect its cursor position in the original record set and will finally retrieve a complete new record set. This is no longer the case from version 5.0 and later versions, because instead Microsoft Dynamics NAV will request a dynamic cursor for this type of statement. However, for example, FindSet with parameter (FALSE) Microsoft Dynamics NAV will reissue the queries to find data. Change Sorting The same happens when you change the sorting of a record set after it was retrieved. SETCURRENTKEY(FieldA); FIND(-); REPEAT SETCURRENTKEY(FieldB); FIND(-); ... UNTIL NEXT = 0; When you change the sorting of a record set and retrieve the first record, Microsoft Dynamics NAV calls for a new record set (and an extra cursor). Change Isolation Level The following code shows an example of a changed isolation level. FINDFIRST; REPEAT ... MODIFY; UNTIL NEXT = 0; Microsoft Official Training Materials for Microsoft Dynamics ® 5-7Your use of this content is subject to your current services agreement
  8. 8. SQL Server Installation and Optimization for Microsoft Dynamics®NAV 2009 Initially, the record set is retrieved with the READUNCOMMITTED isolation level. However, the MODIFY instruction requires a higher isolation level to modify the data. Since it is not possible to change the isolation level, in the middle of the process, Microsoft Dynamics NAV requests for a new record set. Jumping Through Record Sets The following code is a typical example of "jumping through a record set". SETRANGE(FieldA, Value); FIND(-); ... REPEAT SETRANGE(FieldB,Value2); ... FIND(+); ... SETRANGE(FieldB); ... UNTIL NEXT = 0; In this example, a new extra filter is applied to a record set, which leads to a new record set. The FIND(+) instruction requires a new cursor. When the NEXT statement is reached, Microsoft Dynamics NAV needs several queries to reposition its cursor in the original record set. FINDFIRST /FINDLAST with NEXT When NEXT is used in combination with FINDFIRST or FINDLAST, you go from a non-cursor to a cursor situation. The FINDFIRST instruction retrieves the data without cursors. NEXT causes a re-read with a cursor. SETRANGE(FieldA); FINDFIRST; REPEAT ... UNTIL NEXT = 0; Change Key Values In the following code, a field that is part of an active key is changed. SETCURRENTKEY(FieldA); FIND(-); REPEAT ... FieldA := NewValue; ... UNTIL NEXT = 0;5-8 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement
  9. 9. Chapter 5: Improving Application Performance By changing the key field, you disturb the current sorting and at the same time disable the benefits of SQL Servers read-ahead mechanism. When calling the NEXT instruction, SQL Server tries to read the next record based on the new key value. Solutions To eliminate performance problems with NEXT, consider the following solutions: • Browse sets nicely (without jumping) and by preference use a separate looping variable. • Restore original key values, sorting, and filters before the NEXT statement. • If you modify them multiple times then read records to temporary tables, modify within, and write back afterward. • Use FINDSET(TRUE,TRUE). Note also that FINDSET(TRUE,TRUE) is not a "real solution." It is merely a reduction of the costs and should be used only as a last resort. Graphical User Interface (GUI) The GUI overhead can slow down the client, if, for example, a dialog is refreshed 1000 times in a loop. GUI overhead can also cause increased server trips. When users use the default SourceTablePlacement = <Saved> on forms, it costs more than using Last or First. Users should review all forms showing data from large tables to look for performance problems. Another big overhead may come from the "Find As You Type" feature. When Find As You Type is enabled, the system is forced to do another query for each keystroke. This causes extra queries to be sent to the server. Finally, displaying many FlowFields on normal forms such as Customer Card, Item Card, and so on, can adversely affect form retrieval time, as the FlowFields have to be calculated. This can be a problem especially on list forms (showing multiple records at a time). The basic principle is to display these FlowFields on demand rather than by default when the user is not even interested in the information provided. If you need to display many FlowFields, use special forms such as Customer Statistics, Item Statistics, Customer Entry Statistics, Item Entry Statistics, Customer Sales, Item Turnover, and so on. Microsoft Official Training Materials for Microsoft Dynamics ® 5-9Your use of this content is subject to your current services agreement
  10. 10. SQL Server Installation and Optimization for Microsoft Dynamics®NAV 2009SIFT SIFT was originally implemented on SQL Server by using extra summary tables called SIFT Tables, that were maintained through table triggers directly in the table definitions on SQL Server. When an update was performed on a table that contains SIFT indexes, a series of additional updates were necessary to update the associated SIFT tables. This imposed an extra performance penalty - one that grew as the number of SIFT indexes on a table increased. With regards to performance, SIFT tables are one of the biggest Microsoft Dynamics NAV performance problems on SQL Server, as one record update in the base table produces a potentially massive stream of Input/Output (I/O) requests with updates to the records in the SIFT tables, possibly blocking other users during that time. In Microsoft Dynamics NAV 5.0 SP 1, Microsoft replaced SIFT tables with V- SIFT, which are indexed views. However, Microsoft Dynamics NAV developers will likely be involved with older versions, where they may encounter performance issues related to the SIFT tables. It is important for Microsoft Dynamics NAV developers to know how SIFT tables worked before version 5.0 SP1 and how to troubleshoot performance issues related to these tables. Optimizing SIFT Tables SIFT tables are used in Microsoft Dynamics NAV 5.0 and older, to implement SIFT on the SQL Server, and store aggregate values for SumIndexFields for keys in the source tables. The overhead of the separate SIFT tables is massive and should be carefully considered for activation. By default, Microsoft Dynamics NAV activates the SIFT tables when developers create a new index with SumIndexFields. Developers should review all of the existing SIFT indexes and determine whether they need to keep them activated. Developers can de-activate the creation and maintenance of a SIFT table by using the MaintainSIFTIndex property in the Microsoft Dynamics NAV key designer. If they make the property false, and there is no other maintained SIFT index supporting the retrieval of the cumulative sum, Microsoft Dynamics NAV asks SQL Server to calculate the sum itself. For example, if developers have a Sales Line table and put Amount in the SumIndexFields for the primary key ("Document Type, Document No., Line No."), a new SIFT table "CRONUS International Ltd_$37$0" is created and maintained. When a CALCSUM is used to display a FlowField in Microsoft Dynamics NAV showing the sum of all Sales Lines for a specific Sales Header (Order ORD-980001), the resulting query looks as follows: SELECT SUM(s29) FROM "CRONUS International Ltd_$37$0" WHERE "bucket" = 2 AND "f1" = 1 AND "f3" = ORD-9800015-10 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement
  11. 11. Chapter 5: Improving Application Performance If developers disable the SIFT table by clearing the MaintainSIFTIndex check box, Microsoft Dynamics NAV still works, and the resulting query looks as follows: SELECT SUM("Amount") FROM "CRONUS International Ltd_$Sales Line" WHERE "Document Type" = 1 AND "Document No_" = ORD- 980001 This is a very light load on CPU overhead compared to the massive costs of maintaining the SIFT table. SIFT tables are very beneficial when users need to sum a large number of records. With that in mind, developers can check existing SIFT tables and see whether they need all of the level of details. There is no need, for example, to store a cumulative sum of just a few records. Developers can use the property SIFTLevels and disable specific levels by clearing the Maintain for a specific bucket check box, thus reducing the overall overhead of the SIFT table while still keeping the SIFT table in place for summing the larger number of records. However, there is no need, for example, to keep cumulative sums on the top level buckets if they are used, such as a total of Quantity on Location Code in the Item Ledger Entry table, since users always filter on Item No. Table Optimization As explained earlier, every time you update a key or a SumIndexField in a base table all of the SIFT tables associated with the base table must also be updated. This means that the number of SIFT tables that you create, as well as the number of SIFT levels that you maintain, affects performance. If you have a very dynamic base table that constantly has records inserted, modified and deleted, the SIFT tables that are associated with it will constantly need to be updated. As a consequence, the SIFT tables can get very large, both because of the new records that are entered and because the records that are deleted from the base table are not removed from the SIFT tables. This can badly affect performance, especially when the SIFT tables are queried to calculate sums. Microsoft Official Training Materials for Microsoft Dynamics ® 5-11Your use of this content is subject to your current services agreement
  12. 12. SQL Server Installation and Optimization for Microsoft Dynamics®NAV 2009 To keep the SIFT tables from growing very large and to maintain performance, it is important to optimize the tables regularly. To initiate the optimization process, click File, Database, Information, Tables, Optimize in the Microsoft Dynamics NAV client. FIGURE 5.1 TABLE OPTIMIZATION ON LARGE TABLES The optimization process removes any entries that contain zero values in all numeric fields from each SIFT table. The removal of these redundant entries frees space and makes updating and summing SIFT information more efficient. At the same time, the optimization process rebuilds all indexes. As an alternative, you can run an SQL query on the SIFT table to determine how many records there are with zero values in all the sum fields in the table. If there are a large number of these records, you can either initiate the optimization process in Microsoft Dynamics NAV and remove them or schedule a query to delete these records on SQL Server. VSIFT Starting with Microsoft Dynamics NAV 5.0 SP 1, the SIFT tables are replaced by indexed views. Separate SIFT tables are no longer part of Microsoft Dynamics NAV on SQL Server. Microsoft Dynamics NAV 5.0 SP1 uses "indexed views" to maintain SIFT totals. Indexed views are a standard SQL Server feature. An indexed view is similar to a normal SQL Server view except that the contents have been materialized (computed and stored) to disk to speed up the retrieval of data. One indexed view is created for each SIFT key that is enabled. When you create a SIFT key for a table, you must set the MaintainSIFTIndex property for that key to Yes to enable the SIFT key and create the indexed view.5-12 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement
  13. 13. Chapter 5: Improving Application Performance After the indexed view has been created, the contents of the view are maintained so that changes are made to the base table. If you set the MaintainSIFTIndex property for that key to No, the indexed view is dropped and totals are no longer maintained. The indexed view that is used for a SIFT key is always created at the most finely-grained level. Therefore, if you create a SIFT key for AccountNo.,PostingDate, the database will store an aggregated value for each account for each date. This means that in the worst case scenario, 365 records multiplied by the number of unique Account No. must be summed to generate the total for each account for a year. Tuning and Tracing VSIFT As a result of using indexed views, SIFT keys are exposed to SQL Server tracing and tuning tools. For example, the SQL Server Profiler can display information about which indexed views are maintained and the cost associated with maintaining them. This makes it easier for you to make informed decisions about which SIFT indexes are required for optimal performance. Demonstration: Analyzing SIFT Configuration with SQL Server Profiler Perform the following steps to use SQL Profiler to determine the best SIFT index configuration. 1. In the Windows Taskbar, click Start > All Programs > Microsoft SQL Server 2008. 2. Open Performance Tools. 3. Open SQL Server Profiler. 4. Connect to the NAV-SRV-01 Database Engine. 5. Choose a trace template, for example: Tuning. 6. Go to Events Selection. 7. Expand Performance. 8. Select Showplan XML. By default, this information is not included. 9. Press Run to start the trace. Microsoft Official Training Materials for Microsoft Dynamics ® 5-13Your use of this content is subject to your current services agreement
  14. 14. SQL Server Installation and Optimization for Microsoft Dynamics®NAV 2009 There are different possibilities when setting up a new trace. For this example, the output is not saved and you will need to manually stop the trace. FIGURE 5.2 TRACING SIFT CONFIGURATION It is possible to customize the SQL Profiler trace with options. For this example, Showplan XML is added to the Standard (default) template. Showplan XML provides greater flexibility in viewing query plans. In addition to the usability benefits, Showplan XML also provides an overview of certain plan specific information, such as cached plan size, memory fractions (grants distributed across operators in the query plan), parameter list with values used during optimization, and missing indexes. When data is inserted, updated, or deleted in a table, the SIFT keys that have been defined and enabled for the specific table are maintained. Maintaining these SIFT indexes has a performance overhead. The size of the performance overhead depends on the number of keys and the SumIndexFields defined for each table. Defining Efficient Indexes There are several things to consider when designing SIFT indexes. It is important to only create the needed SIFT indexes but at the same time be sure that these indexes cover the sum queries required by Microsoft Dynamics NAV. If a table does not contain a large number of records, there is no need to maintain any SIFT indexes for that table. In this case, set the MaintainSIFTIndex property to No. Be sure to notice the number of SIFT keys defined in the system to ensure that you only maintain the SIFT keys that are important. Combine SIFT indexes, if possible.5-14 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement
  15. 15. Chapter 5: Improving Application Performance You do not have to maintain a SIFT key for a total that is only used periodically. Periodically generated totals can easily be generated by a report instead. FIGURE 5.3 SHOWPLAN XML EXECUTION PLAN DETAILS Even though indexed views are used to support SIFT indexes, when a sum is requested, the SIFT index that best matches the filter or sum fields will be used. In this case, single SIFT indexes that contain all key fields and all sum fields will be used. If such a SIFT index does not exist, the sum will be calculated from the base table (SIFT indexes will not be used). As with regular indexes, the key fields in the SIFT index that are used most regularly in queries will be positioned to the left in the SIFT index. As a general rule, the field that contains the greatest number of unique values will be placed on the left, with the field that contains the second greatest number of unique values positioned to the right and so on. Integer fields generally contain the greatest number of unique values. Option fields contain a fairly small number of values. Even if a specified filter does not supply values for the most left columns in the SIFT index it can still be used and add value. The reason is that the algorithm will use the SIFT index and that the SIFT index/indexed view only contains the sums, so the data that needs to be traversed to calculate a total is very much less than going to the base table.FIND Instructions Unlike Microsoft Dynamics NAV Classic database server, SQL Server can be characterized as a set-based engine. This means that SQL Server is very efficient when retrieving a set of records from a table, but less so when records are accessed one at a time. Microsoft Official Training Materials for Microsoft Dynamics ® 5-15 Your use of this content is subject to your current services agreement
  16. 16. SQL Server Installation and Optimization for Microsoft Dynamics®NAV 2009 Cursors Because SQL Server is set-based, it does not provide a fast way to do this retrieval. SQL Server uses mechanisms called cursors for record-level access. There are different types of cursors which have different capabilities. For example, the forward-only cursor allows fast reading from top to bottom, while the dynamic cursor allows retrieval in either direction. Typically, the FIND instruction is used to retrieve records in a table or a filtered record set. Often, the FIND instruction is used in combination with a filter instruction such as SETFILTER or SETRANGE (to check whether records exist that meet specific criteria) or in combination with the NEXT instruction (to loop through a set of records). In both cases, the FIND instructions will be translated into a Transact-SQL statement that uses a cursor and returns data. Compared to retrieving sets of records, cursors are very expensive. When writing C/AL code to retrieve records, it is important to consider the purpose of the code and to use the correct instructions (and, as a consequence, the correct cursors). By default, the way the dynamic cursors are used is not very efficient. Because cursors have a big effect on performance, handling them in a different way can yield significant improvements. For example, there is no reason to create a cursor for retrieving a single record. To optimize cursors, the following four Microsoft Dynamics NAV commands can be used: • ISEMPTY • FINDFIRST • FINDLAST • FINDSET ISEMPTY The ISEMPTY function allows you to determine whether a C/SIDE table or a filtered set of records is empty. The following code samples check for the presence of a Master record in the Customer table: // Code Sample 1 Customer.SETRANGE(Master, TRUE); IF NOT Customer.FIND(-) THEN ERROR(No Master Customer record has been defined.); // Code Sample 2 Customer.SETRANGE(Master, TRUE); IF Customer.ISEMPTY THEN ERROR(No Master Customer record has been defined.);5-16 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement
  17. 17. Chapter 5: Improving Application Performance When executed, the first code sample will be translated into an SQL statement that uses cursors. In addition, if a record exists, it is returned to the client, causing extra network traffic and disk reads. However, in this case, you do not want to retrieve a record. To avoid this, you can use the ISEMPTY instruction, as shown in the second code sample. When executed, the first code sample will be translated into an SQL statement that uses cursors. In addition, if a record exists, it is returned to the client, causing extra network traffic and disk reads. However, in this case, you do not want to retrieve a record. To avoid this, you can use the ISEMPTY instruction, as shown in the second code sample. When executed, this code results in the following T-SQL command: SELECT TOP 1 NULL FROM … The ISEMPTY instruction will not cause cursors to be used. Note that NULL is used, which means that no record columns are retrieved from the database (as opposed to *, which would get all columns). This makes it a very efficient command that causes just a few bytes to be sent over the network. This can be a significant improvement as long as subsequent code does not use the values from the found record. FINDFIRST Retrieving the first record in a table can also be an unnecessarily expensive command. Consider the following code samples: // Code Sample 1 Customer.SETRANGE(Master, TRUE); IF NOT Customer.FIND(-) THEN ERROR(No Master Customer record has been defined.); // Code Sample 2 Customer.SETRANGE(Master, TRUE); IF NOT Customer.FINDFIRST THEN ERROR(No Master Customer record has been defined.); In the first code sample, the FIND instruction will generate a cursor. To avoid this cost, you can use the FINDFIRST instruction, as shown in code sample 2. The FINDFIRST instruction retrieves the first record in a set based on the current key and filters. As with ISEMPTY, FINDFIRST does not use cursors. When executed, the following T-SQL statement is generated: SELECT TOP 1 * FROM ... ORDER BY ... Note that in this case the * is used, so all columns of the record are returned. Use this function instead of FIND(-) when you need only the first record. Microsoft Official Training Materials for Microsoft Dynamics ® 5-17Your use of this content is subject to your current services agreement
  18. 18. SQL Server Installation and Optimization for Microsoft Dynamics®NAV 2009 WARNING: If using a REPEAT/UNTIL NEXT loop, do not use this command, because the NEXT will need to create a cursor for fetching the subsequent records. FINDLAST FINDLAST works in the same manner as the FINDFIRST instruction. The FINDLAST command retrieves the last record in a set (based on the current key and filters), but, like FINDFIRST, FINDLAST does not use cursors. Consider the following two code samples: // Code Sample 1 Message.SETCURRENTKEY(Date); IF Message.FIND(+) THEN MESSAGE(Last message is dated %1., FORMAT(Message.Date)); // Code Sample 2 Message.SETCURRENTKEY(Date); IF Message.FINDLAST THEN MESSAGE(Last message is dated %1., FORMAT(Message.Date)); This second code sample retrieves the last record in the set, and does not use cursors. When executed, this T-SQL is generated: SELECT TOP 1 * FROM ... ORDER BY ... DESC You should use this function instead of FIND(+) when you need only the last record in a table or set. WARNING: If doing a REPEAT/UNTIL NEXT(-1) loop, do not use this command, because the NEXT will have to create a cursor for fetching the subsequent records. FINDSET FINDSET retrieves a set of records based on the current key and filter and can be used when you need to browse through a set of records. Very often, the scenario of code sample 1 is used: // Code Sample 1 IF RecordVariable.FIND(-) THEN REPEAT UNTIL RecordVariable.NEXT = 0; // Code Sample 2 IF RecordVariable.FINDSET THEN REPEAT UNTIL RecordVariable.NEXT = 0;5-18 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement
  19. 19. Chapter 5: Improving Application Performance From previous paragraphs, you know that FIND will generate a cursor in code sample 1, which is to be avoided. Therefore, it is better to use the FINDSET instruction, as shown in code sample 2. Unlike the FIND(-) command, FINDSET does not use cursors. When executed, the T-SQL result looks as follows: SELECT TOP 500 * FROM ... The value 500 in the code snippet here comes from the database setup. Its default value has been set to 50. The recommended value for this parameter is the average number of sales lines on a sales order. REPEAT/UNTIL NEXT browses through the records locally on the client machine. This is the recommended way to retrieve sets quickly, without any cursor overhead. Note that FINDSET only allows you to loop through the record set from the top down. If you want to loop from the bottom up, use FIND(+). Use this function only when you explicitly want to loop through a record set. You should only use this function in combination with REPEAT/UNTIL. The complete syntax for the FINDSET instruction is as follows: Ok := Record.FINDSET([ForUpdate][, UpdateKey]) Although you can use it without, the FINDSET instruction has two optional parameters which might improve performance. The ForUpdate parameter indicates whether you want to modify the records or not. The UpdateKey parameter indicates whether you want to modify a field in the current key. The UpdateKey parameter does not apply when ForUpdate is FALSE. Using FINDSET without parameters corresponds to FINDSET(FALSE, FALSE). You can use it to obtain a read-only record set. This uses no server cursors and the record set is read with a single server call. NOTE: FINDSET only allows you to loop through the record set from the top down. If you want to loop from the bottom up, use FIND(+). We recommend that you use FINDSET to loop through a set without updating it, as shown in the following example. SalesLine.SETFILTER("Purch. Order Line No.",<>0); IF SalesLine.FINDSET THEN BEGIN REPEAT CopyLine(SalesLine); UNTIL SalesLine.NEXT = 0; END; If you set any or both of the parameters to FALSE, you can still modify the records in the set but these updates will not be performed optimally. Microsoft Official Training Materials for Microsoft Dynamics ® 5-19Your use of this content is subject to your current services agreement
  20. 20. SQL Server Installation and Optimization for Microsoft Dynamics®NAV 2009 The variations of the FINDSET instructions will be discussed in the next sections. FINDSET(TRUE) We recommend that you set the ForUpdate parameter to TRUE to modify any records in the set. If you set the parameter to TRUE, the LOCKTABLE command is issued immediately before the records are read. This variation of FINDSET locks the set that is read, so it is equivalent to a LOCKTABLE followed by FINDSET. FINDSET(TRUE) uses the read-ahead mechanism to retrieve several records instead of just one. Unlike the FINDSET instruction, FINDSET(TRUE) uses a dynamic cursor. The main purpose of this command is to raise the isolation level before reading the set because the resulting records are to be modified. This example shows how to use the FINDSET function to loop through a set and update a field that is not within the current key. SalesLine.SETRANGE("Document Type",DocumentType); SalesLine.SETRANGE("Document No.",DocumentNo); IF SalesLine.FINDSET(TRUE, FALSE) THEN BEGIN REPEAT SalesLine."Location Code" := GetNewLocation(SalesLine); SalesLine.MODIFY; UNTIL SalesLine.NEXT = 0; END; We recommend that LOCKTABLE be used with FINDSET for small sets, and that the FINDSET(TRUE) command be used for sets larger than 50 records (the Record Set parameter in the Alter Database window). We do not recommend that you use FINDSET with a large result set. That is a result set that is larger than the Record Set Size parameter. In this case, you should use Find(-). The reason is that FINDSET means that you are working with a confined set of records and Microsoft Dynamics NAV will use this information to optimize what is being done on SQL server. A good example of using the FINDSET(TRUE) command is for the read of a big set of records and the need to modify those records. For example, when going through all G/L entries for a specific account, and changing a field value based on the record condition, the filtered set will probably have more than 50 records. This might be done as follows: GLEntry.SETRANGE("G/L Account No.", "6100"); IF GLEntry.FINDSET(TRUE) THEN REPEAT IF (GLEntry.Amount > 0) THEN BEGIN GLEntry."Debit Amount" := GLEntry.Amount;5-20 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement
  21. 21. Chapter 5: Improving Application Performance GLEntry."Credit Amount" := 0; END ELSE BEGIN GLEntry."Debit Amount" := 0; GLEntry."Credit Amount" := -GLEntry.Amount; END; GLEntry.MODIFY; UNTIL GLEntry.NEXT = 0; A good example of using the LOCKTABLE and FINDSET command (as opposed to using the FINDSET(TRUE) command) is for the read of a small set of records and the need to modify those records. For example, when going through all sales lines for a specific order, and changing the value of several fields, the filtered set will probably have less than 50 records. SalesLine.SETRANGE("Document Type","Document Type"::Order); SalesLine.SETRANGE("Document No.",S-ORD-06789); SalesLine.LOCKTABLE; IF SalesLine.FINDSET THEN REPEAT SalesLine."Qty. to Invoice" := SalesLine."Outstanding Quantity; SalesLine."Qty. to Ship" := SalesLine."Outstanding Quantity; SalesLine.MODIFY; UNTIL SalesLine.NEXT = 0; FINDSET(TRUE, TRUE) This variation of FINDSET(TRUE) allows the modification of a key value of the current sorting order of the set. The following example shows how to use the FINDSET function to loop through a set and update a field that is within the current key. SalesShptLine.SETRANGE("Order No.",SalesLine."Document No."); SalesShptLine.SETRANGE("Order Line No.",SalesLine."Line No."); SalesShptLine.SETCURRENTKEY("Order No.","Order Line No."); IF SalesShptLine.FINDSET(TRUE, TRUE) THEN BEGIN REPEAT SalesShptLine."Order Line No." := SalesShptLine."Order Line No." + 10000; SalesShptLine.MODIFY; UNTIL SalesShptLine.NEXT = 0; END; Microsoft Official Training Materials for Microsoft Dynamics ® 5-21Your use of this content is subject to your current services agreement
  22. 22. SQL Server Installation and Optimization for Microsoft Dynamics®NAV 2009 Like FINDSET(TRUE), the command uses a dynamic cursor, with the main purpose of raising the isolation level before starting to read the set (because the set needs to be modified). However, it does not use the read-ahead mechanism. Instead it retrieves one record at a time because the set is expected to be invalidated within the loop. Avoid using this command, since the loop code should be changed to a more efficient method of working, such as using a different variable for browsing through the set. Important to understand is that the isolation level and the cursor type have nothing to do with one another. The isolation level is connection wide whereas the cursor type influences the current statement. Microsoft Dynamics NAV uses a dynamic cursor to get a dynamic result set, a result set that contains our own changes. This is done to be consistent with the old classic database. If Microsoft Dynamics NAV used another cursor type or no cursor at all then it might have to reissue the query whenever the code was changing data in the current table. A good example of using the FINDSET(TRUE,TRUE) command (as opposed to using FIND command) is for the read of a set of records and the need to modify a key value. This should be avoided. If there is not a way to avoid this, use FINDSET(TRUE,TRUE). For example, going through all sales lines for a specific order, and changing key value, the filtered set will probably have less than 50 records in the set. This can be done as follows: SalesLine.SETCURRENTKEY("Document Type","Document No.","Location Code"); SalesLine.SETRANGE("Document Type","Document Type"::Order); SalesLine.SETRANGE("Document No.",S-ORD-06789); SalesLine.SETFILTER("Location Code",); IF SalesLine.FINDSET(TRUE,TRUE) THEN REPEAT IF SalesLine.Type = SalesLine.Type::Item THEN SalesLine."Location Code" := GREEN; IF SalesLine.Type = SalesLine.Type::Resource THEN SalesLine."Location Code" := BLUE; SalesLine.MODIFY; UNTIL SalesLine.NEXT = 0; Note that the example can be easily changed into more efficient code using FINDSET as opposed to FINDSET(TRUE,TRUE) and using a separate variable to modify the records. This can be done as follows: SalesLine.SETCURRENTKEY("Document Type","Document No.","Location Code"); SalesLine.SETRANGE("Document Type","Document Type"::Order); SalesLine.SETRANGE("Document No.",S-ORD-06789); SalesLine.SETFILTER("Location Code",); SalesLine.LOCKTABLE; IF SalesLine.FINDSET THEN REPEAT SalesLine2 := SalesLine;5-22 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement
  23. 23. Chapter 5: Improving Application Performance IF SalesLine.Type = SalesLine.Type::Item THEN SalesLine2."Location Code" := GREEN; IF SalesLine.Type = SalesLine.Type::Resource THEN SalesLine2."Location Code" := BLUE; SalesLine2.MODIFY; UNTIL SalesLine.NEXT = 0; There is a parameter in Microsoft Dynamics NAV that is used to set up the maximum number of records retrieved from the database (File, Database, Alter, Advanced tab, Caching, Record Set = 50). If the set is bigger than the maximum, Microsoft Dynamics NAV will continue to work but it will replace the reading mechanism with a dynamic cursor. If there is an indication that this will occur, use the old FIND(-) command as opposed to FINDSET. Use FINDSET for forward direction only; it will not work for REPEAT/UNTIL NEXT(-1). Also, if the LOCKTABLE command is used prior to the FINDSET, the set is locked, and records can be modified within the loop. A good example of an efficient use of cursors (using the old FIND command), is for the read of a big set of records, for example all G/L Entries for a specific account, probably with more than 50 records in the set. GLEntry.SETRANGE("G/L Account No.", "6100"); IF GLEntry.FIND(-) THEN REPEAT UNTIL GLEntry.NEXT = 0; A good example of using the new FINDSET command (as opposed to using the old FIND command), is for the read of a small set of records, such as all sales lines in a sales order, probably always with less than 50 records. This can be done as follows: SalesLine.SETRANGE("Document Type","Document Type"::Order); SalesLine.SETRANGE("Document No.",S-ORD-06789); IF SalesLine.FINDSET THEN REPEAT TotalAmount := TotalAmount + SalesLine.Amount; UNTIL SalesLine.NEXT = 0;Keys One of the largest typical Microsoft Dynamics NAV overheads is the cost of indexes. The Microsoft Dynamics NAV database is over-indexed, since customers require certain reports to be ordered in different ways, and the only way to do it is to create a Microsoft Dynamics NAV key to sort data in these specific ways. SQL Server can sort results quickly if the set is small, so there is no need to keep indexes for sorting purposes only. For example, in the Warehouse Activity Line Microsoft Official Training Materials for Microsoft Dynamics ® 5-23 Your use of this content is subject to your current services agreement
  24. 24. SQL Server Installation and Optimization for Microsoft Dynamics®NAV 2009 table, there are several keys that begin with Activity Type and No. fields, such as the following: • Activity Type,No.,Sorting Sequence No. • Activity Type,No.,Shelf No. • Activity Type,No.,Action Type,Bin Code The issue here is that these indexes are not needed on SQL Server, because the Microsoft Dynamics NAV code always filters on Activity Type and No. when using these keys. With SQL Server, the Query optimizer looks at the filter and realizes that the clustered index is Activity Type,No_,Line No_ and that the set is small, and that there is no need to use an index to retrieve the set and return it in that specific order. It will use only the clustered index for these operations. Additionally, the entire functionality is not used by customers, so if they never pick the stock by Sorting Sequence No. for example, there is no need to maintain the index. Developers should analyze the existing indexes with a focus on use and benefits compared to the overheads, and decide what action is need. Disable the index completely, using the key property Enable, using the KeyGroups property, or using the MaintainSQLIndex property. Indexes that remain active can change structure using the SQLIndex property. Developers can also cluster the table by a different index. If an index exists, sorting by the fields matching the index will be faster, but modifications to the table will be slower. When you write a query that searches through a subset of the records in a table, be careful when defining the keys both in the table and in the query so that Microsoft Dynamics NAV can quickly identify this subset. For example, the entries for a specific customer will usually be a small subset of a table that contains entries for all the customers. The time that is required to complete a query depends on the size of the subset. If a subset cannot be located and read efficiently, performance will deteriorate. To maximize performance, you must define the keys in the table so that they facilitate the queries that you will have to run. These keys must then be specified correctly in the queries. For example, you want to retrieve the entries for a specific customer. To do this, you apply a filter to the Customer No. field in the Cust. Ledger Entry table. SQL Server makes stricter demands than Classic Database Server on the way that keys are defined in tables and on the way they are used in queries. Microsoft Dynamics NAV Classic Database Server has been optimized for low selectivity keys. For example, if there is an index that consists of the Document Type and Customer No. fields and the application filters on the Customer No. field only,5-24 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement
  25. 25. Chapter 5: Improving Application Performance Classic Database Server will search through the index branches and retrieve the result set quickly. However, SQL Server is not optimized to do that, so it scans from the beginning to the end of a range and, in many cases, this results in a non- clustered index scan. To run the query efficiently on SQL Server, you need to define a key in the table that has Customer No. as the first field. You must also specify this key in the query. Otherwise, SQL Server will be unable to answer this query efficiently and will read through the entire table. Define your keys and queries with SQL Server in mind, as this will ensure that your application can run as efficiently on both server options. When designing keys, the following guidelines can be considered: • Redesign keys so that their selectivity becomes higher by putting Boolean, Option, and Date fields toward the end of the index. • Set the MaintainSIFTIndex property to No on small tables or temporary tables (such as Sales Line, Purchase Line and Warehouse Activity Line). • Set the MaintainSQLIndex property to No for indexes that are only used for sorting purposes. • Reduce the number of keys on hot tables. • Use the SQLIndex property to optimize a key on SQL Server. But be careful with this property. If the SQL Server index differs from the Microsoft Dynamics NAV index it can lead to problems with the ORDER BY and the WHERE CLAUSE not fitting the same index. This is largely a problem with dynamic cursors. • Reduce the number of records in static tables (by archiving or using data partitioning). Keys and Performance Searching for specific data is usually easier if several keys have been defined and maintained for the table holding the desired data. The indexes for each of the keys provide specific views that enable quick flexible searches. However, there are both advantages and drawbacks to using a large number of keys. If you increase the number of secondary keys marked as active, performance will improve when you read data, but will deteriorate when updating information (because indexes must be maintained for each secondary key). When you decrease the number of active sortings, performance will slow down when reading data, but updates will be faster. Microsoft Official Training Materials for Microsoft Dynamics ® 5-25Your use of this content is subject to your current services agreement
  26. 26. SQL Server Installation and Optimization for Microsoft Dynamics®NAV 2009 The decision whether to use few or many keys is not easy. The choice of appropriate keys and the number of active keys to use should be the best compromise between maximizing the speed of data retrieval and maximizing the speed of data updates (operations that insert, delete, or modify data). In general, it may be worthwhile to deactivate complex keys if they are rarely used. The overall speed of C/SIDE depends on the following factors: • The size of the database • The number of active keys • The complexity of the keys • The number of records in your tables • The speed of your computer and its disk system Key Properties The keys associated with a table have properties that describe their behavior, just as tables and fields do. When you create a key, C/SIDE automatically suggests several default values for these properties. Depending on the purpose of the key, you may want to change these default values. Enabled Property Enabled property simply turns the specific key on and off. It might have been there for temporary reasons and is no longer needed. If a key is not enabled and is referenced by a C/AL code or CALCSUMS function, users will get a run-time error. KeyGroups Property Use this property to select the (predefined) key groups to which the key belongs. As soon as developers assign this key to one or more key groups, they can selectively activate or deactivate the keys of various groups by enabling and disabling the key groups. To make use of the key groups for sorting, choose the Key Groups option on the Database Information window which appears when they select File, Database, Information, and then press the Tables button. There are key groups that are defined already, such as Acc(Dim), Item(MFG), and so on, but users can create more and assign them to keys they want to control this way. The purpose of key groups is to make it possible to set up a set of special keys that are used rarely (such as for a special report that is run once every year). Since adding lots of keys to tables will eventually decrease performance, using key groups makes it possible to have the necessary keys defined, but only active when they are really going to be used.5-26 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement
  27. 27. Chapter 5: Improving Application Performance MaintainSQLIndex Property This property determines whether a SQL Server index that corresponds to the Microsoft Dynamics NAV key should be created (when set to Yes) or dropped (when set to No). A Microsoft Dynamics NAV key is created to sort data in a table by the required key fields. However, SQL Server can sort data without an index on the fields to be sorted. If an index exists, sorting by the fields matching the index will be faster, but modifications to the table will be slower. The more indexes there are on a table, the slower the modifications become. In situations where a key must be created to allow only occasional sorting (for example, when running infrequent reports), developers can disable this property to prevent slow modifications to the table. SQLIndex Property This property allows users to define the fields that are used in the SQL index. The fields in the SQL index can: • Differ from the fields defined in the key in Microsoft Dynamics NAV. • Be arranged in a different order. If the key in question is not the primary key, and the SQLIndex property is used to define the index on SQL Server, the index that is created contains exactly the fields that users specify and may not be a unique index. It will only be a unique index if it contains all the fields from the primary key. When users define the SQL index for the primary key, it must include all the fields defined in the Microsoft Dynamics NAV primary key. Users can add extra fields and rearrange the fields to suit their needs. Be careful when using the property SQLIndex. It can backfire because the SQL Server query and the SQL index will per definition have a mismatch, as described at the following location (http://blogs.msdn.com/nav_developer/archive/2009/04/10/beware-the-sql-index- property-on-nav-5-0-sp1.aspx): Clustered Property Use this property to determine which index is clustered. By default, the index that corresponds to Microsoft Dynamics NAV primary key will be made clustered. We recommend that you make sure the primary key and the clustered key is the same. If they are not then SQL Server will add the clustered index fields to every index internally while Microsoft Dynamics NAV will add all the primary key fields causing keys to be very long. Microsoft Official Training Materials for Microsoft Dynamics ® 5-27Your use of this content is subject to your current services agreement
  28. 28. SQL Server Installation and Optimization for Microsoft Dynamics®NAV 2009 MaintainSIFTIndex This property allows you to determine whether SIFT structures should be created in SQL Server to support the corresponding SumIndexFields for the Microsoft Dynamics NAV key. SumIndexFields are created in Microsoft Dynamics NAV to support FlowField calculations and other fast summing operations. SQL Server can sum numeric data by scanning the table. If the SIFT structures exist for the SumIndexFields, summing the fields is faster, especially for large sets of records, but modifications to the table are slower because the SIFT structures must also be maintained. In situations where SumIndexFields must be created on a key to enable FlowField calculations, but the calculations are performed infrequently or on small sets of data, you can disable this property to prevent slow modifications to the table. Also be aware that even the new implementation that uses indexed views will cause blocking in the database. For example if two users update the total for an account on the same date. Enable/Disable Keys using C/AL Code To make the information in the tables as useful as possible, many of the tables have several predefined sorting keys. Keys can be set up as part of a key group, which you can enable and disable without risk. To add a key to a key group, set the KeyGroups property to the name of an existing key group. Microsoft Dynamics NAV will generally perform better when you disable key groups (because the system does not have to maintain the keys included in the key group). Adding a large number of keys to database tables decreases performance. However, by making the keys members of predefined key groups you can have the necessary keys defined and only activate them when they will be used.5-28 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement
  29. 29. Chapter 5: Improving Application Performance Key groups can be maintained in the Database Key Groups window. To open the window, select File > Database Information > Tables and click the Key groups button. FIGURE 5.4 THE DATABASE KEY GROUPS WINDOW In this window you can enable and disable existing key groups. You can also add new and delete existing key groups. If you delete an existing key group, all keys that belong to this group will be disabled. In Microsoft Dynamics NAV 5.0, key groups can also be enabled and disabled using C/AL Code. To do this, the following instructions have been introduced: • KEYGROUPDISABLE • KEYGROUPENABLE • KEYGROUPENABLED KEYGROUPDISABLE allows you to disable a key group and all related keys in all tables. KEYGROUPENABLE does the opposite, it allows you to enable a key group and all related keys. KEYGROUPENABLED allows you to check whether a key group is currently enabled. The following code sample shows how to activate the ABC key group, run some code, and disable the key group again. KEYGROUPENABLE(ABC); ... KEYGROUPDISABLE(ABC); Enabling a key group can take some time, depending on the number of keys and the amount of data. Microsoft Official Training Materials for Microsoft Dynamics ® 5-29Your use of this content is subject to your current services agreement
  30. 30. SQL Server Installation and Optimization for Microsoft Dynamics®NAV 2009Locks, Blocks and Deadlocks When data is read from the database, Microsoft Dynamics NAV, outside transaction or in a Browse/Update No Locks transaction mode, uses the READUNCOMMITTED isolation level, meaning that any other user can modify the records that are currently being read. Data that is read is considered "dirty" because it can be modified by another user. When data is modified, Microsoft Dynamics NAV reads the record again with the UPDLOCK isolation level and compares the timestamp of the record. If the record is old, the following Microsoft Dynamics NAV error displays: "Another user has modified the record after you retrieved it from the database." The tradeoff is that care must be taken when writing code that modifies the data. This requires that locking and blocking be employed to synchronize access, but deadlocks - a condition where one or more competing processes are queued indefinitely - can occur as a side-effect. The following subtopics discuss strategies for synchronizing data access while avoiding deadlock. Every write transaction implies an automatic implicit lock and unlock. Explicit locking is also possible using the LOCKTABLE instruction. Explicit locking is necessary to preserve data consistency during complex processes, such as the Posting function. The isolation level can be changed to a more restrictive setting, such as UPDLOCK. In this level, records that are read are locked, meaning that no other user can modify the record. This is referred to as pessimistic locking, and causes the server to protect the record in case there is a need to modify it - making it impossible for others to modify. An example of a lock of a customer record is as follows: Cust.LOCKTABLE; Cust.GET(10000); // Customer 10000 is locked Cust.Blocked := TRUE; Cust.MODIFY; COMMIT; // Lock is removed If the record is not locked up front, the following situation can occur: User A User B Comment Cust.GET(10000); User A reads record without any lock. Cust.GET(10 User B reads same record without any 000); lock. Cust.Blocked User B modifies record. := TRUE; Cust.MODIF Y; COMMIT:5-30 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement
  31. 31. Chapter 5: Improving Application Performance User A User B Comment Cust.Blocked := User A gets an error: "Another user FALSE; has modified the record after you Cust.MODIFY; retrieved it from the database." ERROR SUCCESS Blocking When other users try to lock data that is currently locked, they are blocked and have to wait. If they wait longer than the defined time-out, they receive the following Microsoft Dynamics NAV error: "The ABC table cannot be locked or changed because it is already locked by the user who has User ID XYZ." If you receive this error, you can change the default time-out with File, Database, Alter, Advanced tab, Lock Timeout check box and Timeout duration (sec) value. Based on the previous example, where two users try to modify the same record, the data that is intended to be modified can be locked. This prevents other users from doing the same. This is shown in the following example: User A User B Comment Cust.LOCKTABLE; User A reads record with a Cust.GET(10000); lock. Cust.LOCKTABLE; User B tries to read the same Cust.GET(10000); record with a lock waiting... User B waits and is blocked, because the record is locked by user A. Cust.Blocked := waiting... User A modifies the record. FALSE; User B is kept waiting. Cust.MODIFY; COMMIT; Lock is released. Data is now sent to User B. Cust.Blocked := User B successfully modifies TRUE; record. Cust.MODIFY; COMMIT; Lock is released. SUCCESS SUCCESS There is a potential situation when blocking cannot be resolved by the server in a good way. The situation arises when one process is blocked because another process has locked some data. The other process is also blocked because it tries to lock the first process data. Only one of the transactions can be finished. SQL Server terminates the other and sends the following error message to the client: "Your activity was deadlocked with another user" Microsoft Official Training Materials for Microsoft Dynamics ® 5-31Your use of this content is subject to your current services agreement
  32. 32. SQL Server Installation and Optimization for Microsoft Dynamics®NAV 2009 For example, consider a case in which two users are working concurrently and trying to get one anothers blocked records, as shown in this pseudo code: User A User B Comment Cust.LOCK Cust.LOCKTABLE; Indicates that the next read will TABLE; Vend.LOCKTABLE; use UPDLOCK Vend.LOC KTABLE; Cust.FIND Vend.FINDFIRST; A blocks Record1 from the FIRST; Customer table. B blocks Record 1 from the Vendor table. ... ... Vend.FIND Cust.FINDFIRST; A wants Bs record, while B FIRST; wants As record. A conflict occurs. "Your activity was SQL Server detects deadlock deadlocked with and arbitrarily chooses one another user" over the other, so one will receive an error. SUCCESS ERROR Because SQL Server supports record level locking, there may be a situation where these two activities bypass one another without any problems. Suppose that in this example user A and B try to read the last record in the other table, no conflicts arise, as no records are in contention. The deadlock will only occur if they lock the same rows but in a different order. Note that there would be a deadlock if one of the tables is empty, or contained few records only. A large number of deadlocks can lead to major customer dissatisfaction, but deadlocks cannot always be avoided completely. To minimize the number of deadlocks, do the following: • Process tables in the same sequence. • Process records in the same order. • Keep the transaction length to a minimum. If all code always processed the data in the same order then there would be no deadlocks, only locks. One reason why deadlocks are so expensive is that SQL Server does not immediately discover a deadlock. The initial deadlock discovery frequency is 5 seconds.5-32 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement
  33. 33. Chapter 5: Improving Application Performance Although locking and blocking are necessary to support concurrency, it can lead to decreased performance, especially when tables are locked longer than necessary. To reduce locking time, you can do the following: • Keep the lock time to a minimum by locking the resources as late as possible and releasing the locks as soon as possible. • Test data validity for an entire transaction before starting the transaction. • Keep transactions as short as possible. • Use adequate keys. • Never allow user input during a transaction. • Test conditions of data validity before the start of locking. • Allow some time gap between heavy processes so that other users are less affected. • Make sure SQL Server has sufficient memory. If the transaction is too complex or there is limited time, consider discussing with the customer the possibility of over-night processing of heavy jobs by using a Microsoft Dynamics NAV Application Server. This avoids the daily concurrency complexity and the high costs of rewriting the code. If the over-night processing is not possible because of the complexity of the processes, as a last resort, revert to serializing the code by ensuring that conflicting processes cannot execute in parallel. This can be done by creating a so-called locking semaphore table that is locked at the beginning of a transaction. As long as the table remains locked, other users cannot start the same transaction. This avoids deadlocks, but at the same time, it affects concurrency. For more information about locking order rules, see the Performance Audits chapter.Graphical User Interface When upgrading older installations to SQL Server 2005, users can experience poor performance when they search and filter on data in Microsoft Dynamics NAV and when they open and browse lists. Two main problems were identified: • SQL Server has a feature called "parameter sniffing," which may cause suboptimal plans to be used by SQL Server. • Microsoft Dynamics NAV queries that inherently return an empty result set may cause poor response times. Microsoft Official Training Materials for Microsoft Dynamics ® 5-33 Your use of this content is subject to your current services agreement
  34. 34. SQL Server Installation and Optimization for Microsoft Dynamics®NAV 2009 Parameter Sniffing Microsoft Dynamics NAV uses queries that contain parameters on SQL Server. The first time a Microsoft Dynamics NAV query is executed, SQL Server calculates a plan for accessing the data in the most efficient way. This plan is based on the actual values in the search criteria and parameters. Every time a query is sent to SQL Server, SQL Server makes a query-plan for that query. Then it caches this plan to re-use it for identical queries. This is known as "parameter sniffing." This may lead to suboptimal performance because the first values sent may not be representative of subsequent queries. In Microsoft Dynamics NAV 5.0 SP1 the way that queries are sent to SQL Server has been restructured. As of this version, SQL Server will make query plans that are optimized for average parameter values rather than extreme parameter values. This method ensures that SQL Server makes the plan, without forcing it in a certain direction with index hints or the recompile-option. Microsoft Dynamics NAV 5.0 SP1, issues statements that disables parameter sniffing. This is done by forcing the SQL client to not defer the plan calculation until the statement is executed. This requires an extra database roundtrip the first time an SQL statement is constructed or sent. A built-in statement cache means that the extra roundtrip will only occur once if users are working in an isolated area of the application. This change insures against sub-optimal plans but at the same time inflicts an extra roundtrip for the database. Also, there may only be queries with parameters that fit the sub-optimal plan, so the new behavior may be worse. This method guarantees that SQL Servers query plan will not be affected by the parameter values. It means that sometimes, SQL Server is prevented from making the optimal query plan for a certain set of parameter values. But remember that the query plan will be re-used for other parameter values. So, at the expense of having a few highly optimized queries, the method provides optimized queries with better consistency. Another cost of this method, is that now Microsoft Dynamics NAV requires an extra roundtrip to SQL Server. However, this only happens the first time the query is run. If the same query is run again, Microsoft Dynamics NAV will only run the second query (sp_cursorexecute). You can revert to the old behavior by modifying the contents in the $ndo$dbproperty tables as follows. UPDATE [$ndo$dbproperty] SET [diagnostics]=[diagnostics]+10485765-34 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement
  35. 35. Chapter 5: Improving Application Performance Adding the 1048576 value to the Diagnostics column of the row in ndo$dbproperty will turn off the No Deferred Prepare behavior. The behavior will be the same as in Microsoft Dynamics NAV 4.0 SP3. As an alternative solution, you can manually implement plan guides for poorly performing queries. To implement a plan guide, you should know the combination of the query and the parameters for which you implemented the plan guide. Another possibility is using the $ndo$dbconfig table to add the OPTION (RECOMPILE) query hint. The OPTION (RECOMPILE) query hint instructs the instance of SQL Server to compile a new query plan for the query instead of using a cached plan. Each plan guide works for a specified query. However, you can use a $ndo$dbconfig table to add the OPTION (RECOMPILE) query hint for all queries. To do this, perform the following steps: 1. Run the following script to create the $ndo$dbconfig table in the Microsoft Dynamics NAV database: -- Step 1 CREATE TABLE [$ndo$dbconfig] (config VARCHAR(512) NOT NULL) -- Step 2 GRANT SELECT ON [$ndo$dbconfig] TO public -- Step 3 INSERT INTO [$ndo$dbconfig] VALUES(UseRecompileForTable="G/L Entry"; Company="CRONUS International Ltd."; RecompileMode=1;) 2. Grant the SELECT permission to the Public role for the $ndo$dbconfig table, as shown in Step 2 in the script here. 3. Use the $ndo$dbconfig table to specify the tables for which you want to add the OPTION (RECOMPILE) query hint. Step 3 in the script here shows how to add the OPTION (RECOMPILE) query hint for queries in the G/L Entry table. To add the OPTION (RECOMPILE) query hint for other tables, you can create a new line in the $ndo$dbconfig table for each table. • You do not need to specify the value of the Company parameter if you want to add the OPTION (RECOMPILE) query hint for all companies in the database. Microsoft Official Training Materials for Microsoft Dynamics ® 5-35Your use of this content is subject to your current services agreement

×