MS-Access:SQL JOIN 和 INSERT INTO 与 WHERE 慢

Posted

技术标签:

【中文标题】MS-Access:SQL JOIN 和 INSERT INTO 与 WHERE 慢【英文标题】:MS-Access : SQL JOIN and INSERT INTO with WHERE slow 【发布时间】:2017-05-08 08:14:13 【问题描述】:

长话短说:

通过 INSERT INTO 将具有两个表的 INNER JOIN 的 SELECT 查询插入到新表中。虽然此查询在 20 秒内完成,但在 SELECT 部分添加 WHERE 条件会冻结查询!


详情:

我有两张桌子 (i=1,2)

Table i : Tab_i

ID_i (Long, Indexed, Duplicates possible)
MyDate (Date)
Field_1 (...)
...
Field_N (...)

我创建了一个表 Tab_MATCH 来在比较两个表时存储匹配的 ID

Table Tab_MATCH
ID_1 (Long, Indexed, Duplicates possible)
ID_2 (Long, Indexed, Duplicates possible)

匹配是通过两个表 Tab_1 和 Tab_2 的连接完成的,将匹配的 ID 插入到表 Tab_MATCH 中

INSERT INTO 
  Tab_MATCH
SELECT
  Tab_1.ID_1, 
  Tab_2.ID_2,
FROM 
  Tab_1 
INNER JOIN 
  Tab_2 
ON
  (Tab_1.Field_1 = Tab_2.Field_1) AND
  (...) AND
  (Tab_1.Field_N = Tab_2.Field_N)

此过程在大约 20 秒内运行良好。 然后我想在 Tab_2 的日期上添加一个约束,例如只考虑 2014 年 3 月 1 日(2014 年 3 月 1 日)之前的条目,所以我添加了

INSERT INTO 
  Tab_MATCH
SELECT
  Tab_1.ID_1, 
  Tab_2.ID_2,
FROM 
  Tab_1 
INNER JOIN 
  Tab_2 
ON
  (Tab_1.Field_1 = Tab_2.Field_1) AND
  (...) AND
  (Tab_1.Field_N = Tab_2.Field_N)
WHERE 
  Tab_2.MyDate < #3/1/2014#

此查询现在永远运行。如果我只使用日期约束进行选择,它也会在大约 20 秒内完成,但插入类型会冻结!

我在这里缺少什么?此过程或其他任何连接条目是否涉及任何表扫描? (使用 MS Access 2016(32 位))

【问题讨论】:

MS-Access 的奥秘。很难调试这种东西,因为 Access 没有 EXPLAIN PLAN 机制。您是否尝试过压缩/修复您的数据库? 是的,这很痛苦...我已经压缩/修复(多次)并且还尝试在连接中直接添加 WHERE 子句... INNER JOIN (SELECT * FROM Tab_2 WHERE Tab_2.MyDate &lt; #3/1/2014#) ...,但没有改进... 我只是尝试通过 VBA 循环在 SELECT 查询上作为 DAO.Recordset 进行插入(是的,我已经在这一点上......)而且在这里它只在计算数字时冻结条目数 Dim rs as DAO.Recordset; set rs = CurrentDb.OpenRecordset("SELECT..."); rs.MoveFirst; rs.MoveLast; Debug.Print rs.RecordCount; rs.Close rs.MoveLast 命令再次冻结...删除 WHERE 子句也可以正常工作... 制作一个临时表是您的最佳选择。执行不带 WHERE 子句但包含 ID_1ID_2mydate 列的 INSERT。然后要么删除所有与日期不匹配的记录,要么使用 WHERE 子句插入另一个表。如果您明白我的意思,否则我会写一个正确的答案 嗯,是的,这可能会有所帮助,但问题总是嵌入在更大的上下文中,对多个表进行多重比较。我将测试这个程序。但总的来说,我想了解这里有和没有 INSERT 的 SELECT 之间的区别,以及 WHERE 子句所扮演的角色,以及为什么它冻结INSERT INTO ... SELECT ... INNERJOIN ... WHERE... 查询,这不是一个非常奇特的而是标准任务... 【参考方案1】:

创建并保存这样的查询:

SELECT *
FROM Tab_2 
WHERE MyDate < #3/1/2014#

然后用这个保存的查询替换原始查询中的 Tab_2。

【讨论】:

发布的代码只是一个示例,当然嵌入在更复杂的上下文中。这意味着 WHERE 子句是动态的,需要在不同的条件下应用。我有一个 VBA 脚本在多个表上运行多个比较,工作正常。所以我想使用 ORIGINAL 表(我将受到 *.accdb 文件的 2GB 文件大小限制),而不是为每个比较创建一个 tmp 表。如上面另一条评论所述,我想了解 WHERE 子句对查询的影响... 我刚刚尝试了你的方法,它并没有提高查询速度,即也冻结了。我也看不出外部查询或在我的查询中添加确切代码之间的区别。你能评论一下为什么你会期望有所不同吗? 它强制 Access 在尝试任何连接之前过滤 Tab_2,因此要比较的数据要少得多。真是老套路了。如果冻结了,我猜会发生其他事情;它不能是冻结 Access 的标准。

以上是关于MS-Access:SQL JOIN 和 INSERT INTO 与 WHERE 慢的主要内容,如果未能解决你的问题,请参考以下文章

MS-Access 2016 中的“同一张表”LEFT JOIN ON“同一个公共字段”

通过 LEFT JOIN 优化 SQL 子查询

SQL语句(inner join,left out join,right out join三者的不同

在 sql (MS-Access) 中编写分组查询

使用 SQL 在 Ms-access 查询中运行 Total

MS-Access/SQL 拆分:如果我将其移动到不同的文件夹,前端安全性会发生变化