慢速MS访问查询(使用DSum和DCount函数)

时间:2017-11-08 15:42:25

标签: sql ms-access

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

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

MyTable的:

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  

更改为MyQuery:

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上的表达式生成器中键入):

累积产品:

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])

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

1 个答案:

答案 0 :(得分: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] <= A.[No]替换为B.[Date] <= A.[Date]