Oracle ORA-01792 오류 원인과 해결 방법 완벽 가이드

ORA-01792
2026년 08월 02일 | DBMS Error 가이드

이 글에서 다루는 내용

ORA-01792 에러의 원인 분석, 해결 SQL, 예방 방법을 실무 관점에서 정리합니다.

ORA-01792 maximum number of columns in a table or view is 1000 는?

ORA-01792 에러는 Oracle 데이터베이스에서 단일 테이블 또는 뷰에 정의할 수 있는 컬럼의 최대 개수인 1,000개를 초과하려 할 때 발생하는 에러입니다. 이 제한은 Oracle 데이터베이스의 내부 아키텍처에 의해 부과된 하드 리밋(Hard Limit)으로, 어떠한 파라미터 설정으로도 변경이 불가능합니다. 주로 대규모 데이터 마이그레이션, 레거시 시스템 전환, 동적 SQL을 이용한 테이블 생성, 또는 잘못 설계된 데이터 모델에서 빈번하게 나타납니다.


주요 발생 원인

1. 잘못된 데이터 모델 설계 (비정규화된 Wide Table)

가장 흔한 원인으로, 정규화(Normalization) 과정을 생략하거나 무시하고 모든 속성을 단일 테이블에 몰아넣는 설계 방식에서 발생합니다. 예를 들어, 월별·일별 매출 데이터를 행(Row) 대신 열(Column)로 펼쳐놓거나, 제품의 수백 가지 속성을 개별 컬럼으로 관리하는 경우가 대표적입니다. 이는 단기적으로 쿼리가 단순해 보일 수 있으나, 유지보수성과 확장성 측면에서 심각한 문제를 야기합니다.

2. 레거시 시스템 마이그레이션 또는 외부 데이터 임포트

ERP, CRM 등 레거시 시스템에서 데이터를 Oracle로 이관하는 과정에서 원본 시스템의 구조를 그대로 복제하려 할 때 발생합니다. 특히 Oracle이 아닌 다른 RDBMS(예: SQL Server, MySQL의 일부 버전)는 컬럼 수 제한이 다르거나 더 유연할 수 있어, 마이그레이션 과정에서 이 에러를 마주치게 됩니다. DDL 스크립트를 자동 생성하는 도구를 사용할 때 이 제한을 사전에 검토하지 않으면 문제가 발생합니다.

3. 동적 SQL 또는 CREATE TABLE AS SELECT (CTAS)를 통한 테이블 생성

애플리케이션 코드나 스크립트에서 동적으로 컬럼을 추가하거나, 여러 테이블을 JOIN하여 CTAS(Create Table As Select) 방식으로 새로운 테이블을 생성할 때 발생합니다. 다수의 테이블을 조인하는 복잡한 뷰(View)를 생성하거나, SELECT * 구문을 남용하여 수백 개의 컬럼이 포함된 결과셋을 새로운 테이블로 만들 때 이 제한에 걸릴 수 있습니다. 자동화된 ETL 파이프라인에서 특히 주의가 필요합니다.


해결 방법

해결책 1: 테이블 수직 분할 (Vertical Partitioning / Table Splitting)

가장 근본적인 해결책입니다. 1,000개를 초과하는 컬럼을 논리적 그룹으로 분리하여 여러 테이블로 나눕니다. 공통 PK(Primary Key)를 통해 1:1 관계로 연결하면 데이터 무결성을 유지하면서 제한을 우회할 수 있습니다.

-- 문제 상황: 1,000개 이상의 컬럼을 가진 테이블 생성 시도
-- ORA-01792 발생
CREATE TABLE WIDE_PRODUCT (
    PRODUCT_ID   NUMBER PRIMARY KEY,
    ATTR_001     VARCHAR2(100),
    ATTR_002     VARCHAR2(100),
    -- ... (1,000개 초과)
    ATTR_1001    VARCHAR2(100)  -- 여기서 에러 발생
);

-- 해결책: 테이블을 논리적 그룹으로 분리
-- 기본 정보 테이블
CREATE TABLE PRODUCT_BASE (
    PRODUCT_ID   NUMBER PRIMARY KEY,
    PRODUCT_NAME VARCHAR2(200),
    CATEGORY     VARCHAR2(100),
    CREATE_DATE  DATE
);

-- 속성 그룹 1 (ATTR_001 ~ ATTR_500)
CREATE TABLE PRODUCT_ATTR_GROUP1 (
    PRODUCT_ID   NUMBER PRIMARY KEY,
    ATTR_001     VARCHAR2(100),
    ATTR_002     VARCHAR2(100),
    -- ...
    ATTR_500     VARCHAR2(100),
    CONSTRAINT FK_PAG1_PROD FOREIGN KEY (PRODUCT_ID)
        REFERENCES PRODUCT_BASE(PRODUCT_ID)
);

-- 속성 그룹 2 (ATTR_501 ~ ATTR_999)
CREATE TABLE PRODUCT_ATTR_GROUP2 (
    PRODUCT_ID   NUMBER PRIMARY KEY,
    ATTR_501     VARCHAR2(100),
    ATTR_502     VARCHAR2(100),
    -- ...
    ATTR_999     VARCHAR2(100),
    CONSTRAINT FK_PAG2_PROD FOREIGN KEY (PRODUCT_ID)
        REFERENCES PRODUCT_BASE(PRODUCT_ID)
);

