Schema growth in Oracle 11g - oracle

what is the best way to get the schema growth in Oracle? I tried using many of the dba_hist_ tables and none of them seem to get me the size and growth of the schema for a specific time (7day) period. These tables seem to hold tablespace growth information, not # the schema level.
Can somebody help?
Tried the following tables,
dba_hist_tablespace_stat, dba_hist_seg_stat, dba_hist_seg_stat_obj, dba_hist_snapshot etc.

Check this query:
SELECT b.tsname tablspc_name ,
MAX(b.used_size_mb) cur_used_size_mb ,
ROUND(AVG(inc_used_size_mb),2) avg_incr_mb
FROM
(SELECT a.days,
a.tsname ,
used_size_mb ,
used_size_mb - LAG (used_size_mb,1) OVER ( PARTITION BY a.tsname ORDER BY a.tsname,a.days) inc_used_size_mb
FROM
(SELECT TO_CHAR(sp.begin_interval_time,'MM-DD-YYYY') days ,
ts.tsname ,
MAX(ROUND((tsu.tablespace_usedsize* dt.block_size )/(1024*1024),2)) used_size_mb
FROM dba_hist_tbspc_space_usage tsu ,
dba_hist_tablespace_stat ts ,
dba_hist_snapshot sp,
dba_tablespaces dt
WHERE tsu.tablespace_id = ts.ts#
AND tsu.snap_id = sp.snap_id
AND ts.tsname = dt.tablespace_name
AND sp.begin_interval_time > sysdate-7
GROUP BY TO_CHAR(sp.begin_interval_time,'MM-DD-YYYY'),
ts.tsname
ORDER BY ts.tsname,
days
) a
) b
GROUP BY b.tsname
ORDER BY b.tsname;
And group by owner:
SELECT ds.owner as owner,
MAX(b.used_size_mb) cur_used_size_mb ,
ROUND(AVG(inc_used_size_mb),2) avg_incr_mb
FROM
(SELECT a.days,
a.tsname ,
used_size_mb ,
used_size_mb - LAG (used_size_mb,1) OVER ( PARTITION BY a.tsname ORDER BY a.tsname,a.days) inc_used_size_mb
FROM
(SELECT TO_CHAR(sp.begin_interval_time,'MM-DD-YYYY') days ,
ts.tsname ,
MAX(ROUND((tsu.tablespace_usedsize* dt.block_size )/(1024*1024),2)) used_size_mb
FROM dba_hist_tbspc_space_usage tsu ,
dba_hist_tablespace_stat ts ,
dba_hist_snapshot sp,
dba_tablespaces dt
WHERE tsu.tablespace_id = ts.ts#
AND tsu.snap_id = sp.snap_id
AND ts.tsname = dt.tablespace_name
AND sp.begin_interval_time > sysdate-7
GROUP BY TO_CHAR(sp.begin_interval_time,'MM-DD-YYYY'),
ts.tsname
ORDER BY ts.tsname,
days
) a
) b
JOIN dba_segments ds on ds.tablespace_name = b.tsname
GROUP BY ds.owner
ORDER BY ds.owner;

Related

Adding filters in subquery from CTE quadruples run time

I am working on an existing query for SSRS report that focuses on aggregated financial aid data split out into 10 aggregations. User wants to be able to select students included in that aggregated data based on new vs. returning and 'selected for verification.' For the new/returning status, I added a CTE to return the earliest admit date for a student. 2 of the 10 data fields are created by a subquery. I have been trying for 3 days to get the subquery to use the CTE fields for a filter, but they won't work. Either they're ignored or I get a 'not a group by expression' error. If I put the join to the CTE within the subquery, the query time jumps from 45 second to 400 seconds. This shouldn't be that complicated! What am I missing? I have added some of the code... 3 of the chunks work - paid_something doesn't.
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
Not sure if this helps, but you have something like this:
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;
This query throws ORA-00904 FAS.AID_YEAR invalid identifier. It is because fas.aid_year is nested too deep in subquery.
If you are able to modify your subquery from select count(1) from (select distinct sth from ... where year = fas.year) to select count(distinct sth) from ... where year = fas.year then it has the chance to work.
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
Here is simplified demo showing non-working and working queries. Of course your query is much more complicated, but this is something what you could check.
Also maybe you can use dbfiddle or sqlfiddle to set up some test case? Or show us sample (anonimized) data and required output for them?

Oracle's SDO_CONTAINS not using spatial index on unioned tables?

