The Wayback Machine - https://web.archive.org/web/20111103174023/http://www.databasejournal.com/features/msaccess/article.php/3658041/Queries-On-Steroids--Part-IV.htm

Free Newsletters:
DatabaseDaily  
Database Journal Search Database Journal:
 
MS SQL Oracle DB2 Access MySQL PostgreSQL Sybase PHP SQL Etc SQL Scripts & Samples Links Database Forum DBA Videos
internet.com

» Database Journal Home
» DBA Videos
» Database Articles
» Database Tutorials
MS SQL
Oracle
DB2
MS Access
MySQL
» RESOURCES
Database Tools
SQL Scripts & Samples
Links
» Database Forum
» DBA Jobs
» Sitemap

News Via RSS Feed


follow us on Twitter




internet.commerce
Be a Commerce Partner



Brocade Doubles Down on 16 Gbps Fibre Channel

Microsoft Wants iOS Apps to Run on WP7

Avaya Debuts New Virtual Services Switch

internet.com
IT
Developer
Internet News
Small Business
Personal Technology

Search internet.com
Advertise
Corporate Info
Newsletters
Tech Jobs
E-mail Offers


Database Journal |DBA Support |SQLCourse |SQLCourse2







Technical Specialist – Pre-sales (MA)
Next Step Systems
US-MA-Littleton

Justtechjobs.com Post A Job | Post A Resume

Featured Database Articles

MS Access

February 16, 2007

Queries On Steroids ... Part IV

By Danny Lesandrini

Query analysis tools for the stout of heart.

Let me begin by confessing that I am not qualified to write this article. Everything you read below comes from Internet research, primarily from two sources:

I'd like to give special thanks to the authors of the Access Developer's Handbook, and to the professionals that freely give of their time and expertise on the many user groups, including but not limited to Lyle Fairfield, David Fenton, Albert Kallal and Jim Dettman, whose posts proved most helpful in researching this article.

It has, for some time now, been a goal of mine to understand how to analyze queries in both Microsoft Access and SQL Server. I've bought a few books and even started reading them on more than one occasion. Nevertheless, for some reason, I just can't seem to follow through and really devote the time to it that would be required to become proficient at reading the results of analysis tools. Therefore, this article will cover the tools available and to a limited extent, my understanding of how the results may be interpreted. If you need to analyze your queries, you're going to have to slog through the results yourself and try to make sense of the data returned.

The disclaimer out of the way, let's plunge headlong into two undocumented and unsupported Jet Optimization tools in Microsoft Access that may help you in identifying performance bottlenecks in your queries:

  • Showplan option
  • ISAMStats method

Showplan Option

Showplan is an undocumented option that, once enabled, creates a file named showplan.out where query execution plan information is appended each time a query is run. The location of this file can be a bit elusive, but if you don't find it in the same folder as the currently active mdb file, then look in your My Documents folder. Only one file will be created per folder. Results from all Access database queries are appended to the same file and over time, it will grow large.

Before we describe how to enable this feature, we're obliged to supply this warning:

Jet Showplan should only be enabled for debugging and analysis. It carries with it a notable performance hit and the increased potential for application crashes.

To turn on Showplan, you simply edit one of the Microsoft Jet registry entries. If you are comfortable with the registry, then simply navigate to the following Windows Registry key using Regedit and set the JETSHOWPLAN key to the text value of 'ON'
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Jet\4.0\Engines\Debug.

While I'm comfortable with the Registry, I prefer to create a pair of .reg files for managing this setting with the double-click of my mouse. The following scripts were supplied by the authors of the Access Developer's Handbook, an indispensable resource for Access professionals. Simply copy and paste each of these scripts into Notepad and save them as .reg files.

JET ShowPlan ver 4.0 ON.reg

  Windows
  Registry Editor Version 5.00
  [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Jet\4.0\Engines\Debug]
  "JETSHOWPLAN"="ON"

JET ShowPlan ver 4.0 OFF.reg

  Windows
  Registry Editor Version 5.00
  [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Jet\4.0\Engines\Debug]
  "JETSHOWPLAN"="OFF"

Note: You may have version 3.5 of the Jet engine installed. If so this registry key will be found in the following node:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Jet\3.5\Engines\Debug

Additional Note: For Office 12 (Access 2007), the key is located here, but is still undocumented.
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Office\12.0\Access Connectivity Engine\Engines\Debug]

Once enabled, you need only open a query to begin logging. (Since this file grows rapidly, I found that, for the sake of this article, it was necessary to save off its contents and delete the showplan.out file from time to time.) I created a simple query to select author name and state from the pubs authors table, where state='CA'. Below are the results, before and after an index was added to the state field.

First Query ... single table with where clause:
   SELECT authors.au_lname, authors.au_fname, authors.state
   FROM authors WHERE authors.state='CA';

--- Query1 ---
Author note: most recent query run is on top
- Inputs to Query -
Table 'authors'
- End inputs to Query -
01) Restrict rows of table authors
      using index 'state'
      for expression "authors.state='CA'"

--- Query1 ---  
Author note: First run without index on state column
- Inputs to Query -
Table 'authors'
- End inputs to Query -
01) Restrict rows of table authors
      by scanning
      testing expression "authors.state='CA'"

Second Query ... with primary key links and group by clause:
   SELECT stores.stor_name, sales.ord_date, Sum(sales.qty) AS [Total Books Sold]
   FROM stores INNER JOIN sales ON stores.stor_id = sales.stor_id
   GROUP BY stores.stor_name, sales.ord_date;

