DBMS
 

 

Understanding Multidatabase APIs and ODBC

By Ken North
DBMS, June 1994

The truth about Open Database Connectivity (ODBC) and other APIs, such as QELIB, depends on who you ask.


The benefits of porting database applications by writing to an application programming interface (API) for a virtual DBMS are so appealing to software developers that the computer industry has recently introduced several multidatabase APIs. Developers use these call level interfaces for applications that access multiple databases using a single set of function calls, thereby minimizing differences in application source code. The IDAPI initiative (Borland, Novell, IBM, and WordPerfect) and Oracle Glue are recent solutions to the multidatabase programming problem, but this article focuses on the concepts and feedback from experienced users of APIs from Microsoft Corp. and Q+E Software Inc. Q+E Database Library (QELIB) was the first of these products available to Windows and OS/2 developers. Q+E bundles are available with a variety of products from Microsoft, Computer Associates, IBM, Lotus, Borland, WordPerfect, and other companies. Q+E Software is replacing its earlier QELIB drivers with ODBC-compatible drivers and marketing an ODBC Driver Pack as a separate product. Version 2.0 of QELIB supports ODBC while maintaining backward compatibility with older versions of QELIB. ODBC and the other APIs provide standard database access through a common client side interface. It implements and extends the call level interface from the SQL Access Group (SAG) and X/Open.

ODBC is still a relatively new phenomenon. Several companies (Watcom, Microrim, and Quadbase) shipped early drivers at the end of 1992. Microsoft partnered with PageAhead Software to produce the ODBC Desktop Database Driver Kit in July 1993. Q+E's ODBC Pack and The Ask Group's ODBC driver for Ingres were both summer 1993 releases. ODBC was conceived as an API for Windows clients, but developers such as Q+E and PAL Consulting Ltd. (London, U.K.) are working on ports to OS/2, Macintosh, Unix, and other environments. At the time of this writing, Watcom's implementation for OS/2 is expected to be available in March 1994. (Watcom was recently acquired by Powersoft Corp.) The total number of distributed and downloaded copies of the ODBC SDK was approximately 9100 by September 1993. Microsoft ODBC Marketing Manager Colleen Lambert estimated a monthly shipping rate of 500 copies.

Most early adopters in my feedback survey (see sidebar titled "ODBC Reality and Developer Experiences") have databases in more than one format with combinations of desktop databases and servers. Specialists that view DBMSs solely from the perspective of high-performance, custom OLTP applications must consider the total application mix, including "shrink-wrap" software and desktop databases, when they evaluate interoperability solutions. In simple terms, developers must address requirements for desktop, workgroup, and enterprise solutions. ODBC provides connectivity to many database formats, so developers add it to the toolkit even when they use gateways or routers, which generally provide links only to the more popular DBMSs. This widespread connectivity may be the principal factor that motivated vendors of front-end products, such as Oracle CDE, Powersoft's PowerBuilder, KnowledgeWare's ObjectView, and Gupta's SQLWindows, to add ODBC to their product development plans.

Access and Visual Basic were early ODBC-enabled applications, so many developers evaluated ODBC performance based upon their experience with those products instead of differentiating between the API, driver performance, and client application performance. Access 1.0 was capable of being an ODBC client, and processing sets using an optional SQL passthrough dynamic link library (DLL). Visual Basic 2.0 introduced Object Layer support for ODBC, and VB 3.0 introduced data-aware controls. Among the many client tools that work with ODBC and QELIB are AutoCAD, Pagemaker, PowerBuilder, SAS, ObjectView, Lotus 1-2-3 and Improv, Excel, Crystal Reports, Clear Access, SQLView, WordPerfect, Ami Pro, and Word for Windows. The number of drivers increased as Informix, Oracle, Gupta, IBM, DEC, NCR, The ASK Group, Microsoft, and Sybase developed drivers internally or shipped drivers developed by PageAhead or Q+E. There is at least one ODBC driver for nearly every major SQL DBMS platform. You can also access data on legacy systems by using ODBC drivers for products such as Information Builders' EDA/SQL.

Architecture

