Presented by: Dan Haught, FMS Inc.
Dan Haught has been developing database applications and tools for more than ten years on a variety of platforms and has been using Microsoft® Access since its pre-1.0 days. Dan manages product development for FMS in Vienna, Virginia, where he develops products for the Total Access line, and is the author of several books on Microsoft Access and the Jet database engine.
Email: danh@msn.com
http://www.fmsinc.com
Microsoft® Access 97 represents the second 32-bit release of Microsoft Access. Whether you are converting existing applications to Microsoft Access 97, or starting new development, there are a number of strategies for optimizing and improving performance in your application.
The following topics will be discussed:
One of the identifying characteristics of Microsoft Access 95 was is poor performance in many application development situations. Microsoft has made a large number of enhancements to address these problems.
The memory usage of Microsoft Access has been reduced dramatically. For example, Microsoft Access 97 with the Northwind Traders sample database loaded uses 30% less memory than Microsoft Access 95.
It is much more difficult to lose the compiled state. (See the section on "Improving Module Performance" later in this paper for more information on the Compiled State.) Most of the work here has to do with VBA's tracking of dependencies.
Databases converted from Microsoft Access 2.0 to Microsoft Access 95 can grow in size at an alarming rate. Work has been done in this area to reduce the amount of storage needed. For example, NWIND has been reduced in size by 30%.
Many performance optimizations have been made to improve the time to start Microsoft Access.
Microsoft Access 95 required a number of steps to ensure that converted databases would perform adequately in terms of performance. This typically required:
Fortunately, Microsoft Access 97 is much more intelligent about its conversions. After importing and converting your objects, Microsoft Access compiles all your code and saves the compiled state. It then compacts the database to remove the temporary objects created during conversion, and reclaims unused space.
Note When you install Microsoft Access 97, you are given the option to remove Microsoft Access 2.0 if it exists on your system. Unless you are extremely short on disk space, you may want to leave Microsoft Access 2.0 installed. In the event that Microsoft Access 97 has problems converting your database, you can return to Microsoft Access 2.0 to attempt to solve problems
Every application needs a good environment. You can run Microsoft Access 97 under both Microsoft Windows® 95 and Microsoft Windows NT® 3.51 or later. This section discusses things you can do to your operating environment to make Microsoft Access 97 run faster.
The three most effective things you can do to improve performance are:
The bottom line is: this is the single most effective way to improve performance of all your Windows apps. Microsoft Access 97 is particularly affected by the availability (or lack thereof) of RAM. In fact, you could upgrade your RAM to 32 MB and be very happy with the performance of Microsoft Access 97 without following any of the other tips in this paper! It is that important.
The following table summarizes memory scenarios many developers have encountered:
RAM | Performance |
4 MB | It actually runs! Microsoft Access 97 will run on a machine with 4MB of RAM. It is so slow as to be unusable, but it does eventually finish what is asked of it. |
8 MB | Not much better than 4MB, but it is slightly more usable. |
12 MB | Microsoft’s stated minimum (16MB is the stated minimum for installations using NT as the operating system). Large application performance will probably not be acceptable with this amount of RAM. |
16 MB | A good starting point for development of robust applications. |
24 MB | Now we're talking! Microsoft Access 97 starts to pick up at 24 MB. This is the reasonable minimum for Windows NT installations. |
32 MB | The promised land. Running Microsoft Access 97 on a 32-MB machine with at least a 75mhz Pentium® processor is very nice. This is the recommended configuration for developers using Microsoft Access on a regular basis. Of course, if you are one of the chosen few how have 64MB of RAM in their machines, you are probably wondering what all the complaining is about! |
Table 1 - RAM and Microsoft Access 97
If upgrading the memory on your machine (or your client's machine as the case may be) is at all an option, do it. There is no faster way to make Microsoft Access 97 go faster. If you can't upgrade the memory on your computer, don't lose heart-there are still things you can do. Read on.
Note Several products, marketed under the generic term "RAM Doublers" purport to double the amount of available RAM through software trickery. When evaluating the use of such a product, bear in mind the maxim "You can't get blood from a stone." Indeed, there is at least one product on the market that actually slows down Windows 95. This is currently a hot topic in the trade press. Use of RAM doublers will in no way increase the performance of Microsoft Access 97. Caveat Emptor.
In a word, don't. Microsoft Access 97 does not provide stellar performance when run from a compressed drive. According to the README file, running Microsoft Access 97 on a drive that is compressed using DriveSpace can cause significant decreases in performance.
Again, don't! This is true of almost any application, but really becomes a maxim when the new 32-bit Office applications are involved. The 97 versions of the Microsoft Office components are bigger and more numerous than ever. Its not as simple as the old days when you could run a single EXE file across the network. In modern Windows software, DLLs, OLE objects, help files, type-libraries and executables all contribute to a binary stream of data that is not happy being squeezed through a low-bandwidth network wire. Hard-disk space is cheap enough now that you shouldn’t have to suffer performance problems because lack of local storage is forcing you onto a network.
Windows 95 automatically manages virtual memory (the swapfile in Window 3.1x parlance). In general, it does a good job of balancing available disk space with the amount of real memory in your system. However, some users have reported better performance by experimenting with the size of the swap file. You can modify these settings in Windows 95 by right-clicking on My Computer, selecting Properties clicking the Performance tab and pressing the Virtual Memory button. According to the Microsoft Access 97 Help File, modifying the virtual memory settings can be beneficial in two cases:
There are numerous things you can do to optimize your operating system. Things like eliminating that 1024x768 24-bit color wallpaper you are using. Or turning off System Agent from the Microsoft Plus Pack when you are not using it. Or regularly (at least once a week) defragmenting your hard disks. Or replacing all your real-mode device drivers with 32-bit versions. And so on. There really are a lot of things you can do at the base level of your computer to speed things up and free more resources.
Here are a few other tips:
Jet 3.0 was introduced with Microsoft Access 95. Microsoft Access 97 uses version 3.5 of Microsoft Jet. The following Jet 3.0 coverage is included for those unfamiliar with Microsoft Access 95/Jet 3.0 performance enhancements.
In the area of data access, improvements are related to the use of the new Jet database engine 3.0. New development work on the Jet database engine was focused on performance, particularly in multi-user scenarios. Jet database engine 3.0 is completely 32-bit, and uses multiple threads of execution to provide dramatic performance gains. In fact, 60% of all data access operations through the Jet database engine are over 20% faster in version 3.0 than in version 2.0. The following Figure shows the results of some of the pre-release performance testing, with Jet database engine 2.0 performance indexed as 1.0 for all tests:
Jet Database Engine 3.0 vs. Jet Database Engine 2.0 Performance
With Jet database engine 3.0, multi-user performance may be up to six times faster. The following changes to the Jet database engine enable it to achieve substantially better performance in multi-user scenarios and reveal design changes that developers can make to improve the performance of their Microsoft Access-based solutions:
Developers should be aware that using certain constructs can cause Jet database engine 3.0 operations to be slower than in version 2.0. These are related to the use of internal Unicode interfaces in Microsoft Access 97, which enable internationalization to languages that use extended character sets. To avoid this issue, developers should use SQL updates for bulk operations involving string manipulation whenever possible. Using SQL commands will optimize string manipulations. In the following example, the first method will be slower than the second:
Sub DAOUpdate() ‘This is the slower method. Dim db As Database Dim rs As Recordset Dim sAddress As String Set db = OpenDatabase("NWind.mdb", True, False) Set rs = db.OpenRecordset("SELECT * FROM Customers",dbOpenDynaset) While Not rs.EOF rs.Edit rsAddress = rs!Address rs!Address = sAddress rs.Update rs.MoveNext Wend End Sub Sub DAOSQLUpdate() ‘This is the faster method. Dim db As Database Set db = OpenDatabase("NWind.mdb", False, False) db.Execute "UPDATE Customers SET Address = Address", dbFailOnError End Sub
Microsoft Jet 3.5 is introduced in Microsoft Access 97. Although it does not have nearly as many performance enhancements as the previous version, the following items are new:
New MaxLocksPerFile setting
There is a new registry setting called MaxLocksPerFile. This allows you to improve performance of the completion of large queries when the data being operated on is on a NetWare® or Windows NT-based server. This forces a transaction to only partially commit.
The SetOption method
You can use the new DBEngine.SetOption method to set various Jet engine parameters at runtime. This allows you to set/test/reset various values without having to restart Microsoft Access and Jet.
Other improvements
ODBCDirect
DAO 3.5 offers a new technology called ODBCDirect. This feature allows you to deploy client/server applications using Microsoft Access 97 without using Microsoft Jet as the translation layer. ODBCDirect is an interface directly to ODBC, and as such, is faster in many operations.
With ODBCDirect, you have the following advantages (from the Microsoft Access 97 Help File):
One of the typical things that Microsoft Access 1.x and 2.0 developers have done is to wrap update code in transactions for performance gains. That is, any code operations that add, modify, or delete data are enclosed in a transaction using the BeginTrans...CommitTrans pair. While this offered dramatic speed increases in performance in version 2, Jet 3.0 has been optimized to do this automatically.
If you have code that uses transactions for speed optimizations, try removing the transactions and let Jet handle the buffering. You may see speed increases. Note that you may also see speed decreases. As with most things in this paper, the behavior of your applications depends on many complex interactions with your hardware, OS settings, and your database.
There are a number of settings that you can create and modify in the system registry that control how Microsoft Jet works. The settings are rather complex, and their interactions with Microsoft Access require some trial and error work. All of the settings are documented in the Microsoft Jet Database Engine Programmers Guide from Microsoft Press.
When Microsoft Access 2.0 first appeared, almost everyone was excited by the new events, methods and properties it introduced. But almost as quickly as most users had ripped the shrink-wrap off the boxes, they noticed that their forms loaded slower than they did in Microsoft Access 1. People complained vociferously about how bad Microsoft Access 2.0 was in terms of performance. Sound familiar? Its almost funny how history repeats itself.
After the complaining stopped, developers began to realize that there were a number of ways that they could improve the performance of form loading. Indeed, many developers now agree that Microsoft Access 2.0 is really the epitome of what is good in desktop database products. So before you despair about Microsoft Access 97, look at things in context, take a deep breath, and see what you can do to improve things.
Unlike Microsoft Access 2.0, it is possible to save form and report module code in a compiled state in Microsoft Access 97. As you may recall from your version 2.0 work, Microsoft Access used to compile all form and report module code each time the form or report was loaded. With Microsoft Access 97, it is possible to save the form or report’s code in a compiled state, eliminating the need for Microsoft Access to perform the compilation step each time the form is loaded. For this to work effectively, it is critical to understand the concept of the compiled state and how to maintain it. For more information on this, see “Improving Module Performance” later in this paper.
Forms and reports can use the new Image control in Microsoft Access 97. This control is more efficient at loading, handling, and displaying bitmap images than the bound and unbound frames available in Microsoft Access 2.0. If you are using bitmaps on your forms, consider using this new control to make things run faster.
Microsoft Access 97 contains a native tab control. If you application uses and OCX control for tabs, consider changing to the native control. Since an OCX will no longer be required, load time for the form should be faster.
Microsoft Access 97 introduces the concept of lightweight forms and reports. A lightweight object is one that has no module associated with it. For example, if a form has no module behind it, it is considered lightweight. When the form is loaded, no module needs to be loaded, and VBA does not need to be loaded. Therefore the form loads faster.
As soon as you create a module in a lightweight form, it is no longer lightweight. Note that since there are very few forms that you create as a developer that don't call code or have an associated module, this new feature is not considered a developer enhancement.
It should go without saying that data loading can be one of the most time-consuming tasks when opening a form. While this may seem obvious, you would be amazed how much work can be done on a form’s RecordSource to improve performance. Here are some of the more important query techniques. (Note that these techniques can result in better data retrieval speeds throughout your application, not just for forms):
While there are no Microsoft Access 97-specific report optimizations that I can offer (except for techniques reports share with forms, such as using the Image control to display bitmaps), there is one new event for reports in Microsoft Access 97 that can speed things up. This is the NoData event. This event is fired if a report is opened, and there is no data for that report. In Microsoft Access 2.0, the only way to detect the absence of data was to independently run the query driving the report behind the scenes, and see if it returned any records. Needless to say, this was a highly inefficient (and slow) way of doing things. With the NoData event, you can effectively speed up this part of your database application.
Microsoft Access 97 includes Visual Basic for Applications. Visual Basic for Applications, which replaces Microsoft Access Basic, provides several key benefits for developers and end users, including a common language across applications, a well-known paradigm for Windows-based development, and broad industry support. This section will help developers understand how Microsoft Access 97 and Visual Basic for Applications can work together effectively to provide good performance in projects that use a significant number of Visual Basic for Applications code modules.
This section begins by describing the key differences between Visual Basic for Applications and Microsoft Access Basic and by discussing the advantages of developing with Visual Basic for Applications. Next, it provides an overview of the commands and terminology of Visual Basic for Applications and discusses how these commands affect the development process. Finally, it describes in detail actions that developers can take to improve the performance of their Microsoft Access-based solutions.
Microsoft has worked to minimize the impact on developers of having a new language in Microsoft Access 97. Some changes in development approaches are necessary, but this work will be offset by the benefits of using a standard language and in faster applications for this and future versions of Microsoft Access.
The vision for a common language across applications was first expressed by Bill Gates in a 1987 Byte Magazine article. By providing a standard customization and development language across a suite of products, Microsoft will enable developers and users to customize applications and build solutions rapidly and efficiently. Contrast this with a world of products, each of which requires a separate learning curve in order to achieve even the simplest results.
Today, Microsoft has integrated Visual Basic for Applications into four key applications: Microsoft® Excel, Microsoft® Project, Microsoft Visual Basic 4.0, and now, Microsoft Access. Developers can invest in Visual Basic for Applications and be confident in their ability to leverage the capabilities of each of these products. In the future, Microsoft plans to integrate Visual Basic for Applications into Microsoft Word and Microsoft PowerPoint. Even today, where applications do not directly host Visual Basic for Applications, many of them expose their object models through OLE, and are therefore programmable in Visual Basic for Applications. Examples of these applications include Microsoft PowerPoint for Windows 95, Microsoft Schedule+ for Windows 95, and Microsoft Office for Windows 95 Binders.
In Microsoft Access 2.0, all Microsoft Access Basic code modules are loaded into memory at startup. Visual Basic for Applications loads code only as it is needed by the application. For example, when Microsoft Access 97 opens, only the modules that are called during startup are loaded into memory. Load-on-Demand enables applications with large amounts of code to run faster.
Visual Basic for Applications loads code at the module level. When a function is called, all code in the module containing that function is opened. Furthermore, when a variable is used, the module that contains the variable declaration is also opened.
This section gives an overview of the commands and terminology of Visual Basic for Applications in Microsoft Access and how these commands are used in the development process.
This command is found on the Debug menu in a module’s Design View. The Compile All Modules command opens and compiles all code in the application including code behind forms and reports. Executing this command is the only way to fully compile your application. You should use the Compile And Save All Modules command (discussed below) to save the compiled state of your application.
The Compile All Modules command should be used only when necessary. During development, applications will be decompiled almost all the time. It is a waste of time to carry out a Compile All Modules command unless you are ready to distribute your application or check end-user performance. The Compiling Loaded Modules command (discussed below) will check the syntax of your code without taking the time to compile modules that have not changed.
There is a special case where you may want to use a Compile All Modules command. After converting an application from a previous version of Microsoft Access, you will want to carry out a Compile All Modules command to find 16-bit library calls and other code that requires modification for Microsoft Access 97.
This command is found on the Debug menu in a module’s Design View. After a Compile All Modules command, carrying out a Compile and Save All Modules command saves the fully compiled state. If you close the application without saving, the compilation state will be lost.
This command is found on the Run menu in a module’s Design View. The Compile Loaded Modules command carries out the same command as clicking the Compile button on the toolbar. Unlike the Compile All Modules command, the Compile Loaded Modules command only compiles the modules that are currently open, including code behind open forms and reports. Even if you compile all modified code with this command, the application may not be fully compiled. You must use the Compile All Modules command in the application at the same time to ensure a complete compilation.
During the development process, the Compile Loaded Modules command is the fastest method of checking Visual Basic for Applications syntax.
Microsoft Access can store Visual Basic for Applications code in one of two states: compiled and decompiled. An application becomes decompiled whenever the application’s controls, forms, reports, or modules are modified. The application decompiles whenever you add a new control, form, report, or module; create new Code Behind Form (CBF) or Module; or delete or rename a control, form, report, module, or CBF module. If you do not save the modification, the compilation state of Visual Basic for Applications is preserved on disk.
Developers should be aware that in Microsoft Access 95, if an application is renamed, the name-space of the Visual Basic for Applications code is modified and the application will decompile. This means that if you compact your application into a new name, the compilation will be lost. To prevent this, rename the compacted application back to the original name before running it. Because Microsoft Access 97 does not use the database name for the project name, renaming the database no longer decompiles the project. Use the Tools/Options/Advanced dialog to view and/or modify the project name.
Applications run more slowly when decompiled. If the application is decompiled, Visual Basic for Applications must recompile the code on-the-fly as needed. This causes forms and reports to open more slowly than they do in the fully compiled state. Before the form or report can open, Visual Basic for Applications must compile the code behind the form or module and any module code that is called by the form code.
Decompiled applications also use more memory than compiled applications. If the application is compiled, only the compiled state is loaded into memory. For decompiled applications, the decompiled code is loaded into memory; then, the compiled state is created and loaded as needed. Both the compiled and decompiled states are stored in memory.
Decompiled applications use less disk space than compiled applications. If you import all of your application objects into a new database, all Visual Basic for Applications code will be decompiled. Following this with a compact operation will reduce the application’s size by deleting the compiled state.
Visual Basic for Applications dynamically loads code into memory as needed on a module level. If a function is called or a variable is used, the entire module containing that function or variable is pulled into memory. As you are developing your application, you will pull more an more code into memory. Visual Basic for Applications does not support dynamic unloading of these modules. Because of this, RAM will begin to fill up. To boost development performance, you may want to close the application periodically to unload the modules.
It is especially important to close your application after a Compile All Modules command. The Compile All Modules command pulls all of your code into memory. Closing and reopening the application will unload the code and enable you to develop faster because of the additional free memory.
If you are developing your application in a single-user environment, you can improve your development performance by opening the application exclusively. This allows Visual Basic for Applications to save and compile faster by eliminating multiple-user save situations.
Before you distribute your application, it is a good idea to compile all modules to check for syntax errors. VBA's compilation behavior is affected by the Compile On Demand setting available under the Tools/Options/Modules dialog.
When the CompileOnDemand option is turned on, uncompiled modules are not compiled until VBA needs to load them for execution. If this option is turned off, an uncompiled module is compiled when a module that contains a procedure that calls the uncompiled module is loaded.
Performance of your VBA code may be enhanced if you leave this option on (the Microsoft Access 97 default.)
In Microsoft Access 95, when you call a procedure, VBA must load that procedure's module, as well as all the modules that contain procedures called by the original module. This is called the potential call tree, and resulted in poor VBA load performance in Microsoft Access 95. In Microsoft Access 97, modules are loaded only when they are needed. In other words, if a procedure is called, only the module containing the procedure is loaded. This should enhance the performance of your application.
This section discusses the following two basic application scenarios:
These are applications that do not allow the end user to modify or to create new controls, forms, reports, or modules. Examples of static applications are wizards and other add-ins.
These are applications that modify or create forms, reports, or modules. This modification can be done either by the end user or by the application itself. An example of a dynamic application is an inventory management system where the application creates new reports.
The steps to improve the performance of static applications apply also to dynamic applications.
This section discusses the performance issues that affect applications that are not in danger of becoming decompiled after distribution to end users. These performance topics concern good development practices that will result in faster applications, regardless of whether the application is static or dynamic.
Creating efficient modules
The first development practice that will speed performance is to minimize the amount of code in each module. When a form (or report) opens, it must load the code in all modules called by the form; therefore, relocating unnecessary functions from your modules will improve form-open performance.
Reducing number of modules opened
The second development practice that will speed performance is to minimize the number of modules opened by a form or report. When a form opens, it must load into memory all modules called by the form and all modules that contain declarations of the variables used in the code behind the form. Each module opened by the form must, in turn, open any modules it requires. Your application will run faster (and be easier to manage) if your module call paths are simple. Global routines called by many other modules should be partitioned into separate modules to prevent unnecessary code from being loaded into memory. The same is true of global variables. Loading a module that uses a global variable will cause the module containing the global variable declaration to be loaded.
Opening modules at run time (Application.Run)
You can design your application to load code at run time by using the Run method of the Application object. To call a function in this manner, replace the existing function call
MyFunction(parameter 1, parameter 2,...)
with:
Application.Run “project.MyFunction”, parameter 1, parameter 2, ....
where project is the name of the MDA file containing the function.
In the MyFunction case, MyFunction is loaded whenever the form or module containing the function call is opened. In the Application.Run case, MyFunction is loaded only if and when it is called by the form or module.
This technique is used in the design of Microsoft Access Wizards. A significant percentage of the wizard code is not called by each wizard and the largest block of code is run after the Finish button is clicked. By using the Application.Run syntax, the unneeded code is never loaded, and the large block of code is not loaded until the user clicks the Finish button. If the user clicks Cancel before the wizard task is finished, the largest block of code is not loaded.
The Application.Run syntax is also useful when a command button on a form runs a large amount of code, but the button is not selected by many users or is not selected often. If the button calls a subroutine using the Application.Run method, the code is not loaded when the form is loaded; it is loaded only when the button is clicked.
There are some restrictions to using the Application.Run method, as follows:
This section discusses the performance issues that are unique to applications that allow end users to modify, create, or delete controls, forms, reports, or modules. These applications will normally remain in a decompiled state, but developers can maximize performance by following the suggestions below.
Saving space by not compiling
If end users will make frequent changes to the application, there is little point in distributing a fully compiled application. The extra space required for the compiled state will be useless as soon as the application becomes decompiled. To delete the compiled state completely, import all of your application objects into a new database, and then compact the new application.
Separating decompiled code from global modules
If a significant portion of the application code is contained in modules (as opposed to CBF), application performance can be improved by moving modules to a code library and creating a reference from the application front end. This will allow end users to add new forms and reports without decompiling the library database. There is some overhead in creating the reference to the library, and end users do have to manually establish the library references; therefore, this method should be used mainly for applications with a significant amount of module code. In an application designed in this manner, a form open will compile only the necessary code in the front end and quickly open the library containing the fully compiled module code.
There is a design consideration when moving code into libraries. Circular references are not supported in code libraries. That is, a module cannot call any modules that call functions or variables in the original module. This is true no matter how many intermediate modules are in the chain of references.
Microsoft Access 97 offers the exciting new capability of creating a "Compiled-Only" version of your database. This version (known as an MDE file) is a copy of your database, but it contains none of your VBA code in the source form. Instead, only the compiled version of the VBA code is included in the database.
If you have applications that use VBA code, you can benefit from this new feature. The process of creating and MDE does the following:
This offers the following benefits:
Once you have created an MDE file, the follow actions are disallowed:
It is important to note that when you make an MDE file, you still keep your original database for development work. Think of it this way: your original database is your source code, and the MDE version is the compiled executable.
The Performance Analyzer was a direct result of usability studies conducted with Microsoft Access 2.0 users. We evaluated a number of Microsoft Access 2.0 applications and discovered that many built-in performance features were not being used. Based on this research, we created the Performance Analyzer, a tool which analyzes the design of a Microsoft Access-designed application and suggests a number of techniques to improve the performance of that solution. The Performance Analyzer can then implement any or all of the suggestions automatically.
The Performance Analyzer was designed using our knowledge of how the Jet database engine and the Microsoft Access development environment are designed. Developers can choose to analyze database components, such as tables, forms, or an entire database. The Performance Analyzer is also a way for developers to learn additional performance techniques that they can apply to their own custom applications.
By implementing the suggestions provided by the Performance Analyzer, users and developers may realize performance improvements ranging from 20% to orders of magnitude.
Microsoft Access 97 offers powerful new tools for building high-performance custom solutions. Using the techniques explained in this session will help developers maximize performance in their specific development situations.
© 1997 Microsoft Corporation. All rights reserved.
The information contained in this document represents the current view of Microsoft Corporation on the issues discussed as of the date of publication. Because Microsoft must respond to changing market conditions, it should not be interpreted to be a commitment on the part of Microsoft, and Microsoft cannot guarantee the accuracy of any information presented after the date of publication.
This document is for informational purposes only. MICROSOFT MAKES NO WARRANTIES, EXPRESS OR IMPLIED, IN THIS SUMMARY.
Microsoft, Visual Basic, Windows 95, Windows NT, and PowerPoint are registered trademarks of Microsoft Corporation.
Pentium is a registered trademark of Intel Corporation. NetWare is a registered trademark of Novell, Inc.
Other product or company names mentioned herein may be the trademarks of their respective owners.