MariaDB를 기준으로 작성되었습니다.
내가 원한 데이터는 다음과 같다.
11 | 서비스 1 | 데이터 1 |
11 | 서비스 2 | 데이터 2 |
11 | 서비스 3 | 데이터 3 |
12 | 서비스 1 | 데이터 1 |
12 | 서비스 2 | 데이터 2 |
12 | 서비스 3 | 데이터 3 |
이렇게 시간대별로 서비스의 데이터를 조회하고 싶었다. 해당 테이블은 log성으로 5분마다 데이터가 적재된다.
그러니까 각 시간대별 가장 최근 데이터를 뽑아야 한다.
그래서 쿼리는 다음과 같다.
SELECT TIME, SERVICE_NAME, IFNULL(CPU_USAGE,0) AS CPU_USAGE, IFNULL(MEMORY_TOTAL,0) AS MEMORY_TOTAL, IFNULL(MEMORY_USAGE,0) AS MEMORY_USAGE
FROM (
SELECT @N := @N + 1 AS TIME
FROM 테이블명, (SELECT @N:=0 FROM DUAL) NN -- 1부터 24까지의 값이 있는 컬럼 생성
LIMIT 24
) AS T
LEFT JOIN (
SELECT *
FROM 테이블명
WHERE CREATE_DATE IN (
SELECT MAX(CREATE_DATE) ## 가장 최근 적재된 데이터 조회
FROM 테이블명
WHERE SUBSTR(CREATE_DATE,1,6) = DATE_FORMAT(NOW(),'%y%m%d') ## 오늘 날짜만 조회
GROUP BY SUBSTR(CREATE_DATE, 1, 8), SERVICE_NAME ## 시간 + 서비스명으로 grouping
)
) AS RESULT ON T.TIME = SUBSTR(CREATE_DATE, 7, 2)
ORDER BY T.TIME, LOG_NO;
하나씩 분석하자면 다음과 같다.
SELECT MAX(CREATE_DATE) ## 가장 최근 적재된 데이터 조회
FROM 테이블명
WHERE SUBSTR(CREATE_DATE,1,6) = DATE_FORMAT(NOW(),'%y%m%d') ## 오늘 날짜만 조회
GROUP BY SUBSTR(CREATE_DATE, 1, 8), SERVICE_NAME ## 시간 + 서비스명으로 grouping
먼저 오늘 날짜 데이터만 조회한다. 그다음으로 연월일시 + 서비스명을 기준으로 그룹핑한다.
그럼 다음과 같은 형식으로 데이터가 출력된다. 예를 들어 초록색 데이터가 12시 00분에 적재된 데이터면, 보라색은 12시 5분에 적재된 데이터이다.
서비스 1 | 데이터 1 |
서비스 2 | 데이터 2 |
서비스 3 | 데이터 3 |
서비스 1 | 데이터 1 |
서비스 2 | 데이터 2 |
서비스 3 | 데이터 3 |
그래서 MAX(CREATE_DATE)를 조회하여 최신 데이터를 뽑아왔다.
서비스 1 | 데이터 1 |
서비스 2 | 데이터 2 |
서비스 3 | 데이터 3 |
실행되는 쿼리는 다음과 같다.
SELECT *
FROM 테이블명
WHERE CREATE_DATE IN ([위 결과])
CREATE_DATE 중 위 결과를 포함하는 데이터만 출력한다.
1부터 24까지 값이 있는 칼럼을 만든다. IFNULL처리는 해줘도 되고 안 해줘도 된다.
내가 한 이유는 다음과 같다.
NamedNativeQuery 의 결괏값을 result에 맵핑해줘야 하는데 이때 IFNULL처리가 되어있지 않으면 조회된 데이터가 NULL일 경우
@ColumnResult의 타입을 String.class로 선언해야한다. (= vo도 String으로 선언) 그래서 데이터 타입을 맞추기 위해 IFNULL처리를 하였다.
쉽게 말하면 NamedNativeQuery에서 NULL인 데이터는 String 타입으로 적용된다. 그래서 CPU_USAGE와 같은 INT형 데이터를 String으로 처리해야 한다. DB 데이터 타입은 INT인데 굳이 자바단에서 String으로 변환할 필요는 없을 거 같았다. 그래서 NULL일 경우 명시적으로 0으로 바꿔줬다. 사실 해당 테이블은 로그 형식으로 null인 값이 들어가지는 않겠지만, 그래도 처리해주고 싶었다.
SELECT TIME, SERVICE_NAME, IFNULL(CPU_USAGE,0) AS CPU_USAGE, IFNULL(MEMORY_TOTAL,0) AS MEMORY_TOTAL, IFNULL(MEMORY_USAGE,0) AS MEMORY_USAGE
FROM (
SELECT @N := @N + 1 AS TIME
FROM 테이블명, (SELECT @N:=0 FROM DUAL) NN -- 1부터 24까지의 값이 있는 컬럼 생성
LIMIT 24
) AS T
LEFT JOIN (
[조회문]
) AS RESULT ON T.TIME = SUBSTR(CREATE_DATE, 7, 2)
ORDER BY T.TIME, LOG_NO;
여기까지 했다면, 조회되는 데이터는 다음과 같다.
서비스의 시간대별 가장 최근 데이터가 보임!
11 | 서비스 1 | 데이터 1 |
11 | 서비스 2 | 데이터 2 |
11 | 서비스 3 | 데이터 3 |
12 | 서비스 1 | 데이터 1 |
12 | 서비스 2 | 데이터 2 |
12 | 서비스 3 | 데이터 3 |
오랜만에 쿼리 짜서 재미있었다. 하지만 이게 과연 최적의 코드인가? 에 대한 의문은 늘 따라다니는 거 같다.
나에게는 최선의 코드였기 때문에 조금이나마 도움이 되는 분들이 있었으면 좋겠다.
코드 리뷰나 부족한 설명에 대한 댓글은 언제나 환영입니다.
'🏰 Back-end > DB' 카테고리의 다른 글
Host '192.xxx.xx.xx' is not allowed to connect to this MariaDB server - Maria DB 원격접속 불가 (0) | 2023.04.02 |
---|---|
[DB] 인덱스를 걸 때 원칙 (0) | 2022.10.31 |
[DB] IN을 사용할 때 전제조건 (0) | 2022.10.31 |
댓글