Search code examples
databasevbams-accessms-access-2016

Speeding up an Access Database


I have an Access database to report on event statistics gathered from a mainframe system. The mainframe scheduler (ZEKE) doesn't have robust reporting features, so I export daily event data to report on.

A master listing from a separate source (a static list that will not change on a regular basis) lists the individual applications, including the application code (which is the naming standard for production runs) and the name of the programmer, coordinator, manager, business unit, etc. for that application.

The user can search by any field, application code, programmer, coordinator, etc.
Choose the production center to search in (there are 5) or default to all, and choose all dates, a single date, or a date range.
The query takes the search parameters and starting with either the application code, or the person, searches the table for applications and copies records to a temp table for reporting.

For example, to see how many failures the application coordinator John Doe had for the past week for all of the applications he is responsible for, the query would move all application records listing John Doe as the coordinator to the temp table.
From there, it moves through the temp table for each application and searches the event data for events under that application code which meet the criteria entered for date, production center and event type (success, failure or both).
This is moved to a temp table for the final report.

The table for event data is currently 2.5 million lines (this is 15 days worth of data) and is growing daily.
I put the back end onto a newly created NAS drive on our network.
A report that took two minutes when the back end and front end were on the same machine now takes 29 minutes.

Any suggestions to streamline the queries over a network?

Code which is run from the report criteria selection form and runs the report.

'this macro will generate a report based on multiple input criteria.
'this report allows the user to slect:
'       date range, single date or all dates
'       type of events: Abends, Successes or both
'       centers to pull data from: OCC,QCC,BCC,ITS,DAIN, or ALL centers
'       The type of data to report on: App code, App Coordinator, Custodian, L3, L4 or L5
'Once the user has selected all of the required data and fields, the report will be generated
'based on the selection criteria.

'we begin by defining the active database as the currently open database
Dim db As DAO.Database
    Set db = DBEngine(0)(0)
    
    
On Error GoTo ErrorHandler

'Now we designate the variables which will be used in this macro

   Dim strSQ1 As String
   Dim strSQ2 As String
   Dim strSQ3 As String
   Dim strSQ4 As String
   Dim appl As String
   Dim evstatus As String
   Dim appletype As String
   Dim fullapp As String
   Dim length As Long
   Dim iipmname As String
   Dim iipmcoor As String
   Dim fullappnm As String
   Dim fullappcoor As String
   Dim kinddate As String
   Dim coor As String
Dim cust  As String
Dim appL3  As String
Dim appL4  As String
Dim appL5 As String
   
   Dim ctrOCC As String
   Dim ctrMTL As String
   Dim ctrBCC As String
   Dim ctrITS As String
   Dim ctrDAIN As String
   
   

'We will start by setting some default values

'We will ste the default values for center selection.
'We start by searching for terms we know are not there, then change them to
'valid search terms if the center is selected.

ctrOCC = "notOCC"
ctrMTL = "notMTL"
ctrBCC = "notBCC"
ctrITS = "notITS"
ctrDAIN = "notUSWM"
fullapp = "*"

'First we determine which event types the user wants to look for

state = Me![opt-status].Value

If state = 1 Then
evstatus = " [ev-status] = 'AEOJ'"
ElseIf state = 2 Then
evstatus = " [ev-status] = 'EOJ'"
ElseIf state = 3 Then
evstatus = " ([ev-status] = 'EOJ' OR [ev-status] = 'AEOJ')"
End If

'MsgBox "Event status pulled is:.. " & evstatus & "."

' Next up we will configure the date parameters based on the user input

If [grp-datesel] = 1 Then
Sdte = "1"
Edte = "9999999"
kinddate = "[ev-date] >= " & Sdte & " AND [ev-date] <= " & Edte & " "
End If

If [grp-datesel] = 2 Then
'error handling
If IsNull(Me.[sel-onedate]) Then
MsgBox "You have not entered a date to search....please try again."
Me.[sel-onedate] = Null
Me.[sel-onedate].SetFocus
Exit Sub
End If
'end of error handling

Dim currdte As Date
currdte = Me![sel-onedate].Value
currjul = Format(currdte, "yyyyy")
daycurr = CDbl(currjul)

