Добавление фильтров в подзапрос из CTE вчетверо увеличивает время выполнения

#oracle #reporting-services #subquery

#Oracle #службы отчетов #подзапрос

Вопрос:

Я работаю над существующим запросом для отчета SSRS, который фокусируется на агрегированных данных финансовой помощи, разделенных на 10 агрегатов. Пользователь хочет иметь возможность выбирать учащихся, включенных в эти агрегированные данные, на основе новых или возвращаемых и «выбранных для проверки». Для нового / возвращаемого статуса я добавил CTE, чтобы вернуть самую раннюю дату приема для учащегося. 2 из 10 полей данных создаются подзапросом. Я пытался в течение 3 дней заставить подзапрос использовать поля CTE для фильтра, но они не будут работать. Либо они игнорируются, либо я получаю ошибку «не группируется по выражению». Если я помещаю соединение с CTE в подзапрос, время запроса увеличивается с 45 секунд до 400 секунд. Это не должно быть так сложно! Чего мне не хватает? Я добавил часть кода … 3 фрагмента работают, а paid_something — нет.

 with stuStatus as
(select 
person_uid, min(year_admitted) admit_year
from academic_study
where aid_year between :AidYearStartParameter and :AidYearEndParameter 
group by person_uid)
--- above code added to get student information not originally in qry

select
  finaid_applicant_status.aid_year   
  , count(1) as fafsa_cnt           --works
  , sum(                           --works
    case 
      when (
        package_complete_date is not null
       and admit.status      is not null
     ) 
    then 1
  else 0
end
  ) as admit_and_package


 , (select count(*)               --does't work
from (
select distinct award_by_aid_year.person_uid
      from 
       award_by_aid_year
     where 
       award_by_aid_year.aid_year = finaid_applicant_status.aid_year
       and award_by_aid_year.total_paid_amount > 0  )dta
 where 
   (
    (:StudentStatusParameter = 'N' and stuStatus.admit_year = finaid_applicant_status.aid_year)
    OR 
    (:StudentStatusParameter = 'R' and stuStatus.admit_year <> finaid_applicant_status.aid_year)
    OR :StudentStatusParameter = '%'
       )
  ) 
  as paid_something

  , sum(                           --works
    case 
     when exists (
       select 
         1 
    from 
      award_by_person  abp
    where 
      abp.person_uid            = fafsa.person_uid
      and abp.aid_year          = fafsa.aid_year
      and abp.award_paid_amount > 0
  ) and fafsa.requirement is not null
    then 1
  else 0
end
 ) as paid_something_fafsa

from
 finaid_applicant_status
 join finaid_tracking_requirement fafsa
on finaid_applicant_status.person_uid = fafsa.person_uid
and finaid_applicant_status.aid_year  = fafsa.aid_year
and fafsa.requirement                 = 'FAFSA'
  left join finaid_tracking_requirement admit
on finaid_applicant_status.person_uid  = admit.person_uid
and finaid_applicant_status.aid_year   = admit.aid_year
and admit.requirement                  = 'ADMIT'
and admit.status                      in ('M', 'P')
  left outer join stuStatus
on finaid_applicant_status.person_uid = stuStatus.person_uid

where
  finaid_applicant_status.aid_year between :AidYearStartParameter and :AidYearEndParameter 
 and (
   (:VerifiedParameter = '%') OR
   (:VerifiedParameter <> '%' AND finaid_applicant_status.verification_required_ind = :VerifiedParameter)
     )
    and 
           (
            (:StudentStatusParameter = 'N' and (stuStatus.admit_year IS NULL OR stuStatus.admit_year = finaid_applicant_status.aid_year ))
           OR 
           (:StudentStatusParameter = 'R' and stuStatus.admit_year <> finaid_applicant_status.aid_year)
           OR :StudentStatusParameter = '%'
             )
group by
  finaid_applicant_status.aid_year
order by
  finaid_applicant_status.aid_year
  

Ответ №1:

Не уверен, помогает ли это, но у вас есть что-то вроде этого:

 select aid_year, count(1) c1,
      (select count(1) 
         from (select distinct person_uid 
                 from award_by_aid_year a 
                 where a.aid_year = fas.aid_year))
  from finaid_applicant_status fas
  group by aid_year;
  

Этот запрос выдает ORA-00904 FAS.AID_YEAR invalid identifier . Это потому, что fas.aid_year вложен слишком глубоко в подзапрос.

Если вы можете изменить свой подзапрос с select count(1) from (select distinct sth from ... where year = fas.year) на select count(distinct sth) from ... where year = fas.year , тогда у него есть шанс сработать.

 select aid_year, count(1) c1,
       (select count(distinct person_uid) 
          from award_by_aid_year a 
          where a.aid_year = fas.aid_year) c2
  from finaid_applicant_status fas
  group by aid_year
  

Вот упрощенная демонстрация, показывающая нерабочие и рабочие запросы. Конечно, ваш запрос намного сложнее, но это то, что вы могли бы проверить.

Также, возможно, вы можете использовать dbfiddle или sqlfiddle для настройки некоторого тестового примера? Или покажите нам образец (анонимизированных) данных и требуемый вывод для них?