如何让MS-Access为我的查询选择不同/正确的执行计划

时间:2012-01-27 17:14:50

标签: ms-access sql-execution-plan sql-optimization

我遇到一个相对简单的查询问题,执行计划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秒。如果我删除where子句的AND D.d = 2部分,则查询现在返回4行并立即运行。

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

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

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

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

慢速查询似乎是按逆转顺序执行的。首先连接D和C,然后测试D.d = 2。之后,执行从C到A的连接。通过这种方式,需要从D到C,从C到B以及从B到A连接的数据要大得多。当执行所有JOIN并且在执行A.primaryKey=1之前,数据集将具有120K行。

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

我希望我很清楚。如果我发布查询计划,请告诉我。我没有,因为它们很大。

提前致谢,

熔点

2 个答案:

答案 0 :(得分: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中快速获取记录集,其中d = 2'从tableD中查找您想要的相关信息,但是将所有内容从内存中移除到前端可以访问它的位置可能需要的时间超过他们现在等待的17秒。


事实上,如果你改变qryFast以包含dkey = 2的条件(或pD在tableD上的任何东西),它可能会在裤子中充分踢它


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


或者,正如您在评论中所说,尝试在子查询中包含查询的不同部分,但我认为优化器不会被这样的技巧所欺骗,如果将其中一部分移动到子查询中查询无效。 无论如何,无论如何,都要接受它。

答案 1 :(得分:2)

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

SELECT ... 
FROM (SELECT ... FROM A WHERE a.primaryKey=1) AS qryA
   INNER JOIN B ...
WHERE D.d = 2;