我在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])
任何改进这些类型计算的提示都会有很大帮助!!
答案 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
或使用以下查询。它仍然具有二次成本,但单个查询的效果始终高于对DCount
,DSum
或DLookup
的多次调用。
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]
。