使用来自父级的相同表来使用子查询优化Oracle查询

时间:2012-07-27 13:34:43

标签: sql asp.net-mvc-3 performance optimization oracle10g

我正在开发一个MVC 3项目,其中一些报告将在代码中生成SQL查询,然后在Oracle 10g数据库上执行它们。此外,我理解SQL注入攻击,所有值都来自下拉列表,而不是文本输入,所以这不是问题。我生成的查询“工作”,但它们非常慢。以下是报告工作原理的快速说明:

用户选择了总帐帐户和其他过滤器。 用户选择了一个时间段(会计年度,季度或特定月份)。 用户运行报告。

报告显示总帐帐户(或者如果选择显示所有帐户的帐户)以及每个月花费的值以及该帐户的总计。查询的输出如下所示:

帐号和姓名|第1个月|第2个月|等|总

在生成SQL代码时动态添加第1个月,第2个月等,因此根据用户选择的内容,可能会或可能不会在结果集中返回它。我该怎么做才能使这个查询更快?当我昨天在整个财政年度(并且只有一个帐户)运行此查询时,它需要10分钟才能完成。我觉得这不是可以接受的性能,并且想让它更快。请记住,我只能对查询本身而不是数据库进行更改,因此不会发生索引(DBA会将所有内容锁定)。查询如下。感谢您提供的任何输入。

SELECT gl.gen_led_acct_nbr, gl.gen_led_acct_scr_nm, bu.bus_unit_txt, gl.gen_led_acct_typ_nm,
  (SELECT SUM(fct.pd_txn_amt) Jun2012
FROM Maintable fct
JOIN Dimtable1 gl1 ON fct.gen_led_acct_key = gl1.gen_led_acct_key
JOIN Dimtable2 bu1 ON fct.bus_unit_key = bu1.bus_unit_key
JOIN Dimtable3 cc1 ON fct.cst_ctr_key = cc1.cst_ctr_key
JOIN Dimtable4 oc1 ON fct.cst_ctr_own_org_key = oc1.org_cd_key
JOIN Dimtable5 dt1 ON fct.chk_dt_key          = dt1.dt_key
WHERE gl1.gen_led_acct_nbr = gl.gen_led_acct_nbr
  AND bu1.bus_unit_txt       = bu.bus_unit_txt
  AND dt1.fscl_mo_nbr        = 1
  AND dt1.fscl_yr_nbr        = 2012
  GROUP BY gl1.gen_led_acct_nbr, gl1.gen_led_acct_scr_nm, bu1.bus_unit_txt) Jun2012,
(SELECT SUM(fct.pd_txn_amt) Jun2012
FROM Maintable fct
JOIN Dimtable1 gl2 ON fct.gen_led_acct_key = gl2.gen_led_acct_key
JOIN Dimtable2 bu2 ON fct.bus_unit_key = bu2.bus_unit_key
JOIN Dimtable3 cc2 ON fct.cst_ctr_key = cc2.cst_ctr_key
JOIN Dimtable4 oc2 ON fct.cst_ctr_own_org_key = oc2.org_cd_key
JOIN Dimtable5 dt2 ON fct.chk_dt_key          = dt2.dt_key
WHERE gl2.gen_led_acct_nbr = gl.gen_led_acct_nbr
  AND bu2.bus_unit_txt       = bu.bus_unit_txt
  AND dt2.fscl_mo_nbr        = 2
  AND dt2.fscl_yr_nbr        = 2012
  GROUP BY gl2.gen_led_acct_nbr, gl2.gen_led_acct_scr_nm, bu2.bus_unit_txt) Jul2012,

(etc...)
--The sub queries above can be repeated up to an indefinite amount of times (maybe 20+), but with a different fscl_mo_nbr (and possibly fscl_yr_nbr as well)

FROM Maintable fct
JOIN Dimtable1 gl ON fct.gen_led_acct_key = gl.gen_led_acct_key
JOIN Dimtable2 bu ON fct.bus_unit_key = bu.bus_unit_key
JOIN Dimtable3 cc ON fct.cst_ctr_key = cc.cst_ctr_key
JOIN Dimtable4 oc ON fct.cst_ctr_own_org_key = oc.org_cd_key
JOIN Dimtable5 dt ON fct.chk_dt_key         = dt.dt_key
WHERE gl.gen_led_acct_nbr = 000000
  AND bu.bus_unit_txt       = 'AAAAA'
  AND dt.fscl_mo_nbr        = 1
  AND dt.fscl_yr_nbr        = 2012
GROUP BY gl.gen_led_acct_nbr, gl.gen_led_acct_scr_nm, bu.bus_unit_txt, gl.gen_led_acct_typ_nm
ORDER BY gl.gen_led_acct_nbr, gl.gen_led_acct_typ_nm

1 个答案:

答案 0 :(得分:1)

您的评论:

--The sub query above can be repeated up to another 11 times, but with a different dt1.fscl_mo_nbr

建议一种解决方案是使用“in”而不是“=”,如:

AND dt1.fscl_mo_nbr        in (1, 2, . . . )

然后,您希望将t1.fscl_mo_nbr添加到group by子句中。

我还注意到这是一个很大的相关子查询,这可能也会破坏性能。类似下面的内容应该简化查询并帮助它更快地运行:

SELECT gl.gen_led_acct_nbr, gl.gen_led_acct_scr_nm, bu.bus_unit_txt, 
       gl.gen_led_acct_typ_nm,
       sum(case when year = 2012 and dt.fscl_mo_nbr = 1 then fct.pd_txn_amt end) as Jun2012,
       sum(case when year = 2012 and dt.fscl_mo_nbr = 2 then fct.pd_txn_amt end) as Jul2012,
        etc. 
      FROM Maintable fct
           JOIN Dimtable1 gl ON fct.gen_led_acct_key = gl.gen_led_acct_key
           JOIN Dimtable2 bu ON fct.bus_unit_key = bu.bus_unit_key
           JOIN Dimtable3 cc ON fct.cst_ctr_key = cc.cst_ctr_key
           JOIN Dimtable4 oc ON fct.cst_ctr_own_org_key = oc.org_cd_key
           JOIN Dimtable5 dt ON fct.chk_dt_key          = dt.dt_key
       where dt.fscl_mo_nbr  in (1, 2, 3 . . .)
            AND dt.fscl_yr_nbr  = 2012
       GROUP BY gl.gen_led_acct_nbr, gl.gen_led_acct_scr_nm,
                bu.bus_unit_txt, dt.fscl_mo_nbr

(请原谅任何打字错误......我从所有别名中删除了“1”后缀。)