为什么VBA脚本速度变化很大

时间:2016-10-12 14:10:37

标签: vba performance access-vba ado recordset

这个问题可能无法解决,但我想我会试一试。

我有一个VBA脚本(在Access 2010中运行),它打开一些记录集(ADOX),处理它们,并将结果写入本地Access表。有时这个处理需要几分钟;有时可能需要一个多小时。正在处理的实际数据足够相似,因此特定数据不应成为时差的原因。

当我以中断模式运行代码时(只需按住F8),没有明显的挂断 - 脚本似乎运行正常。

为了增加我的困惑,有时(但不总是)如果脚本运行缓慢,我暂停然后恢复(不进行其他更改),它将在恢复后快速运行。这让我觉得它可能是一个记录缓存问题,因此我将每个记录集的记录缓存增加到略高于该特定记录集的最大记录数,但这似乎没有任何影响。

有谁知道什么可能导致这些类型的波动,更重要的是,我可以做些什么来缓解它们?我可以在必要时发布代码,但考虑到暂停/恢复方案中相同代码的不同行为,我不确定问题是否基于代码。

提前致谢!

编辑:添加以下代码。 Do ... Loop Until循环是速度变化趋于发生的地方。该数据库是在Amazon Web Services上托管的MySQL。

Public Sub ReportTrueAdherenceNew(dtStart As Date, blRebuildIndexes As Boolean)

Dim lngScheduleLoadOrderID As Long
Dim dtEnd As Date
Dim dtShiftStart As Date
Dim dtShiftEnd As Date
Dim lngLCV As Long
Dim strIEXUID As String
Dim strFive9ID As String
Dim strMUNumID As String
Dim lngManagerID As Long
Dim lngTimeOffset As Long
Dim dbs As DAO.Database
Dim cn As ADODB.Connection
Dim cnFive9 As ADODB.Connection
Dim qdf As DAO.QueryDef
Dim strSQLAgentList(1 To 1, 1 To 3) As String
Dim strSQLAgentData(1 To 3, 1 To 3) As String
Dim strSQLAgentStateData(1 To 2, 1 To 3) As String
Dim strSQLMaintenance(1 To 2, 1 To 3) As String
Dim strSQLRebuildIndex(1 To 2, 1 To 3) As String
Dim rsAgentSchedule As ADODB.Recordset
Dim rsAgentState As ADODB.Recordset
Dim rsAgentList As ADODB.Recordset
Dim rsAgentDates As ADODB.Recordset
Dim rsAgentAdherent As ADODB.Recordset
Dim rsOOOEvents As ADODB.Recordset
Dim strOOOEvents As String
Dim lngAdherent As Long
Dim lngSchedStateID As Long
Dim lngActStateID As Long
Dim lngTotalAgents As LongPtr
Dim lngProcessingAgent As Long
Dim varReturn As Variant
Dim strAdherenceFile As String
Dim dtAS As Date

Dim rsSS As ADODB.Recordset
Dim rsAS As ADODB.Recordset
Dim rsADH As ADODB.Recordset

Dim strAgentLim As String
Dim strAgentsExclude As String
Dim strLogFile As String
Dim strMUs As String

strMUs = "1000,2000,6000"
strLogFile = "C:\Logs\ReportTrueAdherenceRecordset.txt"
LogToFile strLogFile, "Begin ReportTrueAdherenceRecordset for " & CStr(dtStart) & "..."
dtEnd = DateAdd("d", 1, dtStart)
lngScheduleLoadOrderID = 3

strSQLMaintenance(1, 1) = "qryADHTransfer"
strSQLMaintenance(1, 2) = "INSERT INTO tblAdherence (ScheduleDate, ScheduleMinute, IEXUID, Adherent, MUNumID, ManagerID, SchedStateID, AgentStateID) SELECT ScheduleDate, ScheduleMinute, IEXUID, Adherent, MUNumID, ManagerID, SchedStateID, AgentStateID FROM tblAdherenceLoad ORDER BY IEXUID, ScheduleDate, ScheduleMinute;"
strSQLMaintenance(1, 3) = "workforce_management"
strSQLMaintenance(2, 1) = "qryADHClearTemp"
strSQLMaintenance(2, 2) = "DELETE FROM tblAdherenceLoad;"
strSQLMaintenance(2, 3) = "workforce_management"

