4.2 스키마 객체 정의
이 페이지는 테이블, 컬럼, 인덱스와 VIEW를 설계할 때 결정할 항목을 정리합니다. SQL 문법과 옵션을 중복해서 나열하지 않고 SQL 문법 사전을 정본으로 사용합니다.
테이블 생성과 삭제
먼저 테이블 타입 선택을 완료합니다. 이 페이지는 선택한 타입에 맞게 테이블 이름, 컬럼, 키, 제약 조건, 인덱스와 VIEW를 정의합니다.
행의 단위와 컬럼의 역할
테이블 하나에서 행의 단위를 일정하게 유지합니다. 설비별 하루 요약과 초 단위 원본을
같은 의미의 행처럼 섞으면 COUNT나 AVG를 해석하기 어렵습니다. 원본과 집계에는
각각 명확한 행의 단위와 조회 이름을 부여합니다.
| 컬럼 역할 | 예 | 설계 원칙 |
|---|---|---|
| 대상 식별 | sensor_id, equipment_id | 표시 이름과 분리한 안정적인 값 사용 |
| 발생 기준 | measured_at, event_time | 실제 발생 시각인지 수신 시각인지 명시 |
| 측정값 | temperature_c, pressure_kpa | 단위, 유효 범위와 보정 방법 정의 |
| 품질 | quality_code | 값 누락, 측정 실패와 정상 0 구분 |
| 기준 속성 | 위치, 설비 종류 | 태그 메타데이터 또는 별도 기준표에서 관리할지 결정 |
외부 장비 코드처럼 업무에서 이미 사용하는 키는 자연키이고, 별도로 발급한 번호는 대리키입니다. 코드가 바뀔 수 있거나 여러 수집원이 같은 코드를 사용하면 식별 범위를 명확히 하거나 대리키를 검토합니다. 자동 증가 번호는 생성 순서를 위한 값이지 발생 시각이나 무중복 수집을 자동 보장하는 값이 아닙니다. TAG의 이름은 측정 행이 아닌 태그를 식별합니다.
테이블 이름은 영문자, 숫자와 밑줄을 사용하고 영문자로 시작하도록 정합니다. 예약어 또는 시스템 객체와 혼동할 수 있는 이름은 피하십시오. 삭제 전에는 의존하는 VIEW, 인덱스, ROLLUP과 보존 정책을 확인합니다.
타입별 생성 예제는 다음 문서를 참고하십시오.
테이블 변경
테이블 타입과 데이터 유무에 따라 컬럼 추가·삭제·이름 변경·타입 변경의 지원 범위가 다릅니다. 운영 테이블을 변경하기 전에 다음 순서로 판단하십시오.
- 대상 Edition과 테이블 타입이 해당
ALTER TABLE동작을 지원하는지 확인합니다. - 기존 데이터, 인덱스, VIEW와 애플리케이션의 컬럼 순서 의존성을 확인합니다.
- 운영과 같은 스키마·데이터량의 검증 환경에서 실행 시간과 잠금 영향을 측정합니다.
- 되돌리기 어렵다면 새 테이블을 만들고 검증 후 전환하는 방식을 사용합니다.
새 컬럼을 추가한 뒤에는 기존 행과 이후 입력한 행을 각각 조회해 NULL·DEFAULT 결과를 확인합니다. 모든 테이블에서 기존 행이 DEFAULT로 채워지는 것은 아닙니다. 예를 들어 VOLATILE의 기존 행과 TAG 메타데이터의 자동 등록 행에는 별도 규칙이 있습니다. ARRAY의 DEFAULT 규칙을 포함해 실제 타입의 DDL 계약을 확인하십시오.
애플리케이션 배포와 스키마 변경의 순서도 정합니다. 가능한 입력 경로에서는 컬럼 목록을 명시하고, 위치 순서에 의존하는 Append와 바인딩 코드는 새 스키마와 대조합니다. 새 테이블로 이전하면 행 수뿐 아니라 키별 건수, 시간 범위, NULL 비율과 대표 집계도 비교하고, 전환 중 새로 들어오는 행의 누락·중복을 어떻게 처리할지 정합니다.
정확한 지원 범위와 구문은 ALTER TABLE 사전과 테이블 타입별 지원 범위를 참고하십시오.
컬럼과 데이터 타입 선택
값의 실제 범위와 연산을 기준으로 가장 작은 적합 타입을 선택합니다. 표시 형식을 저장 타입과 혼동하지 마십시오.
| 데이터 | 권장 검토 타입 | 주의점 |
|---|---|---|
| 정수 계측값·코드 | SHORT·INTEGER·LONG 계열 | NULL 예약값과 범위 확인 |
| 실수 계측값 | FLOAT·DOUBLE | 정밀도, 집계 오차와 NULL 예약값 확인 |
| 정확한 소수 계산이 필요한 값 | DECIMAL | precision·scale과 반올림 규칙을 먼저 결정 |
| 시각 | DATETIME | 표현 범위와 시간대를 클라이언트·세션 정책과 함께 설계 |
| 짧은 문자열 | VARCHAR | 최대 길이와 인코딩 확인 |
| 긴 본문 | TEXT | 지원 테이블 타입, 정렬·집계 제약과 인덱스 비용 확인 |
| 네트워크 주소 | IPV4·IPV6 | 문자열 대신 주소 타입 사용 검토 |
| 구조화 문서 | JSON | 크기 제한, 키 승격 기준과 테이블 타입별 지원 확인 |
| 이진 데이터 | BINARY | 테이블 타입에 따라 가변·고정 길이가 다름 |
| 고정 개수의 숫자 묶음 | 숫자 ARRAY | 요소 타입·길이, 요소별 NULL과 전체 NULL 구분 |
VARCHAR(n)의 길이는 바이트 수입니다. 한글이나 이모지를 포함하면 문자 수와 다를 수
있습니다. 정수 타입은 일부 경계값을 NULL 표현으로 예약하므로 일반 프로그래밍 언어의
정수 범위를 그대로 적용하지 않습니다. FLOAT과 DOUBLE도 양수 최대값을 NULL로 인식하므로
실수 타입이라고 예외는 아닙니다. “작은 타입”보다 유효 범위와 연산 의미가 우선입니다.
정확한 소수가 필요한 값: DECIMAL
금액, 세율, 정산 값처럼 10진 정확성이 필요한 값에는 DECIMAL을 사용합니다. 오차가
허용되고 지수 범위가 넓은 계측값에는 FLOAT·DOUBLE을 사용합니다. 두 계열의 차이는
저장 크기가 아니라 값의 의미이므로, 반올림 결과를 업무에서 그대로 사용하는 값이라면
DECIMAL을 선택합니다.
설계 시 다음을 먼저 정합니다.
| 결정 항목 | 내용 |
|---|---|
| precision | 전체 유효 숫자 수, 1~65 |
| scale | 소수 자릿수, 0~30이며 precision보다 클 수 없음 |
| 생략 규칙 | DECIMAL은 DECIMAL(10,0), DECIMAL(M)은 DECIMAL(M,0) |
scale을 넘는 소수 자릿수는 입력 시점에 0에서 멀어지는 방향의 절반 올림으로 저장됩니다. 반올림이 저장 시점에 확정되므로 업무 규칙과 같은 방향인지 확인합니다. precision을 넘는 값은 잘라내거나 부동소수점으로 바꾸지 않고 오류로 처리하므로, 자릿수는 여유를 두고 정합니다.
SUM, AVG, MIN, MAX와 GROUP BY, ORDER BY, DISTINCT는 exact 경로로
동작합니다. 반면 percentile이나 고급 통계 함수처럼 exact DECIMAL 경로가 없는 연산은
DOUBLE로 변환해 계산하므로 결과가 근삿값입니다. 정확성이 필요한 집계와 참고용 통계를
구분해 설계합니다.
애플리케이션 경로에서 값을 부동소수점으로 경유시키면 저장 타입과 무관하게 정확성이
사라집니다. JDBC는 BigDecimal, Python은 decimal.Decimal, ODBC는 SQL_NUMERIC처럼
각 언어의 decimal 표현이나 문자열로 전달합니다. 선언 규칙, 인덱스, 클라이언트 매핑은
DECIMAL과 NUMERIC 고정소수점 타입을
참고하십시오.
구조화 문서: JSON
수집원마다 키가 다르거나 항목이 계속 늘어나는 부가 속성에는 JSON 컬럼이 적합합니다.
스키마 변경 없이 항목을 추가할 수 있기 때문입니다. 반대로 자주 WHERE나 GROUP BY에
사용하는 값은 JSON 안에 두지 말고 별도 컬럼으로 승격합니다. JSON 컬럼은 primary key로
선언할 수 없고, LOOKUP 테이블에서는 JSON path 인덱스를 지원하지 않습니다.
크기 제한도 설계에 반영합니다. 문서 하나는 최대 32,768 바이트, JSON path는 최대 512 바이트입니다. 원본 payload 전체를 보관하는 용도가 아니라 조회에 필요한 속성을 담는 용도로 사용합니다.
| 테이블 타입 | JSON 컬럼 | 확인할 점 |
|---|---|---|
| TAG·LOG·TRANSACTION | O | JSON 함수와 path 조회 지원 |
| LOOKUP | O | 일반 컬럼으로 지원, JSON path 인덱스는 미지원 |
| VOLATILE | X | JSON 컬럼을 만들 수 없음 |
조회는 -> 연산자와 JSON_EXTRACT_* 계열을, 갱신은 JSON_SET 계열을 사용합니다.
갱신 함수는 해당 테이블 타입이 UPDATE를 지원할 때만 의미가 있으므로, LOG나 TAG처럼
행 수정이 없는 테이블에서는 입력 시점에 문서를 완성합니다. 함수별 지원 범위는
JSON 타입의 테이블 타입별 지원 범위를
참고하십시오.
타입 선택 전에 확인할 제약
| 타입 | 설계 단계에서 확인할 내용 |
|---|---|
TEXT | LOG와 Standard Edition의 TRANSACTION에서만 지원합니다. LOG의 TEXT 컬럼에는 ORDER BY와 GROUP BY를 사용할 수 없고, MODIFY COLUMN으로 VARCHAR로 바꿀 수도 없습니다. 정렬·집계에 쓸 값은 VARCHAR나 숫자 컬럼으로 따로 둡니다. |
BINARY | LOG는 가변 길이 최대 64MB이지만 TAG는 BINARY(n) 고정 길이 1~32,767 바이트로 성격이 다릅니다. LOOKUP과 VOLATILE에서는 지원하지 않습니다. |
DATETIME | 표현 범위는 1970-01-01부터 2262-04-11까지이며 나노초까지 저장합니다. 만료일이나 무기한을 뜻하는 먼 미래 시각을 임의로 넣지 않습니다. |
ARRAY | 고정 길이 1차원 숫자 배열이며 cardinality는 1~1024입니다. 전체 NULL과 요소 NULL을 구분해 설계합니다. |
전체 범위와 테이블 타입별 지원 여부는 데이터 타입 사전을 기준으로 확인하십시오.
제약 조건과 기본값
PRIMARY KEY, NOT NULL, DEFAULT 지원은 테이블 타입마다 다릅니다. 특히 TAG의
PRIMARY KEY는 태그 식별자, LOOKUP·VOLATILE·TRANSACTION의 PRIMARY KEY는 행 식별과
갱신 경로를 결정합니다.
NULL은 알 수 없거나 없는 값이고 0이나 빈 구간과 다릅니다. 측정 실패를 DEFAULT 0으로
대체하면 평균과 정상값 판정이 왜곡될 수 있습니다. COUNT(*)는 행 수, COUNT(value)는
그 컬럼이 NULL이 아닌 행 수이므로 표본 수를 보고할 때 구분합니다.
기본값은 생략한 입력에 대한 정책이며 값의 유효성 검사를 대신하지 않습니다. 테이블이 제공하지 않는 제약은 수집·업무 애플리케이션에서 검증합니다. 예를 들어 외래 키처럼 다른 DBMS의 제약을 이름만 보고 지원한다고 가정하지 말고 TRANSACTION 지원 범위를 확인합니다.
시스템이 제공하는 _ARRIVAL_TIME이나 _RID 같은 컬럼을 애플리케이션의 업무 키로 사용하지
마십시오. 공개된 조회 의미가 필요한 경우에만 참조하고, 시스템 컬럼의 저장 구조나 생성
방식에는 의존하지 않습니다.
인덱스 설계
인덱스는 조회 비용을 낮추지만 입력과 저장 비용을 추가합니다.
대표 조회를 먼저 적고 조건에 맞는 행의 비율(선택도)을 확인합니다. 전체 설비의 한 달
평균과 설비 한 대의 특정 주문 조회는 접근 방식이 다릅니다. 필터·조인 컬럼마다 무조건
인덱스를 만들기보다 EXPLAIN과 실제 실행 시간을 비교해 도움이 되는 인덱스를 남깁니다.
- 시간 범위와 태그 식별자로 충분한 TAG 조회에는 추가 인덱스를 먼저 만들지 않습니다.
- LOG에서 자주 필터링하는 컬럼은 실제 실행 계획과 선택도를 측정한 뒤 인덱스를 검토합니다.
- LOOKUP·VOLATILE·TRANSACTION은 키 조회와 조인 조건을 기준으로 설계합니다.
- 긴 텍스트의 단어 검색은 해당 타입이 지원하는
KEYWORD인덱스를 검토합니다.
생성·삭제 구문과 지원 타입은 인덱스 SQL 사전을 참고하십시오.
VIEW 설계
VIEW는 반복해서 사용하는 조회에 이름을 부여하지만 결과 자체를 저장하지 않습니다. VIEW 정의에서 시간 범위가 고정되거나 불필요한 전체 컬럼을 읽지 않도록 하고, 기반 테이블이나 컬럼을 변경하기 전에 의존 VIEW를 확인하십시오.
자주 쓰는 컬럼 목록과 단위 변환을 VIEW로 일관되게 제공할 수 있습니다. 그러나 VIEW를 만든 것만으로 데이터가 복사되거나 조회 비용이 줄지는 않습니다. 과거 이벤트를 최신 기준표와 조인한 VIEW는 기준표가 바뀌면 과거 결과도 바뀔 수 있으므로, 발생 당시의 속성이 필요하면 버전별 기준 정보나 원본에 기록한 속성을 사용합니다.
VIEW 생성·조회·삭제와 제한은 VIEW SQL 사전을 참고하십시오.