【问题标题】:Slow MS Access Query (Using DSum & DCount Functions)慢速 MS 访问查询(使用 DSum 和 DCount 函数)
【发布时间】:2017-11-08 15:42:25
【问题描述】:

我在 Microsoft Access 中遇到问题,我的查询计算速度非常慢(需要数小时和数小时)。此查询正在读取一个包含 150,000 条记录的表,每条记录属于 4,000 个唯一组之一(称为 API_10)。

查询的目标是计算运行累计生产值(由 API_10日期 组织),以便运行累计生产在每个新的 API_10 组。表中的每条记录都有一个名为 No 的字段,它是 MS Access 计算的自动编号,以便表具有主键。我所描述的示例如下所示:

我的表:

No     API_10       Date           Production
1      1            1/1/2010       1000
2      1            2/1/2010       500
3      2            7/1/2014       300
4      2            8/1/2014       400  

我的查询:

No       API_10         Date              Production   Cumulative_Production
1        1              11/1/2010         1000         1000
2        1              12/1/2010         500          1500
3        2              27/1/2014         300          300
4        2              28/1/2014         400          700

以下是用于在 MyQuery 中创建 Cumulative_Production 列的代码示例(在 MS Access 上的 Expression Builder 中键入):

累积产量:

DSum("[Production]","[MyTable]","[API_10]='" & [API_10] & "' AND [No]<=" & [No])

请注意,这是实际查询/表的简化版本。真正的查询还会计算另一个名为 Normalized_Prod_Month 的字段,它计算每个唯一 API_10 的生产日期数(从 1 开始),如下所示:

NORMALIZED_PROD_MONTH:

DCount("[Date]","[MyTable]","[API_10]='" & [API_10] & "' AND [No]<=" & [No])

任何改进这些类型计算的技巧都会有很大帮助!!

【问题讨论】:

    标签: sql ms-access


    【解决方案1】:

    如果您将此查询应用于每条记录,则您必须访问n * (n + 1) / 2 记录。如果所有 4000 个组都有大约相同大小的 38 条记录,您将获得 4000 * 38 * (38 + 1) / 2 = ~ 3 Mio 访问。但这是最好的情况,因为由于n * (n + 1) / 2 的二次性质,较大的组具有过高的成本。

    最好在 VBA 中循环创建运行总和,并且只访问每条记录一次。

    Dim db As DAO.Database, rs As DAO.Recordset
    Dim lastNoApi As Long, runningSum As Long
    
    Set db = CurrentDb
    Set rs = db.OpenRecordset("SELECT * FROM MyTable ORDER BY NoAPI_10, Date")
    Do Until rs.EOF
        If rs!NoAPI_10 <> lastNoApi Then
           runningSum = 0 
           lastNoApi = rs!NoAPI_10
        End If
        runningSum = runningSum + rs!Production
    
        'TODO: insert the result into a temporary table
    
        rs.MoveNext
    Loop
    rs.Close: Set rs = Nothing
    db.Close: Set db = Nothing
    

    或使用以下查询。它仍然具有二次成本,但单个查询总是比多次调用 DCountDSumDLookup 的性能更好。

    SELECT
        A.API_10,
        A.Date,
        A.Production,
        (Select Sum(B.Production)
         FROM MyTable B
         WHERE B.API_10 = A.API_10 And B.[No] <= A.[No]) AS Cumulative_Production
    FROM MyTable AS A
    ORDER BY A.API_10, A.Date;
    

    假设No 列与日期顺序一致。如果日期是唯一的,您还可以将B.[No] &lt;= A.[No] 替换为B.[Date] &lt;= A.[Date]

    【讨论】:

    • 我对 A.NoAPI_10 有点困惑。这些应该是表中的两个单独的字段。 No 是 Autonumber 字段,API_10 是组
    • 好的,您的问题格式错误,这两列之间没有空格,所以我认为列NoAPI_10 上有。现在更改了查询。
    猜你喜欢
    • 1970-01-01
    • 2014-08-03
    • 1970-01-01
    • 2018-07-09
    • 1970-01-01
    • 1970-01-01
    • 2021-04-12
    • 2019-02-18
    • 1970-01-01
    相关资源
    最近更新 更多