John Carroll
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.TourBookin gID = tblCustomerRooms.TourBooki ngID " _
& "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
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.TourBookin
& "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
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
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
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
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
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.
I was wondering why you would want a list of all guests, past and present who were ever booked into a particular room.
ASKER
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
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
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
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?
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
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
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.
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 ?
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
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
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.
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\
Similar to your comment about downloading lookup tables from your network to the local PC.
ASKER
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.
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
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
ASKER
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".
ASKER
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!
Welcome to EE!
ASKER
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.
ASKER