Sdte = daycurr
Edte = daycurr
kinddate = "[ev-date] >= " & Sdte & " AND [ev-date] <= " & Edte & " "
End If

If [grp-datesel] = 3 Then

'error handling
If IsNull(Me.[sel-Sdate]) Or IsNull(Me.[sel-Edate]) Then
MsgBox "You Must enter a start and end date for the search....please try again."
Me.[sel-Sdate] = Null
Me.[sel-Edate] = Null
Me.[sel-Sdate].SetFocus
Exit Sub
End If
'end of error handling

Dim startdte As Date
Dim enddte As Date
startdte = Me.[sel-Sdate].Value
enddte = Me.[sel-Edate].Value

startjul = Format(startdte, "yyyyy")
endjul = Format(enddte, "yyyyy")
Sday = CDbl(startjul)
Eday = CDbl(endjul)

Sdte = Sday
Edte = Eday

'MsgBox "start date is " & Sdte & " and end date is " & Edte & "."

'check that dates are in proper chronological order
If Sdte > Edte Then
MsgBox "The start Date you entered is after the end date....please try again."
Me.[sel-Sdate] = Null
Me.[sel-Edate] = Null
Me.[sel-Sdate].SetFocus
Exit Sub
End If
'keep going if it's all good

kinddate = "[ev-date] >= " & Sdte & " AND [ev-date] <= " & Edte & " "
End If

MsgBox "Date used is:.. " & kinddate & "."

'Now lets look at center selection

If [chk-allctr].Value = True Then
ctrOCC = "OCC"
ctrMTL = "MTL"
ctrBCC = "BCC"
ctrITS = "ITS"
ctrDAIN = "USWM"

End If

If [chk-OCC].Value = True Then
ctrOCC = "OCC"
End If
If [chk-MTL].Value = True Then
ctrMTL = "MTL"
End If
If [chk-BCC].Value = True Then
ctrBCC = "BCC"
End If
If [chk-RTF].Value = True Then
ctrITS = "ITS"
End If
If [chk-DAIN].Value = True Then
ctrDAIN = "DAIN"
End If

'Error handling if no center is selected
If [chk-OCC].Value = Flase Then
If [chk-MTL].Value = Flase Then
If [chk-BCC].Value = Flase Then
If [chk-RTF].Value = Flase Then
If [chk-DAIN].Value = Flase Then
MsgBox "You have not selected a center to search search....please try again."
Me.[chk-allctr].SetFocus
Exit Sub
End If
End If
End If
End If
End If
'end of error handling

'MsgBox "centers used are: Chr(10) " & ctrOCC & " Chr(10) " & ctrBCC & " Chr(10) " & ctrMTL & " Chr(10) " & ctrITS & " Chr(10) " & ctrDAIN & " For this run"

'All good so far, now we will parse the application code if an
'application code report is selected

appl = "*"

If [opt-criteria].Value = 1 Then
'error handling
If IsNull(Me.[sel-appcode]) Then
MsgBox "You have not entered an application code to search....please try again."
Me.[sel-appcode] = Null
Me.[sel-appcode].SetFocus
Exit Sub
End If
'end of error handling
End If
If [opt-criteria].Value = 1 Then

appl = Me![sel-appcode].Value
End If

'trust = "no"
'If Mid(appl, 3, 2) = "RT" Then trust = "yes"

'length = Len(appl)
'If length = 2 Then appltype = "short"
'If length = 3 Then appltype = "long"

'If appltype = "short" Then fullapp = "" & appl & "00"
'If appltype = "long" Then fullapp = "" & appl & "0"

'If trust = "yes" Then fullapp = appl

'End If

fullapp = appl

'MsgBox "App to use is: " & appl & " fullapp code is " & fullapp & "."


'Now we set values if names are used

coor = "*"
cust = "*"
appL3 = "*"
appL4 = "*"
appL5 = "*"

If [opt-criteria].Value = 2 Then
'error handling
If IsNull(Me.[sel-coor]) Then
MsgBox "You have not entered a Coordinator to search....please try again."
Me.[sel-coor] = Null
Me.[sel-coor].SetFocus
Exit Sub
End If
'end of error handling

