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 에 대한 설명은 다음 목차에서...
가끔 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 Type
은 OID Type
엄연히 다른 타입인데 =
연산이 되는 게 이상하지 않나요?
이게 가능한 이유는 RegClass Type
은 OID Type
을 기반으로 만들어진 Alias
타입이기
때문입니다. 그래서 OID 와 관련된 연산을 수행할 때 OID
가 아닌 RegClass
타입의
피연산자를 사용하더라도 Postgresql DBMS
가 알아서 연산이 되도록 잘 처리해줍니다.
그런데 RegClass 는 OID 와의 연산 기능만 제공하는 게 아닙니다.
OID::RegClass
처럼 캐스팅하면 OID
와 매치되는 Object
의 이름을 추출할 수 있습니다.
select 'users'::regclass::oid; -- 저는 25015 가 나오네요.
select 25015::regclass; -- users 가 출력됩니다.
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 공식 문서에 작성된 내용 중 일부입니다.
옛날, 정확히는 postgresql 12 이전 버전
에서는 create table
문법에서 OID 관련된
문법(WITH OIDS
)이 존재했습니다.
WITH OIDS
를 세팅하면 사용자가 생성한 table
에는 OID
(숨김) 컬럼이 생성되고,
해당 컬럼에 값이 자동으로 들어갑니다. 이를 통해서 table 의 각 ROW 에 매칭되는
고유한 값인 OID
가 생성되는 것이죠.
하지만 OID
는 unsigned 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
을 생성하는 문법은 사용하지 마시기 바랍니다. 애초에 시스템 테이블이 사용하려는 건데,
그걸 가져다 사용할 이유가 없습니다. 각 테이블에 맞는 기본키를 제공해주세요.
oid
를 검색해보세요. 11은 보일 것이고, 12는 안 보일 겁니다.
좋은 글 감사합니다.