Link to home
Start Free TrialLog in
Avatar of John Carroll
John CarrollFlag for Canada

asked on

Access 2010: UDF in calulated query field runs painfully slow over network

I have a UDF in a calculated query field that returns the names of one or more people connected to each record. It runs great in my laptop but when I run it over our network (front-end on my PC and back-end on server) the form can take up to 12 seconds to open. If I remove the calculated field from the query (troubleshooting) the form opens immediately. Any idea how I can speed this up or do this a different way?

I have attached a snapshot of the query. Here is the function:

Function GuestNames(lngRoomID As Long) As String
 
  Dim dbs As DAO.Database
  Dim rst As DAO.Recordset
  Dim strSQL As String
  Dim strGuestNames As String

  Set dbs = CurrentDb()

  strSQL = "SELECT tblCustomers.LastName " _
          & "FROM (tblCustomers INNER JOIN tblTourBookings " _
          & "ON tblCustomers.CustomerID = tblTourBookings.CustomerID) " _
          & "INNER JOIN tblCustomerRooms " _
          & "ON tblTourBookings.TourBookingID = tblCustomerRooms.TourBookingID " _
          & "WHERE tblCustomerRooms.RoomID = " & lngRoomID & " " _
          & "ORDER BY tblCustomers.LastName;"

  Set rst = dbs.OpenRecordset(strSQL, dbOpenDynaset)

  If Not rst.EOF Then
    rst.MoveFirst
    Do While Not rst.EOF
      strGuestNames = strGuestNames & rst!LastName
      rst.MoveNext
      If Not rst.EOF Then
        strGuestNames = strGuestNames & ", "
      End If
    Loop
    GuestNames = strGuestNames
  Else
    GuestNames = "Enter Name(s)"
  End If
 
  rst.Close
  Set rst = Nothing
  dbs.Close

End Function
SOLUTION
Avatar of DatabaseMX (Joe Anderson - Former Microsoft Access MVP)
DatabaseMX (Joe Anderson - Former Microsoft Access MVP)
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of John Carroll

ASKER

I will try your suggestions on the network tomorrow and report back. Thanks.
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
TempVar >>> TempVars() .... better choice than Globals ... but for now ... try with Globals.

And pretty sure the Loop can be simplified

However even with these simplifications, you may not see a big change. Over a network compared to a laptop is an entirely different paradigm :-(

mx
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Good point, Scott.  

I was wondering why you would want a list of all guests, past and present who were ever booked into a particular room.
Yes when I run from my laptop I have both the front and back-end on my laptop and when on the network I am running the front-end on my laptop and back-end on the server.

As you can see attached, once you select the tour and the hotel the subform displays a list of all of the rooms booked in that hotel as a datasheet as well as the last name(s) of those in each room. Double-clicking on a room record opens another form showing more detail about the booking as well as allowing you to add or delete those staying in the room and ability to edit any other details.

It would not make sense to move the last names of those staying in a room to another subform (but I understand why one would suggest this).

I hope to try the suggestions of speeding up the function shortly.
Rooms.jpg
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
By Global to you mean Public? I know you are trying to see if it helps the speed but isn't it dangerous to use Global/Public variables? I would think you would have to give them a unique name as a best practise.

BTW: The using the With statement (don't know why I didn't think of this) cut the time down from 12 sec to 9 sec so 25% improvement is not bad.

Using a temporary table in place of network calls would most certainly solve the speed issue but repeated creation and deleting of a table could cause the client to bloat. Have you experienced this?
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
When you use the UpdateTempTable code in that article, one of the arguments is "InCurrentDB".  If you set this argument to False, then the temp table will be created in an external database and linked into your application, so you will not see any bloating.  Additionally, it is safe to set the CompactOnClose property of the database to True, which will reduce any possible bloating.

Make sure that when your application closes, you use the DeleteObject method to remove that temp table from the application, and then delete the actual temporary database.
"Have you experienced this?"
Not for me. My database loader copies a FE 'master' down to local workstation, as well as all lookup tables ... and in some cases, active records from the BE into a local 'temp' (for lack of a better word). table. This happens a least 1x/day ... so front end bloating is a non issue.

"then the temp table will be created in an external database and linked into your application, "
But it seems that could result in some potential performance hit ... being linked and on the network ?
ASKER CERTIFIED SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Joe,

The subroutine in my article creates the temp table on the users PC, in the directory where the front end resides.  I've thought about that a lot lately, and am probably going to modify it so that it creates the table in the C:\Users\UserName\AppData\ folder.

Similar to your comment about downloading lookup tables from your network to the local PC.
I've requested that this question be closed as follows:

Accepted answer: 0 points for Frozone's comment #a40716222

for the following reason:

Since it was determined that the best speed increase I could expect with optimizing the current method, I decided to settle for looking at my data in another acceptable way in order to not have to use eliminate the function in question all together. This bring performance back to a workable level and probably a better solution in the long run.
"Since it was determined that the best speed increase I could expect with optimizing the current method, "
However, this determination was made via the input from the three experts participating in this question. So I'm not understanding why you are Accepting your own comment - whereas w/o the input from us, you could not have reached this conclusion.

mx
I agree so what's your point? Based on the input from those who responded I came to the conclusion that it was not going to be possible to do what I needed to do at an acceptable speed. So the only solution I could come up with was to simplify the query and make do with a little less information on this screen. Have I done something wrong?
I think Joe's point is that you could not have come to that conclusion without the help of the experts, so you should award points as appropriate to the expert comments which helped you reach your "solution".
I'm not sure how the points thing works but I have no problem with that. I just thought we were supposed to mark the final solution. So what do I use, the Accept Multiple solutions or is there another way to award points?
If it were me ... in this case as the OP, I would Accept that post as you did at the Accepted Answer, then divvy of Assists among the other participants - as appropriate.
so, if you are new here, the first step is to go to your explanation of what you decided to do.  Click the "Select Multiple Solutions" hyperlink.  Then go to the expert comments that helped you to come to your solution and divide those points among the various comments by typing in the specific point values for each solution.

Welcome to EE!
After evaluating feedback from those who responded it was apparent that it was not going to be possible to speed up the function (which populates a calculated field in the subform query) enough to make for form usable. So I decided to eliminate the use of the calculated field with function and just return on name per record which speeds things up considerably.