데이터베이스 기술/POSTGRESQL

PostgreSQL TAM을 통한 그래프 성능 향상 방법론

(주)비트나인 2023. 9. 9. 17:42

1. 목적 : Table Access Method(이하 TAM)를 통한 그래프 성능 향상 방법론 제시

 

PostgreSQL은 12 버전부터 CREATE ACCESS METHOD라는 기능을 제공한다. 이는 기존의 테이블 접근 방식인 Heap 구조를 벗어나 테이블에 데이터를 저장하는 대체 방법을 제공한다. 

이를 통해 OLTP 작업을 위한 Heap 접근, OLAP 작업을 위한 컬럼 기반 테이블, 초고속 검색 처리를 위한 인메모리 기반 테이블 등 근본적인 성능 향상이 가능한 획기적인 방법론들을 제시해 준다.

그렇다면 그래프DB에는 TAM을 통해 어떤 방식으로 응용될 수 있을지 알아보겠다. 이를 위해서 사전적으로 이해할 개념은 아래와 같다.

 

  1. 그래프 DBMS 데이터 저장 방식 : Native Graph Storage VS Non-Native Graph Storage
  2. Autocluster TAM

 

 

2. 그래프 DBMS 데이터 저장 방식

그래프 DBMS의 데이터 저장 방식은 Native Graph 스토리지와 Non-Native Graph 스토리지로 나뉜다. 

Native Graph 스토리지 방식은 노드와 관계를 서로 가깝게 배치하는 저장 및 데이터 처리에서 많은 최적화가 적용되어 효율적인 접근 방식을 제공한다. 그에 반해 Non-Native Graph 스토리지 방식은 RDBMS, Column Stores, Document Stores와 같은 스토리지에서 작동하는 Query 엔진을 통해 관계를 명시하기 때문에 계산 비용이 많이 든다. 

 

Native Graph Storage
Non-Native Graph Storage

 

[참조] Native vs. Non-Native Graph Database(https://neo4j.com/blog/native-vs-non-native-graph-technology/)

 

3. Autocluster TAM

Autocluster TAM은 테이블의 모든 값에 마지막으로 삽입된 행을 추적하여 클러스터 데이터에 대한 더 빠른 접근을 가능하게 한다. 즉, 이전 행과 동일한 데이터 블록에 새 행을 추가함으로써, 관련 데이터에 대한 접근 시간을 줄일 수 있다. 

 

Autocluster 예제

(참조 : https://www.enterprisedb.com/docs/pg_extensions/advanced_storage_pack/using/#autocluster-example)

 

1) 테이블 생성 및 autocluster를 적용한 기준 컬럼 지정

Autocluster TAM을 적용한 테이블 생성 특정 컬럼(thermostat_id)에 대한 인덱스 생성 및 autocluster 적용
CREATE TABLE iot (
    thermostat_id         bigint NOT NULL,
    recordtime            varchar NOT NULL,
    measured_temperature  float4,
    temperature_setting   float4
) USING autocluster ;
CREATE INDEX ON iot USING btree(thermostat_id);
SELECT autocluster.autocluster(
    rel := 'iot'::regclass,
    cols := '{1}',    # thermostat_id 컬럼을 가리킴
    max_objects := 10000
);

 

2) 샘플 데이터 입력

INSERT INTO iot (thermostat_id, recordtime) VALUES (456, 12:01);
INSERT INTO iot (thermostat_id, recordtime) VALUES (8945, 04:55);
INSERT INTO iot (thermostat_id, recordtime) VALUES (456, 15:32);
INSERT INTO iot (thermostat_id, recordtime) VALUES (6785, 01:36);
INSERT INTO iot (thermostat_id, recordtime) VALUES (456, 19:25);
INSERT INTO iot (thermostat_id, recordtime) VALUES (5678, 03:44);
 
3)CTID를 통한 autocluster 적용된 결과 확인
SELECT ctid, thermostat_id, recordtime FROM iot ORDER BY CTID;

OUTPUT
ctid   | thermostat_id | recordtime
-------+---------------+------------
 (0,1) |           456 |      12:01
 (0,2) |           456 |      15:32
 (0,3) |           456 |      19:25
 (2,2) |          8945 |      04:55
 (2,5) |          5678 |      03:44
 (3,2) |          6785 |      01:36
(6 rows)

 

CTID는 테이블 내부의 특정 row의 물리적 위치를 말하는데, thermostat_id의 값(456)이 동일한 같은 페이지(Data Block과 동일한 개념, default 8192 Bytes) 내에 있는 것을 확인할 수 있다.

 

그렇다면 Graph DB에서 Autocluster TAM이 어떤 방식으로 Native Graph Storage 방식의 최적화에 기여할 수 있는지 살펴보자.



4.
Autocluster TAM을 활용한 Graph DB Storage 개선 방안

아래의 그림은 AgensGraph의 Node 및 Edge의 실제 데이터를 조회한 결과이다.