I'm trying to use Oracle's sdo_contains spatial operator, but it seems, that it's not really working, when you use it on unioned tables.
The below code runs in 2 mins, but you have to duplicate the spatial operator for every source table:
SELECT -- works
x.code,
count(x.my_id) cnt
FROM (select
c.code,
t.my_id
from my_poi_table_1 t,my_shape c
WHERE SDO_contains(c.shape,
sdo_geometry(2001,null,SDO_POINT_type(t.latitude, t.longitude,null),null,null)
) = 'TRUE'
union all
select
c.code,
t.my_id
from my_poi_table_2 t,my_shape c
where SDO_contains(c.shape,
sdo_geometry(2001,null,SDO_POINT_type(t.lat, t.lng,null),null,null)
) = 'TRUE'
) x
group by x.code
I wanted to make it simple, so I tried to first create the points, and then just once use the sdo_contains on it, but it's running for more then 25 mins, because it's not using the spatial index:
SELECT -- does not work
c.code,
count(x.my_id) cnt
FROM my_shape c,
(select
my_id,
sdo_geometry(2001,null,SDO_POINT_type(latitude, longitude,null),null,null) point
from my_poi_table_1 t
union all
select
my_id2,
sdo_geometry(2001,null,SDO_POINT_type(lat, lng,null),null,null) point
from my_poi_table_2 t
) x
WHERE SDO_contains(c.shape,
x.point
) = 'TRUE'
group by c.code
Is there a way to use the sdo_contains on the results of multiple tables without having to include it in the select several times?
Oracle: 12.1.0.2
It seems, that sdo_contains cannot (efficiently) read from a subselect: if I put one of the poi tables into a subselect, then Oracle will not use spatial index for that part:
SELECT -- does not work
x.code,
count(x.my_id) cnt
FROM (select --+ ordered index(c,INDEX_NAME)
c.code,
t.my_id
from my_shape c,(select t.*,rownum rn from my_poi_table_1 t) t
WHERE SDO_contains(c.shape,
sdo_geometry(2001,null,SDO_POINT_type(t.latitude, t.longitude,null),null,null)
) = 'TRUE'
union all
select
c.code,
t.my_id
from my_poi_table_2 t,my_shape c
where SDO_contains(c.shape,
sdo_geometry(2001,null,SDO_POINT_type(t.lat, t.lng,null),null,null)
) = 'TRUE'
) x
group by x.code

oracle : joining subquery with outer query

I have two queries with a union as follows:
select '00/00/0000' as payment_date , h1.customer_no
from payments h1
where not exists ( select 1 from payments h2 where h2.customer_no = h1.customer_no and h2.ctype = 'CASH' )
and h1.customer_no = 400
group by h1.customer_no
union
select to_char(h1.payment_date, 'MM/DD/YYYY') , h1.customer_no
from payments h1 inner join ( select customer_no, max(payment_date ) as max_date from payments where ctype = 'CASH' group by customer_no ) subQ
on ( h1.customer_no = subQ.customer_no
and h1.payment_date = subQ.max_date )
and h1.customer_no = 400
group by h1.payment_date, h1.customer_no
Now, I want to use this union in another query.
select * from (
select '00/00/0000' as payment_date , h1.customer_no
from payments h1
where not exists ( select 1 from payments h2 where h2.customer_no = h1.customer_no and h2.ctype = 'CASH' )
and h1.customer_no = p.customer_no
group by h1.customer_no
union
select to_char(h1.payment_date, 'MM/DD/YYYY') , h1.customer_no
from payments h1 inner join ( select customer_no, max(payment_date ) as max_date from payments where ctype = 'CASH' group by customer_no ) subQ
on ( h1.customer_no = subQ.customer_no
and h1.payment_date = subQ.max_date )
and h1.customer_no = p.customer_no
group by h1.payment_date, h1.customer_no ) sq,
payments p
where p.customer_no = 400
and sq.customer_no = p.customer_no
when I run this, I get ORA-00904: "P"."CUSTOMER_NO": invalid identifier. I need to join h1.customer_no to outer queries customer_no.
I have seen some queries with rank but I couldn't quite figure it out. How do I join the inner query with the outer query?
thanks in advance.
Does your payments table have a customer_no column? That seems to be what your error is indicating.
As for how to join the subqueries, you might want to look into factored subqueries. You can do:
WITH z AS (
SELECT ...
UNION
SELECT ...
), y AS (
SELECT ...
)
SELECT ...
FROM y
JOIN z ON y.x = z.x
JOIN some_other_table t ON z.a = t.a

self join with max value