strSQLRebuildIndex(1, 1) = "qryAdherenceIndexesDrop"
strSQLRebuildIndex(1, 2) = "ALTER TABLE `workforce_management`.`tbladherence` " & _
    "DROP FOREIGN KEY `fk_Adherence_IEXUID`, " & _
    "DROP FOREIGN KEY `fk_Adherence_MUNumID`, " & _
    "DROP FOREIGN KEY `fk_Adherence_ManagerID`, " & _
    "DROP INDEX `idxScheduleDate`, " & _
    "DROP INDEX `idxScheduleMinute`, " & _
    "DROP INDEX `idxIEXUID`, " & _
    "DROP INDEX `idxMUNumID`, " & _
    "DROP INDEX `idxManagerID`;"
strSQLRebuildIndex(1, 3) = "ODBC;DSN=workforce_management;"
strSQLRebuildIndex(2, 1) = "qryAdherenceIndexesRebuild"
strSQLRebuildIndex(2, 2) = "ALTER TABLE `workforce_management`.`tbladherence` " & _
    "ADD INDEX `idxScheduleDate` (`ScheduleDate` ASC), " & _
    "ADD INDEX `idxScheduleMinute` (`ScheduleMinute` ASC), " & _
    "ADD INDEX `idxIEXUID` (`IEXUID`), " & _
    "ADD INDEX `idxMUNumID` (`MUNumID`), " & _
    "ADD INDEX `idxManagerID` (`ManagerID`), " & _
    "ADD CONSTRAINT `fk_Adherence_IEXUID` " & _
    "  FOREIGN KEY (`IEXUID`) " & _
    "  REFERENCES `workforce_management`.`tblAgentData` (`IEXUID`) " & _
    "  ON DELETE NO ACTION " & _
    "  ON UPDATE NO ACTION, " & _
    "ADD CONSTRAINT `fk_Adherence_MUNumID` " & _
    "  FOREIGN KEY (`MUNumID`) " & _
    "  REFERENCES `workforce_management`.`tblmu` (`MUNumID`) " & _
    "  ON DELETE NO ACTION " & _
    "  ON UPDATE NO ACTION, " & _
    "ADD CONSTRAINT `fk_Adherence_ManagerID` " & _
    "  FOREIGN KEY (`ManagerID`) " & _
    "  REFERENCES `workforce_management`.`tblmanager` (`ManagerID`) " & _
    "  ON DELETE NO ACTION " & _
    "  ON UPDATE NO ACTION;"
strSQLRebuildIndex(2, 3) = "ODBC;DSN=workforce_management;"

strAgentsExclude = ADHLoadIEXUID(dtStart)

If strAgentsExclude <> "" Then
    strAgentLim = "AND ad.IEXUID NOT IN(" & strAgentsExclude & ") "
    LogToFile strLogFile, "Excluded: " & strAgentsExclude
End If

strSQLAgentList(1, 1) = "qryAdherenceAgentList"
strSQLAgentList(1, 2) = "SELECT DISTINCT ad.IEXUID, ad.Five9ID, ad.MUNumID, ad.ManagerID, mu.TimeOffset " & _
    "FROM tblAgentData ad " & _
        "INNER JOIN tblAgentScheduleData asd ON ad.IEXUID = asd.IEXUID " & _
        "INNER JOIN tblMU mu ON ad.MUNumID = mu.MUNumID " & _
    "WHERE asd.ScheduleDate = '" & Format(dtStart, "YYYY-MM-DD") & "' AND mu.MUSetID IN(" & strMUs & ") AND asd.ScheduleActivity NOT IN(SELECT SchedState FROM tblSchedState WHERE InOffice=0) " & _
    strAgentLim & _
    "UNION SELECT a.IEXUID, ad.Five9ID, a.MUNumID, a.ManagerID, mu.TimeOffset " & _
    "FROM tblAttendance a " & _
        "LEFT JOIN (SELECT DISTINCT adh.MUNumID, adh.ManagerID, adh.IEXUID, adh.ScheduleDate FROM tblAdherence adh WHERE adh.ScheduleDate = '" & Format(dtStart, "YYYY-MM-DD") & "') adh2 ON a.IEXUID = adh2.IEXUID AND a.ScheduleDate = adh2.ScheduleDate " & _
        "INNER JOIN tblAgentData ad ON a.IEXUID = ad.IEXUID " & _
        "INNER JOIN tblMU mu ON a.MUNumID = mu.MUNumID " & _
    "WHERE (adh2.IEXUID IS NULL AND adh2.ScheduleDate IS NULL) AND a.ScheduleDate = '" & Format(dtStart, "YYYY-MM-DD") & "' AND a.ScheduleDate <= (SELECT MAX(adh3.ScheduleDate) FROM tblAdherence adh3) AND a.MUSetID IN(" & strMUs & ") " & _
    strAgentLim & _
    "ORDER BY IEXUID;"
