【问题标题】:Optimizing An Oracle Query with Sub-Queries Using Identical Tables From the Parent使用来自父级的相同表优化具有子查询的 Oracle 查询
【发布时间】:2012-07-27 13:34:43
【问题描述】:

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

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

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

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

第 1 个月、第 2 个月等是在生成 SQL 代码时动态添加的,因此根据用户选择的内容,它可能会或可能不会在结果集中返回。我该怎么做才能使这个查询更快?当我昨天对整个财政年度(并且只有 1 个帐户)运行此查询时,它需要 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

【问题讨论】:

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


    【解决方案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”后缀。)

    【讨论】:

    • 我不确定它是如何工作的,因为每个日期都需要是查询返回的结果集中的单独列。
    • 您修改后的查询,使用 SUM 和 CASE 子句肯定似乎有很大帮助。我在整个 2012 财年运行了一个稍微修改过的版本,再次为 1 gl 帐户运行,它在 21 秒内完成,与昨天的 10 分钟相反。感谢您的帮助戈登!我真的很感激。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-11-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多