Tag 메타데이터
개요
Tag 메타데이터는 태그의 정적 속성을 저장하는 영역입니다. 센서 위치, 장비 상태, 설치 정보, 외부 식별자, JSON 문서형 속성을 메타데이터에 둘 수 있습니다.
이번 기능으로 다음 작업을 TAG METADATA 문법으로 직접 처리할 수 있습니다.
- 메타데이터 전용 조회
- 메타데이터 조건 기반
UPDATE/DELETE - metadata row 마지막 변경 시각 조회
JSON타입 메타데이터 컬럼 선언- JSON path 조회와 JSON path 인덱스
- JSON 문서 일부만 수정하는 부분 갱신
사용자는 내부 저장 테이블을 직접 다룰 필요 없이 TAG METADATA 문법만 사용하면 됩니다.
메타데이터 컬럼 정의
메타데이터 컬럼은 CREATE TAG TABLE 의 METADATA (...) 절에서 정의합니다.
CREATE TAG TABLE sensors (
name VARCHAR(20) PRIMARY KEY,
time DATETIME BASETIME,
value DOUBLE
)
METADATA (
location VARCHAR(100),
status VARCHAR(20),
srcip IPV4
);메타데이터 컬럼은 태그 이름별로 1행만 저장됩니다.
메타데이터 입력
메타데이터는 INSERT INTO ... METADATA 로 입력합니다.
INSERT INTO sensors METADATA VALUES (
'TEMP_001',
'Building-A/F1',
'READY',
'192.168.0.11'
);컬럼 목록을 지정할 수도 있습니다.
INSERT INTO sensors METADATA (name, status, srcip, location)
VALUES ('TEMP_002', 'STOP', '192.168.0.12', 'Building-A/F2');주의사항:
VALUES (...)의 순서는 항상NAME다음에 메타데이터 정의 순서를 따릅니다.- 지정하지 않은 메타데이터 컬럼은
NULL로 저장됩니다. - 메타데이터 행의 식별자는 항상
NAME입니다. - 메타데이터 행이 생성되면
_LAST_UPDATE_TIME이 서버 시각으로 자동 기록됩니다.
메타데이터 조회
메타데이터만 조회
메타데이터 전용 조회는 FROM TAG METADATA 를 사용합니다.
SELECT name, location, status, srcip
FROM sensors METADATA
ORDER BY name;이 조회는 태그 이름당 1행을 반환합니다.
SELECT *
FROM sensors METADATA
ORDER BY name;SELECT * 와 table_alias.* 는 NAME 과 메타데이터 컬럼만 반환합니다.
_LAST_UPDATE_TIME 같은 시스템 관리 컬럼은 SELECT * 결과에 표시되지 않습니다. 필요한 경우 컬럼명을 명시합니다.
마지막 변경 시각 조회
TAG metadata에는 각 metadata row의 마지막 변경 시각을 나타내는 시스템 관리 컬럼 _LAST_UPDATE_TIME 이 있습니다.
_LAST_UPDATE_TIME 은 tag data row의 마지막 입력 시각이 아니라, tag metadata row가 생성되거나 실제 metadata 값이 변경된 시각입니다.
조회 방법
_LAST_UPDATE_TIME 은 명시적으로 컬럼명을 지정해서 조회합니다.
SELECT name, _last_update_time
FROM sensors METADATA;다른 metadata 컬럼과 함께 조회하거나 조건에 사용할 수 있습니다.
SELECT name, location, status, _last_update_time
FROM sensors METADATA
WHERE name = 'TEMP_001';SELECT * 와 table_alias.* 결과에는 _LAST_UPDATE_TIME 이 표시되지 않습니다.
자동 기록 및 갱신 규칙
metadata row가 새로 생성되면 _LAST_UPDATE_TIME 이 자동으로 기록됩니다.
INSERT INTO sensors METADATA(name, location, status)
VALUES('TEMP_003', 'Building-A/F3', 'READY');사용자 metadata 값이 실제로 변경되면 _LAST_UPDATE_TIME 이 갱신됩니다.
UPDATE sensors METADATA
SET status = 'DONE'
WHERE name = 'TEMP_003';같은 값으로 update하거나 JSON missing path 제거처럼 저장 결과가 바뀌지 않는 update는 실제 변경으로 보지 않습니다. 이 경우 _LAST_UPDATE_TIME 은 유지됩니다.
UPDATE sensors METADATA
SET status = 'DONE'
WHERE name = 'TEMP_003';JSON metadata 컬럼 info 가 있는 테이블에서는 존재하지 않는 경로 제거도 저장값을 바꾸지 않으면 no-op으로 처리됩니다.
UPDATE sensors METADATA
SET info = JSON_REMOVE(info, '$.missing')
WHERE name = 'TEMP_003';직접 입력 및 수정 제한
_LAST_UPDATE_TIME 은 시스템 관리 컬럼이므로 사용자가 직접 값을 넣거나 수정할 수 없습니다.
다음 문장은 허용되지 않습니다.
INSERT INTO sensors METADATA(name, location, status, _last_update_time)
VALUES('TEMP_004', 'Building-A/F4', 'READY', now);UPDATE sensors METADATA
SET _last_update_time = now
WHERE name = 'TEMP_003';또한 TAG name 컬럼명, TAG metadata 컬럼명, ALTER TABLE ... METADATA ADD COLUMN 대상 컬럼명으로 _LAST_UPDATE_TIME 을 사용할 수 없습니다. ALTER TABLE ... METADATA DROP COLUMN 으로 _LAST_UPDATE_TIME 을 삭제할 수도 없습니다.
CREATE TAG TABLE invalid_sensor (
_last_update_time VARCHAR(128) PRIMARY KEY,
time DATETIME BASETIME,
value DOUBLE
);CREATE TAG TABLE invalid_sensor_meta (
name VARCHAR(128) PRIMARY KEY,
time DATETIME BASETIME,
value DOUBLE
)
METADATA (
_last_update_time DATETIME
);_LAST_UPDATE_TIME2 처럼 prefix만 같은 이름은 별도 사용자 컬럼으로 사용할 수 있습니다.
시간 조건 조회 및 자동 인덱스
_LAST_UPDATE_TIME 에는 시간 조건 조회를 위한 인덱스가 자동으로 제공됩니다.
SELECT name, location, _last_update_time
FROM sensors METADATA
WHERE _last_update_time >= TO_DATE('2026-06-08 00:00:00')
ORDER BY _last_update_time;따라서 같은 컬럼에 사용자가 별도 인덱스를 중복 생성할 필요가 없습니다.
machloader / tagmetaimport 사용 시 주의사항
TAG metadata를 import할 때 입력 파일이나 form 파일에는 NAME 과 사용자 metadata 컬럼만 포함합니다. 내부 컬럼인 _ID 와 시스템 관리 컬럼 _LAST_UPDATE_TIME 은 입력 대상이 아닙니다.
metadata가 location, status 인 경우 입력 데이터는 다음 형태를 사용합니다.
TEMP_001,Building-A/F1,READY
TEMP_002,Building-A/F2,STOP_LAST_UPDATE_TIME 은 import 시 서버가 자동으로 채웁니다.
일반 LOG, LOOKUP, VOLATILE 테이블에서 사용자가 _LAST_UPDATE_TIME 이라는 이름의 컬럼을 정의한 경우에는 일반 사용자 컬럼으로 동작합니다. 예약 동작은 TAG metadata 시스템 컬럼에만 적용됩니다.
데이터와 함께 조회
메타데이터 조건으로 시계열 데이터를 조회할 때는 일반 FROM TAG 를 사용합니다.
SELECT name, status, time, value
FROM sensors
WHERE status = 'READY'
ORDER BY name, time;이 조회는 데이터 row 기준으로 반환되므로, 같은 tag의 메타데이터 값은 각 데이터 row마다 반복됩니다.
주의사항:
FROM TAG METADATA에서는TIME,VALUE같은 데이터 컬럼을 조회할 수 없습니다.FROM TAG는 데이터 조회 모드이고,FROM TAG METADATA는 메타데이터 조회 모드입니다.TAG METADATA에서는 내부 컬럼_ID,_RID를 사용할 수 없습니다.
메타데이터 수정
메타데이터 수정은 UPDATE TAG METADATA 를 사용합니다.
UPDATE sensors METADATA
SET status = 'DONE',
srcip = '10.0.0.20'
WHERE name = 'TEMP_001';메타데이터 조건으로 여러 태그를 한 번에 수정할 수도 있습니다.
UPDATE sensors METADATA
SET status = 'DONE'
WHERE status = 'READY';주의사항:
- 수정 대상은
NAME과 메타데이터 컬럼입니다. TIME,VALUE같은 데이터 컬럼은UPDATE ... METADATA에서 수정할 수 없습니다.- 내부 컬럼은 수정할 수 없습니다.
- 실제 metadata 값이 바뀐 경우에만
_LAST_UPDATE_TIME이 갱신됩니다.
메타데이터 삭제
메타데이터 삭제는 DELETE FROM TAG METADATA 를 사용합니다.
특정 태그의 메타데이터를 삭제하려면 WHERE 절에서 tag name 조건을 지정합니다.
DELETE FROM sensors METADATA
WHERE name = 'TEMP_002';메타데이터 조건으로 여러 태그를 한 번에 삭제할 수도 있습니다.
DELETE FROM sensors METADATA
WHERE status = 'STOP';WHERE 절을 생략하면 해당 TAG 테이블의 모든 메타데이터를 삭제합니다.
DELETE FROM sensors METADATA;주의사항:
- 삭제 대상 중 하나라도 실제 데이터 row를 가지고 있으면 문장 전체가 실패합니다.
- 즉, 사용 중인 tag의 메타데이터는 삭제할 수 없습니다.
- 전체 삭제 시에도 사용 중인 tag가 하나라도 있으면 일부만 삭제하지 않고 문장 전체가 실패합니다.
사용 중인 tag의 메타데이터를 삭제하려면 먼저 해당 tag의 데이터 row를 삭제한 뒤 메타데이터 삭제를 다시 수행합니다.
DELETE FROM sensors
WHERE name = 'TEMP_001';
DELETE FROM sensors METADATA;JSON 메타데이터 컬럼
메타데이터에 JSON 컬럼을 선언할 수 있습니다.
CREATE TAG TABLE ships (
name VARCHAR(20) PRIMARY KEY,
time DATETIME BASETIME,
value DOUBLE
)
METADATA (
status VARCHAR(20),
info JSON
);JSON 메타데이터 입력 예:
INSERT INTO ships METADATA VALUES (
'SHIP_001',
'READY',
'{"name":"alpha","ship":{"status":"READY"}}'
);주의사항:
JSON메타데이터 컬럼은 길이를 지정하지 않습니다.- 유효하지 않은 JSON 문자열은 오류가 발생합니다.
- raw JSON 컬럼 자체에는 자동 인덱스가 생성되지 않습니다.
JSON path 조회
JSON 메타데이터는 -> 연산자로 조회할 수 있습니다.
SELECT name,
info->'$.name',
info->'$.ship.status'
FROM ships METADATA
WHERE info->'$.ship.status' = 'READY'
ORDER BY name;데이터 조회에서도 같은 방식으로 사용할 수 있습니다.
SELECT name, time, value
FROM ships
WHERE info->'$.ship.status' = 'READY'
ORDER BY name, time;경로 표기 규칙
조회와 부분 갱신에서 사용하는 path는 full JSONPath를 사용합니다.
- 일반 key:
$.name - 중첩 key:
$.ship.status - key 이름에
.또는-가 포함되면 bracket 표기 사용
SELECT info->'$[''ship.owner'']'
FROM ships METADATA;
SELECT info->'$[''ship-owner'']'
FROM ships METADATA;JSON path 인덱스
테이블 생성 시 함께 선언
자주 조회하는 JSON path는 메타데이터 정의 시 함께 인덱싱할 수 있습니다.
CREATE TAG TABLE ships (
name VARCHAR(20) PRIMARY KEY,
time DATETIME BASETIME,
value DOUBLE
)
METADATA (
status VARCHAR(20),
info JSON INDEX('name', 'ship.status')
);INDEX(...) 안의 문자열은 다음 규칙으로 해석합니다.
'name'은$.name'ship.status'는$.ship.status- 특수 문자가 있는 key나 복잡한 경로는 full JSONPath를 직접 사용
INFO JSON INDEX('$[''ship.owner'']')생성 후 인덱스 추가
테이블 생성 후에도 JSON path 인덱스를 추가할 수 있습니다.
CREATE INDEX idx_ship_owner
ON ships METADATA (info->'$.owner');인덱스 삭제
인덱스 이름만으로 삭제합니다.
DROP INDEX idx_ship_owner;생성 시 INFO JSON INDEX(...) 로 자동 생성된 인덱스 이름은 SHOW INDEX 로 확인하는 것이 가장 안전합니다.
SHOW INDEX idx_ship_owner;인덱스 사용 시 주의사항
현재 JSON path 인덱스는 문자열 비교 중심으로 동작합니다.
SELECT name
FROM ships METADATA
WHERE info->'$.status' = 'READY';문자열 literal 비교는 인덱스를 사용할 수 있습니다. 반면 숫자 literal 비교는 full scan으로 처리될 수 있습니다.
예:
info->'$.num' = '10': 인덱스 사용 가능info->'$.num' = 10: full scan 가능
JSON 부분 갱신
JSON 메타데이터는 문서 전체를 다시 쓰지 않고 일부만 갱신할 수 있습니다.
JSON_SET
SQL scalar 값을 JSON scalar로 저장합니다.
UPDATE ships METADATA
SET info = JSON_SET(info, '$.ship.status', 'DONE')
WHERE name = 'SHIP_001';JSON_SET_JSON
입력 문자열을 JSON으로 해석해 object 또는 array를 저장합니다.
UPDATE ships METADATA
SET info = JSON_SET_JSON(info, '$.owner', '{"name":"machbase","team":"db"}')
WHERE name = 'SHIP_001';JSON_REMOVE
특정 멤버 또는 하위 경로를 삭제합니다.
UPDATE ships METADATA
SET info = JSON_REMOVE(info, '$.owner.team')
WHERE name = 'SHIP_001';부분 갱신 규칙
JSON_SET(..., path, NULL)은 JSONnull을 저장합니다.JSON_SET_JSON(..., path, NULL)의 결과는 SQLNULL입니다.- JSON 문서 인자가
NULL이면 함수 결과는 SQLNULL입니다. - path 가
NULL이거나 빈 문자열이면 오류가 발생합니다. - 존재하지 않는 경로에 대한
JSON_REMOVE는 오류가 아니라 no-op 입니다. JSON_REMOVE(..., '$')는 허용되지 않습니다.- 부분 갱신은 object 경로 중심으로 지원합니다.
- array element 경로 갱신 예:
$.items[0]는 지원하지 않습니다.
전체 예제
CREATE TAG TABLE ships (
name VARCHAR(20) PRIMARY KEY,
time DATETIME BASETIME,
value DOUBLE
)
METADATA (
status VARCHAR(20),
srcip IPV4,
info JSON INDEX('name', 'ship.status')
);
INSERT INTO ships METADATA VALUES (
'SHIP_001',
'READY',
'192.168.0.11',
'{"name":"alpha","ship":{"status":"READY"}}'
);
INSERT INTO ships VALUES ('SHIP_001', '2026-04-01 00:00:00', 10.5);
SELECT name, status, info
FROM ships METADATA;
SELECT name, time, value
FROM ships
WHERE info->'$.ship.status' = 'READY';
CREATE INDEX idx_ship_owner
ON ships METADATA (info->'$.owner');
UPDATE ships METADATA
SET info = JSON_SET(info, '$.ship.status', 'DONE')
WHERE name = 'SHIP_001';
DROP INDEX idx_ship_owner;요약
- 메타데이터 전용 조회는
FROM TAG METADATA - 데이터 조회는
FROM TAG - 메타데이터 수정/삭제는
UPDATE/DELETE ... METADATA - JSON 메타데이터는
INFO JSON _LAST_UPDATE_TIME은 metadata row의 마지막 변경 시각이며 명시적으로 조회할 수 있습니다- JSON path 인덱스는
INFO JSON INDEX(...)또는CREATE INDEX ... ON TAG METADATA (...) - JSON 부분 갱신은
JSON_SET,JSON_SET_JSON,JSON_REMOVE _LAST_UPDATE_TIME은 서버가 자동 관리하며 standard와 cluster 환경에서 동일하게 동작합니다