'Alternate list of those with attendance records but no longer in an active MU
strSQLAgentList(1, 3) = "workforce_management"

Set dbs = CurrentDb()
Set cn = New ADODB.Connection
cn.CursorLocation = adUseClient
cn.Open "DSN=workforce_management;"
DoCmd.SetWarnings False

If blRebuildIndexes Then
    LogToFile strLogFile, "Dropping indexes on tblAdherence..."
    cn.Execute strSQLRebuildIndex(1, 2)
    LogToFile strLogFile, "Indexes dropped on tblAdherence..."
End If

Set rsOOOEvents = New ADODB.Recordset
rsOOOEvents.Open "SELECT SchedState FROM tblSchedState WHERE InOffice=0;", cn, adOpenForwardOnly, adLockReadOnly
Do
    strOOOEvents = strOOOEvents & rsOOOEvents.Fields(0) & ";"
    rsOOOEvents.MoveNext
Loop Until rsOOOEvents.EOF
rsOOOEvents.Close
Set rsOOOEvents = Nothing

Set rsAgentList = New ADODB.Recordset
rsAgentList.Open strSQLAgentList(1, 2), cn, adOpenStatic, adLockReadOnly
rsAgentList.CacheSize = 200

If Not (rsAgentList.BOF And rsAgentList.EOF) Then
    LogToFile strLogFile, "Clearing temp table..."
    dbs.Execute "DELETE * FROM tblAdherenceLoadLocal;"
    lngTotalAgents = rsAgentList.RecordCount
    LogToFile strLogFile, CStr(lngTotalAgents) & " total agents"
    lngProcessingAgent = 1

    Do
        varReturn = Access.SysCmd(acSysCmdSetStatus, "Processing agent " & lngProcessingAgent & " of " & lngTotalAgents & " (" & CStr(dtStart) & ")")

        strIEXUID = rsAgentList.Fields("IEXUID")
        strFive9ID = rsAgentList.Fields("Five9ID")
        strMUNumID = rsAgentList.Fields("MUNumID")
        lngManagerID = rsAgentList.Fields("ManagerID")
        lngTimeOffset = CInt(rsAgentList.Fields("TimeOffset")) + 2

        LogToFile strLogFile, "Processing - Agent: " & strFive9ID & ", IEXUID: " & strIEXUID
        strSQLAgentData(1, 1) = "qryAdherenceShiftStart"
        strSQLAgentData(1, 2) = "SELECT MIN(tblAgentScheduleData.StartTime) AS ShiftStart, MAX(tblAgentScheduleData.EndTime) AS ShiftEnd " & _
            "FROM tblAgentScheduleData " & _
            "WHERE (((tblAgentScheduleData.IEXUID)=" & strIEXUID & ") AND ((tblAgentScheduleData.ScheduleDate)='" & Format(dtStart, "YYYY-MM-DD") & "') AND ScheduleLoadOrderID=" & lngScheduleLoadOrderID & ");"
        strSQLAgentData(1, 3) = "workforce_management"

        strSQLAgentData(2, 1) = "qryAdherenceSchedule"
        strSQLAgentData(2, 2) = "SELECT tblAgentScheduleData.* " & _
            "FROM tblAgentScheduleData " & _
            "WHERE (((tblAgentScheduleData.IEXUID)=" & strIEXUID & ") AND ((tblAgentScheduleData.ScheduleDate)='" & Format(dtStart, "YYYY-MM-DD") & "') AND ScheduleLoadOrderID=" & lngScheduleLoadOrderID & ");"
        strSQLAgentData(2, 3) = "workforce_management"

        strSQLAgentData(3, 1) = "qryAdherenceActual"
        strSQLAgentData(3, 2) = "SELECT five9_agent_state.*, DATE_ADD(Timestamp, INTERVAL " & lngTimeOffset & " HOUR) AS AdjTimestamp " & _
            "FROM five9_agent_state " & _
            "WHERE (((five9_agent_state.Agent_Email)='" & strFive9ID & "') AND ((five9_agent_state.Timestamp) Between '" & Format(dtStart, "YYYY-MM-DD") & "' And '" & Format(dtEnd, "YYYY-MM-DD") & "')) " & _
            "ORDER BY timestamp;"
        strSQLAgentData(3, 3) = "five9"

        Set rsAgentDates = New ADODB.Recordset
        rsAgentDates.Open strSQLAgentData(1, 2), cn, adOpenStatic, adLockReadOnly

        dtShiftStart = CDate(dtStart & " " & TimeValue(Nz(rsAgentDates.Fields("ShiftStart"), #12:00:00 AM#)))
        rsAgentDates.Close
        Set rsAgentDates = Nothing

        Set rsAgentSchedule = New ADODB.Recordset
        rsAgentSchedule.Open strSQLAgentData(2, 2), cn, adOpenStatic, adLockReadOnly
        rsAgentSchedule.CacheSize = 50

        Set cnFive9 = New ADODB.Connection
        cnFive9.Open "DSN=five9;"

        Set rsAgentState = New ADODB.Recordset
        rsAgentState.Open strSQLAgentData(3, 2), cnFive9, adOpenStatic, adLockReadOnly
        rsAgentState.CacheSize = 200

        If Not (rsAgentState.BOF And rsAgentState.EOF) Then
            rsAgentState.MoveLast
            rsAgentState.MoveFirst
        End If

        Set rsSS = New ADODB.Recordset
        rsSS.Open "tblSchedState", cn, adOpenStatic, adLockReadOnly
        rsSS.CacheSize = 50

        If Not (rsAgentSchedule.BOF And rsAgentSchedule.EOF) Then
            rsSS.MoveFirst
            rsSS.Find "SchedState = '" & rsAgentSchedule.Fields("ScheduleActivity") & "'"
            lngSchedStateID = rsSS.Fields("SchedStateID")
        End If

        Set rsAS = New ADODB.Recordset
        rsAS.Open "tblAgentState", cn, adOpenStatic, adLockReadOnly
        rsAS.CacheSize = 100

        Set rsADH = New ADODB.Recordset
        rsADH.Open "tblAdherentState", cn, adOpenStatic, adLockReadOnly
        rsADH.CacheSize = 100

        Do While dtShiftStart < dtShiftEnd
            lngAdherent = 0
            If Not (rsAgentState.BOF And rsAgentState.EOF) Then

                If TimeValue(dtShiftStart) >= TimeValue(rsAgentSchedule.Fields("EndTime")) Then
                    rsAgentSchedule.MoveNext
                    rsSS.MoveFirst
                    rsSS.Find "SchedState = '" & rsAgentSchedule.Fields("ScheduleActivity") & "'"
                    lngSchedStateID = rsSS.Fields("SchedStateID")
                End If

                rsAgentState.Find "AdjTimestamp>#" & dtShiftStart & "#"
                If Not rsAgentState.BOF Then rsAgentState.MovePrevious
                If Not rsAgentState.BOF Then
                    If rsAgentState.Fields("Agent_State_Time") = "24:00:00" Then
                        dtAS = 0
                    Else
                        dtAS = rsAgentState.Fields("Agent_State_Time")
                    End If
'                    If TimeValue(dtShiftStart) > DateAdd("h", lngTimeOffset, TimeValue(rsAgentState.Fields("Timestamp")) + TimeValue(rsAgentState.Fields("Agent_State_Time"))) Then
                    If TimeValue(dtShiftStart) > DateAdd("h", lngTimeOffset, TimeValue(rsAgentState.Fields("Timestamp")) + dtAS) Then
                        rsAgentState.MoveNext
                    End If
                End If

                If Not (rsAgentState.BOF Or rsAgentState.EOF) Then
                    rsAS.MoveFirst
                    rsAS.Find "AgentState = '" & rsAgentState.Fields("Agent_State") & "'"
                    lngActStateID = rsAS.Fields("AgentStateID")
                    rsADH.MoveFirst
                    rsADH.Filter = "SchedStateID = " & lngSchedStateID & " AND AgentStateID = " & lngActStateID
                    If Not (rsADH.BOF And rsADH.EOF) Then lngAdherent = 1
                    rsADH.Filter = ""
                Else
                    lngActStateID = 10
                End If
            End If

            If InStr(1, strOOOEvents, rsAgentSchedule.Fields("ScheduleActivity"), vbTextCompare) = 0 Then
                dbs.Execute "INSERT INTO tblAdherenceLoadLocal (ScheduleDate, ScheduleMinute, IEXUID, Adherent, MUNumID, ManagerID, SchedStateID, AgentStateID) " & _
                    "VALUES (#" & dtStart & "#,#" & dtShiftStart & "#," & strIEXUID & "," & lngAdherent & "," & strMUNumID & "," & lngManagerID & "," & lngSchedStateID & "," & lngActStateID & ");"
            End If

            dtShiftStart = DateAdd("n", 1, dtShiftStart)
        Loop

        rsSS.Close
        rsAS.Close
        rsADH.Close
        rsAgentSchedule.Close
        rsAgentState.Close
        cnFive9.Close

        Set rsSS = Nothing
        Set rsAS = Nothing
        Set rsADH = Nothing
        Set rsAgentSchedule = Nothing
        Set rsAgentState = Nothing
        Set cnFive9 = Nothing

        If Not rsAgentList.EOF Then rsAgentList.MoveNext
        lngProcessingAgent = lngProcessingAgent + 1
        LogToFile strLogFile, "Completed Processing: " & strFive9ID
    Loop Until rsAgentList.EOF
Else
    LogToFile strLogFile, "No agents selected"
End If

LogToFile strLogFile, "Completed All Agents;Begin Upload to MYSQL"

varReturn = Access.SysCmd(acSysCmdSetStatus, "Inserting processed records")

LogToFile strLogFile, "Generating output file..."
strAdherenceFile = "C:\Temp\" & Format(dtStart, "YYYYMMDD") & "AdherenceFile.csv"
DoCmd.TransferText acExportDelim, , "qryTrueAdherenceExport", strAdherenceFile, False
strAdherenceFile = VBA.Replace(strAdherenceFile, "\", "\\")

Set qdf = New DAO.QueryDef
qdf.Name = "qryTrueAdherenceTransfer"
qdf.Connect = "ODBC;DSN=workforce_management;"
qdf.SQL = "LOAD DATA LOW_PRIORITY LOCAL INFILE '" & strAdherenceFile & "' INTO TABLE workforce_management.tblAdherence FIELDS TERMINATED BY ',' ( @dummy, @var1, @var2, IEXUID, Adherent, MUNumID, ManagerID, SchedStateID, AgentStateID ) SET ScheduleDate = DATE_FORMAT(STR_TO_DATE(@var1, '%m/%d/%Y %H:%i:%s'), '%Y-%m-%d'), ScheduleMinute = DATE_FORMAT(STR_TO_DATE(@var2, '%m/%d/%Y %H:%i:%s'), '%H:%i:%s');"
qdf.ReturnsRecords = False
qdf.ODBCTimeout = 600
dbs.QueryDefs.Append qdf
Set qdf = Nothing

LogToFile strLogFile, "Importing results to server..."
dbs.Execute "qryTrueAdherenceTransfer"
dbs.QueryDefs.Delete "qryTrueAdherenceTransfer"

varReturn = Access.SysCmd(acSysCmdSetStatus, "Clearing temp tables...")
LogToFile strLogFile, "Clearing temp table..."
dbs.Execute "DELETE * FROM tblAdherenceLoadLocal;"
For lngLCV = LBound(strSQLMaintenance, 1) To UBound(strSQLMaintenance, 1)
    If ExistObject(strSQLMaintenance(lngLCV, 1), acQuery) Then dbs.QueryDefs.Delete strSQLMaintenance(lngLCV, 1)
    Set qdf = New DAO.QueryDef
    qdf.Name = strSQLMaintenance(lngLCV, 1)
    qdf.SQL = strSQLMaintenance(lngLCV, 2)
    qdf.Connect = "ODBC;DSN=" & strSQLMaintenance(lngLCV, 3) & ";"
    qdf.ReturnsRecords = False
    dbs.QueryDefs.Append qdf
    qdf.Execute
    Set qdf = Nothing
    If ExistObject(strSQLMaintenance(lngLCV, 1), acQuery) Then dbs.QueryDefs.Delete strSQLMaintenance(lngLCV, 1)
Next lngLCV

LogToFile strLogFile, "Temp tables cleared."

If blRebuildIndexes Then
    varReturn = Access.SysCmd(acSysCmdSetStatus, "Rebuilding database indexes...")
    LogToFile strLogFile, "Rebuilding indexes on tblAdherence..."
    If ExistObject(strSQLRebuildIndex(2, 1), acQuery) Then dbs.QueryDefs.Delete strSQLRebuildIndex(2, 1)
    Set qdf = New DAO.QueryDef
    qdf.Name = strSQLRebuildIndex(2, 1)
    qdf.SQL = strSQLRebuildIndex(2, 2)
    qdf.Connect = strSQLRebuildIndex(2, 3)
    qdf.ReturnsRecords = False
    qdf.ODBCTimeout = 180
    dbs.QueryDefs.Append qdf
    Set qdf = Nothing
    dbs.Execute strSQLRebuildIndex(2, 1)
    LogToFile strLogFile, "Indexes rebuilt on tblAdherence..."
    dbs.QueryDefs.Delete strSQLRebuildIndex(2, 1)
End If

varReturn = Access.SysCmd(acSysCmdClearStatus)
DoCmd.SetWarnings True

LogToFile strLogFile, "Process completed successfully"

cn.Close
Set cn = Nothing

Set dbs = Nothing

End Sub

0 个答案:

没有答案