2. 컴퓨터 이야기/프로그래밍

특정 화면에서 조건에 맞는 순위 목록 보여 주기

래빗 크리스 2009. 1. 30. 13:04

오늘 작업할 내용은 다소 복잡하다. 요건은 다음과 같다.

1. 순위 데이타 추출 및 노출
2. 특정 게시물에서만 노출
3. 특정 기간 동안만 노출

순위 데이타를 추출하려면 오라클 DB 쿼리 함수중 rank() over (order by ...) 라는 것을 이용한다.
rank() 를 사용하면 1, 2, 2, 2, 5, 5, 7, .. 이런식으로 순위가 나오고..
dense_rank() 를 이용하면 1, 2, 2, 2, 3, 3, 4, ... 이런식으로 순위가 나온다.
여기서는 partition 옵션을 사용할 필요는 없다.

그런데 rank 함수는 튜닝을 해도 속도가 느릴 수밖에 없다.
이를 해결하려면 중간 테이블을 하나 두어서 순위 목록을 가져올 때는 중간 테이블에서 select 해 오고,
특정 조건에서 중간 테이블에 순위 데이타를 insert 해 주면 된다.
중간 테이블에 순위 데이타를 부어줄때 Oracle 의 Job 을 이용하기도 하는데,
Job 이 많이 돌고 있다면 Job 들간의 상호 간섭을 고려하여야 하기 때문에 이것도 대략 난감.
그렇다면 관리자나 사용자가 특정 페이지에 접근할때 순위 데이타를 중간 테이블에 넣어 주면 되겠다.
관리자가 이거 하려고 매번 접속할 수는 없으니까, 사용자가 접속할 때 돌게 하고..
사용자가 접속할때 화면이 그냥 멍하니 있으면 곤란하니까, iframe 과 resize 또는 Ajax 를 쓰면 되겠는데..
Ajax 는 글쎄 뭐 좋아 보이지는 않고, 사용하는데 제한사항도 있어서리.. (Ajax 는 왜 그런지 정이 안간다.. ㅋㅋ)
여기서는 iframe 을 resize 하겠다.

일단 중간 테이블에 데이타를 부어 넣는 쿼리는 다음과 같이 insert into ~ select ~ 문을 사용한다.
주의할 것은 insert into 부분에서 실제로 데이타가 필요한 필드(칼럼)명을 모두 기술하라는 것.
그렇지 않으면 나중에 칼럼이 추가 된다든가, 어떠한 이유로든 칼럼 순서가 바뀌게 되면 오류 발생.
rank 를 10 위권 안으로 할지 어떨지 확정되지 않아서 PreparedStatement 로 파라미터를 넘기는 방식 채택.
rank 를 이용할 때도 그 안에서 먼저 돌아가는 쿼리는 튜닝을 마친 상태.
rank 를 잡은 다음에도 Alias c 의 테이블에서 정보를 가져오도록 하였음.
rank 작업시 Alias c 를 Join 하면 더 오랜 시간이 소요되므로 rank 문 안에서는 적은 데이타를 다루도록 처리한 것.
rank 작업 안에서 사용된 Alias b 와 exists 문은 rank 조건이기 때문에 rank 문 안에서 처리.



자, 이제는 사용자가 접속했을때 상기 insert 문을 이용할 것인지 체크하는 로직 필요.
일단 Alias a.lst_date 가 마지막으로 insert 문이 돌아간 일자. (insert ~ select ~ 할때 isrt_date 를 생성)
Alias b.end_date 는 상기 목록이 보여지는 마지막 일자 (DB 로 유효기간 관리).
case 문에 의해 중간 테이블에 최종적으로 데이타가 들어간 일자와
DB 상에서 유효기간이 관리되는 마지막 일자를 비교하고,
최종 데이타 일자가 어제 일자인지 점검해서 맞으면 1, 아니면 0. (1 이면 중간 테이블에 데이타 부어넣기).
decode 를 사용할 수도 있겠지만, case 문이 복잡한 조건처리에 딱 맞음.
목록을 보여주는 데이타는 어제일자 기준으로 수집된 정보여야 하고, 유효기간 안에서만 정보가 수집되어야 하기 때문.
참고로, 아래 쿼리들은 관련 테이블에 적절한 index 가 잡혀 있기 때문에 Full Scanning 되지 않습니다. ^^>
항상 튜닝을 고려하면서 쿼리를 만드는 습관이 중요합니다.



목록을 가져오는 쿼리는 간단하기 때문에 설명을 생략하고, 이제는, JSP 쪽을 손 봐야 할 차례.
if 문을 통해서 특정 조건일 경우에만 아래 코드들이 작동하게 한다.
ReturnDomain 클래스를 통해서 실서버인지 테스트(개발)서버인지 확인하여,
실서버이면 Expiration 클래스를 이용하여 2/1 ~ 3/2 까지 목록이 나오게 하고,
개발 서버이면 기간에 상관없이 목록을 보이도록 한다. (체크해야 하니까 개발서버에는 나오게 한다)
iframe 이 onLoad 될 때 doResize 자바스크립트 함수를 호출하여 순위 목록에 맞게 높이를 조정한다.
iframe 의 width 는 doResize 에서 조정해도 되겠지만 처음에 체크한 대로 사용한다.
iframe 이 td 태그 안에서 resize 되는 것이 엉뚱한 여백을 남기지 않아 좋은 방법.




작업이 완료되면 아래와 같은 결과물이 얻어진다.



ReturnDomain.getReturnDomain 은, 현재 웹페이지가 서비스 되는 서버가 어떤 것인지 체크합니다.
Host 명을 사용하여 체크하는데 여기에서는 몇가지 만 체크하였지만 필요한 만큼 체크해 놓으면 되겠습니다.



Expiration.isPopupOk 는, 오늘이 fromDate 와 toDate 기간에 해당하면 true 를 리턴하는 메소드.
숫자만 추출하기 위해 Expiration.getNumberCharacter 메소드를 이용하였는데,
fromDate.replaceAll("[^0-9]","") 와 같이 이용해도 무난합니다.
SimpleDateFormt 을 이용하려면 java.text.SimpleDateFormat 를 import 해야 합니다.
fromDate 와 toDate 에 값을 넣지 않고 "" 로 isPopupOk 를 호출하는 경우 무한대로 추측합니다.
이를테면 isPopupOk("20090130", "") 라고 하면, 1/30 부터 어느 때든지 true 를 리턴합니다.


이상입니다.