5

我对相对简单的查询和 Access 为其选择的执行计划有疑问。

查询是这种形式

SELECT somethings
FROM A INNER JOIN (B INNER JOIN (C INNER JOIN D ON ...) ON ...) ON ...
WHERE A.primaryKey= 1 AND D.d = 2;

C 和 D 的行数相对较少。A 和 B 有几千行。

返回 2 行的查询(不确定这是否相关)真的很慢。它在 17 秒内运行。如果我删除AND D.d = 2where 子句的一部分,查询现在返回 4 行并立即运行。

所以我的理解是,JET 引擎可以在没有过滤器的情况下立即在 Dd 上运行查询,然后立即执行所述过滤器(仅过滤 4 行)。D.d = 2因此,使用过滤器运行查询不应该太长。

我尝试创建一个没有过滤器的子查询,并将其包含在另一个只过滤结果的查询中,但它仍然很慢。我的猜测是 JET 引擎足够聪明,可以“扁平化”子查询,所以结果是一样的。

由于我无法按照我的意愿运行查询,因此我使用了 JETSHOWPLAN 东西,以便 Access 输出它的执行计划。这是我发现的:

对于快速查询(没有D.d = 2的查询),查询计划的第一步是A.primaryKey = 1在 A 表上应用过滤器。这导致超过 30000 行中的 1 行的数据集。然后连接似乎是使用索引从 A 到 D 执行的,数据集从不超过 4 行。

慢查询似乎以相反的顺序执行。D 和 C 先连接,然后D.d = 2进行测试。之后,执行从 C 到 A 的连接。通过这种方式,需要从 D 连接到 C、从 C 连接到 B 以及从 B 连接到 A 的数据要大得多。当所有的 JOIN 都被执行并且 beforeA.primaryKey=1被执行时,数据集将有 120K 行。

有没有办法可以在 Access 上强制执行正确的查询计划?

我希望我很清楚。让我知道是否应该发布查询计划。我没有,因为它们很大。

提前致谢,

mp

4

2 回答 2

2

用VBA代码做吗?想法是取出慢的部分并执行快速返回的查询,然后将慢的部分附加到sql中。

db.execute "select * from qryFast inner join d on qryfast.dkey = d.d where d.d = 2

不,模块中的 VBA 代码与子查询不同。@HansUp 已向我们说明,如上所示,一步执行代码不会提高性能。如果您熟悉在模块中编写代码,您应该能够在内存中快速获得结果,但是在需要的地方获取输出可能会更慢。


换句话说,您应该能够快速将 qryFast 的结果放入内存中的记录集,然后在 qryFast.dkey = d 上应用过滤器,并且还可以从 'select * from tableD where d=2' 快速获取记录集从 tableD 中查找您想要的相关信息,但是将所有这些东西从内存中取出并放到前端可以访问的地方可能需要比他们现在等待的 17 秒更长的时间。


实际上,如果您将 qryFast 更改为包含 dkey = 2 的条件(或任何 pk 在 tableD 上的条件),它可能会踢得够呛


另一个想法:有 3 个查询,qryFast、qryD 和 qryFastWithD 加入两者。我只是在这里抛出想法。


或者,正如您在评论中所说,尝试在子查询中包含查询的不同部分,但我认为优化器不会被这种技巧所愚弄,如果将其中的一部分移动到子查询中没有'不工作。无论如何,无论什么有效,都接受它。

于 2012-01-27T18:03:09.243 回答
2

我终于通过混合起来让它工作,直到查询计划者同意我的意见。我在子查询中隔离了“A.primaryKey= 1”,以确保它在 A 加入 B 之前执行。它是这样的:

SELECT ... 
FROM (SELECT ... FROM A WHERE a.primaryKey=1) AS qryA
   INNER JOIN B ...
WHERE D.d = 2;
于 2012-01-28T02:21:21.237 回答