| 항목 | PostgreSQL | MySQL·MariaDB | Oracle | SQL Server |
|---|---|---|---|---|
| 오늘 날짜 | CURRENT_DATE |
CURDATE() · CURRENT_DATE |
TRUNC(SYSDATE) |
CAST(GETDATE() AS date) |
| 현재 시각 | NOW() · CURRENT_TIMESTAMP |
NOW() · CURRENT_TIMESTAMP |
SYSDATE · SYSTIMESTAMP |
GETDATE() · SYSDATETIME() |
| 시간대 포함 | CURRENT_TIMESTAMP (timestamptz) |
— | SYSTIMESTAMP |
SYSDATETIMEOFFSET() |
| 상대 시각 | NOW() - INTERVAL '1 hour' |
NOW() - INTERVAL 1 HOUR |
SYSDATE - 1/24 |
DATEADD(hour, -1, GETDATE()) |
Oracle 의 SYSDATE 는 DB 서버 OS 의 시각이고 CURRENT_DATE 는 세션 시간대 기준 시각이다. 서버와 클라이언트 시간대가 다르면 두 값이 다르다. PostgreSQL 의 NOW() 는 트랜잭션 시작 시각이라 한 트랜잭션 안에서는 여러 번 불러도 같은 값이고, 매번 실제 시각이 필요하면 clock_timestamp() 를 쓴다.
-- 인덱스를 못 쓴다
WHERE created_at::date = CURRENT_DATE
-- 범위 조건으로 바꾸면 인덱스를 탄다
WHERE created_at >= CURRENT_DATE
AND created_at < CURRENT_DATE + INTERVAL '1 day'
"최근 N 분" 같은 조건도 마찬가지다.
WHERE created_at >= NOW() - INTERVAL '5 minutes'
컬럼이 timestamptz(TIMESTAMP WITH TIME ZONE)이면 PostgreSQL 은 값을 UTC 로 저장하고 조회할 때 세션 시간대로 보여 준다. NOW() 도 timestamptz 를 돌려주므로 둘을 그대로 비교해도 맞다.
SHOW TIME ZONE;
SET TIME ZONE 'Asia/Seoul';
timestamp(시간대 없음)와 timestamptz 를 섞어 비교하면 세션 시간대를 적용해 암묵 변환이 일어난다. 세션 시간대가 바뀌면 결과가 달라지므로 명시하는 편이 안전하다.
WHERE ts_col AT TIME ZONE 'Asia/Seoul' >= TIMESTAMP '2026-09-20 00:00:00'
"오늘" 의 경계는 시간대에 따라 다르다. 배치가 UTC 로 도는 컨테이너에서 돌면 한국 시간 기준 오늘과 아홉 시간 어긋난다. 배치 쿼리에서는 시간대를 코드에 박아 명시한다.
WHERE ts_col >= (CURRENT_DATE AT TIME ZONE 'Asia/Seoul')
AND ts_col < ((CURRENT_DATE + 1) AT TIME ZONE 'Asia/Seoul')
쿼리는 대상 DBMS 의 문법을 그대로 따른다. 수집기가 변환해 주지 않는다.
queries:
- query_name: recent_logins
query: |
SELECT COUNT(*) AS logins_last_hour
FROM user_logins
WHERE login_time >= NOW() - INTERVAL '1 hour'
수집 주기와 쿼리의 시간 범위를 맞춘다. 1분마다 수집하면서 1시간 범위를 세면 같은 행이 60번 반복해 집계된다. 게이지로 현재 상태를 보려는 것인지, 카운터로 누적을 보려는 것인지 먼저 정한다.
수집 쿼리에 타임아웃을 걸지 않으면 느린 쿼리가 쌓여 대상 DB 에 부담을 준다. 수집 간격보다 짧은 statement_timeout 을 세션에 걸어 둔다.