I am have a table with 500k transactions. I want to fetch the last balance for a particular date. So I have have returned a query like below.
SELECT curr_balance
FROM transaction_details
WHERE acct_num = '10'
AND is_deleted = 'N'
AND ( value_date, srl_num ) IN(
SELECT MAX( value_date ), MAX( srl_num )
FROM transaction_details
WHERE TO_DATE( value_date, 'dd/mm/yyyy' )
<= TO_DATE( ADD_MONTHS( '05-APR-2012', 1 ), 'dd/mm/yyyy' )
AND acct_num = '10'
AND is_deleted = 'N'
AND ver_status = 'Y' )
AND ver_status = 'Y'
This has to be executed for incrementing of 12 months to find the last balance for each particular month. But this query is having more cpu cost, 12 times it is taking huge time. How to remodify the above query to get the results in faster way. Whether this can be broken into two part in PL/SQL to achieve the performance. ?
Try:
select * from(
SELECT value_date, srl_num, curr_balance
FROM transaction_details
WHERE acct_num = '10'
AND is_deleted = 'N'
AND ver_status = 'Y'
row_number() over (partition by trunc(value_date - interval '5' day,'MM')
order by srl_num desc
) as rnk
)
where rnk = 1;
You'll get a report with the ballance on last srl_num on each month in your table.
The benefit is that your approach scans the table 24 times for 12 months report and my approach scans the table once.
The analytic function gets the rank of record in current month(partition by clause) ordering the rows in the month after srl_num.
You don't have to query your table twice. Try using analytic functions
SELECT t.curr_balance
-- , any other column you want as long it is in the subselect.
FROM (
SELECT
trans.curr_balance
, trans.value_date
-- any other column you want
, trans.srl_num
, MAX(trans.srl_num) OVER(PARTITION BY trans.value_date, trans.srl_num) max_srl_num
, MAX(trans.value_date) OVER(PARTITION BY trans.value_date, trans.srl_num) max_date
FROM transaction_details trans
WHERE TO_DATE( value_date, 'dd/mm/yyyy' ) <= TO_DATE( ADD_MONTHS( '01-APR-2012', 1 ), 'dd/mm/yyyy' )
AND acct_num = '10'
AND is_deleted = 'N'
AND ver_status = 'Y'
) t
WHERE t.max_date = t.value_date
AND t.max_srl_num = t.srl_num
A couple of thoughts.
Why do you have TO_DATE( value_date...? Isn't your data type DATE? this might be breaking your index if you have one in that column.
Note that (this is a wild guess) if your srl_num is not the highest for the latest date, you will have incorrect results and might not return any rows.

Trying to pull a variable only on row with max(date) while summing a different variable on all rows

I need to pull a value from the row that has the maximum date, while also summing all the values of a different column.
What I mean is something like this:
select
a.account_number,
a.client,
a.referral_date,
sum(b.amount),
max(b.date),
case when b.date = max(b.date) then b.due end as due
from a join b on a.account_number = b.account_number
group by a.account_number, a.client, a.referral_date, sum(b.amount), max(b.date), case when b.date = max(b.date) then b.due end
I'm sorry if this doesn't make sense, but I'm trying to sum ALL of "amount" while only getting "due" from the row with the maximum "date".
So if I join them so it only pulls max(date) I won't be able to sum ALL of the amounts.
I've been searching forever for this, but frankly I don't even know what to type into a search engine for this question. Thank you in advance for your help! Let me know how I can further clarify!
Steven
Wouldn't this work:
select a.account_number
, a.client,
, a.referral_date
, sum(b.amount)
, case when b.date = max(b.date) then b.due end as due
from a join b
on a.account_number = b.account_number
group by a.account_number, a.client, a.referral_date
... and if you're using PL\SQL then untested but:
select account_number
, a.client
, a.referral_date
, sum(b.amount)
, max_date
from ( select a.account_number
, a.client,
, a.referral_date
, b.amount
, max(b.date) over ( partition by a.account_number, a.client, a.referral_date ) as max_date
from a join b
on a.account_number = b.account_number )
group by a.account_number, a.client, a.referral_date, max_date
Not sure I precisely understand your goal, but how about this:
SELECT account_number, client, referral_date, amount, due
FROM (SELECT a.account_number,a.client,a.referral_date, b.due, b.date TheDate
, SUM(b.amount) OVER (PARTITION BY b.account_number) amount
, MAX(b.date) OVER (PARTITION BY b.account_number) max_dt
FROM a JOIN b ON a.account_number = b.account_number)
WHERE TheDate = max_dt;

Resources