date value frequence
2015-12-26 10 m
2015-11-20 11 m
2016-10-22 13 m
2016-06-02 15 m
2016-04-01 9 m
2016-03-24 4 m
위와 같은 형태의 테이블이 있습니다.
예시로 그리진 않았지만 분포도는 freq가 d인 데이터는 4800만건, m인 데이터는 200만건 정도가 테이블에 있습니다.
위와 같은 데이터에서 매월말일 리스트를 만들어서 row별 말일에 가장 가까운 날짜의 데이터를 가져오고 싶습니다.
(이때 frequence가 m인 데이터만 가져옵니다.)
date value
2015-12-31 10
2015-11-30 11
2015-10-31 13
2015-09-30 15
2015-08-31 15
2015-07-31 15
2015-06-30 15
2015-05-31 9
.
.
.
위와 같은 월 말일 기준 리스트에 가장 가까운 날짜의 value값을 붙여야 하는데요...
쿼리 하나로 해결하려 했으나 제 인덱싱과 쿼리 짜는 수준의 한계인지 너무 느립니다.
위와 같은 상태의 DB에서 해당 쿼리를 1초 이내로 뽑는 방법이 있을까요?
select id, dt, max(ddt) ddt
from (
select a.id id, a.dt dt, b.ddt ddt from @tempMonth a
join table b on a.id = b.id and a.dt >= b.ddt) a
group by id, dt
위와 같이 매월 말일에 말일보다 작은 날짜의 데이터를 모두 join한 후 max값을 가져왔습니다.
느릴 수 밖에 없을 구조의 쿼리인듯해서 개선할 수 있는 방법이 있을까요.
아니면 커서를 돌려서 한줄 씩 처리하는 방법밖에 없나요?
Comment 8
-
Terry
2016.05.25 10:28
-
호머
2016.05.25 11:10
Terry//
Group by Month 로 할 수 없는게 당월 뿐만 아니라 전월 데이터가 최신 데이터 일 가능성이 있습니다 ㅜㅜ
2015-12-31 기준으로 최신 데이터를 가져올때 2015-10-10일 데이터가 최신이면 10월 데이터를 12월에 매핑 해야합니다.
조언 감사드립니다 ㅜㅜ
-
Terry
2016.05.25 12:22
최신데이터라는 기준이 어떤건지요?
글에서 유추되는 정보로는 알 수 있는 방법이 없네요^^;;
-
향지
2016.05.25 11:53
1초만에 될지는 모르겠는데요
월별 마지막 값으로 한번 가공한뒤에
조인을 하면 더 빠를것 같습니다.
매월 지날때마다 월별 마지막 값을 따로 가공하는 테이블을 두시면 1초안에도 가능할것 같습니다.
-
호머
2016.05.25 13:47
향지// 일단 freq가 m인 값은 월 1개만 있습니다.
역시 매월이나 매일 따로 가공 테이블에 데이터를 만들어 두는 방법밖에 없나보네요..ㅜㅜ
답변 감사합니다.
-
minsouk
2016.05.25 13:51
평균 9.6ms 정도 걸리네요...use tempdbgoif object_id ('tblx') is not nulldrop table tblxgocreate table tblx(cDate datetime,cValue int,cFrequence char(1))goinsert into tblxselect top 2000000 dateadd(day, dayBefore * -1, convert(char(8), getdate(), 112)) as cDate, abs(checksum(newid()) % 100) cValue, 'm' cFrequencefrom (select abs(checksum(newid()) % 1000) dayBeforefrom sysobjects across join sysobjects a1cross join sysobjects a2cross join sysobjects a3cross join sysobjects a4cross join sysobjects a5) agocreate clustered index cl_tblx on tblx (cFrequence, cDate)godelete from tblx where cDate >= '20160201'godelete from tblx where cDate between '20150801' and '20151001'goselect *from(select top 12dateadd(month, row_number() over (order by (select 1)) * -1 +2 , convert(char(6), getdate(), 112) + '01') - 1 cMonthfrom sysobjectsorder by 1 desc) aouter apply(select top 1 *from tblxwhere (cDate >= convert(char(6), cMonth, 112)+'01' and cDate <= cMonth and cFrequence ='m')or (cDate <= cMonth and cFrequence ='m')order by cDate desc) bgo -
호머
2016.05.25 15:18
minsouk // 친절한 조언 감사드립니다^^
모르던 내용들이 엄청 많네요 ㄷㄷ 공부하고 확인 적용 해보겠습니다.
정말 감사드립니다^^
-
향지
2016.05.25 18:03
엇 저도 잘 배워 갑니다 __)
(
Select '2015-12-26',10,'m' Union All
Select '2015-12-30',8,'m' Union All
Select '2015-11-20',11,'m' Union All
Select '2016-10-22',13,'m' Union All
Select '2016-06-02',15,'m' Union All
Select '2016-04-01',9 ,'m' Union All
Select '2016-03-24',4 ,'m'
)
Select a.date
,b.value
From
(
Select Max(a.date ) date
From tblA a
Where a.frequence = 'm'
Group By Left(a.date,7)
) a
Inner Join
tblA b
On a.date = b.date