【发布时间】:2012-01-27 17:14:50
【问题描述】:
我有一个相对简单的查询和 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 上强制执行正确的查询计划?
我希望我很清楚。让我知道是否应该发布查询计划。我没有,因为它们很大。
提前致谢,
mp
【问题讨论】:
-
由于您无法向查询规划器提供提示,我怀疑您是 SOL。如果这对性能至关重要,您可以将查询的快速部分附加到临时表中,并将其用于另一个
D.d = 2查询。我知道这听起来很糟糕(确实如此!),但我不知道除了忍受你现在的单个查询的缓慢之外你还能做什么。 -
@HansUp:感谢您的意见。我担心我将不得不使用如此丑陋的黑客,但如果我找不到任何其他解决方案,我将不得不使用一个。我的用户每天都在等待这个查询的结果几次,而 17 秒是很长的时间,而你所做的只是盯着屏幕。
标签: ms-access sql-execution-plan sql-optimization