INF: Performance Considerations with the ODBC Access 2.0 DriveLast reviewed: September 9, 1996Article ID: Q126552 |
The information in this article applies to:
SUMMARYThis article discusses methods to enhance the performance of the ODBC Access version 2.0 driver. It discusses both the ODBC API issues and the Microsoft Foundation Database Classes (MFC) programming considerations for improving the speed of an application that uses the Access 2.0 driver.
MORE INFORMATIONThe ODBC Access driver is a very feature rich, high performance driver. Because it is feature rich, it offers multiple ways to do inserts, deletes, and updates. Some ways are better than others in terms of performance. Carefully designing your application to use such methods, whenever possible, will help you maximize the performance of your ODBC application.
Using Prepared ExecutionsQueries can be executed in one of two ways:
Every time a query has to be executed with SQLExecDirect(), the ODBC Driver has to parse the query and generate an execution plan for it. The query is then executed using the execution plan. When you use SQLPrepare(), the above steps are done once and the execution plan is stored; it is invoked every time SQLExecute() is called. This means that the performance is significantly enhanced if the query is executed multiple times.
Using Stored QueriesThe Access 2.0 ODBC driver lets you use stored queries in an Access .MDB database. Stored queries cannot be created by using the Access driver; they are created using Access or Visual Basic. Stored queries can be used in one of 2 ways using the Access ODBC drivers:
Using TransactionsWhen you are executing multiple INSERT, DELETE or UPDATE statements, performance can be enhanced by turning autocommit mode off; this can be done by calling SQLSetConnectOption on the connection handle (HDBC). This is because in autocommit mode, the driver must ensure that each individual INSERT, DELETE, or UPDATE statement is flushed to the safe store (usually disk). If they are grouped in a transaction, the driver can clump the writes to the disk and do them only once during commit time. Since disk I/O takes a relatively long time, turning autocommit mode off enhances performance.
Using Engine Cursors vs. Cursor LibraryThe Access 2.0 ODBC driver supports the ODBC cursor API. As a result, positioned inserts, deletes, and updates can be done using the SQLSetPos() function. Using SQLSetPos() to perform these operations is much faster than doing the same operations using a SQL statement. The reason is, when you use SQLSetPos, the table is already open; there is no need to look into the catalog. Because no SQL statement exists, there is nothing to parse. Performance can be further enhanced by wrapping these operations in a transaction. Static updateable cursors are provided by the cursor library. But using the cursor library to do a positioned update is much slower than using SQLSetPos()/SQL_UPDATE because the cursor library adds a lot of overhead. The cursor library has to look at the buffered results and generate an UPDATE statement; this update statement has to be parsed and an execution plan needs to be generated; there is also catalog lookup involved to open the table which is being updated.
INSERT, DELETE, AND UPDATE PerformanceIn general, INSERT, DELETE, and UPDATE statements can be done six different ways. They are listed below in order of increasing performance. To make the comparison more concrete, 100 inserts were done using each of these methods into an Access 2.0 table that had 5 columns of text data. NOTE: These do not represent exhaustive bench marking results. Hence, it should not be treated as such. They are just provided to illustrate the relative merits of these methods.
What Does This Mean if You Use the MFC Database Classes?The CRecordset C++ class provided with the MFC prepares queries before execution using the SQLPrepare() ODBC API function. The CRecordset::Requery() function can be used to re-execute the query for the CRecordset without the ODBC driver re-parsing the SQL statement again because the statement has already been prepared the first time. By default, the MFC database classes load the cursor library. The cursor library permits updateable snapshots. To get updateable recordsets but not use the cursor library, you might want to consider using a dynaset CRecordset. You specify this by passing CRecordset::dynaset for the first argument of CRecordset::Open(). With the 32-bit MFC database classes, it is not enough to pass CRecordset::dynaset to CRecordset::Open(). You must pass FALSE for the last argument of the CDatabase::Open(). This prevents the cursor library from loading. The code looks like this:
CDatabase db; db.Open("DataSourceName",FALSE,FALSE,"ODBC;",FALSE); CYourRecordset rs(&db); rs.Open(CRecordset::dynaset);The 16-bit MFC database classes do not let you get updateable dynasets with the code that is provided. You must acquire the DYNSET.EXE code mentioned in the following article in the visualc database within the Microsoft Knowledge Base:
ARTICLE-ID: Q124915 TITLE : SAMPLE: Using Dynasets with the 16-Bit MFC Database ClassesBy using dynasets, using DYNSET.EXE code or 32-bit classes, you will be using the SQLSetPos() functionality of the Access 2.0 ODBC driver when performing updates, deletes, or inserts. As mentioned earlier, this will greatly increase the speed of your application. The Access 2.0 ODBC driver does not support MFC transactions but comes close. The MFC database classes require ODBC drivers to support recordset cursor preservation across rollbacks and commits of transactions (see documentation for SQLGetInfo and parameters SQL_CURSOR_COMMIT_BEHAVIOR and SQL_CURSOR_ROLLBACK_BEHAVIOR in the ODBC Programmer's Reference). The Access 2.0 driver does not guarantee this; however, you can use transactions if you requery following any transaction so that the cursor is restored back to first record in the recordset. You must also force the CDatabase::m_bTransactions to TRUE before using BeginTrans(). Your code could look like this:
class CTransactDatabase: public CDatabase { public: void SetTransactions(){ m_bTransactions=TRUE;} }; . . . CTransactDatabase db; db.Open("SomeDataSourceName",FALSE,FALSE,"ODBC;",FALSE); db.SetTransactions(); db.BeginTrans(); CPerftestSet rs(&db); rs.Open(CRecordset::dynaset); . . .Use CDatabase::CommitTrans() and CDatabase::Rollback() to commit and rollback transactions.
Notes:
|
Additional reference words: 2.00.2317 ODBC Desktop Database Drivers
© 1998 Microsoft Corporation. All rights reserved. Terms of Use. |