coor = Me![sel-coor].Value
'MsgBox "Coordinator report selected for: " & coor & "."
End If

If [opt-criteria].Value = 3 Then
'error handling
If IsNull(Me.[sel-custodian]) Then
MsgBox "You have not entered a Custodian to search....please try again."
Me.[sel-custodian] = Null
Me.[sel-custodian].SetFocus
Exit Sub
End If
'end of error handling
cust = Me![sel-custodian].Value
'MsgBox "Custodian report selected for: " & cust & "."
End If

If [opt-criteria].Value = 4 Then
'error handling
If IsNull(Me.[sel-L3]) Then
MsgBox "You have not entered an L3 to search....please try again."
Me.[sel-L3] = Null
Me.[sel-L3].SetFocus
Exit Sub
End If
'end of error handling

appL3 = Me![sel-L3].Value
'MsgBox "L3 report selected for: " & appL3 & "."
End If

If [opt-criteria].Value = 5 Then
'error handling
If IsNull(Me.[sel-L4]) Then
MsgBox "You have not entered an L4 to search....please try again."
Me.[sel-L4] = Null
Me.[sel-L4].SetFocus
Exit Sub
End If
'end of error handling

appL4 = Me![sel-L4].Value
'MsgBox "L4 report selected for: " & appL4 & "."
End If

If [opt-criteria].Value = 6 Then
'error handling
If IsNull(Me.[sel-L5]) Then
MsgBox "You have not entered an L5 to search....please try again."
Me.[sel-L5] = Null
Me.[sel-L5].SetFocus
Exit Sub
End If
'end of error handling

appL5 = Me![sel-L5].Value
'MsgBox "L5 report selected for: " & appL5 & "."
End If

'Most of these reports take a while to build with this macro, so to make sure the user
'knows that the macro is still working, we didsplay a splash screen. It's cute and has
'hamsters, cause everyone loves hamsters.

DoCmd.OpenForm "PlsWaitFrm", acWindowNormal
[Forms]![PlsWaitFrm].Repaint



'All of out criteria values are now selected.  We can move on to pulling data from the tables.
'We start by populating the IIPM table with the information that we require for applications.

strSQ1 = "DELETE * from [tbl-RPT-IIPM] "
db.Execute strSQ1

strSQ2 = "INSERT INTO [tbl-RPT-IIPM] " & _
         "SELECT * FROM [tbl-IIPM] " & _
         "WHERE (([AppCode] like '" & fullapp & "')" & _
         "AND ([AppCoordinator] like '" & coor & "') " & _
         "AND ([AppCustodian] like '" & cust & "') " & _
         "AND ([L3] like '" & appL3 & "') " & _
         "AND ([L4] like '" & appL4 & "') " & _
         "AND ([L5] like '" & appL5 & "')) "
db.Execute strSQ2

'MsgBox "made it past the populate of rpt-iipm"


'Now we have populated the IIPM report table, it's time to populate the event report table.
'We will loop through all fields in the IIPM report table and pull information for each
'application code.

strSQ3 = "DELETE * from [tbl-EVENTREPORT] "
db.Execute strSQ3

Dim rs As DAO.Recordset

Set db = CurrentDb
Set rs = db.OpenRecordset("tbl-RPT-IIPM") 'this opens the IIPM report table just populated

'populate the table
rs.MoveLast
rs.MoveFirst

Do While Not rs.EOF
'we will execute these action against the selected record.

'first step - parse the application code to display the full application code

appl = rs![AppCode].Value
length = Len(appl)
If length = 1 Then appl = "" & appl & "00"

rptdelin = Mid(appl, 3, 1)

rptcode = Mid(appl, 1, 3)
If rptdelin = "0" Then rptcode = Mid(appl, 1, 2)
If rptdelin = "R" Then rptcode = "RT" & Mid(appl, 1, 2) & ""

'MsgBox "searching for: " & rptcode & "."

applist = applist & "," & appl