-- 통합 뷰 생성 (애플리케이션은 뷰를 통해 접근)
CREATE OR REPLACE VIEW PRODUCT_FULL_VIEW AS
SELECT b.*, g1.ATTR_001, g1.ATTR_002, -- ...필요한 컬럼
       g2.ATTR_501, g2.ATTR_502        -- ...필요한 컬럼
FROM   PRODUCT_BASE b
LEFT JOIN PRODUCT_ATTR_GROUP1 g1 ON b.PRODUCT_ID = g1.PRODUCT_ID
LEFT JOIN PRODUCT_ATTR_GROUP2 g2 ON b.PRODUCT_ID = g2.PRODUCT_ID;

해결책 2: EAV(Entity-Attribute-Value) 모델로 재설계

컬럼 수가 매우 많고 희소(Sparse)한 경우, 즉 대부분의 행에서 많은 컬럼이 NULL인 경우 EAV 모델이 효과적입니다.

-- EAV 모델 구현
CREATE TABLE PRODUCT_MASTER (
    PRODUCT_ID   NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
    PRODUCT_NAME VARCHAR2(200) NOT NULL,
    CREATE_DATE  DATE DEFAULT SYSDATE
);

CREATE TABLE PRODUCT_ATTRIBUTES (
    ATTR_ID      NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
    PRODUCT_ID   NUMBER NOT NULL,
    ATTR_NAME    VARCHAR2(100) NOT NULL,   -- 속성 이름 (예: 'COLOR', 'WEIGHT')
    ATTR_VALUE   VARCHAR2(4000),            -- 속성 값
    ATTR_TYPE    VARCHAR2(20),              -- 데이터 타입 힌트 (VARCHAR, NUMBER, DATE)
    CONSTRAINT FK_PA_PROD FOREIGN KEY (PRODUCT_ID)
        REFERENCES PRODUCT_MASTER(PRODUCT_ID),
    CONSTRAINT UQ_PA_PROD_ATTR UNIQUE (PRODUCT_ID, ATTR_NAME)
);

-- 인덱스 생성 (조회 성능 확보)
CREATE INDEX IDX_PA_PRODUCT_ID ON PRODUCT_ATTRIBUTES(PRODUCT_ID);
CREATE INDEX IDX_PA_ATTR_NAME  ON PRODUCT_ATTRIBUTES(ATTR_NAME);

-- 데이터 삽입 예시
INSERT INTO PRODUCT_MASTER (PRODUCT_NAME) VALUES ('Oracle Database 19c');
INSERT INTO PRODUCT_ATTRIBUTES (PRODUCT_ID, ATTR_NAME, ATTR_VALUE, ATTR_TYPE)
VALUES (1, 'VERSION', '19.3.0', 'VARCHAR');
INSERT INTO PRODUCT_ATTRIBUTES (PRODUCT_ID, ATTR_NAME, ATTR_VALUE, ATTR_TYPE)
VALUES (1, 'RELEASE_YEAR', '2019', 'NUMBER');

-- PIVOT을 이용한 조회 (동적 컬럼화)
SELECT *
FROM (
    SELECT PRODUCT_ID, ATTR_NAME, ATTR_VALUE
    FROM   PRODUCT_ATTRIBUTES
    WHERE  PRODUCT_ID = 1
)
PIVOT (
    MAX(ATTR_VALUE)
    FOR ATTR_NAME IN ('VERSION' AS VERSION, 'RELEASE_YEAR' AS RELEASE_YEAR)
);

해결책 3: 현재 컬럼 수 확인 및 뷰 컬럼 수 점검

에러 발생 전 현황을 파악하는 진단 쿼리입니다.

-- 테이블별 컬럼 수 확인 (900개 이상인 테이블 조회 - 위험 임박 테이블)
SELECT TABLE_NAME,
       COUNT(*) AS COLUMN_COUNT,
       CASE
           WHEN COUNT(*) >= 1000 THEN '★ 한도 초과'
           WHEN COUNT(*) >= 900  THEN '▲ 위험 수준'
           WHEN COUNT(*) >= 800  THEN '△ 주의 수준'
           ELSE '정상'
       END AS STATUS
FROM   DBA_TAB_COLUMNS
WHERE  OWNER = 'YOUR_SCHEMA'  -- 스키마명 변경
GROUP BY TABLE_NAME
HAVING COUNT(*) >= 800
ORDER BY COLUMN_COUNT DESC;

-- 뷰별 컬럼 수 확인
SELECT VIEW_NAME,
       COUNT(*) AS COLUMN_COUNT
FROM   DBA_TAB_COLUMNS
WHERE  OWNER = 'YOUR_SCHEMA'
  AND  TABLE_NAME IN (SELECT VIEW_NAME FROM DBA_VIEWS WHERE OWNER = 'YOUR_SCHEMA')
GROUP BY VIEW_NAME
HAVING COUNT(*) >= 800
ORDER BY COLUMN_COUNT DESC;

