回复:您“将计算移至后端 SQL Server”
我假设您的意思是您将数据移动到后端服务器。这并不意味着计算发生在那里,或者更快。
事实上,它更有可能增加计算时间,因为计算仍然由运行查询的任何机器完成(我假设你的前端,除非你做了一些花哨的编码来执行存储的 SQL后端的程序等,并正在从那里检索您的数据。
...所以现在它仍然是同一台机器像以前一样执行计算——但现在数据必须从服务器中提取到每个本地机器运行查询的时间,而不是以前,当数据已经在本地时。
常见的罪魁祸首
没有看到您的数据库,没有人能做的只是猜测,我的猜测是您有多个设计不佳的查询填充每个正在打开的表单。
...可能是同一查询的各种化身一遍又一遍地运行?例如,我的经验中的一个常见问题:是否有一个组合框列出员工姓名或其他数据,根据各种标准进行限制?也许必须为每个表单运行类似的查询?可能每个表单都有多个查询?
需要精简此类重复的工作负载,具体如何执行取决于您的具体情况。对于上面的示例,每次员工列表更改时都可以生成一个静态表,其中仅包含应包含在组合框中的名称。该表可以存储在本地,因此可以替换在每次打开数据库时都会计算多次的重复查询。
另一个常见错误是在查询中使用耗时的自定义函数,该函数必须针对数千条记录运行该函数。如果单个查询调用 10,000 次,则需要 1/4 秒才能运行的函数可能会成为真正的问题。
每个步骤的计时
确定哪些进程造成了大部分延迟的一种有点混乱但有效的方法是进入并通过调用一个记录每个进程运行时间的过程“大量添加”您的代码。 (我刚刚经历了这导致处理“巨大”文件所需的时间大大减少。)
以下是我作为示例一起拍打的程序。您想要记录多少或多少取决于您的情况(以及您诊断问题的速度)。
请记住,这是为临时使用而设计的,因为它会增加额外的处理时间(虽然不像您现有的流程那样多,但听起来!)
示例实现
当您打开数据库时,可能会发生几件事。也许您有一个运行过程的AutoExec 宏,该过程打开表单并运行调用函数的查询等。
这里的目标是弄清楚每个步骤需要多长时间。有点糟糕的例子,但希望它有意义:
Sub YourOnOpenProcedure()
'<-- add our logging sub here
SomeProcessYouCall_1
'<-- add our logging sub here
SomeProcessYouCall_1
'<-- add our logging sub here
SomeFormYouOpen
'<-- add our logging sub here
SomethingElseYouDo
'<-- add our logging sub here (no 'EventName')
End Sub
Function SomeFunctionCalledByYourQuery() As Integer
'<-- add our logging sub here
SomeFunctionCalledByYourQuery = 1 + 2
End Function
程序-定时程序
添加此过程和变量或类似于公共模块的内容:
Option Compare Database
Option Explicit ' <-- Always, especially when troubleshooting!
Public startTime As Single, prevEventName As String
Sub timeIt(eventName As String)
'call this sub with the name of an event/process/sub/form/etc you're about to run
'prints time of previous event, and prepare for the next one if specified
'specify an empty string ("") after the end of the last event to return the last runtime.
If startTime <> 0 Then 'log the duration of the last event
'log the previous event
Debug.Print "-> " & prevEventName & ":", Round(Timer - startTime, 1) & " seconds"
'optional: log "event' in a local table (needs table, see notes)
'DoCmd.SetWarnings False 'supress record-append confirmation
'DoCmd.RunSQL "insert into tblLog select '" & prevEventName & "' as eName, " & Timer - startTime & " as eRunTime"
'DoCmd.SetWarnings True
startTime = 0
prevEventName = ""
End If
If eventName <> "" Then
startTime = Timer 'prepare for the next event
prevEventName = eventName
End If
End Sub
在表格中记录数据是可选的(请参阅下面的表格设置),并且取决于您的情况,例如此问题的范围。照原样,它将在即时窗口中报告(Ctrl+G 从 VBA 打开)。
就我个人而言,我总是选择“更多数据”这一边,几分钟的额外工作可以更容易地看出哪些流程一直很麻烦。
示例用法:
如果我们假设您正在运行的进程是 MsgBox 的:
Sub DemoProcedure()
timeIt "msgbox1:Hi"
MsgBox "hi"
timeIt "msgbox2:Hello"
MsgBox "hello"
timeIt "msg3:Heya"
MsgBox "heya"
timeIt "msg4:Hola"
MsgBox "hola"
timeIt "" '<-- call with empty string to get the last time
End Sub
示例输出:
这会在即时窗口中产生类似的输出:
-> msgbox1:Hi: 1.2 seconds
-> msgbox2:Hello: 1.1 seconds
-> msg3:Heya: 222.7 seconds
-> msg4:Hola: 0.4 seconds
很明显,我的 msg "heya" 程序是这里的问题。 :)
记录到表
要将计时数据记录到本地表(以及即时窗口),请取消注释代码中的三个相关行并添加如下表:
它将记录数据,例如:
提高 Access 数据库性能的提示
- 使用压缩和修复
-
仅加载您需要的内容
- 确保所有表都有主键
- 通过添加二级索引
进行优化
-
拆分数据库
更多信息请访问source。
...网上还有许多其他文章提供有关提高 Access 性能的建议。
最重要的是,这不太可能是一个问题。 “整个数据库健康”包括自下而上的超组织是至关重要的。在同样的情况下,成本效益比甚至可以证明重新设计一个“完美”数据库是合理的,从绘图板开始(字面意思!)...
祝你好运!