我继承了 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 秒)。我将范围缩小到这些表单的记录源,它们都使用相同的查询或变体。
用户在主窗体中输入作业编号并按 Enter 键。然后,底层查询根据唯一键 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 获取单个条目并将它们连接到单个数据集,而是首先连接两个表,然后才查找用户感兴趣的单个数据集。
我无法找到决定执行顺序的解决方案。我尝试了不同的方法,比如用嵌套的 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 支持。
我尝试在 Access 中将查询拆分为两个查询 q1 和 q2,分别从 t1 中提取数据。 t2 和第三个查询 q3 对这些假设的子集进行连接,但没有效果。 q1 和 q2 分别以极快的速度运行并获得预期的数据结果,但 q3 通常需要 7-10 秒。
我当前正在研究的方法是运行 q1 和 q2 并将获取的数据保存到两个临时表 tq1 和 tq2 中,然后将它们连接到最后一个查询中。这有效,它快速加载数据并将其显示在编辑器中(< 0.5 seconds, hurray!).
我现在面临的问题是将用户在编辑器表单中所做的任何更改更新到后端表 t1 和 t2。 目前,关闭并重新打开作业/编辑器时,用户更改不会生效并且会丢失。
有什么方法可以使这个
INNER JOIN
查询快速而无需整个临时表解决方法吗?
如果没有,我将如何从本地临时表更新后端表?编辑器中的更改将保存在临时表中,直到重新打开编辑器被覆盖。
我已经添加了中间查询,即添加了相应的查询。临时表的主键(这不能直接在创建表查询中完成)。
我还尝试在关闭编辑器时使用更新查询,这似乎不起作用,但我可能必须调试该查询,我不确定它现在会做什么。
最明显的返工是将过滤器移至连接中:
SELECT *
FROM t1
INNER JOIN t2 ON (t1.JobNr = t2.JobNr AND t2.JobNr = [Forms]![Main]![JobNr])
我的猜测是,如果您在 t1 或 t2 上进行过滤,则无关紧要,但我的猜测是 Access 足够智能,可以在加入时进行过滤,但这似乎是不正确的,因此请检查一下。
对于更详细的性能分析,查询计划往往会有所帮助。请参阅如何从 Access 2010 获取查询计划 (showplan.out)?
当然,将14调整为你的版本号。
需要给
t2.JobNr
添加唯一索引,最好还是主键。
此时其他一切都只是浪费时间。
设置用户退出前端的日期和时间,必要时将其踢出:强制所有用户断开与 2010 Access 后端数据库的连接
从长远来看,从 Access 后端迁移到服务器后端(如免费的 SQL Server Express)将是一个好主意。
编辑:您是否尝试过如果根本不执行 JOIN 会发生什么?
SELECT *
FROM t1, t2
WHERE t1.JobNr = [Forms]![Main]![JobNr]
AND t2.JobNr = [Forms]![Main]![JobNr]
通常您希望避免这种情况,但在这种情况下可能会有所帮助。