如何在相关表中优化此SQL查询求和量?

时间:2013-10-29 21:49:38

标签: sql sql-server vba ms-access relational-database

我有一个实现SQL的Access项目,我一直在努力优化协调过程。此过程使用凭证系统将所有表链接在一起。 每个表中的每个记录都有一个特定的凭证ID,其中包含金额。 优惠券本身是独一无二的,可以包含多个优惠券号码,如下所示。

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

我有8个其他表格,这些表格通过这些凭证ID链接。我正在尝试将所有表连接在一起,以显示distict凭证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 

3 个答案:

答案 0 :(得分:0)

很容易说,编写此查询的“传统”方法是使用from谓词将表移动到join子句。但是,这可能会引入不必要的笛卡尔积。你的方法确实没问题;替代方案是对聚合子查询进行left join

表现上的杀手可能是因为在桌子上骑自行车以找到比赛。通过在每个查询的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(我尽可能避免使用的软件产品)。

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

答案 1 :(得分: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分钟减少到几秒钟!谢谢你的帮助。现在开始匹配所有内容!

答案 2 :(得分:0)

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

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

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

<强> rec_vouchers

聚集索引(v_id,凭证)

过滤的非群集索引(v_num)WHERE v_num不喜欢'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