-- 특정 테이블의 컬럼 목록 및 순서 확인
SELECT COLUMN_ID,
       COLUMN_NAME,
       DATA_TYPE,
       DATA_LENGTH,
       NULLABLE
FROM   DBA_TAB_COLUMNS
WHERE  OWNER      = 'YOUR_SCHEMA'
  AND  TABLE_NAME = 'YOUR_TABLE'
ORDER BY COLUMN_ID;

예방 방법

1. 설계 단계에서 컬럼 수 모니터링 및 아키텍처 리뷰 의무화

데이터베이스 설계 단계에서 논리적 데이터 모델(ERD)을 검토할 때 단일 엔티티의 속성 수가 300개를 초과하면 반드시 설계 리뷰를 수행하도록 팀 내 규칙을 수립합니다. CI/CD 파이프라인 또는 DDL 배포 프로세스에 아래와 같은 사전 검증 스크립트를 포함시켜 900개 이상의 컬럼을 가진 테이블에 대한 DDL 실행 전 경고 또는 차단 메커니즘을 구축하는 것을 권장합니다.

-- DDL 배포 전 컬럼 수 사전 검증 스크립트 (임계치: 900개)
DECLARE
    v_col_count NUMBER;
    v_table_name VARCHAR2(30) := 'TARGET_TABLE_NAME'; -- 검사할 테이블명
    v_owner      VARCHAR2(30) := 'YOUR_SCHEMA';
BEGIN
    SELECT COUNT(*)
    INTO   v_col_count
    FROM   DBA_TAB_COLUMNS
    WHERE  OWNER      = v_owner
      AND  TABLE_NAME = v_table_name;

    IF v_col_count >= 900 THEN
        DBMS_OUTPUT.PUT_LINE('[경고] ' || v_table_name ||
            ' 테이블의 현재 컬럼 수: ' || v_col_count ||
            '개. 1,000개 한도까지 ' || (1000 - v_col_count) || '개 남음. 설계 검토 필요!');
    ELSE
        DBMS_OUTPUT.PUT_LINE('[정상] ' || v_table_name ||
            ' 테이블 컬럼 수: ' || v_col_count || '개');
    END IF;
END;
/

2. 정규화 원칙 준수 및 JSON/XML 컬럼 활용 검토

3NF(제3정규형) 이상의 정규화를 기본 설계 원칙으로 삼고, 속성이 매우 많고 동적으로 변하는 데이터는 Oracle 12c 이상에서 지원하는 JSON 컬럼 또는 XMLType을 활용하여 설계합니다. 이를 통해 컬럼 수를 획기적으로 줄이면서도 유연한 데이터 구조를 유지할 수 있습니다.

-- Oracle 12c 이상: JSON을 활용한 유연한 속성 관리
CREATE TABLE PRODUCT_JSON (
    PRODUCT_ID   NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
    PRODUCT_NAME VARCHAR2(200) NOT NULL,
    ATTRIBUTES   CLOB,  -- JSON 형태로 수백 개의 속성 저장
    CREATE_DATE  DATE DEFAULT SYSDATE,
    CONSTRAINT CHK_ATTR_JSON CHECK (ATTRIBUTES IS JSON)
);

-- JSON 데이터 삽입
INSERT INTO PRODUCT_JSON (PRODUCT_NAME, ATTRIBUTES)
VALUES ('Sample Product',
        '{"color": "red", "weight": 1.5, "dimensions": {"width": 10, "height": 20}}');

-- JSON 속성 조회 (Oracle 12c+)
SELECT PRODUCT_ID,
       PRODUCT_NAME,
       JSON_VALUE(ATTRIBUTES, '$.color')              AS COLOR,
       JSON_VALUE(ATTRIBUTES, '$.weight')             AS WEIGHT,
       JSON_VALUE(ATTRIBUTES, '$.dimensions.width')   AS WIDTH
FROM   PRODUCT_JSON
WHERE  JSON_VALUE(ATTRIBUTES, '$.color') = 'red';

관련 에러

  • ORA-01795: maximum number of expressions in a list is 1000 — IN 절에 1,000개를 초과하는 값을 사용할 때 발생하며, ORA-01792와 마찬가지로 Oracle의 1,000이라는 내부 한계와 관련됩니다.
  • ORA-00910: specified length too long for its datatype — 컬럼 데이터 타입의 길이 제한 초과 시 발생하며, 넓은 테이블 설계 시 함께 마주칠 수 있습니다.
  • ORA-01401: inserted value too large for column — 컬럼 크기 정의가 부적절할 때 발생하며, 대규모 테이블 설계 오류와 연관될 수 있습니다.
  • ORA-00604: error occurred at recursive SQL level — 내부 딕셔너리 작업 중 제약이 걸릴 때 ORA-01792와 함께 나타날 수 있습니다.

DBMS 에러 코드 시리즈

주요 DBMS error code를 정리하는 시리즈입니다.
블로그 홈에서 다른 에러도 확인하세요.

본 포스트는 AI가 생성한 기술 가이드입니다. 운영 환경 적용 전 충분한 검토를 권장합니다.

댓글 남기기