我正在开发一个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
答案 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”后缀。)