--- Query2 ---
Results after adding Primary Keys to tables
- Inputs to Query -
Table 'sales'
    Using index 'storessales'
    Having Indexes:
    storessales 21 entries, 1 page, 6 values
      which has 1 column, fixed
    PrimaryKey 21 entries, 1 page, 21 values
      which has 3 columns, fixed, unique, primary-key, no-nulls
Table 'stores'
- End inputs to Query -
01) Inner Join table 'stores' to table 'sales'
      using index 'sales!storessales'
      join expression "stores.stor_id=sales.stor_id"
02) Group result of '01)'
--- Query2 ---
First query run without primary keys defined
- Inputs to Query -
Table 'sales'
Table 'stores'
- End inputs to Query -
01) Sort table 'sales'
02) Inner Join table 'stores' to result of '01)'
      using temporary index
      join expression "stores.stor_id=sales.stor_id"
03) Group result of '02)'

Now comes the hard part ... interpreting the results. I've marked what I believe to be the critical results above with red text. In the first query example, we are informed that rows were returned as a result of "scanning." This is bad. We want the query optimizer to find an index, as it does in the second run (top result) after having added the state index.

In the second query example, linked tables had no primary keys defined, and no indexes. The first run (bottom result) shows that a temporary index was used. I suppose it's good that Access created a temporary index, but I suspect it's better to have created the indexes myself. The second run takes advantage of the 'sales!storessales' index that was created when I added a primary key to Store, and created a relationship to the sales table.

These examples are simple and obvious. To test something more complex, I cleared the showplan.out file and launched my most complicated application. After the splash screen and startup functions, I selected a search from the menu and loaded a complex form with subforms. From that form, I double-clicked to drill to an additional form. The results? Showplan grew to 77 kb which took up 77 pages in Microsoft Word. A total of 216 entries were made to Showplan.out in less than 2 minutes.

What does this mean? I don't know. I'd have to pore over all these results to identify each and decide which, if any, could be optimized. Clearly, this is not the way to use the showplan option.

One of the newsgroup posts I found was from an accomplished developer named David Fenton. He posted the following to Comp.Databases.MS-Access on 2002/01/28 ...

It's an eye opener. I had one app where running a single normal everyday process caused the log file to grow from 38K to nearly 2MBs (it was updating fields in a temp table using functions that used DAO to get their values; every call to those DAO functions got listed in Showplan, in one case for a couple of thousand records in the updated table!). I completely re-architected that component of the app, and the users are delighted.

ISAMStats method

If it can be said that I know little about Showplan, I know even less about ISAMStats, but having run across it in my research, I'm compelled to include it for those of you who wish to take your query analysis to another level. Again I emphasize that the code below is something revealed by my research and credit should go to the two references at the top of this article.

The ISAMStats return metadata such as disk reads and writes. The DAO method for retrieving this information is shown below. I also created a disposable function to run DiskStats against two similar queries. The first is the query analyzed above named Query1. It simply selects a list of authors who live in the state of CA. After having run the DiskStats 3 times and recording the results, I changed the query where clause to allow the user to enter a state.

Option Compare Database
Option Explicit
Public Function DiskStats(bolReset As Boolean)
  On Error Resume Next
   
  Dim lngTemp    As Long
  If bolReset = True Then
    DBEngine(0).BeginTrans
    DBEngine(0).CommitTrans
    lngTemp = DBEngine.ISAMStats(0, True)
    lngTemp = DBEngine.ISAMStats(2, True)
  Else
    MsgBox "disk read = " & DBEngine.ISAMStats(0) & vbCrLf & _
           "disk write = " & DBEngine.ISAMStats(1) & vbCrLf & _
           "cache read = " & DBEngine.ISAMStats(2) & vbCrLf & _
           "read ahead = " & DBEngine.ISAMStats(3) & vbCrLf & _
           "locks placed = " & DBEngine.ISAMStats(4) & vbCrLf & _
           "locks released = " & DBEngine.ISAMStats(5) & vbCrLf
  End If
End Function
Function TestDiskStats()
  Call DiskStats(True)
  DoCmd.OpenQuery "Query1"
  Call DiskStats(False)
End Function

I can't say the results were surprising, because I really didn't know what to expect. What's more, I can't interpret them for you either. For that, you'll have to check MSDN or post your question to the newsgroups where you will find someone who knows more about it than I do. However, I can analyze the results and see that where the state was 'hard coded' to CA, it required fewer disk reads, fewer cache reads and fewer locks. So, while I don't necessarily understand what each attribute represents, I can use them for making comparisons. Run the stats, modify the query and re-run stats to determine which method is more efficient.

Does this help?

I had promised 4 installments of Queries on Steroids, including a discussion of Showplan. I'm not sure how helpful it is to me, let alone my readers, but as usual I'd be happy to hear from you. Perhaps you can add to this discussion and share your techniques on analyzing and interpreting the results of Jet Showplan and ISAMStats.

» See All Articles by Columnist Danny J. Lesandrini

Tools:
Add databasejournal.com to your favorites
Add databasejournal.com to your browser search box
IE 7 | Firefox 2.0 | Firefox 1.5.x
Receive news via our XML/RSS feed

MS Access Archives

Comment and Contribute

 

 



Latest Forum Threads
MS Access Forum
Topic By Replies Updated
VBE7.DLL Fault deth12332 0 October 20th, 12:45 PM
How to create user login form (MS Access 2000 - 2003) meLady 84 October 11th, 12:47 PM
Access 2007 VBA - Insert query snytax error Moe1950 1 October 7th, 02:59 AM
Access 2007 - Modify Query At Run Time Moe1950 7 October 6th, 10:14 AM