strSQ4 = "INSERT INTO [tbl-EVENTREPORT] " & _
         "SELECT * FROM [tbl-EVENT DATA] " & _
         "WHERE (([ev-jobname] LIKE '?" & rptcode & "*') " & _
         "AND (([ev-ctr] = '" & ctrOCC & "')" & _
         "OR ([ev-ctr] = '" & ctrMTL & "')" & _
         "OR ([ev-ctr] = '" & ctrBCC & "')" & _
         "OR ([ev-ctr] = '" & ctrITS & "')" & _
         "OR ([ev-ctr] = '" & ctrDAIN & "'))" & _
         "AND (" & kinddate & ") " & _
         "AND " & evstatus & ")"
         
db.Execute strSQ4

 'now we're done with this report, we move on to the next

   rs.MoveNext             'press Ctrl+G to see debuG window beneath
Loop

'END OF LOOPING CODE

'MsgBox "made it past the looping"

'Now we have completed populating the table that the report will be based on.
'Next step is to gather master statistics to produce abend and success percentages.

totfail = DCount("[ev-status]", "tbl-EVENTREPORT", "[ev-status] = 'AEOJ'")
totsucc = DCount("[ev-status]", "tbl-EVENTREPORT", "[ev-status] = 'EOJ'")

Dim allabend As Long
Dim allsucc As Long

allabend = DCount("[ev-status]", "[tbl-EVENT DATA]", "[ev-status] = 'AEOJ' AND ([ev-date] >= " & Sdte & " AND [ev-date] <= " & Edte & ")")
allsucc = DCount("[ev-status]", "[tbl-EVENT DATA]", "[ev-status] = 'EOJ' AND ([ev-date] >= " & Sdte & " AND [ev-date] <= " & Edte & ")")

Dim pctabend As Long
Dim pctsucc As Long

pctabend = (totfail / allabend) * 100
pctsucc = (totsucc / allsucc) * 100

'Now we will generate the reports for display based on what type of report was selected
'by the user in the initial form.

'Before we open the report, we will close the splash screen
DoCmd.Close acForm, "PlsWaitFrm", acSaveNo

'Now we open the report

If [opt-criteria].Value = 1 Then

fullappnm = DLookup("AppName", "tbl-RPT-IIPM", "AppCode = '" & fullapp & "' ")
fullappcoor = DLookup("AppCoordinator", "tbl-RPT-IIPM", "AppCode = '" & fullapp & "' ")



DoCmd.OpenReport "rpt-APPLREPORT", acViewReport

[Reports]![rpt-APPLREPORT]![rpt-appcode].Value = fullapp
[Reports]![rpt-APPLREPORT]![rpt-appname].Value = fullappnm
[Reports]![rpt-APPLREPORT]![rpt-appcoor].Value = fullappcoor
[Reports]![rpt-APPLREPORT]![rpt-abendtot].Value = totfail
[Reports]![rpt-APPLREPORT]![rpt-succtot].Value = totsucc
[Reports]![rpt-APPLREPORT]![rpt-abdpct].Value = pctabend
[Reports]![rpt-APPLREPORT]![rpt-succpct].Value = pctsucc

End If

If [opt-criteria].Value = 2 Then

DoCmd.OpenReport "rpt-COORREPORT", acViewReport

[Reports]![rpt-COORREPORT]![rpt-appcode].Value = applist
[Reports]![rpt-COORREPORT]![rpt-appcoor].Value = coor
[Reports]![rpt-COORREPORT]![rpt-abendtot].Value = totfail
[Reports]![rpt-COORREPORT]![rpt-succtot].Value = totsucc
[Reports]![rpt-COORREPORT]![rpt-abdpct].Value = pctabend
[Reports]![rpt-COORREPORT]![rpt-succpct].Value = pctsucc

End If

If [opt-criteria].Value = 3 Then

DoCmd.OpenReport "rpt-CUSTREPORT", acViewReport

[Reports]![rpt-CUSTREPORT]![rpt-appcode].Value = applist
[Reports]![rpt-CUSTREPORT]![rpt-appcoor].Value = cust
[Reports]![rpt-CUSTREPORT]![rpt-abendtot].Value = totfail
[Reports]![rpt-CUSTREPORT]![rpt-succtot].Value = totsucc
[Reports]![rpt-CUSTREPORT]![rpt-abdpct].Value = pctabend
[Reports]![rpt-CUSTREPORT]![rpt-succpct].Value = pctsucc
End If

