【问题标题】:Slow INNER JOIN Query in MS-Access 2016, Workaround?MS-Access 2016 中的慢速 INNER JOIN 查询,解决方法?
【发布时间】:2022-01-17 21:03:47
【问题描述】:

这是我在这里的第一个问题,请温柔。

在工作中,我继承了 MS Access 数据库的责任,这对我的部门来说至关重要。

该数据库已经发展了 20 多年,不断添加、删除和更改内容。很快,这是一个令人费解的混乱。 VBA 代码包含这样的好东西,我不骗你:

Dim p, strText, A, B, C, d, E, F, G, H, i, j, K, L, M, N, O, Z, R, Q, kd, AfGb, T, LN, DC, EntBez, TP, pack, Press, Fehler, ksoll, Y, zeileninhalt, dateipfad, auslesezeile As String

我正在慢慢清理它,但是……无论如何:

问题

打开某些表单时速度很慢(加载时间为 7-10 秒)。我能够将其缩小到这些表单的记录源,它们都使用基本相同的查询或它的变体。

用户在主窗体中输入作业编号并按回车键。然后,底层查询根据唯一键 JobNr 从两个表中提取数据。结果是包含此作业的所有信息的单行。这些信息显示在编辑器表单中,使用查询作为记录源。

数据库分为前端和后端,t1 和 t2 是后端表,每个表大约有 20k 个条目。后端位于公司服务器上的某个位置,前端保存在本地的每台用户计算机上。

这是查询:

SELECT *
FROM t1 
INNER JOIN t2 ON t1.JobNr = t2.JobNr
WHERE JobNr = [Forms]![Main]![JobNr];

t1 具有 JobNr 作为主键,t2 具有 ID 作为主键,JobNr 未编入索引。我想尝试对其进行索引以希望获得更好的性能,但目前无法在繁忙的工作日对后端进行更改...

这个简单的查询实在是太慢了。问题似乎是执行顺序。 Access 似乎不是从 t1 和 t2 获取单个条目并将它们加入单个数据集,而是首先将两个 friggin 表作为一个整体加入,然后才查找用户感兴趣的单个数据集。

我无法找到指定执行顺序的解决方案。我尝试了不同的方法,比如用嵌套的 Selects 重写 SQL 代码,比如:

SELECT *
FROM 
    (SELECT * FROM t1 
     WHERE t1.JobNr = [Forms]![Main]![JobNr]) AS q1
INNER JOIN
    (SELECT * FROM t2 
     WHERE t2.JobNr = [Forms]![Main]![JobNr]) AS q2 ON q1.JobNr = q2.JobNr;

还是很慢……

我想尝试WITH 对 SQL 代码进行分区,但 MS Access SQL 显然不支持。

我尝试在访问中将查询拆分为两个查询 q1 和 q2,分别从 t1 中提取数据。 t2 与第三个查询 q3 连接这些假定的子集......无济于事。 q1 和 q2 分别运行得非常快,得到了预期的数据结果,但 q3 通常需要 7-10 秒。

