When you refer to an object or a collection more than once, you can improve performance by caching a reference to that object or collection. There are three ways to do this:
When you refer to an object or collection more than once in your code, you may want to create an object variable and assign a reference to the object to that object variable. Not only does this make your code faster for lengthy operations, it also makes it easier to read.
The following two examples both return the names of all tables in a database, all fields in each table, and the names and values of all properties on those fields. The first example, which stores references to objects in object variables, is considerably faster than the second. In these examples, strDbPath
is the path to a database:
' 1 - Faster, easier to read. Dim dbs As Database, tdf As TableDef Dim fld As Field, prp As Property Set dbs = OpenDatabase(strDbPath) For Each tdf In dbs.TableDefs Debug.Print tdf.Name For Each fld In tdf.Fields Debug.Print fld.Name For Each prp In fld.Properties On Error Resume Next Debug.Print prp.Name, prp.Value Next prp Next fld Next tdf dbs.Close Set dbs = Nothing ' 2 - Slower, more cumbersome. Dim intW As Integer, intX As Integer, intY As Integer OpenDatabase strDbPath For intW = 0 To DBEngine(0)(0).TableDefs.Count - 1 Debug.Print DBEngine(0)(0).TableDefs(intW).Name For intX = 0 To DBEngine(0)(0).TableDefs(intW).Fields.Count - 1 Debug.Print DBEngine(0)(0).TableDefs(intW).Fields(intX).Name For intY = 0 To _ DBEngine(0)(0).TableDefs(intW).Fields(intX).Properties.Count - 1 On Error Resume Next Debug.Print _ DBEngine(0)(0).TableDefs(intW).Fields(intX).Properties(intY).Name, _ DBEngine(0)(0).TableDefs(intW).Fields(intX).Properties(intY).Value Next Next Next
You can improve performance by using the For Each…Next and With…End With statements. Both of these cache a reference to an object, so that your code doesn’t have to repeatedly retrieve the reference in order to use the object.
The following example uses both of these statements to print all of the values in a recordset. In this example, strDbPath
is the path to a database, and strRstSource
is the source for a recordset:
Dim dbs As Database, tdf As TableDef Dim rst As Recordset, fld As Field Set dbs = OpenDatabase(strDbPath) Set rst = dbs.OpenRecordset(strRstSource) With rst Do Until .EOF For Each fld In rst.Fields Debug.Print fld.Name, fld.Value Next fld .MoveNext Loop Debug.Print End With rst.Close Set rst = Nothing dbs.Close Set dbs = Nothing
The following example uses a For loop rather than the For Each…Next statement, and it refers to the Recordset object variable explicitly each time it’s used rather than caching it with the With statement. The performance differences are not apparent for small recordsets, but become more significant with larger recordsets. When strDbPath
is the path to the NorthwindTables database and strRstSource
is the Orders table, the following example runs several seconds more slowly than the preceding one:
Dim dbs As Database, tdf As TableDef Dim rst As Recordset, fld As Field Dim intC As Integer Set dbs = OpenDatabase(strDbPath) Set rst = dbs.OpenRecordset(strRstSource) Do Until rst.EOF For intC = 0 To rst.Fields.Count - 1 Debug.Print rst.Fields(intC).Name, rst.Fields(intC).Value Next rst.MoveNext Loop Debug.Print rst.Close Set rst = Nothing dbs.Close Set dbs = Nothing
Another important consideration for performance is whether or not your object variables are strictly typed. When you strictly type an object variable, you declare the object variable according to the type of object that it will represent. In the following example, the object variables are not strictly typed according to the object type they are to represent. When a variable isn’t typed, Visual Basic automatically designates it as type Variant. This example is otherwise identical to the preceding example, but runs at nearly half the speed for the Orders table in the NorthwindTables database:
Dim dbs, tdf Dim rst, fld Dim intC Set dbs = OpenDatabase(strDbPath) Set rst = dbs.OpenRecordset(strRstSource) Do Until rst.EOF For intC = 0 To rst.Fields.Count - 1 Debug.Print rst.Fields(intC).Name, _ rst.Fields(intC).Value Next rst.MoveNext Loop Debug.Print rst.Close Set rst = Nothing dbs.Close Set dbs = Nothing