0

我有一个实现 SQL 的 Access 项目,并且我一直致力于优化协调过程。此过程使用将所有表格链接在一起的凭证系统。每个表中的每条记录都有一个与金额相关联的特定凭证 ID。优惠券本身是唯一的,可以包含多个优惠券编号,如下所示。

Table: Rec_Vouchers
v_id       v_num      voucher
1          12341234   12341234
2          10101010   10101010;22222222
2          22222222   10101010;22222222
...

我有 8 个由这些凭证 ID 链接的其他表。我正在尝试将所有表格连接在一起,以显示具有特定凭证 ID 的每个表格的不同凭证 ID 和凭证以及所有相应的金额总和。以下是查询和结果示例。我已经为此工作了一段时间,它开始让我头疼。此查询有效,但需要很长时间才能执行。

此外,在某些时候,我需要将所有这些值匹配在一起,以确定凭证是“匹配”、“不匹配”还是“有差异匹配”。到目前为止,我只尝试在下面的代码中创建一个函数,该函数将返回字符串值“M”、“NM”或“MwD”,以显示在每个凭证的列中。同样,这有效,但需要很长时间。我还尝试让 VBA 使用查询返回的记录集来做脏活,这也需要很长时间,但只要在我的 sql 查询中创建函数就不会了。这是下一步,所以如果你能帮助解决所有这些问题,那就太好了,但我真的只需要优化我给出的查询。

我知道这有很多事情要处理,所以如果您需要更多信息,请告诉我。任何帮助,将不胜感激。谢谢!

select a.v_id, a.voucher,
(Select sum(b.amount) from rec_month_4349_test b where b.voucher = a.v_id) as GL, 
(Select sum(c.payments) from rec_daily_balancing_test c where c.voucher = a.v_id) as DB,
(Select count(x.v_num) from rec_vouchers x where a.v_id = x.v_id and x.v_num not like 'ONL%') as GLcount,
(select count(c.batch_num) from rec_daily_balancing_test c where a.v_id = c.voucher) as DBcount,
(select sum(d.amount) from rec_ed_test d where a.v_id = d.voucher) as ED, 
(select sum(e.batchtotal) from rec_eft_batches_new_test e where a.v_id = e.voucher) as EFT, 
(select sum(f.batchtotal) from rec_check_batch_test f where a.v_id = f.voucher) as CHK, 
(select sum(g.idxtotal) from rec_lockbox_test g where a.v_id = g.voucher) as LBX, 
(select sum(h.amount) from rec_lcdl_test h where a.v_id = h.voucher) as LCDL, 
((select sum(i.payment_amount) from rec_electronic_files_test i where a.v_id = i.voucher) + (select sum(j.amount) from rec_electronic_edits_test j where a.v_id = j.voucher)) as Elec
from rec_vouchers a
group by a.v_id, a.voucher

Sample Results:
v_id     GL         DB         GLcount   DBcount     ED     EFT     CHK     LBX     LCDL     Elec
6131     19204.00   19204.00   1         1           NULL   NULL    NULL    NULL    NULL     NULL
6132     125330.00  14932.00   6         6           NULL   NULL    NULL    NULL    NULL     14932.00
6133     18245.00   NULL       2         0           NULL   NULL    NULL    NULL    NULL     NULL
6175     98.93      98.93      1         1           NULL   98.93   NULL    NULL    NULL     NULL 
4

3 回答 3

0

很容易说编写此查询的“传统”方法是from使用join谓词将表移动到子句。但是,这可能会引入不必要的笛卡尔积。你的方法其实还可以;left join另一种方法是对聚合子查询执行s 。

性能上的杀手可能是由于在表格中循环查找匹配项。where您可以通过在每个查询的子句中使用的字段上建立索引来显着提高性能。例如,对于前两个表,您应该在rec_month_4349_test(voucher)和上有一个索引rec_daily_balancing_test(voucher)

在 SQL Server 中,您还可以通过在索引中包含用于求和的变量来进一步优化此查询。以下索引会更好: rec_month_4349_test(voucher, amount)rec_daily_balancing_test(voucher, payments)(或者您可以将它们包含在索引中而不可搜索,这有点高级)。

这种优化适用于大多数数据库(索引扫描而不是索引查找)。我不知道它是否适用于 MS Access(我尽可能避免使用的软件产品)。

请记住,您需要对所有表执行此操作。

于 2013-10-29T22:31:22.523 回答
0

相关子查询是我最喜欢的选择。

我建议编写子查询并连接每个表,以便每个表都可以利用它们的索引。

在每个表上创建以下索引并查看以下查询。

rec_vouchers

聚集索引(v_id,凭证)