Node Label(person / movie) Edge Label(acted_in) 
[person]
ctid  |  id  |                  properties
--------+------+----------------------------------------------
 (0,1)  | 4.1  | {"born": 1964, "name": "Keanu Reeves"}
 (0,2)  | 4.2  | {"born": 1967, "name": "Carrie-Anne Moss"}
 (0,3)  | 4.3  | {"born": 1961, "name": "Laurence Fishburne"}
 (0,4)  | 4.4  | {"born": 1960, "name": "Hugo Weaving"}
 (0,5)  | 4.5  | {"born": 1967, "name": "Andy Wachowski"}

[Movie]
ctid  |  id  |                  properties
--------+------+----------------------------------------------
(0,1) | 3.1 | {"title": "The Matrix", "tagline": "Welcome to the Real World", "released": 1999}
 (0,2) | 3.2 | {"title": "The Matrix Reloaded", "tagline": "Free your mind", "released": 2003}
 (0,3) | 3.3 | {"title": "The Matrix Revolutions", "tagline": "Everything that has a beginning has an end", "released": 2003}
ctid  |  id   | start | end  |                                                    properties
--------+-------+-------+------+------------------------------------------------------------------------------------------
 (0,1)  | 5.1   | 4.1   | 3.1  | {"roles": ["Neo"]}
 (0,2)  | 5.2   | 4.2   | 3.1  | {"roles": ["Trinity"]}
 (0,3)  | 5.3   | 4.3   | 3.1  | {"roles": ["Morpheus"]}
 (0,4)  | 5.4   | 4.4   | 3.1  | {"roles": ["Agent Smith"]}
 (0,5)  | 5.5   | 4.1   | 3.2  | {"roles": ["Neo"]}
 (0,6)  | 5.6   | 4.2   | 3.2  | {"roles": ["Trinity"]}
 (0,7)  | 5.7   | 4.3   | 3.2  | {"roles": ["Morpheus"]}
 (0,8)  | 5.8   | 4.4   | 3.2  | {"roles": ["Agent Smith"]}
 (0,9)  | 5.9   | 4.1   | 3.3  | {"roles": ["Neo"]}
 (0,10) | 5.10  | 4.2   | 3.3  | {"roles": ["Trinity"]}
 (0,11) | 5.11  | 4.3   | 3.3  | {"roles": ["Morpheus"]}
 (0,12) | 5.12  | 4.4   | 3.3  | {"roles": ["Agent Smith"]}

 

Perso, movie, Acted_in 노드/관계 데이터의 CTID는 동일하게 보이나, 실질적으로 별도의 다른 파일에 존재해 있다. 데이터 삽입 방식에 따라 하나의 페이지(=데이터 블록) 안에 연관된 데이터가 존재하게 할 수 있으나, 원칙상으로는 순차 적재 방식이라 관계 데이터의 클러스터링은 어렵다. 

 

만약 여기에 Autocluster TAM 방식이 도입된다면 Acted_in Label은 아래와 같이 관계 데이터가 클러스터링이 되며 조회 시 Disk I/O를 최소화시킬 수 있다. 

Start ID 기준으로 클러스터링 적용 시, Start Node와 관련된 Edge Record는 동일한 page안에 존재하게 된다. 따라서 추후 Edge가 추가되더라도 같은 페이지(=데이터 블록) 안에 적재되는 구조이다. 

ctid  |  id   | start | end  |                                                    properties
--------+-------+-------+------+------------------------------------------------------------------------------------------
 (0,1)  | 5.1   | 4.1   | 3.1  | {"roles": ["Neo"]}
(0,2)  | 5.5   | 4.1   | 3.2  | {"roles": ["Neo"]}
(0,3)  | 5.9   | 4.1   | 3.3  | {"roles": ["Neo"]}

 (1,1)  | 5.2   | 4.2   | 3.1  | {"roles": ["Trinity"]}
(1,2)  | 5.6   | 4.2   | 3.2  | {"roles": ["Trinity"]}
(1,3) | 5.10  | 4.2   | 3.3  | {"roles": ["Trinity"]}

 (2,1)  | 5.3   | 4.3   | 3.1  | {"roles": ["Morpheus"]}
(2,2)  | 5.7   | 4.3   | 3.2  | {"roles": ["Morpheus"]}
(2,3) | 5.11  | 4.3   | 3.3  | {"roles": ["Morpheus"]}

(3,1)  | 5.4   | 4.4   | 3.1  | {"roles": ["Agent Smith"]}
(3,2)  | 5.8   | 4.4   | 3.2  | {"roles": ["Agent Smith"]}
(3,3) | 5.12  | 4.4   | 3.3  | {"roles": ["Agent Smith"]}

 

5. 결론

PostgreSQL은 오픈소스 RDBMS로 시작하여 Replication 기능에 의한 클라우드 확장에 최적화된 DB, DB레벨의 샤딩이 가능한 DB, GiS, 시계열에 최적화된 DB, 오라클 호환성 DB 등 기존에도 강력한 확장성을 가졌었으나, Table Access Method라는 스토리지 레벨의 핸들링을 통해 보다 다양한 기능들이 가능하게 되었다. 그에 따라 PostgreSQL 기반 그래프DB의 진화도 더욱 기대된다.   

 

 

 

글 : 최광석 수석보 ( 비트나인 DB Tech팀 )