Reputation: 985
Date Range query taking too much time. Just i removed the one condition then it working fine taking 2 second. If adding then 30 seconds.
SELECT UserName,COUNT ('t') TOTAL
FROM TRANSACTIONS E1
WHERE E1.START_DATE BETWEEN TO_DATE ('20130101', 'YYYYMMDD') AND TO_DATE ('20140101', 'YYYYMMDD')
AND
(
TO_CHAR (E1.START_DATE, 'D') in ( 7)
OR Exists(SELECT 1 FROM HOLIDAYS TT
WHERE E1.START_DATE BETWEEN TT.DATE_FROM AND TT.DATE_TO )
)
AND EXISTS (SELECT 't' FROM TRANSACTIONS_ORG E2 WHERE E1.TRANTYPE = E2.tran_type)
GROUP BY UserName;
HOLIDAYS table
Id FromDate ToDate Description
1 1-Feb-11 3-Feb-11 Maintance
3 2-Sep-09 5-Sep-09 Eid Holiday Fine Block
4 3-Dec-09 4-Dec-09 Due to System Problem
5 4-Dec-07 04-Dec-07 National Day
EIDTED I figured out that the issue is not in the date range. but the OR clause in the
TO_CHAR (E1.START_DATE, 'D') in ( 5,6)
OR
Exists(SELECT 1 FROM HOLIDAYS TT
WHERE E1.START_DATE BETWEEN TT.DATE_FROM AND TT.DATE_TO )
if removed OR and put AND then fine and if shuffle conditions with OR still same issue.
Upvotes: 0
Views: 136
Reputation: 12843
The problem is likely with the OR <subquery>
construct.
If there can only be one holiday for a particular date, then you could use the following:
select username
,count(*)
from transactions e1
left join holidays tt on(e1.start_date between tt.date_from and tt.date_to)
where e1.start_date between date '2017-02-01' and date '2018-02-01'
and ( to_char(e1.start_date, 'D') in(5, 6)
or tt.date_from is not null)
)
and exists(
select *
from transactions_org e2
where e1.trantype = e2.tran_type
)
group
by username;
This entire category of problems can be solved by implementing a Calendar table. If you had such a table with one record per date, you could easily add columns indicating day of week and holiday flags and such. If your calendar table looked something like this:
DAY DAYNAME IS_WEEKEND IS_WEEKDAY HOLINAME
---------- --------- ---------- ---------- ------------
2017-02-01 WEDNESDAY 0 1
2017-02-02 THURSDAY 0 1
2017-02-03 FRIDAY 0 1 Some holiday
2017-02-04 SATURDAY 1 0
2017-02-05 SUNDAY 1 0
2017-02-06 MONDAY 0 1
2017-02-07 TUESDAY 0 1
2017-02-08 WEDNESDAY 0 1
Your query could be rewritten as:
from transactions e1
join calendar c on(c.day = trunc(e1.start_date, 'DD')) -- Remove hours, minutes
where e1.start_date between date '2017-02-01' and date '2018-02-01'
and ( c.weekday in('THURSDAY', 'FRIDAY') -- Either specific weekdays
or c.holiname is not null -- or there is a holiday
)
and exists(
select *
from transactions_org e2
where e1.trantype = e2.tran_type
)
Upvotes: 3