【问题标题】:Why is my access database so slow when loading?为什么我的访问数据库加载时这么慢?
【发布时间】:2018-09-17 11:35:37
【问题描述】:

首先,我已经阅读了这篇文章; What is causing my access database to be so slow?

但就像 8 年前一样,我觉得我可以再次问这个问题。

我有一个 access 2016 数据库,它有一个后端 sql 服务器,用于数据库上的所有计算。数据库用于有多个job数据,每个用户可以在job之间切换查看数据。

它在计算方面相当复杂,但是数据库本身只有 15mb 大小。每次加载每个表单几乎需要 10 秒,从用户的角度来看,这几乎是不可用的。

对加快数据库速度的最佳方法有什么建议吗?它位于远程服务器上,每个用户都登录到远程服务器以使用它。所以没有数据库拆分或任何东西。我再次在线阅读这些文章,例如http://www.granite.ab.ca/access/performancefaq.htmhttp://www.granite.ab.ca/access/performanceldblocking.htm

但是,正如几年前讨论的那样,我只是想知道是否有一种更新的方法可以使数据库更快地运行。

问候, 迈克尔

【问题讨论】:

  • 什么需要 10 秒才能发生?您是否在这段时间运行查询、做 DML 的事情,或者做其他事情?
  • 嗨蒂姆,加载每个表单需要 10 秒。例如,当您单击一个工作名称时,它会将您带到该工作的财务报告,但此过程需要 10 秒或更长时间。在此期间,左下角显示“正在计算……”。但是我把所有的计算都移到了后端的 sql server 上?
  • 您应该尝试找出这 10 秒中有多少用于延迟(数据进出数据库所需的时间),以及数据库实际花费了多少做工作。您最适合回答这些问题。
  • 从分析开始:Profiling ODBC Driver Performance (ODBC)。然后在您找到性能瓶颈后回来,并通过minimal reproducible example 提出具体问题。如果没有任何信息,我们无法追踪阻碍您的数据库性能的原因。
  • 如果直接在 Access 中打开只包含几条记录的链接表会怎样?如果这也很慢,则说明您有配置问题。如果速度很快,那么您的表单会提取太多数据,或者强制对应该在服务器上运行的数据进行本地处理。

标签: sql ms-access vba


【解决方案1】:

回复:您“将计算移至后端 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 数据库性能的提示

  1. 使用压缩和修复
  2. 仅加载您需要的内容
  3. 确保所有表都有主键
  4. 通过添加二级索引
  5. 进行优化
  6. 拆分数据库

更多信息请访问source

...网上还有许多其他文章提供有关提高 Access 性能的建议。

最重要的是,这不太可能是一个问题。 “整个数据库健康”包括自下而上的超组织是至关重要的。在同样的情况下,成本效益比甚至可以证明重新设计一个“完美”数据库是合理的,从绘图板开始(字面意思!)...

祝你好运!

【讨论】:

  • 非常感谢!!我会立即查看每一个。
  • 告诉我你在 5 分钟内输入了这个答案,你就是我的新超级英雄。伟大的史诗般的答案。
【解决方案2】:

我会先建立一个测试表格。

将表单绑定到一个“大”的 sql 表。

然后试试这段代码:

Docmd.OpenForm "frmTest",,,"id = 10"

在上面,将“10”替换为表的已知 PK id。

此表单的加载速度是慢还是快?

如果表单加载缓慢,那么我们可以确定表单的“缓慢”加载不是由于数据过多或从表中提取的数据过多。请记住,上面的命令只会从表中拉出一条记录。

那么这个测试表是慢还是快?

如果表单速度很快,那么我们可以消除数据连接问题,或者访问只是花时间。

如果表单加载缓慢,那么数据优化不是您的问题。

上述测试需要 30 秒的时间来烹饪和测试。只需创建绑定的表单,保存,然后敲ctrl-g,在调试窗口输入上面的docmd.OpenForm即可。

如果上面的速度很快,那么明显的表单会导致数据拉取过多。

更好的办法是创建一个独立的测试 accDB,只有一个链接表和一个测试表单。再次,测试——是快还是慢?

如果表单加载速度很快,那么我们回到实际的应用程序有问题。例如,不存在的打印机或链接到其他 mdb/accdb 文件是我要查看的下一个问题(如果测试表单运行速度很快)。

另一个问题是您没有提及 SQL 服务器的位置,并且此连接涉及某种类型的“wan”(例如在网站上运行的 sql,或在其他建筑物/位置您使用 WAN 而不是 LAN 来连接到该数据库。

我经常点击 3+ 百万行的 sql server 表,尽管表单直接绑定到那个大表,但我们看到并发现负载不到 1 秒。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-10-04
    • 1970-01-01
    • 2012-02-13
    • 2021-11-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多