0

我有一个作为函数的一部分运行的查询,该函数生成一个包含计数、平均值和逗号分隔列表的单行表,如下所示:

select
  (select 
    count(*)
    from vw_disp_details
    where round = 2013
    and rating = 1) applicants,
  (select 
    count(*)
    from vw_disp_details
    where round = 2013
    and rating = 1
    and applied != 'yes') s_applicants,
  (select 
    LISTAGG(discipline, ',')
    WITHIN GROUP (ORDER BY discipline) 
    from (select discipline,
          count(*) discipline_number 
          from vw_disp_details
          where round = 2013
          and rating = 1
          group by discipline)) disciplines,
  (select 
    LISTAGG(discipline_count, ',')
    WITHIN GROUP (ORDER BY discipline)
    from (select discipline,
          count(*) discipline_count
          from vw_disp_details
          where round = 2013
          and rating = 1
          group by discipline)) disciplines_count,
  (select 
    round(avg(util.getawardstocols(application_id,'1','AWARD_NAME')), 2) 
    from vw_disp_details 
    where round = 2013
    and rating = 1) average_award_score,
  (select
    round(avg(age))
    from vw_disp_details
    where round = 2013
    and rating = 1) average_age
from dual;

除了不是 6 个主要子查询,而是有 23 个。

这将返回类似这样的内容(如果它是 CSV):

applicants | s_applicants | disciplines               | disciplines_count | average_award_score | average_age
107        | 67           | "speed,accuracy,strength" | 3                 | 97                  | 23

现在我以编程方式将 where 子句的“rating = 1”部分换成其他表达式。它们都运行得相当快,除了“rating = 1”需要大约 90 秒才能运行,这是因为 vw_disp_details 视图中的 rating 列本身是由子查询编译的:

(SELECT score
FROM read r,
eval_criteria_lookup ecl
WHERE r.criteria_id        = ecl.criteria_id
AND r.application_id       = a.lgo_application_id
AND criteria_description   = 'Overall Score'
AND type                   = 'ABC'
) reader_rank

因此,当函数运行时,这个额外的查询似乎会大大减慢一切。

我的问题是,有没有更好(更有效)的方法来运行这样的查询,基本上只是一系列计数和平均值,我如何重构以优化速度,以便评级 = 1 查询不需要运行 90 秒。

4

3 回答 3

1

您可以选择 MATERIALIZE vw_disp_details VIEW。这将预先计算评级列的值。对于如何保持物化视图的最新状态有多种选择,您可能希望使用 ON COMMIT 子句,以便 vw_disp_details 始终正确。

查看官方文档,看看是否适合您。 http://docs.oracle.com/cd/B28359_01/server.111/b28286/statements_6002.htm

于 2013-03-07T23:36:31.553 回答
0

只需一个即可完成所有大部分查询。而不是这样做:

select
  (select (count(*)                           from my_tab) as count_all,
  (select avg(age)                            from my_tab) as avg_age,
  (select avg(mypkg.get_award(application_id) from my_tab) as_avg-app_id 
from dual;

做就是了:

select count(*), avg(age),avg(mypkg.get_award(application_id)) from my_tab;

然后,也许你可以为其他结果做一些联合。但这一步本身应该会有所帮助。

于 2013-03-07T10:57:24.590 回答
0

我可以通过做两件事来解决这个问题:创建一个只显示我需要的结果的新视图,这让我在速度上获得了边际收益,并且在该视图中将导致延迟的子查询的 where 子句移到视图的 where 子句并将子查询的结果作为视图中的列添加。这仍然会返回相同的结果,这要归功于表中总是会有记录,为视图查询的每一行访问的子查询。

SELECT
  a.application_id,
  util.getstatus (a.application_id) status,
  (SELECT score
    FROM applicant_read ar,
    eval_criteria_lookup ecl
    WHERE ar.criteria_id        = ecl.criteria_id
    AND ar.application_id       = a.application_id
    AND criteria_description   = 'Overall Score'        //THESE TWO FIELDS
    AND type                   = 'ABC'                  //ARE CRITERIA_ID = 15
    ) score
  as.test_total test_total
FROM application a,
  applicant_scores as
WHERE a.application_id = as.application_id(+);

成为

SELECT
  a.application_id,
  util.getstatus (a.application_id) status,
  ar.score,
  as.test_total test_total
FROM application a,
  applicant_scores as,
  applicant_read ar
WHERE a.application_id = as.application_id(+)
AND ar.application_id  = a.application_id(+)
AND ar.criteria_id     = 15;
于 2013-03-11T16:20:48.853 回答