我正在使用的当前方法是运行 q1 和 q2 并将获取的数据保存到两个临时表 tq1 和 tq​​2 中,然后在最后一个查询中加入它们。这非常有效,因为它可以快速加载数据并将其显示在编辑器中(

太好了,我错过了什么/做错了什么?有没有办法在没有整个临时表解决方法的情况下使这个INNER JOIN 查询快速?

如果没有,我将如何从本地临时表更新后端表?编辑器中的更改会保存在临时表中,直到被重新打开编辑器覆盖。

我已经添加了中间查询,添加了相应的查询。临时表的主键(这不能直接在创建表查询中完成......)但是......

我还尝试在关闭编​​辑器时使用更新查询,这似乎也不起作用,但我可能必须调试那个,我不确定它现在是否会死掉...

抱歉,文字太长了!

提前向您致以诚挚的问候和感谢!

【问题讨论】:

  • 顺便说一句,Dim 声明太棒了。 :(

标签: sql vba ms-access ms-access-2016


【解决方案1】:

你需要给t2.JobNr添加一个唯一索引,最好把它作为主键。

此时其他一切都只是浪费时间。

设置用户退出前端的日期和时间,必要时将其踢出:Force all users to disconnect from 2010 Access backend database

从长远来看,从 Access 后端迁移到服务器后端(如免费的 SQL Server Express)将是一个好主意。


编辑:你有没有试过如果你根本不做 JOIN 会发生什么?

SELECT *
FROM t1, t2
WHERE t1.JobNr = [Forms]![Main]![JobNr]
  AND t2.JobNr = [Forms]![Main]![JobNr]

通常您希望避免这种情况,但在这种情况下可能会有所帮助。

【讨论】:

  • 感谢您的回答!我今天一大早进来,把 t2.JobNr 设为主键。这根本没有提高性能:(
  • 我也试过你的 SQL 解决方案。它以惊人的速度提取数据(耶!)但随后我面临与 Erik A 的方法相同的问题:“记录集不可更新”了。我似乎有一个普遍的问题,我今天将不得不研究它......服务器后端听起来很棒,但我只是没有时间进行大的改变,这只是一个副项目......可悲的是, “又快又脏”是和概率。永远是这里的作案手法:-/
  • PK 没有改变性能是相当令人惊讶的。我不认为我有任何其他想法。可能是时候聘请顾问来实际查看数据库和查询了。 -- 回复:“又快又脏”——我认为从长远来看,这不会因为 这对我的部门至关重要而有所削减。
  • 我能够通过采纳 Erik A 关于避免 JOIN 的建议来解决我的问题,而是将内容拆分为 MainForm (t1) 和 SubForm (t2),这是一项乏味的工作,但可能是这里最好的解决方案.再次感谢您的帮助!
【解决方案2】:

最明显的返工是将过滤器移到连接中:

SELECT *
FROM t1 
INNER JOIN t2 ON (t1.JobNr = t2.JobNr AND t2.JobNr = [Forms]![Main]![JobNr])

我的猜测是,如果您在 t1 或 t2 上进行过滤,这无关紧要,但我的猜测也是 Access 足够聪明,可以在加入时进行过滤,这似乎是不正确的,所以请检查一下。

对于更详细的性能分析,查询计划往往会有所帮助。见How to get query plans (showplan.out) from Access 2010?

当然,将 14 调整为您的版本号。

【讨论】:

  • 非常感谢您的回答。这加快了初始查询、编辑器表单和数据加载速度。遗憾的是,这些字段现在不可编辑。我不明白为什么。我在慢速版本和这个版本之间切换了多次,没有改变任何其他内容,但是对于快速版本,我什至无法在文本字段中输入内容。机器人左角有一条消息“记录集不可更新”。很奇怪,我得研究一下……
  • 好吧,对于临时表,它也不可编辑,因为要编辑表的临时副本。以单一形式编辑多个表中的数据,通过共享主键以外的任何内容连接是一件非常非常可疑的事情,并且会带来大量的锁定开销。考虑将表单拆分为主表单和子表单,两者都直接绑定到表格。这将是一次重大的返工,但会带来更多的性能优势。
  • 据我所知,整个“记录集不可更新”似乎是另一个 Access SQL 特定的东西。在 Arturo Azcorra 的“Microsoft Access 和 SQL 数据库闪电指南”中,第 345 页和第 345 页,其中有一章是关于“如何编写“ON”子句?”详细说明了关于 ON 子句的 Access 有多棘手。 (Google Books 上的摘录) 另外,当我尝试将该 SQL 语句从 SQL 切换到设计视图时,我收到一条错误消息。我认为这是 Access 无法真正解决此问题的证据,但这只是我的最佳猜测......
  • link(我希望这个链接能正常工作......)
  • 我很清楚是什么原因造成的。我要说明的一点是:您不希望加入非主键的可更新查询。如果你这样做,你会得到各种奇怪的东西。如前所述,解决此问题的最佳方法是使用子表单并直接绑定到表,因为当您直接工作并仅锁定单个表时,您不会获得锁定/锁定/更新开销。 Access 无法在设计视图中表示大量查询,如果您认真编写查询,通常不应该使用设计视图,即使只是因为括号过载。
猜你喜欢
  • 2015-08-25
  • 2015-11-27
  • 2018-07-09
  • 1970-01-01
  • 2012-12-04
  • 2020-11-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多