

기계 번역으로 제공되는 번역입니다. 제공된 번역과 원본 영어의 내용이 상충하는 경우에는 영어 버전이 우선합니다.

# Oracle ROWID 기능을 AWS 기반 PostgreSQL로 마이그레이션
<a name="migrate-oracle-rowid-functionality-to-postgresql-on-aws"></a>

*Rakesh Raghav, Ramesh Pathuri, Amazon Web Services*

## 요약
<a name="migrate-oracle-rowid-functionality-to-postgresql-on-aws-summary"></a>

이 패턴은 Amazon Relational Database Service(Amazon RDS) for PostgreSQL, Amazon Aurora PostgreSQL-Compatible Edition 또는 Amazon Elastic Compute Cloud(Amazon EC2)에서 Oracle Database의 `ROWID` 가상 열 기능을 PostgreSQL 데이터베이스로 마이그레이션하는 옵션을 설명합니다.

Oracle 데이터베이스에서 `ROWID` 가상 열은 테이블 행의 물리적 주소입니다. 이 가상 열은 테이블에 프라이머리 키가 없더라도 행을 고유하게 식별하는 데 사용됩니다. PostgreSQL에는 `ctid`라는 유사한 가상 열이 있지만 `ROWID`로 사용할 수는 없습니다. [PostgreSQL 설명서](https://www.postgresql.org/docs/current/ddl-system-columns.html)에 설명된 대로 업데이트되거나 `VACUUM` 프로세스가 끝날 때마다 `ctid`를 변경될 수 있습니다.

`ROWID` PostgreSQL에서 가상 열 기능을 생성할 수 있는 세 가지 방법이 있습니다.
+ 테이블의 행을 식별하려면 `ROWID` 대신 프라이머리 키 열을 사용하십시오.
+ 테이블의 논리적 프라이머리/고유 키(복합 키일 수 있음)를 사용하십시오. 
+ 자동 생성된 값이 있는 열을 추가하고 `ROWID`를 모방할 프라이머리/고유 키를 만듭니다.

이 패턴은 세 가지 구현을 모두 안내하고 각 옵션의 장단점을 설명합니다.

## 사전 조건 및 제한 사항
<a name="migrate-oracle-rowid-functionality-to-postgresql-on-aws-prereqs"></a>

**사전 조건 **
+ 활성 상태의 AWS 계정
+ 절차적 언어/PostgreSQL(PL/PgSQL) 코딩 전문 지식
+ Source Oracle Database
+ Amazon RDS for PostgreSQL 또는 Aurora PostgreSQL-Compatible 클러스터 또는 PostgreSQL 데이터베이스를 호스팅하기 위한 EC2 인스턴스

**제한 사항 **
+ 이 패턴은 `ROWID` 기능에 대한 해결 방법을 제공합니다. PostgreSQL은 Oracle Database에서 `ROWID`와 동등한 기능을 제공하지 않습니다.

**제품 버전**
+ PostgreSQL 11.9 이상

## 아키텍처
<a name="migrate-oracle-rowid-functionality-to-postgresql-on-aws-architecture"></a>

**소스 기술 스택  **
+ Oracle Database

**대상 기술 스택  **
+ Aurora PostgreSQL-Compatible, Amazon RDS for PostgreSQL 또는 PostgreSQL 데이터베이스가 있는 EC2 인스턴스

![Oracle Database를 AWS 기반 PostgreSQL로 전환](http://docs.aws.amazon.com/ko_kr/prescriptive-guidance/latest/patterns/images/pattern-img/9a2ce994-4f68-4975-aab2-796cc20a3c82/images/6e7c2ef6-f440-476a-9003-f1f166718e15.png)


**구현 옵션**

테이블에 프라이머리 키 또는 고유 인덱스, 논리적 프라이머리 키 또는 자격 증명 속성이 있는지 여부에 따라 PostgreSQL에서 `ROWID`가 지원되지 않는 문제를 해결하는 세 가지 옵션이 있습니다. 프로젝트 일정, 현재 마이그레이션 단계, 애플리케이션 및 데이터베이스 코드에 대한 종속성 등에 따라 선택이 달라집니다.


| 
| 
| 옵션 | 설명 | 장점 | 단점 | 
| --- |--- |--- |--- |
| **프라이머리 키 또는 고유 인덱스** | Oracle 테이블에 프라이머리 키가 있는 경우 이 키의 속성을 사용하여 행을 고유하게 식별할 수 있습니다.  | 전용 데이터베이스 기능에 종속되지 않습니다.프라이머리 키 필드가 인덱싱되므로 성능에 미치는 영향이 최소화됩니다. | 자격 증명 속성으로 전환하는 데 `ROWID`에 의존하는 애플리케이션 및 데이터베이스 코드를 변경해야 합니다.  | 
| **논리적 프라이머리/고유 키** | Oracle 테이블에 논리적 프라이머리 키가 있는 경우 이 키의 속성을 사용하여 행을 고유하게 식별할 수 있습니다. 논리적 프라이머리 키는 행을 고유하게 식별할 수 있는 속성 또는 속성 집합으로 구성되지만 제약 조건을 통해 데이터베이스에 적용되지는 않습니다. | 전용 데이터베이스 기능에 종속되지 않습니다. | 자격 증명 속성으로 전환하는 데 `ROWID`에 의존하는 애플리케이션 및 데이터베이스 코드를 변경해야 합니다.논리적 프라이머리 키의 속성이 인덱싱되지 않을 경우 성능에 상당한 영향을 미칩니다. 그러나 고유 인덱스를 추가하여 성능 문제를 방지할 수 있습니다. | 
| **ID 속성** | Oracle 테이블에 프라이머리 키가 없는 경우 `GENERATED ALWAYS AS IDENTITY`로 추가 필드를 생성할 수 있습니다. 이 속성은 테이블에 데이터를 삽입할 때마다 고유한 값을 생성하므로 데이터 조작 언어(DML) 작업에서 행을 고유하게 식별하는 데 사용할 수 있습니다. | 전용 데이터베이스 기능에 종속되지 않습니다.PostgreSQL 데이터베이스는 속성을 채우고 고유성을 유지합니다. | 자격 증명 속성으로 전환하는 데 `ROWID`에 의존하는 애플리케이션 및 데이터베이스 코드를 변경해야 합니다.추가 필드가 인덱싱되지 않을 경우 성능에 큰 영향을 미칩니다. 그러나 인덱스를 추가하여 성능 문제를 방지할 수 있습니다. | 

## 도구
<a name="migrate-oracle-rowid-functionality-to-postgresql-on-aws-tools"></a>
+ [Amazon Relational Database Service(RDS) for PostgreSQL](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/CHAP_PostgreSQL.html)는 AWS Cloud에서 관계형 데이터베이스를 설정, 운영 및 규모를 조정하는 데 도움이 됩니다.
+ [Amazon Aurora PostgreSQL-Compatible Edition](https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/Aurora.AuroraPostgreSQL.html)은 PostgreSQL 배포를 설정, 운영 및 규모를 조정할 수 있는 완전관리형의 ACID 준수 관계형 데이터베이스 엔진입니다.
+ [AWS Command Line Interface(AWS CLI)](https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-welcome.html)는 명령줄 쉘에서 명령을 사용하여 AWS 서비스와 상호 작용할 수 있는 오픈 소스 도구입니다. 이 패턴에서는 AWS CLI를 사용하여 **pgAdmin**을 통해 SQL 명령을 실행할 수 있습니다.
+ [pgAdmin](https://www.pgadmin.org/)은 PostgreSQL을 위한 오픈 소스 관리 도구입니다. 데이터베이스 객체를 생성, 유지 관리 및 사용하는 데 도움이 되는 그래픽 인터페이스를 제공합니다.
+ [AWS Schema Conversion Tool(AWS SCT)](https://docs.aws.amazon.com/SchemaConversionTool/latest/userguide/CHAP_Welcome.html)은 소스 데이터베이스 스키마와 대부분의 사용자 지정 코드를 대상 데이터베이스와 호환되는 형식으로 자동 변환하여 이기종 데이터베이스 마이그레이션을 지원합니다.

## 에픽
<a name="migrate-oracle-rowid-functionality-to-postgresql-on-aws-epics"></a>

### 소스 테이블 식별
<a name="identify-the-source-tables"></a>


| 작업 | 설명 | 필요한 기술 | 
| --- | --- | --- | 
| `ROWID` 속성을 사용하는 Oracle 테이블을 식별합니다. | AWS Schema Conversion Tool(AWS SCT)를 사용하여 `ROWID` 기능이 있는 Oracle 테이블을 식별할 수 있습니다. 자세한 내용은 [AWS SCT 설명서](https://docs.aws.amazon.com/SchemaConversionTool/latest/userguide/CHAP_Source.Oracle.ToPostgreSQL.html#CHAP_Source.Oracle.ToPostgreSQL.ConvertRowID)를 참조하십시오.—또는—Oracle에서는 `DBA_TAB_COLUMNS` 뷰를 사용하여 `ROWID` 속성이 있는 테이블을 식별할 수 있습니다. 이러한 필드는 영숫자 10바이트 문자를 저장하는 데 사용될 수 있습니다. 사용량을 결정하고 필요한 경우 이를 `VARCHAR` 필드로 변환합니다. | DBA 또는 개발자 | 
| 이러한 테이블을 참조하는 코드를 식별합니다. | AWS SCT를 사용하여 마이그레이션 평가 보고서를 생성하여 `ROWID`의 영향을 받는 절차를 식별합니다. 자세한 내용은 [AWS SCT 설명서](https://docs.aws.amazon.com/SchemaConversionTool/latest/userguide/CHAP_AssessmentReport.html)를 참조하십시오.—또는—소스 Oracle 데이터베이스에서 `dba_source` 테이블의 텍스트 필드를 사용하여 `ROWID` 기능을 사용하는 객체를 식별합니다. | DBA 또는 개발자 | 

### 프라이머리 키 사용 결정
<a name="determine-primary-key-usage"></a>


| 작업 | 설명 | 필요한 기술 | 
| --- | --- | --- | 
| 프라이머리 키가 없는 테이블을 식별합니다. | 소스 Oracle 데이터베이스에서 `DBA_CONSTRAINTS`를 사용하여 프라이머리 키가 없는 테이블을 식별합니다. 이 정보는 각 테이블의 전략을 결정하는 데 도움이 됩니다. 예제:<pre>select dt.*<br />from dba_tables dt<br />where not exists (select 1<br />                  from all_constraints ct<br />                  where ct.owner = Dt.owner<br />                    and ct.table_name = Dt.table_name<br />                    and ct.constraint_type = 'P'<br />                  )<br />and dt.owner = '{schema}'</pre> | DBA 또는 개발자 | 

### 솔루션 식별 및 적용
<a name="identify-and-apply-the-solution"></a>


| 작업 | 설명 | 필요한 기술 | 
| --- | --- | --- | 
| 정의되거나 논리적인 프라이머리 키가 있는 테이블에 변경 사항을 적용합니다. | 고유한 프라이머리 키를 사용하거나 테이블의 행을 식별하는 논리적 프라이머리 키를 사용하도록 [추가 정보](#migrate-oracle-rowid-functionality-to-postgresql-on-aws-additional) 섹션에 표시된 애플리케이션 및 데이터베이스 코드를 변경합니다. | DBA 또는 개발자 | 
| 정의되거나 논리적인 프라이머리 키가 없는 테이블에 필드를 추가합니다. | `GENERATED ALWAYS AS IDENTITY` 유형의 속성을 추가합니다. [추가 정보](#migrate-oracle-rowid-functionality-to-postgresql-on-aws-additional) 섹션에 표시된 애플리케이션 및 데이터베이스 코드를 변경합니다. | DBA 또는 개발자 | 
| 필요한 경우 인덱스를 추가합니다. | 추가 필드 또는 논리적 프라이머리 키에 인덱스를 추가하여 SQL 성능을 개선합니다. | DBA 또는 개발자 | 

## 관련 리소스
<a name="migrate-oracle-rowid-functionality-to-postgresql-on-aws-resources"></a>
+ [PostgreSQL CTID](https://www.postgresql.org/docs/current/ddl-system-columns.html)(PostgreSQL 설명서)
+ [생성된 컬럼](https://www.postgresql.org/docs/current/ddl-generated-columns.html)(PostgreSQL 설명서)
+ [ROWID 가상 열](https://docs.oracle.com/en/database/oracle/oracle-database/19/sqlrf/ROWID-Pseudocolumn.html#GUID-F6E0FBD2-983C-495D-9856-5E113A17FAF1)(Oracle 설명서)

## 추가 정보
<a name="migrate-oracle-rowid-functionality-to-postgresql-on-aws-additional"></a>

다음 섹션에서는 세 가지 접근 방식을 설명하는 Oracle 및 PostgreSQL 코드 예제를 제공합니다.

**시나리오 1: 프라이머리 고유 키 사용**

다음 예제에서는 `emp_id`를 프라이머리 키로 사용하여 `testrowid_s1` 테이블을 생성합니다.

*Oracle 코드:*

```
create table testrowid_s1 (emp_id integer, name varchar2(10), CONSTRAINT testrowid_pk PRIMARY KEY (emp_id));
INSERT INTO testrowid_s1(emp_id,name) values (1,'empname1');
INSERT INTO testrowid_s1(emp_id,name) values (2,'empname2');
INSERT INTO testrowid_s1(emp_id,name) values (3,'empname3');
INSERT INTO testrowid_s1(emp_id,name) values (4,'empname4');
commit;

SELECT rowid,emp_id,name FROM testrowid_s1;
ROWID                  EMP_ID NAME
------------------ ---------- ----------
AAAF3pAAAAAAAMOAAA          1 empname1
AAAF3pAAAAAAAMOAAB          2 empname2
AAAF3pAAAAAAAMOAAC          3 empname3
AAAF3pAAAAAAAMOAAD          4 empname4

UPDATE testrowid_s1 SET name = 'Ramesh' WHERE rowid = 'AAAF3pAAAAAAAMOAAB' ;
commit;

SELECT rowid,emp_id,name FROM testrowid_s1;
ROWID                  EMP_ID NAME
------------------ ---------- ----------
AAAF3pAAAAAAAMOAAA          1 empname1
AAAF3pAAAAAAAMOAAB          2 Ramesh
AAAF3pAAAAAAAMOAAC          3 empname3
AAAF3pAAAAAAAMOAAD          4 empname4
```

*PostgreSQL 코드:*

```
CREATE TABLE public.testrowid_s1
(
    emp_id integer,
    name character varying,
    primary key (emp_id)
);

insert into public.testrowid_s1 (emp_id,name) values 
(1,'empname1'),(2,'empname2'),(3,'empname3'),(4,'empname4');

select emp_id,name from testrowid_s1;
 emp_id |   name   
--------+----------
      1 | empname1
      2 | empname2
      3 | empname3
      4 | empname4

update testrowid_s1 set name = 'Ramesh' where emp_id = 2 ;

select emp_id,name from testrowid_s1;
 emp_id |   name   
--------+----------
      1 | empname1
      3 | empname3
      4 | empname4
      2 | Ramesh
```

**시나리오 2: 논리적 프라이머리 키 사용**

다음 예제에서는 논리적 프라이머리 키를 `emp_id`로 사용하여 `testrowid_s2` 테이블을 생성합니다.

*Oracle 코드:*

```
create table testrowid_s2 (emp_id integer, name varchar2(10) );
INSERT INTO testrowid_s2(emp_id,name) values (1,'empname1');
INSERT INTO testrowid_s2(emp_id,name) values (2,'empname2');
INSERT INTO testrowid_s2(emp_id,name) values (3,'empname3');
INSERT INTO testrowid_s2(emp_id,name) values (4,'empname4');
commit;

SELECT rowid,emp_id,name FROM testrowid_s2;
ROWID                  EMP_ID NAME
------------------ ---------- ----------
AAAF3rAAAAAAAMeAAA          1 empname1
AAAF3rAAAAAAAMeAAB          2 empname2
AAAF3rAAAAAAAMeAAC          3 empname3
AAAF3rAAAAAAAMeAAD          4 empname4

UPDATE testrowid_s2 SET name = 'Ramesh' WHERE rowid = 'AAAF3rAAAAAAAMeAAB' ;
commit;

SELECT rowid,emp_id,name FROM testrowid_s2;
ROWID                  EMP_ID NAME
------------------ ---------- ----------
AAAF3rAAAAAAAMeAAA          1 empname1
AAAF3rAAAAAAAMeAAB          2 Ramesh
AAAF3rAAAAAAAMeAAC          3 empname3
AAAF3rAAAAAAAMeAAD          4 empname4
```

*PostgreSQL 코드:*

```
CREATE TABLE public.testrowid_s2
(
    emp_id integer,
    name character varying
);

insert into public.testrowid_s2 (emp_id,name) values 
(1,'empname1'),(2,'empname2'),(3,'empname3'),(4,'empname4');

select emp_id,name from testrowid_s2;
 emp_id |   name   
--------+----------
      1 | empname1
      2 | empname2
      3 | empname3
      4 | empname4

update testrowid_s2 set name = 'Ramesh' where emp_id = 2 ;

select emp_id,name from testrowid_s2;
 emp_id |   name   
--------+----------
      1 | empname1
      3 | empname3
      4 | empname4
      2 | Ramesh
```

**시나리오 3: 자격 증명 속성 사용**

다음 예제에서는 프라이머리 키가 없는 상태에서 자격 증명 속성을 사용하여 `testrowid_s3` 테이블을 생성합니다.

*Oracle 코드:*

```
create table testrowid_s3 (name varchar2(10));
INSERT INTO testrowid_s3(name) values ('empname1');
INSERT INTO testrowid_s3(name) values ('empname2');
INSERT INTO testrowid_s3(name) values ('empname3');
INSERT INTO testrowid_s3(name) values ('empname4');
commit;

SELECT rowid,name FROM testrowid_s3;
ROWID              NAME
------------------ ----------
AAAF3sAAAAAAAMmAAA empname1
AAAF3sAAAAAAAMmAAB empname2
AAAF3sAAAAAAAMmAAC empname3
AAAF3sAAAAAAAMmAAD empname4

UPDATE testrowid_s3 SET name = 'Ramesh' WHERE rowid = 'AAAF3sAAAAAAAMmAAB' ;
commit;

SELECT rowid,name FROM testrowid_s3;
ROWID              NAME
------------------ ----------
AAAF3sAAAAAAAMmAAA empname1
AAAF3sAAAAAAAMmAAB Ramesh
AAAF3sAAAAAAAMmAAC empname3
AAAF3sAAAAAAAMmAAD empname4
```

*PostgreSQL 코드:*

```
CREATE TABLE public.testrowid_s3
(
    rowid_seq bigint generated always as identity,
    name character varying
);

insert into public.testrowid_s3 (name) values 
('empname1'),('empname2'),('empname3'),('empname4');

select rowid_seq,name from testrowid_s3;
 rowid_seq |   name   
-----------+----------
         1 | empname1
         2 | empname2
         3 | empname3
         4 | empname4

update testrowid_s3 set name = 'Ramesh' where rowid_seq = 2 ;

select rowid_seq,name from testrowid_s3;
 rowid_seq |   name   
-----------+----------
         1 | empname1
         3 | empname3
         4 | empname4
         2 | Ramesh
```