If [opt-criteria].Value = 4 Then

DoCmd.OpenReport "rpt-L3REPORT", acViewReport

[Reports]![rpt-L3REPORT]![rpt-appcode].Value = applist
[Reports]![rpt-L3REPORT]![rpt-appcoor].Value = appL3
[Reports]![rpt-L3REPORT]![rpt-abendtot].Value = totfail
[Reports]![rpt-L3REPORT]![rpt-succtot].Value = totsucc
[Reports]![rpt-L3REPORT]![rpt-abdpct].Value = pctabend
[Reports]![rpt-L3REPORT]![rpt-succpct].Value = pctsucc
End If


If [opt-criteria].Value = 5 Then

DoCmd.OpenReport "rpt-L4REPORT", acViewReport

[Reports]![rpt-L4REPORT]![rpt-appcode].Value = applist
[Reports]![rpt-L4REPORT]![rpt-appcoor].Value = appL4
[Reports]![rpt-L4REPORT]![rpt-abendtot].Value = totfail
[Reports]![rpt-L4REPORT]![rpt-succtot].Value = totsucc
[Reports]![rpt-L4REPORT]![rpt-abdpct].Value = pctabend
[Reports]![rpt-L4REPORT]![rpt-succpct].Value = pctsucc
End If

If [opt-criteria].Value = 6 Then

DoCmd.OpenReport "rpt-L5REPORT", acViewReport

[Reports]![rpt-L5REPORT]![rpt-appcode].Value = applist
[Reports]![rpt-L5REPORT]![rpt-appcoor].Value = appL5
[Reports]![rpt-L5REPORT]![rpt-abendtot].Value = totfail
[Reports]![rpt-L5REPORT]![rpt-succtot].Value = totsucc
[Reports]![rpt-L5REPORT]![rpt-abdpct].Value = pctabend
[Reports]![rpt-L5REPORT]![rpt-succpct].Value = pctsucc
End If



ErrorHandler:
If Err.Number = 7874 Then
Resume Next 'Tried to delete a non-existing table, resume
End If
End Sub
'''

Solution

  • OK, with some more information, some more answers that may (or may not!!) help. Again, you will need to run timing tests to see which works best for you.

    Try adding a "Yes/No" field to the table [tbl-EVENT DATA]. You can then use an UPDATE statement to indicate which fields to include in the report, rather than using the slow INSERT query.

    Another thing to try would be to replace the INSERT statement with several, each using a different value for [ev-ctr]. Or else rather than using OR try using IN:

    strSQ4 = "INSERT INTO [tbl-EVENTREPORT] " & _
             "SELECT * FROM [tbl-EVENT DATA] " & _
             "WHERE [ev-jobname] LIKE '?" & rptcode & "*' " & _
             "AND [ev-ctr] IN('" & ctrOCC & "','" & ctrMTL & "','" & ctrBCC & "','" & ctrITS & "','" & ctrDAIN & "')" & _
             "AND " & kinddate &  _
             "AND " & evstatus 
    

    Also, I notice that kinddate is set to effectively include all dates in one instance, and that evstatus is set to include both "EOJ" and "AEOJ" in one instance. Rather than including these fields as criteria in these cases, you may wish to not include them at all:

    If state = 1 Then
        evstatus = " AND [ev-status] = 'AEOJ'"
    ElseIf state = 2 Then
        evstatus = " AND [ev-status] = 'EOJ'"
    ElseIf state = 3 Then
        evstatus = " "
    End If
    

    And then you would rewrite " AND " & evstatus to & evstatus in the SQL statement.

    A final thing to look at is to actually run the INSERT directly in the backend, rather than operating on linked tables in the frontend, as Access will be dragging vast amounts of data across the network and then sending it back. As a basic guide, something like this:

    Sub sUpdateQuery()
        Dim objAccess As New Access.Application
        objAccess.OpenCurrentDatabase "J:\downloads\test.accdb"
        objAccess.DoCmd.RunSQL "UPDATE test2 SET Field1=UCASE(Field1);"
        objAccess.CloseCurrentDatabase
        Set objAccess = Nothing
    End Sub
    

    Regards,