[PostgreSQL] OID (Object Identifier) & RegClass

식빵·2023년 5월 21일
1

postgresql-memo

목록 보기
23/34
post-thumbnail

OID Type

Postgresql DBMS 은 시스템 자신의 내부에 있는 객체(ex: table, index, sequence, etc...)들을 구분하기 위해서 특별한 타입을 사용하는데,

그게 바로 OID(Object Identifier) Type 입니다.

아래 그림은 DBMS 내의 스키마 정보를 보관하는 system catalogs 테이블의
한 종류인 pg_attribute 입니다. 보시면 oid 타입을 사용하는 걸 확인할 수 있습니다.


Postgresql DBMS 는 각 테이블, 인덱스 등의 객체들이 생성될 때마다
각자 고유한 OID 값 (범위: unsigned integer)을 자동으로 부여합니다.

그렇기 때문에 저희가 매순간 객체를 생성하면 무조건 OID 값이 할당됩니다.
아래 쿼리를 실행하여 정말로 그런지 확인해보시기 바랍니다.

create table public.users(id int, name varchar(200));
select 'public.users'::regclass::oid; -- regclass 에 대한 설명은 다음 목차에서...



RegClass Type

가끔 System_Catalog을 조회하거나, OID 값을 통해서 뭔가를 해야되는 경우도 있습니다.
문제는 그때마다 일일이 Db Object 에 매칭되는 OID 를 찾아봐야 합니다.

-- `pg_class`, `pg_attribute` 둘 다 system table 입니다.
SELECT * FROM pg_attribute
  WHERE attrelid = (SELECT oid FROM pg_class WHERE relname = 'users');

매번 저런 subquery 를 짤 생각을 하면 아찔하네요 😫.
하지만 다행히 Postgresql 에서는 RegClass Type 을 제공하여 이를 방지합니다.

-- pg_attribute.attrelid 의 column type 은 oid 입니다!
SELECT * FROM pg_attribute WHERE attrelid = 'public.users'::regclass; -- 깔끔하죠?

보면 알겠지만 단순히 table 명칭(public.users)을 regclass 로 타입 캐스팅한
것만으로도 oid type 컬럼(attrelid) 과 비교 연산이 가능해졌습니다!


여기서 살짝 이상하다고 느낄 수 있습니다.
RegClass TypeOID Type 엄연히 다른 타입인데 = 연산이 되는 게 이상하지 않나요?

이게 가능한 이유는 RegClass TypeOID Type 을 기반으로 만들어진 Alias 타입이기
때문입니다. 그래서 OID 와 관련된 연산을 수행할 때 OID 가 아닌 RegClass 타입의
피연산자를 사용하더라도 Postgresql DBMS 가 알아서 연산이 되도록 잘 처리해줍니다.


그런데 RegClass 는 OID 와의 연산 기능만 제공하는 게 아닙니다.
OID::RegClass 처럼 캐스팅하면 OID 와 매치되는 Object 의 이름을 추출할 수 있습니다.

select 'users'::regclass::oid; -- 저는 25015 가 나오네요.
select 25015::regclass; -- users 가 출력됩니다.




nextval 테스트

Postgresql 에서는 OID 를 인자로 받는 다양한 Built-in Function 들이 존재합니다.
대표적으로 Sequence 의 다음값을 받아오는 nextval function 이 있습니다.

지금부터 nextval 을 사용해서 정말로 OID, RegClass 타입을 인자를 받아서
제대로 동작하는지 확인해보겠습니다.

create sequence public.test_seq;

-- regclass Type
select nextval('public.test_seq'::regclass);

-- oid Type
select nextval('public.test_seq'::regclass::oid);

-- oid 의 정수값을 통해서도 가능합니다!
select to_regclass('public.test_seq')::oid; -- 25386 조회됨
select nextval(25386);

-- 단순 문자열도 가능하네요! WOW!
select nextval('public.test_seq');

마지막의 nextval 에서는 regclass 타입도 아닌 일반 문자열 타입을 사용했는데도,
nextval 이 제대로 동작하는 것을 확인할 수 있습니다.

이런 동작 방식이 가능한 건 Postgresql DBMS 가 자체적으로 바꿔주는 것이기 때문입니다.
아래 이미지는 Postgresql 공식 문서에 작성된 내용 중 일부입니다.




참고: WITH OIDS - Deprecated!

옛날, 정확히는 postgresql 12 이전 버전 에서는 create table 문법에서 OID 관련된
문법(WITH OIDS)이 존재했습니다.

WITH OIDS 를 세팅하면 사용자가 생성한 table 에는 OID (숨김) 컬럼이 생성되고,
해당 컬럼에 값이 자동으로 들어갑니다. 이를 통해서 table 의 각 ROW 에 매칭되는
고유한 값인 OID 가 생성되는 것이죠.

하지만 OIDunsigned integer 만큼의 값만 갖을 수 있기 때문에
사용자들의 테이블이 추후에 얼마나 데이터가 많이 생길지 모르는 상태에서
무분별하게 OID 가 사용되는 것은 큰 문제를 일으킬 수 있었습니다.

이를 문제 삼은 Postgresql 은 결국 12 버전 이후부터 직접적으로 WITH OIDS 문법을
사용한 Create Table Syntax 를 제공하지 않도록 조치했습니다.
이외에도 어떠한 방식으로도 table row 에 OID 세팅하는 방법을 일체 없애버렸습니다.

참고 링크: https://qr.ae/pyvmiJ

From PostgreSQL 12, oids cannot be used anymore.

This is because oid is implemented using unsigned 4 byte integer and hence,
it’s dangerous to rely on them for uniqueness especially when your tables are massively growing.

Based on my personal experience with PostgreSQL, it’s always better to use a user-defined column value such as Surrogate Key to uniquely identify records if your table does not have a primary key.

혹시나 postgresql 12 버전 이전을 사용하시는 분들이더라도 부디 테이블에 OID column
을 생성하는 문법은 사용하지 마시기 바랍니다. 애초에 시스템 테이블이 사용하려는 건데,
그걸 가져다 사용할 이유가 없습니다. 각 테이블에 맞는 기본키를 제공해주세요.




참고 링크

profile
백엔드를 계속 배우고 있는 개발자입니다 😊

2개의 댓글

comment-user-thumbnail
2024년 6월 26일

좋은 글 감사합니다.

1개의 답글