Chelle
Chelle

Reputation: 177

DCount then OpenForm query in Access 2007 too slow

I have a number of buttons on a form which provide additional information to the user, each using DCount to see if there is any information to display and if so, opening a popup form to display it. All had been working well but now for one particular button, it is taking anything between 30 seconds and a minute to open the popup form, which is obviously unacceptable. Can't understand why it worked fine originally but has now gone so slow. All the other buttons still open their form in under a second. VBA is:

Private Sub btnNotes_Click()
  'open the popup notes for the current record, if there are associated records
  If DCount("ID","qlkpIDForNotes") = 0 Then
    MsgBox "There are no notes for this patient", vbOKOnly, "No information"
  Else
    DoCmd.OpenForm "fsubNotes",,,"ID = " & Me.displayID
  End If
End Sub

The table being queried has approx 40,000 rows, where the largest table checked for the other buttons has about 12,000. Have tried doing the DCount directly on the table rather than through a query, but doesn't make any difference. Also tried taking out a section of the data from the original table, copying about 1100 rows into a new table and testing on that. It still took 12 seconds to open. Any ideas, anyone?

Upvotes: 1

Views: 1203

Answers (1)

Renaud Bompuis
Renaud Bompuis

Reputation: 16786

Using DCount() just to find out if there are any row in the table or query can be rather inefficient since DCount() will have to run the whole query and go through all records to return the total count just so you can compare that to 0.

Depending on the complexity of that query, and the joins in it, and whether the joins use fields that have indexes or not, the cost of having to run that query can be exponentially proportional to the number of records in the underlying tables.

To solve your issue try this:

  1. make sure there is an index on the underlying table's ID field in the qlkpIDForNotes query, and that all fields used in the JOIN or WHERE clauses also have indexes.

  2. check if you can use the main underlying table or use a simplified query just to test if there are records that may be returned by qlkpIDForNotes, in short, you may not need to run that query in full just to find out if it would have some records.

  3. use a separate function such as HasAny() below instead of DCount() when you only need to find out if a query returns any results:

'-------------------------------------------------------------------------'
' Returns whether the given query returned any result at all.             '
' Returns true if at least one record was returned.                       '
' To call:                                                                '
'   InUse = HasAny("SELECT TOP 1 ID FROM Product WHERE PartID=" & partID) '
'-------------------------------------------------------------------------'
Public Function HasAny(ByVal selectquery As String) As Boolean
    Dim db As DAO.database
    Dim rs As DAO.RecordSet
    Set db = CurrentDb
    Set rs = db.OpenRecordset(selectquery, dbOpenForwardOnly)
    HasAny = (rs.RecordCount > 0)
    rs.Close
    Set rs = Nothing
    Set db = Nothing
End Function

With this, you can simply rewrite your code as :

Private Sub btnNotes_Click()
  'open the popup notes for the current record, if there are associated records '
  If Not HasAny("qlkpIDForNotes") Then
    MsgBox "There are no notes for this patient", vbOKOnly, "No information"
  Else
    DoCmd.OpenForm "fsubNotes",,,"ID = " & Me.displayID
  End If
End Sub

Upvotes: 2

Related Questions