Microsoft's Open Database Connectivity (ODBC), a component of the Windows Open Services Architecture (WOSA), is conceptually similar to the Windows print model, where the application developer writes to a generic printer interface and a loadable driver maps that logic to hardware-specific commands. This approach virtualizes the target printer or DBMS because the person with the specialized knowledge to make the application logic work with the printer or database is the driver developer and not the application programmer. The application interacts with the ODBC Driver Manager, which is a Windows DLL or a Macintosh System 7 Shared Library Manager. The Driver Manager (odbc.dll), which fields the application calls to the database, sits at a layer above one or more single- or multiple-tier drivers. It loads and unloads drivers, performs status checking, and manages multiple connections between applications and data sources. Single-tier drivers sit directly above a data source and process ODBC calls and SQL statements. Multiple-tier drivers process the function calls and pass the SQL request to a server for processing. The Driver Manager fields and processes some ODBC calls without calling a driver.

Figures 1 and 2 illustrate the software architecture of two common ODBC implementations. In either scenario, the ODBC Driver Manager DLL processes the application's function calls and directs them to the appropriate loadable driver. It is at this point that implementations vary. Some drivers map the ODBC functions into calls to a library of proprietary functions, that is, a native API (Figure 2). An example of a driver that follows the translation layer architecture of Figure 2 would be a SQL Server driver that maps ODBC functions to DB-Library function calls. Drivers that conform to the Figure 1 model include those that provide SQL access to databases without a native SQL API (such as Btrieve, Paradox, and dBASE), those that implement ODBC/SAG as a native API (for example, Coromandel Industries' Integra and Microrim's R:Base SQL), and those that work directly on databases without using gateways or native API function libraries (such as NCR's Teradata). If a driver follows the translation layer model, its installation will require the proprietary function library to be present.

ODBC Programming: Hints and Kinks

ODBC provides an abstraction called a data source that encapsulates a server, database name, schema, network library, and other information for linking a client application with data. ODBC supports transaction commit and rollback, asynchronous processing, an option to cancel a query, stored procedures, primary and foreign keys, and five levels of transaction isolation (the first four levels conform to SQL2). It defines multiple levels of conformance with the SQL grammar (minimum, core, extended) and the API (0-2, with level 0 conforming to the SAG CLI). As an application moves to levels 1 and 2, it can draw upon more features, data types, a richer DML and DDL, expressions and batch support, and stored procedures. Table 1 lists ODBC functions and their conformance levels. When considering an ODBC solution, it is important to differentiate between the API, the features of the back-end server or engine, and the features implemented by a specific driver. For example, the API may define support for features such as bidirectional scrollable cursors and stored procedures, but the back end or the driver may not include those capabilities.

Many of the concepts supported by the ODBC API are common to SQL programming (fetches, transactions, and cursors), but other APIs don't include functions that address the requirement of matching a client programming interface to a variety of back ends. ODBC applications that use multiple databases require context management logic to manage multiple connections and multiple SQL requests. ODBC uses handles to track the storage and context for the environment, connections, and statements. One of the first steps of an ODBC application is to allocate an environment handle by calling SQLAllocEnv. The application must allocate a handle for a database connection (SQLAllocConnect) before calling connection functions (SQLConnect, SQLDriverConnect, SQLBrowseConnect). To set or retrieve options for the current connection, the application calls SQLGetConnectOption and SQLSetConnectOption. As part of its termination logic, every application should close connections and free the connection and environment handles by calling SQLDisconnect, SQLFreeConnect, and SQLFreeEnv.

To obtain status information about the driver or DBMS, call SQLGetInfo. To get metadata or data-dictionary information, call SQLGetTypeInfo, SQLTablePrivileges, or SQLTables. One weakness of some early drivers was repetitive calls for information such as metadata. Astute developers recognized the performance hit and added caching to their applications. To control transactions and asynchronous queries, an application uses SQLCancel and SQLTransact, respectively. Use SQLTransact in your code to implement commit and rollback. ODBC does not have explicit rules functions but it supports the concept of integrity constraints using SQLForeignKey and SQLPrimaryKey.

ODBC includes several functions to prepare and execute SQL and retrieve results. To process statements, an application must first acquire a handle by calling SQLAllocStmt. There is a function for direct execution of a SQL statement (SQLExecDirect) and functions to prepare and execute statements (SQLPrepare and SQLExecute). A program calls SQLSetParam to use parameters and associate storage for parameter markers in a prepared statement. To free statement handles, a program calls SQLFreeStmt. An application can use named cursors by getting and setting the cursor name for a statement (SQLGetCursorName and SQLSetCursorName).

