

Understanding Cursors
When starting out with ASP development many struggle just getting ADO to work, let along worrying about how or
why it works. What results in code that is more expensive than is really required - in order to get the code working
developers always use the most expensive cursors, since they will support all operations, rather than using
the most appropriate cursor for the job. If you don't know much about setting the cursor type for an
ADO Recordset object you might want to read this first.
What is a cursor?
This is a difficult concept to explain - but I'll give it a go :-) A relational DBMS (like SQL Server) returns the results of your
query as a set based recordset. Basically the results are the subset of records from the table(s) that match your search
criteria.
However most people, and applications, don't operate on the results as a set. Instead they work on the results in a
sequential order. E.g. you edit the first record, update the database, move to the second record & edit it, update the
database etc, or perhaps you just wish to write the results into a HTML table - you write the 1st record, then start a new
row, write the 2nd record, start a new row etc.
In order to facilitate this movement one uses an ADO cursor. A cursor keeps track
of which record you are currently at in the recordset. Different types of cursors allow different types of actions. Some
cursors allow only movement forwards. Others allow movement forwards, backwards, and allow you to set
"bookmarks" so you can quickly jump to a pre-set position in the recordset.
Which cursor type should I use?
As mentioned above, each cursor type allows different types of operations. One allows forward movement only
(adOpenForwardOnly), whereas others allow movement backwards and forwards. The question that is asked is:
"Why should I use a forwardonly cursor when I can get additional benefits from using
the more sophisticated cursors?". The answer to the question is "performance". The
more sophisticated the cursor the more work Jet, and ADO have to do in order to keep track of the records in
the Recordset. For example, with a ForwardOnly cursor, once you have moved past a record, ADO & Jet can
forget all about it (since you can't move backwards). However with an adOpenStatic cursor, ADO & Jet have to
keep track of all the records since you can always move backwards.
My personal experience with various tests (and also my reading) is that an adOpenStatic cursor is about twice
as expensive as an adOpenForwardOnly cursor. By this, I mean that performing operations like writing out the records
in the recordset take twice as long using an adOpenStatic cursor compared to an adOpenForwardOnly cursor.
What types of cursors are there?
There are 4 types of cursors supported by ADO. We'll look at them all briefly now:
adOpenForwardOnly: This is the lightest (cheapest) cursor, and the default
when opening a recordset. It allows only forwards movement. Only the most minimal information about the
recordset is calculated by Jet (eg you can't even get a .recordCount of the total number of records in the
recordset). If you try to move backwards using this cursor, the recordset is closed, and the query re-executed.
Avoid doing this!
adOpenStatic: A static snap-shot of the records that match your search
criteria are put into the recordset. You can scroll forwards and backwards, and set bookmarks. Changes made
to the database by other users however are not visible - all you can see are the records that matched your
search at the point in time when the query was executed
adOpenKeyset: A static snap-shot of the primary key values of the records that
match your search criteria are put into the recordset. As you scroll backwards and forwards, the primary key
value in the recordset is used to fetch the current data for that record from the database. This cursor thus allows
you to see updates to the data made by other users, but it doesn't let you see new records that have been added
by other users (because the primary key values for those records are not in your recordset).
adOpenDynamic: A dynamic snapshot of the database is maintained by OLEDB/ADO.
All changes by other users to the underlying database are visible. Obviously this is the most sophisticated cursor, and thus
is usually the most expensive. Because the data in the recordset is dynamic, attributes like AbsolutePosition and AbsolutePage
can not be set. The adOpenDynamic cursor is not supported by the Jet OLEDB Provider
(see below).
What cursors are supported by Jet?
This is a tricky question to answer. When you open the recordset you can request any of the 4 cursor types above. However,
depending on the locktype you request, and the command type that you specify, the Jet OLEDB Provider may change the
cursortype to something else behind your back! Jet never changes the locktype that you request however.
The table below shows the cursor type that you get, depending on the cursor and locktype you request:
|
ForwardOnly |
Static |
KeySet |
Dynamic |
adLockReadOnly |
ForwardOnly |
Static |
Keyset |
Static |
adLockOptimistic |
Keyset |
Keyset |
Keyset |
Keyset |
adLockPessimistic |
Keyset |
Keyset |
Keyset |
Keyset |
adLockBatchOptimistic |
Keyset |
Keyset |
Keyset |
Keyset |
There is one caveat to the above. If you set the CommandType to adCmdTableDirect you always get an adOpenKeyset cursor. The
above values told for CommandTypes adCmdText and adCmdTable. Also be aware that using client-side cursors results in an adOpenStatic
cursor no matter what cursor type you request. This behaviour is common to all OLEDB Providers, not just Jet. The default cursor location is
server-side, so you don't have to worry about this unless you explicitly set the cursor location to client-side.
If you would like to see the code that generates the above results table click here.
Back to FAQ Listing
|