【问题标题】:Optimize MS ACCESS SQL with Nested Sub-Queries使用嵌套子查询优化 MS ACCESS SQL
【发布时间】:2014-04-17 02:49:59
【问题描述】:

问题

我在一个 MS Access 数据库中工作,该数据库将发票条目转换为会计总帐代码。数据库有时会“拆分”记录(例如,包含单一费用的发票可能需要将该费用分配给多个不同的业务部门)。在使用 INSERT INTO 查询将“拆分”记录插入数据库表后,我编写了一个 SQL 查询来删除“父”记录。不幸的是,我主要是通过反复试验来编写的,而且运行速度非常慢(我相信这是嵌套子查询的结果)。

我可以做些什么来优化这个查询?

数据库说明

举例来说,如果表格包含以下内容:
[类型]----[费用]----[说明]--------[发票金额]
5000------NoDept------40 SQL 头盔--------------$500

该记录的拆分可能如下所示:
[类型]----[费用]----[说明]--------[发票金额]
5000--------NoDept------40 SQL 头盔-------------$500
5000-----NoDept-----40 SQL Helmets_%Split----$200
5000-----NoDept-----40 SQL Helmets_%Split----$75
5000-----NoDept-----40 SQL Helmets_%Split----$225

在我的 SQL 语句清理完表之后,它应该是这样的:
[类型]----[费用]----[说明]--------[发票金额]
5000-----NoDept-----40 SQL Helmets_%Split----$200
5000-----NoDept-----40 SQL Helmets_%Split----$75
5000-----NoDept-----40 SQL Helmets_%Split----$225

当前 SQL

DELETE * 
FROM [tblManipulateW] 
WHERE EXISTS 
    (SELECT * FROM 
        (SELECT SUM([Dupe].[Invoice Amount]) AS [SumInvoices], 
    [Dupe].[Type], 
        [Dupe].[Charge], 
        LEFT([Dupe].[Description], Len([Dupe].[Description]) - 7) As DescriptionLessSplit 
        FROM [tblManipulateW] AS [Dupe] 
        GROUP BY [Dupe].[Type], 
        [Dupe].[Charge], 
        LEFT([Dupe].[Description], LEN([Dupe].[Description])-7), 
        [Dupe].[Description] LIKE "*_%Split"
        HAVING [Dupe].[Description] LIKE "*_%Split") AS [Dupe2] 
    WHERE [Dupe2].[DescriptionLessSplit] = [tblManipulateW].[Description] 
    AND [Dupe2].[Type] = [tblManipulateW].[Type] 
    AND ROUND([Dupe2].[SumInvoices],2) = ROUND([tblManipulateW].[Invoice Amount],2) 
    AND [Dupe2].[Charge] = [tblManipulateW].[Charge]);

SQL解释

子子查询构建了一个名为 Dupe2 的查询,该查询查找所有已拆分的类似费用并返回:
- 他们发票金额的总和
- 他们的描述少了短语“_%Split”
- 他们的收费代码
- 他们的类型代码

子查询正在检查主表中的项目何时与从子查询(即 Dupe2)返回的项目相匹配。如果一个条目确实匹配每个字段,那么它将被删除。

非常感谢您看这个!

【问题讨论】:

    标签: sql performance ms-access optimization subquery


    【解决方案1】:

    我建议在您的 tblManipulateW 表中再添加两列:一个自动增量主键 (ID) 和一个 ParentID 列(可以是 null),以便拆分可以选择性地识别其父母。原因如下。

    想象一下你有这样一个主键。并假设您的 500 美元的“40 SQL Helmets”条目最初具有 ID 25。现在,当您执行拆分例程时,您实际上可以为所有子拆分设置 ParentID,而不是在 Description 上附加一些文本到 25. 现在你可以很容易地找到所有的父分裂——它们都是有孩子的分裂:

    select t1.*
    from tblManipulateW as t1
    inner join tblManipulateW as t2
    on t1.ID = t2.ParentID
    

    这个查询很容易优化——事实上,如果您将ID 列设置为自动增量主键,Access 会自动为您完成。还有一个额外的好处是数据比以前更加规范化(您将父子关系存储在单独的列中,而不是在Description 列中添加一些文本)。

    附录:您还可以进行一项更重要的优化:将ParentID 列设为引用ID 列的外键。以下应该可以做到这一点:*

    alter table tblManipulateW
    add column ParentID long
    constraint ManipulateW_ParentID
    references tblManipulateW (ID)
    on delete set null;
    

    以上完全描述了ParentID 列。最后一行 (on delete set null) 是可选的;如果父拆分被删除,它会自动将拆分中的ParentID 值设置为null,从而帮助保持引用完整性。

    ParentID 设为外键的好处是Access 会将其作为数据库中的索引来实现,这将自动加快我之前展示的连接速度。

    * 请注意,此 SQL 采用 ANSI-92 语法,Access“前端”SQL 编辑器不支持该语法。您需要使用一点 VBA 来执行它:CurrentProject.Connection.Execute "alter table ..."

    【讨论】:

    • Argh- 谈谈“保持简单,愚蠢”是最佳策略的案例!感谢您的洞察力!
    • 很高兴它有帮助。我实际上可以提出另一种优化建议,我回家后会详细修改我的答案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-07-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多