[PostgreSql] 로그 테이블(파티션) 관리자 로그 조회 및 페이징 SQL
로그 테이블(파티션) 관리자 로그 조회 및 페이징 SQL 예제 코드입니다. 아래 연관된 글이 있으니 서두가 필요하신 분은 아래 글들을참고하세요.
[PostgreSql] 로그 테이블(파티션) 생성 방안 (파티션 + 6개월 자동 삭제 + 인덱스 + 페이징 조회)
[PostgreSql] 로그 테이블(파티션) 백업 및 DROP 방법 (로그 테이블에서 DELETE 하면 DB 터집니다.
목표
✅ 파티션을 신경 쓰지 않고 조회
✅ 기간 / URI / 로그인ID / 타입 검색
✅ 성능 유지
✅ 관리자 화면용 SQL
파티션 UNION VIEW (관리자용 통합 조회)
PostgreSQL 11+ 파티션이면 사실 부모 테이블 조회만 해도 자동으로 파티션 스캔하지만,
관리자 조회용 전용 VIEW를 만들어두면 관리가 훨씬 편합니다.
CREATE OR REPLACE VIEW VW_APP_LOG_ALL AS
SELECT * FROM TB_APP_LOG;
👉 이 한 줄이면 모든 파티션 자동 포함됩니다.
(파티션은 부모 테이블 쿼리 시 자동 UNION 처리됨)
관리자 기본 조회 SQL
SELECT *
FROM VW_APP_LOG_ALL
WHERE CREATED_AT BETWEEN :fromDate AND :toDate
ORDER BY CREATED_AT DESC
LIMIT 100;
조건별 검색 SQL
로그 타입
SELECT *
FROM VW_APP_LOG_ALL
WHERE LOG_TYPE = :logType
AND CREATED_AT BETWEEN :fromDate AND :toDate
ORDER BY CREATED_AT DESC;
URI 검색
SELECT *
FROM VW_APP_LOG_ALL
WHERE URI LIKE '%' || :uri || '%'
AND CREATED_AT BETWEEN :fromDate AND :toDate
ORDER BY CREATED_AT DESC;
로그인 ID
SELECT *
FROM VW_APP_LOG_ALL
WHERE LOGIN_ID = :loginId
AND CREATED_AT BETWEEN :fromDate AND :toDate
ORDER BY CREATED_AT DESC;
복합 조건
SELECT *
FROM VW_APP_LOG_ALL
WHERE (:logType IS NULL OR LOG_TYPE = :logType)
AND (:loginId IS NULL OR LOGIN_ID = :loginId)
AND (:uri IS NULL OR URI LIKE '%'||:uri||'%')
AND CREATED_AT BETWEEN :fromDate AND :toDate
ORDER BY CREATED_AT DESC
LIMIT :size OFFSET :offset;
기간별 파티션 자동 스캔 (성능 핵심)
WHERE CREATED_AT BETWEEN '2026-01-01' AND '2026-01-31'
이 조건이 있으면 PostgreSQL이
👉 해당 월 파티션만 조회합니다.
(Partition Pruning)
관리자 통계 SQL
일별 로그 건수
SELECT date_trunc('day', created_at) AS day, count(*)
FROM VW_APP_LOG_ALL
WHERE created_at >= now() - interval '7 days'
GROUP BY 1
ORDER BY 1;
타입별 로그
SELECT log_type, count(*)
FROM VW_APP_LOG_ALL
WHERE created_at >= now() - interval '30 days'
GROUP BY log_type;
관리자 화면 성능 팁
| 조건 | 이유 |
|---|---|
| 기간 필수 | 파티션 pruning |
| ORDER BY created_at | 인덱스 사용 |
| LIMIT 필수 | 화면 페이징 |
| like 앞 % 최소화 | 인덱스 무력화 방지 |
필수 인덱스 (부모 테이블에 생성)
CREATE INDEX IDX_APP_LOG_CREATED_AT ON TB_APP_LOG (CREATED_AT);
CREATE INDEX IDX_APP_LOG_TYPE_CREATED ON TB_APP_LOG (LOG_TYPE, CREATED_AT);
CREATE INDEX IDX_APP_LOG_LOGIN_CREATED ON TB_APP_LOG (LOGIN_ID, CREATED_AT);
👉 파티션에도 자동 전파됨
실무 구조 요약
관리자 화면
↓
VW_APP_LOG_ALL
↓
TB_APP_LOG (부모)
↓
월별 파티션 자동 조회
관리자는
👉 파티션 구조 전혀 몰라도 됨.
실무 한 줄 요약
파티션은 DB만 알면 된다
관리자는 VIEW만 보면 된다
관리자 로그 조회 페이징 SQL
✅ 기본 페이징 구조 (LIMIT / OFFSET)
SELECT *
FROM VW_APP_LOG_ALL
WHERE CREATED_AT BETWEEN :fromDate AND :toDate
ORDER BY CREATED_AT DESC
LIMIT :pageSize
OFFSET (:pageNo - 1) * :pageSize;
파라미터 예
| 이름 | 값 |
|---|---|
| pageNo | 1 |
| pageSize | 50 |
✅ 조건 포함 페이징 (실무 표준)
SELECT *
FROM VW_APP_LOG_ALL
WHERE CREATED_AT BETWEEN :fromDate AND :toDate
AND (:logType IS NULL OR LOG_TYPE = :logType)
AND (:loginId IS NULL OR LOGIN_ID = :loginId)
AND (:uri IS NULL OR URI LIKE '%' || :uri || '%')
ORDER BY CREATED_AT DESC
LIMIT :pageSize
OFFSET (:pageNo - 1) * :pageSize;
✅ 전체 건수 조회 (페이징용 COUNT)
SELECT COUNT(*)
FROM VW_APP_LOG_ALL
WHERE CREATED_AT BETWEEN :fromDate AND :toDate
AND (:logType IS NULL OR LOG_TYPE = :logType)
AND (:loginId IS NULL OR LOGIN_ID = :loginId)
AND (:uri IS NULL OR URI LIKE '%' || :uri || '%');
👉 이 결과로totalCount / pageSize → 총 페이지 계산
⚠ 성능 주의
OFFSET이 커지면 느려집니다.
| 페이지 | 성능 |
|---|---|
| 1~100 | 빠름 |
| 1000+ | 느려짐 |
로그 테이블에서는 보통 1000페이지 이상 조회 안 함 → 실무에서 문제 없음.
🚀 고성능 방식 (Keyset Paging, 선택사항)
대용량일 경우:
SELECT *
FROM VW_APP_LOG_ALL
WHERE CREATED_AT < :lastCreatedAt
AND CREATED_AT BETWEEN :fromDate AND :toDate
ORDER BY CREATED_AT DESC
LIMIT :pageSize;
👉 무한 스크롤 / 다음 페이지 방식
✅ 관리자 화면 페이징 흐름
- COUNT 쿼리 실행
- 목록 쿼리 실행
- 페이지 계산
- 화면 표시
✅ 인덱스 필수
CREATE INDEX IDX_APP_LOG_CREATED_AT ON TB_APP_LOG (CREATED_AT DESC);
🎯 실무 한 줄 요약
관리자 페이징은
OFFSET 방식으로 충분
- created_at 인덱스 필수
원하시면 다음 단계로
👉 MyBatis Mapper XML
👉 Pageable DTO
👉 Controller API 예제
👉 관리자 화면 응답 JSON 구조
까지 바로 실무 코드로 이어서 만들어 드릴 수 있습니다.



