MS Access前端连MySQL后端双JOIN查询引发大量冗余查询问题
Access前端连接MySQL后端的冗余查询性能问题
表结构
Customers表
+----+------+-----+---------------+----------------+ | ID | Name | ... | OfficeCountry | BillingCountry | +----+------+-----+---------------+----------------+ | 1 | Bill | ... | 1 | 1 | | 2 | Joe | ... | 2 | 1 | +----+------+-----+---------------+----------------+
(已删减无关字段)
Countries表
+----+-------------+ | ID | Name | +----+-------------+ | 1 | USA | | 2 | Netherlands | +----+-------------+
OfficeCountry和BillingCountry分别对应办公地与账单地址的国家ID,二者可能不同。
自定义查询
为关联获取国家名称,编写了双LEFT JOIN查询:
SELECT ID, some, fields, Countries_1.Name AS OfficeCountryName, Countries_2.Name AS BillingCountryName FROM Customers LEFT JOIN Countries AS Countries_1 ON Customers.OfficeCountry = Countries_1.ID LEFT JOIN Countries AS Countries_2 ON Customers.BillingCountry = Countries_2.ID
环境与问题
应用采用MS Access作为前端,通过ODBC连接MySQL后端,Customers表约有15000条记录。加载DynaSet数据到表单时性能极差,查询日志显示执行了三类查询:
- 上述自定义查询;
- 一条使用旧版
{oj ...}语法的额外OUTER JOIN查询(未手动指定,且数据未被前端使用); - 30000条针对Countries表的单条查询(数量为Customers记录数的2倍),语句为
SELECT ID FROM Countries WHERE ID = N(N为对应Customer的国家ID)。
疑问
- 这条额外的OUTER JOIN查询来自哪里?
- Access为何要针对每条记录单独查询Countries表?明明已经知道关联的ID,这类查询毫无意义。
补充说明:即使是简单查询搭配简洁表单,也会生成两类查询:
- 查询所有ID的语句(包含Customer表及两个关联表);
- 针对每条返回记录,为每个表单独执行一次查询,例如
SELECT * FROM Customers WHERE Id = 当前查看记录ID。
问题原因与优化方案
1. 额外{oj ...}查询的来源
{oj ...}是ODBC标准的外连接语法,Access通过ODBC连接非Access后端时,会自动将部分SQL语句转换为这种ODBC兼容格式——这条额外查询是Access表单处理DynaSet记录源时,后台自动生成的验证或元数据查询,和你手动编写的查询无关。
2. 单条Countries查询的原因
这是Access DynaSet记录集的逐行延迟加载特性导致的:Access默认不会一次性拉取所有关联数据,先加载主表核心字段,等到需要显示关联字段(如OfficeCountryName)时,再单独查询关联表。加上你有两个关联字段,每条Customer记录会触发2次Countries查询,最终形成30000次冗余请求。此外,表单绑定控件关联Countries字段、开启参照完整性、组合框行来源设置等,也会触发这类查询。
无需大规模重构的性能优化方法
- 切换为Snapshot记录集:将表单的记录集类型从DynaSet改为Snapshot,Access会一次性拉取所有查询结果,不会逐行触发关联查询(仅适用于无需编辑数据的场景);
- 明确指定查询字段:不要用
some, fields模糊写法,列出所有需要的字段,避免Access为获取元数据额外查询; - 关闭不必要的验证:在ODBC链接表属性中,关闭参照完整性验证、自动链接等非必需选项;
- 将查询转为MySQL视图:在MySQL端创建包含双LEFT JOIN逻辑的视图,Access直接链接该视图,所有关联计算在MySQL端完成,Access仅拉取最终结果;
- 限制加载记录数:添加筛选条件(如按地区、日期),减少一次性加载的记录量,缓解性能压力。
内容的提问来源于stack exchange,提问作者Niek van der Steen
相关产品推荐
相关产品推荐