过滤的非聚集索引 (v_num) WHERE v_num NOT LIKE 'ONL%'

rec_month_4349_test

非聚集索引(凭证)包含(金额)

rec_daily_balancing_test

非聚集索引(凭证)包括(付款)

rec_ed_test

非聚集索引(凭证)包含(金额)

rec_eft_batches_new_test

非聚集索引(凭证)包括(batchtotal)

rec_check_batch_test

非聚集索引(凭证)包括(batchtotal)

rec_lockbox_test

非聚集索引(凭证)包括(idxtotal)

rec_lcdl_test

非聚集索引(凭证)包含(金额)

rec_electronic_files_test

非聚集索引(凭证)包括(payment_amount)

rec_electronic_edits_test

非聚集索引(凭证)包含(金额)

    SELECT a.v_id,a.voucher
            ,t1.GL ,t2.DB ,t3.GLcount
            ,t4.DBcount ,t5.ED ,t6.EFT
            ,t7.CHK ,t8.LBX ,t9.LCDL
            ,(t10.Elec1+t11.Elec2) AS Elec
    FROM
    ( SELECT  t0.v_id ,t0.voucher
        FROM rec_vouchers t0
        GROUP BY t0.v_id ,t0.voucher
    )a
    JOIN
    ( SELECT SUM(b.amount) AS GL,b.voucher
      FROM rec_month_4349_test b
      Group By b.voucher
    ) t1
        ON a.v_id=t1.voucher
    JOIN
    ( SELECT SUM(c.payments) AS DB,c.voucher
      FROM rec_daily_balancing_test c
      Group By c.voucher
    ) t2 
        ON a.v_id=t2.voucher
    JOIN
    ( SELECT COUNT(x.v_num) AS GLcount,x.v_id
      FROM rec_vouchers x
      WHERE x.v_num NOT LIKE 'ONL%'
      Group BY x.v_id
    ) t3 
        ON a.v_id=t3.v_id
    JOIN
    ( SELECT COUNT(c.batch_num) AS DBcount,c.voucher
      FROM rec_daily_balancing_test c
      Group By c.voucher
    ) t4 
        ON a.v_id=t4.voucher
    JOIN
    ( SELECT SUM(d.amount) AS ED,d.voucher
      FROM rec_ed_test d
      Group By d.voucher
    ) t5 
        ON a.v_id=t5.voucher
    JOIN
    ( SELECT SUM(e.batchtotal) AS EFT,e.voucher
      FROM rec_eft_batches_new_test e
      Group By e.voucher
    ) t6 
        ON a.v_id=t6.voucher
    JOIN
    ( SELECT SUM(f.batchtotal) AS CHK,f.voucher
      FROM rec_check_batch_test f
      Group By f.voucher
    ) t7 
        ON a.v_id=t7.voucher
    JOIN
    ( SELECT SUM(g.idxtotal) AS LBX,g.voucher
      FROM rec_lockbox_test g
      Group By g.voucher
    ) t8 
        ON a.v_id=t8.voucher
    JOIN
    ( SELECT SUM(h.amount) AS LCDL,h.voucher
      FROM rec_lcdl_test h
      Group By h.voucher
    ) t9 
        ON a.v_id=t9.voucher
    JOIN
    ( SELECT SUM(i.payment_amount) AS Elec1,i.voucher
        FROM rec_electronic_files_test i
        GROUP BY i.voucher
    ) t10 
        ON a.v_id=t10.voucher
    JOIN
    ( SELECT SUM(j.amount) AS Elec2,j.voucher
        FROM rec_electronic_edits_test j
        GROUP BY j.voucher
    ) t11
        ON a.v_id=t11.voucher
于 2013-10-31T16:12:37.143 回答
0

不确定这是否是最佳解决方案,但我为每个表创建了单独的视图以选择凭证以及每个特定凭证的金额总和。每个视图看起来都类似于以下内容:

rec_sum4349

SELECT voucher, sum(amount) AS GL
FROM rec_month_4349_test
GROUP BY voucher

然后,我有一个视图,它使用以下完整连接将所有单独的视图组合在一起:

rec_vouch_test

SELECT a.voucher, a.GL, b.DB
FROM rec_sum4349 a
FULL JOIN rec_sumDB b
ON a.voucher = b.voucher
WHERE a.voucher IS NOT NULL AND a.voucher <> ''
ORDER BY a.voucher

在我看到这非常有效之后,我为需要汇总金额的其余表创建了视图,并将它们添加到上面的视图中。结果正是我想要的,运行时间从近 2 分钟缩短到几秒钟!感谢所有的帮助。现在开始匹配一切!

于 2013-10-30T15:58:10.783 回答