Impala 로 테이블을 조회하거나 만들 때 아래와 같은 오류가 난다.
AnalysisException: Column does not have the decimal precision set
Impala 의 DECIMAL 은 정밀도(precision) 와 스케일(scale) 을 반드시 갖는 타입이다. DECIMAL(10,2) 처럼 전체 자릿수와 소수부 자릿수가 메타데이터에 있어야 한다. 이 값이 비어 있는 컬럼을 만나면 Impala 가 분석 단계에서 거부한다.
DDL 을 Impala 로 직접 쓴 경우에는 잘 나지 않는다. 대부분 메타데이터가 Impala 밖에서 만들어졌을 때 생긴다.
Hive 나 Spark 로 만든 테이블을 Impala 가 읽는 경우, Hive 는 DECIMAL 을 정밀도 없이 선언하는 것을 허용했던 시기가 있고 그때 만들어진 컬럼은 정밀도가 비어 있다. Hive 0.13 이후의 기본값은 DECIMAL(10,0) 이지만, 그 전에 만들어졌거나 마이그레이션으로 옮겨 온 메타데이터에는 값이 없을 수 있다.
Avro · Parquet 스키마를 그대로 받아 외부 테이블을 만든 경우에도 논리 타입 정보가 온전히 옮겨지지 않으면 같은 상태가 된다.
DESCRIBE FORMATTED db.tbl;
문제 컬럼의 타입이 decimal 로만 찍히고 괄호가 없으면 정밀도가 비어 있는 것이다. 정상이라면 decimal(10,2) 처럼 나온다.
컬럼 타입을 명시적으로 지정한다. 기존 테이블은 컬럼 정의를 바꾼다.
ALTER TABLE db.tbl CHANGE amount amount DECIMAL(18,2);
INVALIDATE METADATA db.tbl;
새로 만들 때는 처음부터 값을 준다.
CREATE TABLE db.tbl (
id BIGINT,
amount DECIMAL(18,2)
)
STORED AS PARQUET;
Hive 에서 만든 테이블이면 Hive 쪽에서 고친 뒤 Impala 에 반영한다.
-- Hive
ALTER TABLE db.tbl CHANGE amount amount DECIMAL(18,2);
-- Impala
INVALIDATE METADATA db.tbl;
DECIMAL(p, s) 에서 p 는 전체 유효 자릿수, s 는 그중 소수부 자릿수다. 정수부에 쓸 수 있는 자릿수는 p - s 이므로, DECIMAL(10,2) 는 정수부가 8자리까지다. 금액 컬럼을 DECIMAL(10,2) 로 잡았다가 값이 1억을 넘으면서 NULL 이 되거나 오버플로가 나는 사고가 흔하다.
Impala 가 지원하는 최대 정밀도는 38 이다. 여유가 필요하면 DECIMAL(38,s) 까지 쓸 수 있지만, 정밀도가 18 을 넘으면 내부 표현이 넓어져 저장 크기와 연산 비용이 늘어난다. 실제 값 범위를 보고 정한다.
연산 결과의 타입도 주의한다. DECIMAL 끼리 나누거나 곱하면 결과 정밀도가 규칙에 따라 커지고, 38 을 넘으면 스케일이 줄어들며 값이 잘린다. 중간 계산에서 스케일이 얼마가 되는지는 DESCRIBE 로 확인하기 어려우므로, 정밀한 계산이 필요하면 각 단계에서 CAST 로 명시한다.
이미 적재된 Parquet 파일의 실제 값이 새 정밀도를 넘으면 조회 시점에 오류가 나거나 NULL 이 된다. 타입을 좁히는 방향으로 바꿀 때는 먼저 최댓값을 확인한다.
SELECT MAX(LENGTH(CAST(amount AS STRING))) FROM db.tbl;
INVALIDATE METADATA 와 REFRESH 의 차이.