A program retrieves a row in a result set by calling SQLFetch. It calls SQLBindCol before doing the SQLFetch in order to associate storage and conversions for columns of the result set. This technique of fetching a bound result set applies to data and metadata, such as the information from SQLTables and SQLProcedures. Programs obtain information about columns by calling SQLColAttributes, SQLProcedureColumns, or SQLDescribeCol, and retrieve a column of data by calling SQLGetData. Applications obtain information about statement results by calling SQLRowCount and SQLNumResultCols. ODBC's support for scrollable and named cursors includes a function (SQLSpecialColumns) that permits applications to use custom scrollable cursors. SQLSpecialColumns supports rowids (the best set of columns that uniquely identify a row). Applications use SQLSetPos to track cursor position in a rowset and two new ODBC 2.0 functions (SQLOpenTable and SQLBindKey) to navigate ISAM databases.

ODBC functions can post zero, one, or more errors, so checking for errors after calling SQLError is good programming practice. An application can call SQLError at any time, but most applications call it when ODBC functions return SQL_ERROR or SQL_SUCCESS_WITH_INFO. To get a clear representation of status, a developer should check SQLState and make repetitive calls to SQLError until ODBC returns SQL_NO_DATA_FOUND. Developers using ODBC and QELIB to write for more than one back end will encounter a variety of error messages and error codes. Multidatabase programmers are looking for a magic-bullet solution in this area, so this represents an opportunity for someone to create components such as an error handler with an extensive database of error messages.

Adaptive or Least Common Denominator?

Success in developing software often depends on matching tools and techniques to requirements. Developers maintain an API view and not a product-specific view of ODBC, as a component of a toolkit. ODBC provides developers with more than one option for writing portable database applications. One strategy is to define identical databases across DBMS platforms and write a generic program that does not take advantage of unique DBMS features. A more sophisticated adaptive strategy is to bind at run time to the capabilities of the back end. An adaptive application will interrogate the back end to determine available features, functions, and data types and make the appropriate programmatic decisions. This strategy of run-time binding or adaptation may be foreign to programmers that use embedded SQL's compile-time binding.

The key "interrogating" functions are SQLGetInfo, SQLGetTypeInfo, and SQLGetFunctions. SQLGetInfo provides information such as availability of stored procedures, outer joins and IEF, cursor commit and rollback behavior, default transaction isolation levels, scrollable cursors, concurrency options, conversion functions, and so on. SQLGetTypeInfo returns a result set that includes the native data types and the ODBC data types of a data source. SQLGetFunctions identifies whether a driver supports a specific ODBC function.

You'll find a program listing (INTRGATE.CPP) on the DBMS CompuServe Forum (GO DBMS) that illustrates interrogating the data source at run time to determine its features. INTRGATE creates and displays one or two lists, depending on the capabilities of the back end. The first list shows driver and server information for all ODBC data sources. If the back end supports stored procedures, it displays a count and list of stored procedures for that data source.

SQL Passthrough

