【问题标题】:MS Access performace dlookup on query or dsum?查询或 dsum 中的 MS Access 性能 dlookup?
【发布时间】:2010-08-13 14:23:50
【问题描述】:

我知道所有域聚合函数都很慢,但我正在寻找最小的弊端。

以下两个选项哪个更快?

  1. 创建一个查询,该查询将按唯一值分组并对总数求和。使用 dlookup 从查询中获取我的总和。
  2. 在主表上执行 dsum,条件与选项 1 中的 GROUP BY 列相同?

编辑 1
我的问题是一个通用问题,我在很多情况下都想知道,但下面是目前正在考虑的具体情况。

在我的时间输入详细信息子表单中,我需要显示在这项工作中使用了多少材料。文本框的控制源如下所示:

=DLookUp("[SumOfPrice]","tm_materialsUsedByPart","[Part]=" & [cmbPart])

tm_materialsUsedByPart 当前是一个查询,它正在汇总所有使用的材料。

使用具有基本相同条件的 dsum 会更快,还是执行查询然后获取符合我的条件的单行会更快?

【问题讨论】:

    标签: performance ms-access


    【解决方案1】:
    =DLookUp("[SumOfPrice]","tm_materialsUsedByPart","[Part]=" & [cmbPart])
    

    没有看到 tm_materialsUsedByPart 的 SQL,我们只能猜测它在做什么。也许它会读取整个表或一组 JOINed 表,并使用 GROUP BY 将 Sum(Price) 聚合为 SumOfPrice。

    对基础表进行 DSum 应该更快,尤其是在 [Part] 字段被索引的情况下。

    =DSum("[Price]", "tblRowSource", "[Part]=" & Me.cmbPart)
    

    这样,您要求数据库引擎仅读取包含您想要的 [Part] 值的行。您的 materialsUsedByPart 查询需要读取所有行,然后提取所需的单个组值。不要那样做。让数据库引擎读取尽可能少的行以获得所需的信息。

    编辑:我错了,针对基表的 DSum 比针对聚合查询的 DLookup 更快。正如@Thomas 建议的那样,在我的简单测试中,这两种情况的查询计划都是相同的。

    这是我的查询,qryMinutesPerClient

    SELECT Time_Sub.CLIENT_ID, Sum(Time_Sub.MINUTES) AS SumOfMINUTES
    FROM Time_Sub
    GROUP BY Time_Sub.CLIENT_ID;
    

    然后

    DLookup("SumOfMINUTES","qryMinutesPerClient","CLIENT_ID = 11111")
    

    这个查询计划的结果:

    - Inputs to Query -
    Table 'Time_Sub'
    - End inputs to Query -
    
    01) Restrict rows of table Time_Sub
          using rushmore
          for expression "Time_Sub.CLIENT_ID=11111"
    02) Group result of '01)'
    

    还有

    DSum("MINUTES","Time_Sub","CLIENT_ID = 11111")
    

    计划是一样的:

    - Inputs to Query -
    Table 'Time_Sub'
    - End inputs to Query -
    
    01) Restrict rows of table Time_Sub
          using rushmore
          for expression "CLIENT_ID=11111"
    02) Group result of '01)'
    

    最重要的性能问题涉及“使用 rushmore”,这是可能的,因为我的 CLIENT_ID 字段已编入索引。如果没有该索引,则无法在查询计划中使用 Rushmore,并且 DLookup 和 DSum 方法都明显比使用 Rushmore 慢。

    【讨论】:

    • 所以 MS Access 还不够智能,无法像我目前那样使用索引? [零件] 已编入索引。此外,您对 tm_materialsUsedByPart 查询的作用有一个很好的看法,它正在执行单个 JOIN。
    • 我喜欢@Thomas 的建议,即在表单的记录源中包含总计,只要记录源可以是只读的,我就会这样做。如果您需要在时间条目详细信息子表单中编辑记录源值,请使用 DSum()。
    • Access 没有任何作用。但是 Jet/ACE 数据库引擎可以。如果您想了解它如何优化查询,您可以使用 Google SHOWPLAN,但这无助于了解域聚合函数的工作原理。通常,Jet/ACE(和域聚合函数)将使用所有索引,但有少数例外(例如不与子查询一起使用,有时它仅在比较的一侧使用索引)。
    【解决方案2】:

    还有两个其他选项:相关子查询或派生表。相关子查询需要将查询中的列声明为自身为查询:

    Select ...
     , ( Select Sum(Foo)
         From Bar
         Where Bar.FK = Gamma.PK ) As Total
    From Gamma
    

    在 Access 中,派生表将涉及创建一个保存的查询来执行所有总计,然后将该查询加入到您的主查询中。尽管可以在主查询中动态构建总计查询,但我的经验是,Access 对保存的查询和标准连接更满意。如果您向我们展示更多关于您要完成的工作,您可能会得到一些更具体的答案。

    编辑

    IMO,最快的解决方案是通过保存的查询将总数包含在表单的源中。即,不使用 DLookup 或 DSum,而是通过加入计算总计的查询将总计作为表单的 RecordSource 的一部分。

    其次,要真正了解哪个函数的性能最好,您需要对数据进行一些性能测试。我的猜测是两者之间的性能相当。即使对存储的查询使用 DLookup,Access 也应该足够聪明,可以注入过滤条件,并实际上获得与使用 DSum 相当的执行计划。

    最后,如果您要使用域聚合函数,并且 DLookup 中使用的查询的唯一目的是为此表单提供总计,那么 IMO,使用 DSum 更有意义,因为它使您的意图域聚合函数的使用对读者来说更清楚。

    【讨论】:

    • 我添加了编辑 1。希望这会让我的要求更清楚。
    • 我无法将该字段添加到表单的记录源,因为表单数据需要可编辑。在记录源中使用 GROUP BY 查询将不允许数据可编辑。
    • @jeffreymb - 记录源中不需要分组依据。如果您使用已保存的查询,则只有已保存的查询具有分组依据。主查询不会。如果您在记录源中使用关联子查询,则只有它有一个分组依据,而不是主查询。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-12-11
    • 2014-08-03
    • 2017-01-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多