One feature that is common to ODBC and other multidatabase APIs is the ability to pass SQL strings to a back end without translation or modification. This SQL passthrough provides the client-side user with the ability to use native SQL features that are specific to a back end (such as DB2's OPTIMIZE FOR n rows). Visual Basic and Access include a passthrough option for execution of stored procedures and other performance benefits.

Setting up for ODBC Development

To run ODBC applications, you'll need to install ODBC (the administrator and drivers) and configure data sources. The ODBC installation kit adds an ODBC Administrator icon to your Windows Control Panel. Before you can access data from an application, you must use the ODBC Administrator to add data sources and define information such as server name, database name, network library, schema, and other details. When you install a driver from a DBMS vendor or a software house, it will appear in the installed driver list of the administrator. C++ users may find it necessary to wrap a linkage specifier around the ODBC functions in the headers (SQL.H and SQLEXT.H) of the ODBC SDK. Revised headers may be available by the time you read this article, but if you encounter linker errors on ODBC functions, you should add an extern "C" { } wrapper to your headers.

Visual Basic Programming

Visual Basic's architecture is extensible by adding third-party data-aware tools, but the Pro Edition, even without add-ons, includes several programming levels at which developers may access ODBC databases. The levels include programmatic access using the Access engine and Object Layer, and visual development using data-aware controls or direct calls to ODBC functions. If you also consider the options to use SQL passthrough and a choice of static or dynamic result sets, you have seven distinct programming techniques for ODBC access. Developers considering these solutions must evaluate the relative importance of ease of development, features, and performance of their transaction mix. Data-aware controls are point-and-click programming solutions that are a fast-track developer's tool.

Programmers that are willing to trade features and ease of programming for better performance, make direct calls to the ODBC functions. Visual Basic and Access users learn the ins and outs of programming for the Access engine, commonly called JET. These products support a static result set (a snapshot) and a dynamic result set (a dynaset). Performance tends to be better using snapshots for smaller result sets and dynasets for larger result sets. Developers that write applications that use a lot of simple, single-table queries prefer the direct API technique because the payback for JET's overhead comes into play with complex queries and remote joins that take advantage of the Access engine's optimization features. Table 2 (Part C) shows the results of using this variety of techniques to run identical queries with the same data source.

Benchmarking Tools

ODBC is still unfamiliar territory to many developers, so there is much interest in performance information. For many people, their first exposure to ODBC was Access and Visual Basic. Visual tools such as VB's data controls provide ease of development but it isn't an "apples-to-apples" comparison to measure them against mature, native C API programs. One problem for developers is differentiating between performance of the client application, the driver, and the API. The next issue is to recognize that performance may vary even when using the same programming language and driver (as in Visual Basic). Another issue is the relative importance of published benchmarks and other tests that model your own application. Two VB programs are useful references for comparing these techniques. The VBDEMO program in the ODBC SDK uses the technique of making ODBC function calls, and VB's VISDATA sample application uses the Access engine, Object Layer, and data controls. My first measurements used VISDATA, VBDEMO, and other applications to perform the same query used with a custom C application that runs on desktops at single-user sites or servers in work groups. Next, I performed a query using the same tools against SQL Server's Pubs database, because that example database is available to many readers. My goals were to compare performance using a variety of tools and programming techniques, and to evaluate performance improvements with newer versions of drivers. I timed the queries by hand, except VISDATA's tests, which I ran with the performance measurements enabled. Table 2 contains these informal measurements.

If one looks at the timings while using different applications, or the response times from using various programming techniques, it becomes obvious that understanding the lay of the land may affect the success of ODBC projects. My rationale for presenting these comparisons is to simply demonstrate that there are many ODBC programming solutions, and you must evaluate those techniques in the context of your specific application. An application doing primarily single selects that require rapid response times is probably better served by avoiding data-aware controls. On the other hand, if the application requires rapid development of a data-entry program, then it is difficult to beat the ease of development with data controls. Writing to the API might be a preferred solution for applications doing simple queries, but the Access engine might be your choice for complex queries unless you are prepared to handle details such as caching and optimizing multitable queries across heterogeneous DBMSs. The message to readers is that ODBC is not unlike other software solutions that require analysis to match the tool to the task at hand.

Q+E Database Library 2.0

Q+E Software Inc. sells its Q+E Database Library (QELIB) as a multiplatform product that supports ODBC and IDAPI while maintaining backward compatibility. The latest release of this product includes ODBC drivers and many new features, such as parameterized query functions, a data dictionary, a Query Builder, statement parsing, and functions that correspond to ODBC's facility to interrogate the back end about its capabilities.

What's Next

The readers that responded to my informal survey about ODBC and QELIB were Windows developers, but the participants in a similar future survey are likely to include Macintosh and OS/2 developers. To date, ODBC has been an all-SQL, 16-bit proposition, but the mix is likely to change to include developers using the navigational API and the 32-bit implementation introduced with ODBC 2.0. Not all ODBC 1.0 drivers implement scrollable cursors, so ODBC 2.0 includes a cursor library with bookmarks and additional scroll options.

Microsoft must also address the requirement for thunking software to do conversions between 16- and 32-bit addresses. A universal thunking manager can convert in either direction and support a mix of 16- and 32-bit ODBC components. One of the survey participants (Casey Kiernan) used ODBC to build a repository for Microsoft MIS, so one might expect that future repository products will support ODBC integration. The architecture may change as OLE objects and Cairo (Microsoft's object-oriented operating system) become more prominent, but any changes are likely to remain consistent with the Windows Open Services Architecture (WOSA) model. If one looks at printing and APIs such as ODBC, TAPI (telephony), and MAPI (messaging), it becomes clear that Microsoft's goal is to simplify programming for Windows and Windows NT application developers.

When asked to define the present and future role of ODBC and WOSA, Jonathan Lazarus, Microsoft's vice president of Systems Strategy, states that, "WOSA provides core services on the Windows platform that would otherwise need to be developed by individual ISV's and corporate developers (two of Microsoft's most important partners). By providing single interfaces to data (ODBC), mail (MAPI), interapplication communication (OLE), and other services on all Windows platforms, we provide a flexible architecture to customers who have a diverse set of systems they need to tie together. ODBC as a component of WOSA is part of our long-term strategy for Windows."


Ken North is a consultant with experience in mainframe, mini, desktop, and client/server systems. This article draws upon source code from his book, Windows Multi-DBMS Programming (Wiley & Sons, 1994). You can contact him via CompuServe at 71301,1306.


* Borland International Inc., 100 Borland Way, Scotts Valley, CA 95066-3249; 800-331-0877, 408-431-1000, or fax 408-439-8088.
* Coromandel Industries Inc., 70-15 Austin St., 3rd Fl., Forest Hills, NY 11375; 800-535-3267, 718-793-7963, or fax 718-793-9710. * Crystal Services, 1050 W. Pender St., Ste. 2200, Vancouver, B.C., Canada V6E 3S7; 800-877-2340, 604-681-3435, or fax 604-681-2934.
* Gupta Corp., 1060 Marsh Rd., Menlo Park, CA 94025; 800-876-3267; 415-321-9500, or fax 415-321-5471.
* KnowledgeWare Inc., 3340 Peachtree Rd., N.E., Ste. 1100, Atlanta, GA 30326-1050; 800-444-8575, 404-231-8575, or fax 404-364-0883.
* Microrim Inc., 15395 Southeast 30th Pl., Bellevue, WA 98007; 800-628-6990, 206-649-9500, or fax 206-649-9350.
* Microsoft Corp., One Microsoft Way, Redmond, WA 98052-6399; 800-677-7377, 206-882-8080, or fax 206-883-8101.
* NCR Corp., 1700 S. Patterson Blvd., Dayton, OH 45479; 800-225-5627, 513-445-5000, or fax 513-445-4184.
* Oracle Corp., Desktop Products Division, 500 Oracle Pkwy., Redwood Shores, CA 94065; 800-672-2531, 415-506-7000, or fax 415-506-7200.
* PageAhead Software Corp., 2125 Western Ave., Ste. 301, Seattle, WA 98121; 800-967-9671, 206-441-0340, or fax 206-441-9876. * Powersoft Corp., 70 Blanchard Rd., Burlington, MA 01803; 800-273-2841, 617-229-2200, or fax 617-273-2540.
* Quadbase Systems Inc., 790 Lucerne Dr., Ste. 51, Sunnyvale, CA 94086; 408-738-6989 or fax 408-738-6980.
* Q+E Software Inc., 5540 Centerview Dr., Ste. 324, Raleigh, NC 27606; 800-876-3101, 919-859-2220, or fax 919-859-9334.
* Watcom International Corp., 415 Phillip St., Waterloo, Ontario, Canada N2L 3X2; 800-265-4555, 519-886-3700, or fax 519-747-4971.




Figure 1. ODBC without proprietary API translation



Figure2. ODBC mapping to proprietary API


TABLE 1. ODBC functions

LevelNavPurpose
Environment/
Connection
SQLAllocConnect0NAllocate connection handle
SQLAllocEnv0NAllocate environment handle
SQLConnect0Connect to data source
SQLFreeConnect0NFree connection handle
SQLFreeEnv0NFree environment handle
SQLDisconnect0NDisconnect from data source
SQLDriverConnect1NExtended connect options, driver prompt
SQLBrowseConnect2Iterate through available connections
SQLDataSources2NEnumerate data sources
Statement
SQLAllocStmt0NAllocate statement handle
SQLFreeStmt0NFree statement handle
SQLPrepare0Prepare SQL request for execution
SQLSetParam0Specify parameter marker storage, length, and type
SQLExecute0Execute prepared statement
SQLExecDirect0Execute a preparable statement
SQLSetCursorName0Associate cursor name with statement handle
SQLGetCursorName0Return cursor name for a statement
SQLOpenTable*NOpen table for navigation
SQLParamData1NProvide parameter data at execution time
SQLPutData1NSend parameter's data at execution time
SQLNativeSql2Return SQL string after driver translation
SQLNumParams2Return the count of parameters in a statement
SQLDescribeParam2Describe parameter marker of prepared statement
Results
SQLNumResultCols0NReturn the number of columns in a result set
SQLColAttributes0NReturn column descriptors for result set
SQLDescribeCol0Describe column characteristics
SQLRowCount0Number of rows in UPDATE, DELETE, INSERT
SQLBindCol0NIdentify columns to be fetched
SQLBindKey*NSpecify storage, type, length, and scale for a key
SQLFetch0Acquire data for bound columns
SQLColumns1NReturn columns in tables
SQLGetData1NGet data
SQLExtendedFetch2NExtend fetch with block and scrollable cursors
SQLSetPos2NSet cursor position in rowset
SQLMoreResults2Check for more data available from query
Features and
Information
SQLGetFuctions1NEnumerate functions supported by driver
SQLGetInfo1NDescribe data-souce capabilities
SQLDrivers2NEnumerate driver attributes
Metadata
SQLGetTypeInfo1NEnumerate available data types
SQLTables1NReturn tables in catalog
SQLSpecialColumns1Info about unique row ID and updated columns
SQLStatistics1NRetrieve stats about table and indexes
SQLPrimaryKeys2Identify primary-key column names for a table
SQLForeignKeys2Foreign-key columns for table or tables
SQLTablePrivileges2List tables and associated privileges
SQLColumnPrivileges2List columns and associated privileges
SQLProcedures2Return stored-procedure list
SQLProcedureColumns2Return columns of procedure
Options
SQLSetConnectOption1NSet connection options
SQLGetConnectOption1NGet connection options
SQLSetStmtOption1NSet statement options
SQLGetStmtOption1NGet statement options
SQLParamOptions2Specify multiple values for parameters
SQLSetScrollOptions2Set options that control cursor behavior
Transaction and
Query Control
SQLTransact0Commit or rollback transaction
SQLCancel0Cancel current asynchronous function
Error Processing
SQLError0NRetrun error and state information
Source: Windows Multi-DBMS Programming (Wiley & Sons, Inc.).
*Not supported in version 1.0 drivers.
--ODBC functions and their API conformance levels (0, 1, or 2) in column two. Navigational drivers, new for ODBC 2.0, must support functions marked with an N in column three.



TABLE 2. ODBC 1.0 informal performance measurements (in seconds)

A. Driver Improvement
Upgraded drivers show improved performance.

1. Open table, populate grid



2. Single table SELECT with ORDER BY
(6000-row result set)

VIS = VB's VISDATA application (Access Engine)
DEM = VBDEMO of ODBC SDK (direct API calls)
INTG = Integra VDM
Q+E 1.0 = ODBC Pack 1.0 dBASE driver
Q+E 1.1 = ODBC Pack 1.1 dBASE driver


B. Performance with SQL passthrough (VISDATA)
Performance of VB dynasets (no data control) and snapshots (grid) with and without SQL passthrough to the dBASE driver and SQL Server: SQL passthrough has an advantage.
Single table SELECT w/ ORDER BY
Q+E 1.1 dBASE (6000 rows)
without SQL passthrough
with SQL passthrough

Single table SELECT w/ ORDER BY
Microsoft SQL Server (23 rows)
without SQL passthrough
with SQL passthrough


C. Visual Basic Techniques: data control, dynasets, snapshots, and direct ODBC API
Four programming techniques using the same single-table query. Performance varies with the technique.

D. Access engine caching
The effect of the Access engine's caching is seen in the execution time of a series of snapshots:
Seconds per snapshot

E. Typical application query times while accessing SQL Server and dBASE files
SELECT w/ dBASE
6000 rows, ORDER BY
ODBC Pack 1.1

SELECT w/ SQL Server
23 rows, ORDER BY
Microsoft driver

ACC = Access 1.1 w/o SQL passthrough
DEM = VBDEMO of ODBC SDK (direct API calls)
INTG = Integra VDM
OVW = ObjectView 2.1
VIS = VB's VISDATA application (Access engine) snapshots w/o SQL passthrough
VSP = VB's VISDATA application Snapshots w/SQL passthrough
XL = Excel 5.0 (MS Query)



TABLE 2
--Except where noted, the response times listed represent an average calculated after performing the same query five times.
Subscribe to DBMS and Internet Systems -- It's free for qualified readers in the United States
Table of Contents | Article Index | Search | Site Index | Home

DBMS and Internet Systems (http://www.dbmsmag.com)
Copyright © 1994 Miller Freeman, Inc. ALL RIGHTS RESERVED
Redistribution without permission is prohibited.
Please send questions or comments to dbms@mfi.com
Updated Friday, January 24, 1997.