📗 Docs

PostgreSQL의 특징 및 주요기능에 대해 알아보기

date
Jun 1, 2023
slug
db-postgresql
author
status
Public
tags
Blog
Database
summary
PostgreSQL의 주요기능에 대해 한걸음씩 알아가기
type
Post
thumbnail
postgresql_icon.png
category
📗 Docs
updatedAt
Jun 6, 2023 09:33 PM
 

 
다음 포스팅에서는 Docker를 활용하여 PostgreSQL를 세팅해보고 간단한 실습을 진행해보겠습니다 🙂
 

 

PostgreSQL

PostgreSQL은 대규모 데이터베이스 처리에 높은 확장성과 성능을 제공합니다. 병렬 처리, 인덱싱 기술, 쿼리 최적화 및 튜닝 기능 등을 통해 뛰어난 성능을 발휘할 수 있습니다.
PostgreSQL은 다양한 고급 기능을 제공하며, 사용자 정의 데이터 타입, JSON/JSONB 데이터 타입, 범위 타입, 지리 공간 데이터 타입 등 다양한 데이터 타입을 지원합니다. 또한, 풍부한 내장 함수, 저장 프로시저, 트리거, 외래 키, 뷰 등을 활용하여 데이터를 유연하게 다룰 수 있습니다.
  • 고급 기능과 다양한 설정 옵션을 제공하기 때문에 초기 설정과 관리가 다소 복잡할 수 있습니다. 상대적으로 더 많은 관리 작업과 경험이 필요할 수 있습니다.
 

관계형 데이터베이스 시스템

MySQL과 PostgreSQL은 모두 관계형 데이터베이스 시스템으로서 테이블 간 관계를 통해 데이터를 저장하고 관리합니다.
RDBMS의 주요특징
💡
RDBMS(Relational Database Management System)
  • 테이블
    • RDBMS에서 데이터는 테이블(table)로 구성됩니다. 테이블은 행(row)과 열(column)로 구성되며, 각 행은 고유한 식별자(primary key)로 식별됩니다. 각 열은 특정한 데이터 유형과 제약 조건을 가지며, 테이블은 특정 주제나 엔티티에 대한 정보를 담고 있습니다.
  • 관계
    • RDBMS는 테이블 간의 관계를 통해 데이터를 연결합니다. 주요한 관계 유형은 일대일(one-to-one), 일대다(one-to-many), 다대다(many-to-many) 관계입니다. 이러한 관계를 통해 데이터의 일관성과 무결성을 유지하며, 데이터 간의 관련성을 표현할 수 있습니다.
  • SQL
    • SQL(Structured Query Language): RDBMS는 SQL을 사용하여 데이터를 조작하고 관리합니다. SQL은 데이터베이스에 대한 쿼리, 데이터의 삽입, 업데이트, 삭제 등을 수행하는 표준 데이터베이스 언어입니다. SQL을 사용하여 데이터를 검색하고 조작할 수 있으며, 데이터베이스 스키마를 정의하고 관리할 수 있습니다.
  • ACID 특성
    • RDBMS는 ACID 특성을 준수합니다. ACID는 원자성(Atomicity), 일관성(Consistency), 고립성(Isolation), 지속성(Durability)을 나타내는 트랜잭션의 속성입니다. 이러한 특성은 데이터베이스의 안정성과 신뢰성을 보장합니다.
 

ANSI SQL

PostgreSQL은 ANSI SQL 표준을 상당히 준수하고 있습니다. 기본적인 SQL 문법과 데이터 조작 기능을 비롯하여 테이블, 뷰, 인덱스, 조인, 집계 함수 등 다양한 기능을 표준에 맞게 구현하고 있습니다.
 

병렬처리 지원

PostgreSQL은 병렬처리를 지원하는 기능을 가지고 있습니다. 병렬처리는 하나의 작업을 여러 개의 작은 작업으로 분할하여 동시에 처리함으로써 성능을 향상시키는 방식입니다. 병렬처리는 대량의 데이터 처리, 복잡한 쿼리, 집계 작업 등에서 특히 유용합니다.
PostgreSQL의 여러 가지 방식의 병렬처리
  1. 병렬 스캔: 대규모 테이블 스캔 작업에서 효율적인 병렬 처리를 제공합니다. 테이블을 여러 개의 조각으로 분할하고, 각각의 조각을 독립적으로 스캔하여 데이터를 읽어옵니다. 이를 통해 데이터를 병렬로 처리하고 결과를 조합하여 최종 결과를 생성합니다.
  1. 병렬 조인: 병렬 스캔과 함께 사용되는 기능으로, 조인 작업을 병렬로 처리하여 빠른 결과를 얻을 수 있습니다. 조인 작업은 여러 테이블 간의 연결 작업이므로, 병렬 처리를 통해 조인 성능을 향상시킬 수 있습니다.
  1. 병렬 집계: 복잡한 집계 작업에서 병렬 처리를 지원합니다. 여러 개의 데이터 조각을 병렬로 처리하고, 그 결과를 조합하여 최종 집계 결과를 생성합니다. 이를 통해 대량의 데이터를 효율적으로 집계할 수 있습니다.
병렬처리를 활용하기 위해서는 몇 가지 조건을 충족해야 합니다. 예를 들어, 병렬 처리에 필요한 리소스(메모리, CPU 등)가 충분히 확보되어야 하며, 작업의 병렬화 가능성을 판단하는 비용 기반 옵티마이저가 적절한 계획을 수립해야 합니다.
병렬처리는 PostgreSQL의 성능을 향상시키는 강력한 기능 중 하나이며, 대량의 데이터 처리와 복잡한 작업에 유용합니다. 그러나 모든 작업에 대해 병렬처리를 적용하는 것은 항상 효과적이지 않을 수 있으므로, 쿼리 실행 계획을 분석하고 적절한 설정과 튜닝을 수행하는 것이 중요합니다.
 

다양한 클라이언트 도구와 활발한 오픈 소스 커뮤니티

PostgreSQL의 클라이언트 도구로는 pgAdmin, psql, DBeaver, Navicat for PostgreSQL 등이 있습니다.
활발한 오픈 소스 커뮤니티와 함께 개발되었으며, 다양한 확장 모듈과 도구들이 존재합니다. 또한, 대규모 기업과 개발자들이 PostgreSQL을 사용하고 지원하고 있어 풍부한 자료와 지원을 받을 수 있습니다.
 
 

 

PostgreSQL의 데이터 타입

  1. Numeric 데이터 타입
      • integer: 정수를 저장합니다. 예: integer (4 바이트 크기), smallint (2 바이트 크기), bigint (8 바이트 크기)
      • numeric 또는 decimal: 고정소수점 숫자를 저장합니다. 예: numeric(5,2) 는 최대 세 자리의 정수와 두 자리의 소수를 표현합니다.
      • real and double precision: 부동소수점 숫자를 저장합니다. 예: real (4 바이트 크기), double precision (8 바이트 크기)
  1. Character 데이터 타입
      • character varying(n) 또는 varchar(n): 최대 길이가 n인 가변 길이 문자열을 저장합니다. 예: varchar(50)
      • character(n) 또는 char(n): 길이가 n인 고정 길이 문자열을 저장합니다. 예: char(5)
      • text: 가변 길이 문자열을 저장합니다. 이 타입은 길이 제한이 없습니다.
  1. Binary 데이터 타입
      • bytea: 바이너리 데이터를 저장합니다. 예: E'\\xDEADBEEF'
  1. Temporal 데이터 타입
      • date: 날짜를 저장합니다. 예: date '2004-10-19'
      • time: 시간을 저장합니다. 예: time '04:05:06'
      • timestamp: 날짜와 시간을 저장합니다. 예: timestamp '2004-10-19 10:23:54'
      • interval: 시간 간격을 저장합니다. 예: interval '1 day 10 hours'
  1. Boolean 데이터 타입
      • boolean: 참 또는 거짓 값을 저장합니다. 예: boolean true
  1. Geometric 데이터 타입
      • 이들은 점, 선, 경로, 다각형 등 다양한 기하학적 형태를 나타냅니다. 예: point '(1,2)'
  1. UUID 데이터 타입
      • uuid: 유니버설 고유 식별자(Universal Unique Identifier)를 저장합니다. 예: uuid 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'
  1. Array 데이터 타입
      • 이 데이터 타입은 동일한 데이터 타입의 요소를 가진 배열을 저장합니다. 예: integer[] '{1,2,3,4}'
  1. JSON 데이터 타입
      • jsonjsonb: JSON 데이터를 저장합니다. jsonb는 이진 형식으로 저장되며, json보다 검색과 인덱싱이 더 효율적입니다. 예: json '{"name": "John", "age": 30}'
      • JSON 데이터 타입을 사용하면 복잡한 JSON 문서를 저장하고 쿼리할 수 있으며, JSONB 데이터 타입은 이진 형식으로 저장되어 검색과 인덱싱 성능을 향상시킵니다.
  1. 사용자 정의 데이터 타입(User-Defined Types)
      • PostgreSQL은 사용자가 새로운 데이터 타입을 정의할 수 있는 기능을 제공합니다. 이를 통해 데이터베이스 스키마를 정확하게 사용자의 요구 사항에 맞게 설정할 수 있습니다.
      예:
      -- 사용자 정의 Point 타입 생성 CREATE TYPE point AS ( x float, y float ); -- 테이블 생성 CREATE TABLE shapes ( id serial primary key, shape_name varchar(50), position point ); -- 데이터 삽입 INSERT INTO shapes (shape_name, position) VALUES ('Square', ROW(10.0, 20.0)), ('Circle', ROW(30.0, 40.0)); -- 데이터 조회 SELECT shape_name, position.x, position.y FROM shapes;
      위의 예시에서는 point라는 사용자 정의 데이터 타입을 생성하고, 이를 shapes 테이블에서 사용합니다. point 데이터 타입은 xy 두 개의 속성으로 구성된 좌표를 나타냅니다. shapes 테이블에서는 도형의 이름과 해당 도형의 위치를 저장합니다.
      데이터를 삽입할 때는 ROW 함수를 사용하여 point 데이터를 생성하고 저장합니다. 데이터를 조회할 때는 position.xposition.y와 같은 방식으로 사용자 정의 데이터 타입 내의 속성에 접근할 수 있습니다.
  1. 범위 타입(Range Types)
      • PostgreSQL의 범위 타입은 값의 범위를 나타내는 데이터 타입입니다. 예를 들어, int4range는 정수의 범위를, daterange는 날짜의 범위를 나타냅니다. 이를 통해 특정 범위 내에 값이 있는지를 효율적으로 확인할 수 있습니다.
  1. 열거형 타입(Enum Types)
      • 열거형 타입은 특정 값들의 목록을 나타내는 데이터 타입입니다. 예를 들어, 'red', 'green', 'blue'와 같은 색상을 나타내는 열거형 타입을 생성할 수 있습니다.
  1. 비트 문자열 타입(Bit String Types)
      • 비트 문자열 타입은 이진 데이터를 나타내는 데이터 타입입니다. 이는 주로 'bit'와 'bit varying' 두 가지 형태로 사용됩니다. 'bit(n)'는 고정 길이 n의 비트 문자열을, 'bit varying(n)'는 최대 길이 n의 비트 문자열을 나타냅니다.
  1. NoSQL 스타일의 데이터 타입(hstore, 키-값 쌍을 저장하는 데이터 타입)
    1. 예:
      -- 테이블 생성 CREATE TABLE user_data ( id SERIAL PRIMARY KEY, attributes HSTORE ); -- 데이터 삽입 INSERT INTO user_data (attributes) VALUES ('"name" => "John", "age" => "30", "city" => "New York"'); -- 데이터 조회 SELECT attributes->'name' AS name, attributes->'age' AS age FROM user_data;
      위의 예시에서 user_data 테이블은 attributes라는 hstore 컬럼을 가지고 있습니다. attributes 컬럼은 키-값 쌍을 저장하며, 각 키와 값은 문자열 형태로 저장됩니다. 이를 통해 유연한 데이터 모델을 구성할 수 있습니다.
      위 예시에서는 'name', 'age', 'city'와 같은 키에 대한 값을 저장하고, 쿼리하여 해당 값을 가져오는 것을 확인할 수 있습니다. 이렇게 hstore를 사용하면 스키마가 고정되어 있지 않고 동적인 데이터 모델을 적용할 수 있습니다.
 
 

 

PostgreSQL의 인덱싱

B-Tree 인덱스

  • PostgreSQL에서 가장 일반적으로 사용되는 인덱스 타입입니다. 이 인덱스는 키를 정렬된 순서로 저장하므로, 대등(equal) 및 범위(range) 비교에 효과적입니다.

Hash 인덱스

  • 키의 해시 값을 사용하여 데이터를 저장합니다. 이 인덱스는 대등 비교에만 효과적이며, 키의 순서에 대해서는 알지 못합니다.

GiST (Generalized Search Tree) 인덱스

  • 다양한 데이터 타입에 대해 여러 종류의 쿼리를 효율적으로 지원할 수 있는 "일반화된" 인덱스입니다. 공간 및 텍스트 검색 같은 복잡한 데이터 구조에 유용합니다.

SP-GiST (Space-Partitioned GiST) 인덱스

  • "공간 분할" 데이터에 최적화된 GiST의 변형입니다. 이 인덱스는 트리, IP 네트워크, 다각형 등과 같이 비-중첩(non-overlapping), 공간 분할 데이터 구조에 사용됩니다.

GIN (Generalized Inverted Index) 인덱스

  • 이 인덱스는 다중 값 컨테이너에 효과적입니다. 배열, 텍스트 문서 등에 사용됩니다.

BRIN (Block Range INdex) 인덱스

  • 매우 큰 테이블에 효과적입니다. BRIN은 특정 연속 블록 범위에 대한 요약 정보를 저장합니다.

Partial 인덱스

  • Partial 인덱스는 특정 조건을 만족하는 행만 인덱스화하는 인덱스 유형입니다. 이를 통해 특정 데이터 부분집합에 대한 검색 성능을 향상시킬 수 있습니다. WHERE 절을 사용하여 인덱스가 적용되는 행을 제한할 수 있습니다.
예:
예를 들어, "orders" 테이블에는 "status"라는 열이 있고, 이 열은 주문의 상태를 나타냅니다. 주문 상태가 "completed"인 주문만을 검색할 때 Partial 인덱스를 사용할 수 있습니다.
-- Partial 인덱스 생성 CREATE INDEX idx_completed_orders ON orders (order_id) WHERE status = 'completed'; -- 상태가 "completed"인 주문 조회 SELECT order_id, status FROM orders WHERE status = 'completed';
위의 예시에서 "idx_completed_orders"라는 Partial 인덱스를 생성했습니다. 이 인덱스는 "status"가 'completed'인 주문에 대한 검색을 최적화합니다. 이제 "status"가 'completed'인 주문을 조회하는 쿼리를 실행하면 Partial 인덱스를 활용하여 검색 속도를 향상시킬 수 있습니다.
Partial 인덱스를 사용하면 인덱스 크기와 성능을 최적화할 수 있습니다. 특정 조건을 충족하는 행만을 인덱싱하기 때문에 인덱스 크기가 작아지고, 검색할 행의 수도 줄어듭니다. 이는 인덱스의 유용성을 향상시키고 성능을 최적화하는 데 도움이 됩니다.
또한, PostgreSQL은 다중 열 인덱스(multicolumn index)를 지원하며, 이를 통해 여러 열을 기반으로 한 쿼리의 성능을 향상시킬 수 있습니다.
인덱스를 만드는 것은 리소스를 소모하므로, 데이터의 양, 쿼리의 종류, 테이블의 변경 빈도 등에 따라 적절한 인덱싱 전략을 선택하는 것이 중요합니다.
 
 
 

 

PostgreSQL의 트랜잭션 처리

PostgreSQL은 ACID(Atomicity, Consistency, Isolation, Durability) 성질을 갖는 트랜잭션을 지원합니다. 이는 데이터베이스 작업이 신뢰성있고, 예측 가능하며, 오류에 대해 회복 가능해야 함을 의미합니다.
  1. Atomicity (원자성)
    1. 트랜잭션 내의 모든 작업이 성공하거나, 아무것도 수행되지 않아야 합니다. 이는 트랜잭션이 '모두 또는 없음'의 원칙을 따른다는 것을 의미합니다.
  1. Consistency (일관성)
    1. 트랜잭션이 데이터베이스를 한 일관된 상태에서 다른 일관된 상태로 이동시키는 것을 보장합니다. 이는 데이터베이스의 무결성 제약 조건이 항상 충족되는 것을 의미합니다.
  1. Isolation (고립성)
    1. 각 트랜잭션은 독립적으로 실행되며, 다른 트랜잭션의 작업에 영향을 받지 않습니다.
  1. Durability (영속성)
    1. 트랜잭션이 성공적으로 커밋된 후에는, 그 결과는 영구적이어야 합니다. 시스템 장애가 발생하더라도 커밋된 트랜잭션의 변경사항은 유지되어야 합니다.
 
PostgreSQL은 이러한 ACID 성질을 유지하기 위해 여러 가지 기술과 메커니즘을 사용합니다.
  • Write-ahead logging (WAL)
    • 모든 변경사항이 디스크에 안전하게 기록되기 전에는 트랜잭션이 커밋되지 않도록 보장하는 기술입니다. 이는 Durability를 보장합니다.
  • Multi-Version Concurrency Control (MVCC)
    • 각 트랜잭션이 데이터베이스의 '스냅샷'에 대해 작동하도록 하여, 다른 트랜잭션의 변경사항에 영향을 받지 않도록 하는 메커니즘입니다. 이는 Isolation을 보장합니다.
  • Locking and Concurrency Control (락과 동시성 제어)
    • PostgreSQL은 트랜잭션 간의 충돌을 방지하고, 데이터 무결성을 보장하기 위해 다양한 잠금과 동시성 제어 메커니즘을 사용합니다.
 
 

 

PostgreSQL의 기능

저장 프로시저와 사용자 정의 함수(User-Defined Functions)

저장 프로시저는 데이터베이스에 미리 정의된 SQL 코드 블록입니다. 이 코드 블록은 데이터베이스에서 저장되어 필요할 때마다 호출할 수 있습니다. 저장 프로시저는 데이터의 처리, 로직의 실행, 복잡한 작업의 수행 등에 사용됩니다.
저장 프로시저 예:
calculate_total_price라는 저장 프로시저를 생성합니다. 이 저장 프로시저는 order_items 테이블에서 특정 주문(order)의 총 가격(total_price)을 계산하여 orders 테이블에 업데이트하는 작업을 수행합니다.
저장 프로시저는 CREATE OR REPLACE PROCEDURE 문을 사용하여 생성되며, 프로시저의 본문은 AS $$ ... $$ LANGUAGE plpgsql 구문으로 정의됩니다. 본문 내에서는 SQL 문과 PL/pgSQL 언어의 문법을 사용하여 로직을 작성합니다.
-- 저장 프로시저 생성 CREATE OR REPLACE PROCEDURE calculate_total_price(order_id INT) AS $$ DECLARE total DECIMAL; BEGIN SELECT SUM(price * quantity) INTO total FROM order_items WHERE order_id = calculate_total_price.order_id; UPDATE orders SET total_price = total WHERE id = calculate_total_price.order_id; END; $$ LANGUAGE plpgsql;
-- 저장 프로시저 실행 CALL calculate_total_price(123);
저장 프로시저는 데이터베이스 내에서 중복 코드를 방지하고, 로직을 재사용하며, 성능을 향상시킬 수 있는 장점이 있습니다. 또한, 프로시저는 데이터베이스 내에서 원자적으로 실행되므로 데이터의 일관성을 보장할 수 있습니다.
참고로, PostgreSQL에서는 다양한 언어로 저장 프로시저를 작성할 수 있으며, PL/pgSQL은 그 중 하나입니다. 다른 언어로 저장 프로시저를 작성하려면 해당 언어의 확장 모듈을 설치하고 사용해야 합니다.
 
PostgreSQL은 여러 가지 언어를 사용하여 사용자 정의 함수를 작성할 수 있습니다. 주로 SQL, PL/pgSQL, PL/Python, PL/Perl, PL/Java 등의 언어를 지원하며, 다른 언어 확장도 가능합니다.
사용자 정의 함수 예:
cancel_order() 이 함수는 주문을 취소하는 역할을 합니다. 주문 ID를 입력으로 받아 해당 주문을 취소 상태로 변경합니다.
CREATE FUNCTION cancel_order(order_id INT) RETURNS VOID AS $$ BEGIN UPDATE orders SET status = 'Cancelled' WHERE order_id = order_id; END; $$ LANGUAGE plpgsql;
 
사용자 정의 함수와 저장 프로시저는 PostgreSQL에서 코드를 재사용하고 로직을 실행하는 데 사용되는 개체입니다. 그러나 둘 사이에 몇 가지 차이점이 있습니다.
  1. 호출 방식: 사용자 정의 함수는 단일 SQL 문 내에서 직접 호출될 수 있습니다. 함수는 SELECT 문이나 WHERE 절과 같은 다른 SQL 문 내에서 호출될 수 있습니다. 반면에, 저장 프로시저는 CALL 문을 사용하여 명시적으로 호출되어야 합니다.
  1. 결과 반환: 사용자 정의 함수는 일반적으로 결과를 반환합니다. SELECT 문에서 함수를 호출하면 함수의 결과를 사용할 수 있습니다. 반면에, 저장 프로시저는 일반적으로 결과를 직접 반환하지 않습니다. 저장 프로시저는 주로 데이터를 수정하거나 처리하는 데 사용됩니다.
  1. 트랜잭션 제어: 사용자 정의 함수는 트랜잭션 내에서 실행되는 경우 트랜잭션의 일부로 처리됩니다. 함수의 실행이 롤백되는 경우, 이전 상태로 돌아갑니다. 저장 프로시저는 별도의 트랜잭션을 사용하거나 트랜잭션 외부에서 실행될 수 있습니다.
  1. 파라미터 전달: 사용자 정의 함수와 저장 프로시저는 모두 파라미터를 전달할 수 있습니다. 그러나 사용자 정의 함수는 다른 SQL 문 내에서 호출되는 경우에도 파라미터를 전달할 수 있지만, 저장 프로시저는 명시적인 호출을 통해만 파라미터를 전달할 수 있습니다.
  1. 코드 구조: 사용자 정의 함수는 일반적으로 단일 SQL 문을 실행하는 작은 코드 조각으로 작성됩니다. 반면에, 저장 프로시저는 더 큰 규모의 로직을 포함하는 복잡한 코드 블록으로 작성됩니다. 저장 프로시저는 변수 선언, 제어 구문 (if-else, 반복문 등), 예외 처리 등을 포함할 수 있습니다.
사용자 정의 함수와 저장 프로시저는 각각 다른 용도와 적합한 시나리오에서 사용됩니다. 사용자 정의 함수는 계산, 변환, 필터링 등 데이터를 처리하고 반환하는 데 주로 사용됩니다. 반면에, 저장 프로시저는 데이터베이스 내에서 특정 작업을 수행하거나 복잡한 비즈니스 로직을 실행하는 데 사용됩니다.
 

윈도우 함수(Window Functions)

Window Functions(윈도우 함수)는 PostgreSQL에서 제공하는 특별한 종류의 함수로, 결과 집합에 대해 계산을 수행하는 함수입니다. 윈도우 함수는 행 그룹에 대한 계산을 효율적으로 수행할 수 있도록 지원합니다. 윈도우 함수를 사용하면 데이터를 파티션별로 분할하고 정렬하여 특정 윈도우에 대한 연산을 수행할 수 있습니다. 예를 들어, 특정 행 그룹에 대한 합계, 평균, 순위 등을 계산할 수 있습니다.
윈도우 함수 기본구문:
<함수>(<표현식>) OVER ([PARTITION BY <파티션 기준>] [ORDER BY <정렬 기준>] [ROWS <범위/행 기준>])
  • <함수> 적용할 윈도우 함수의 종류를 나타냅니다. 예를들어, SUM, AVG, ROW_NUMBER 등이 있습니다.
  • <표현식> 윈도우 함수의 계산 대상이 되는 열 또는 표현식입니다.
  • [PARTITION BY <파티션 기준>] 행 그룹을 나눌 때 사용하는 기준 열 또는 표현식입니다. 해당 기준에 따라 결과가 분할됩니다.
  • [ORDER BY <정렬 기준>] 윈도우 함수를 적용할 때 정렬할 열 또는 표현식입니다. 결과 집합 내에서 정렬된 순서로 함수가 적용됩니다.
  • [ROWS <범위/행 기준>] 윈도우 함수가 적용될 행의 범위를 지정합니다. 예를 들어, ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW와 같이 사용할 수 있습니다.
    • PRECEDING 상대적인 행의 개수를 나타내어 윈도우 프레임의 시작을 나타냅니다. PRECEDING을 사용하면 현재 행으로부터 이전 행들의 개수를 기준으로 범위를 지정할 수 있습니다. 예를 들어, "ROWS BETWEEN 2 PRECEDING AND CURRENT ROW"는 현재 행으로부터 이전 2개 행들을 포함하여 윈도우 프레임을 정의합니다.
    • UNBOUNDED PRECEDING 행의 개수나 범위를 지정하지 않고, 현재 행을 기준으로 이전 모든 행을 포함하여 윈도우 프레임을 정의합니다. UNBOUNDED PRECEDING은 시작 지점을 나타내는 키워드로, 이전 모든 행들을 범위에 포함시킵니다. 예를 들어, "ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW"는 현재 행을 포함하여 이전 모든 행들을 윈도우 프레임으로 지정합니다.
윈도우 함수 예1:
1. 행 그룹에 대한 합계 계산
SELECT product_category, product_price, SUM(product_price) OVER (PARTITION BY product_category) AS category_total FROM products;
위의 예시에서는 products 테이블에서 product_category 별로 제품 가격의 합계를 계산합니다. SUM 함수에 OVER (PARTITION BY product_category)를 사용하여 행 그룹에 대한 합계를 계산합니다.
2. 순위 지정
SELECT product_name, product_price, RANK() OVER (ORDER BY product_price DESC) AS rank FROM products;
위의 예시에서는 products 테이블에서 제품 가격에 따라 순위를 지정합니다. RANK 함수에 OVER (ORDER BY product_price DESC)를 사용하여 제품 가격을 기준으로 순위를 지정합니다.
3. 이동 평균 계산
SELECT date, revenue, AVG(revenue) OVER (ORDER BY date ROWS BETWEEN 2 PRECEDING AND CURRENT ROW) AS moving_average FROM sales;
위의 예시에서는 sales 테이블에서 매출(revenue)에 대한 이동 평균을 계산합니다. AVG 함수에 OVER (ORDER BY date ROWS BETWEEN 2 PRECEDING AND CURRENT ROW)를 사용하여 이동 평균을 계산합니다.
윈도우 함수 예2:
1. ROW_NUMBER() 함수를 사용한 순위 매기기
SELECT order_id, customer_id, order_date, ROW_NUMBER() OVER (ORDER BY order_date) AS row_num FROM orders;
위의 쿼리는 주문 테이블에서 주문일자를 기준으로 각 주문의 순위를 매깁니다. ROW_NUMBER() 함수는 윈도우 프레임을 사용하지 않으므로 기본적으로 현재 행만을 대상으로 작동합니다. ORDER BY 절을 통해 주문일자를 기준으로 정렬하여 순위를 매기고, row_num 열에 순위 값을 반환합니다.
2. SUM() 함수를 사용한 누적 합산
SELECT order_id, customer_id, order_date, SUM(order_total) OVER (ORDER BY order_date) AS cumulative_total FROM orders;
위의 쿼리는 주문 테이블에서 주문일자를 기준으로 누적 주문 총액을 계산합니다. SUM() 함수를 사용하고, ORDER BY 절을 통해 주문일자를 기준으로 정렬하여 누적 합산을 수행합니다. 윈도우 프레임이 기본적으로 UNBOUNDED PRECEDING부터 현재 행까지로 지정되어 있으므로, 현재 행을 포함하여 이전 값들의 합을 계산합니다.
 
  • 윈도우 프레임(SPECIFYING THE WINDOW FRAME) 정의
    • PostgreSQL은 기본적으로 RANGE나 ROWS를 사용하여 윈도우 프레임을 정의할 수 있습니다.
      윈도우 프레임은 윈도우 명세 내에서 계산에 포함되는 행들의 범위를 지정합니다. ROWS BETWEEN 또는 RANGE BETWEEN 절로 정의됩니다.
      ROWS BETWEEN 절은 행의 개수를 기준으로 윈도우 프레임을 지정합니다. 예를 들어, ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING은 현재 행을 포함하여 이전 행과 다음 행까지의 범위를 지정합니다.
      RANGE BETWEEN 절은 값의 범위를 기준으로 윈도우 프레임을 지정합니다. 예를 들어, RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW은 현재 행을 포함하여 이전 값과의 범위를 지정합니다.
  • Null 처리 정렬
    • 윈도우 함수에서 NULL 값을 처리하는 방식에 차이가 있습니다. PostgreSQL은 기본적으로 NULLS FIRST 또는 NULLS LAST와 같은 NULL 정렬 옵션을 사용하여 NULL 값을 처리합니다. MySQL은 NULL 값을 기본적으로 가장 작은 값으로 처리합니다.
 

일정(Schedule)

PostgreSQL은 일정 기능을 지원하여 특정 시간 간격에 따라 작업을 실행할 수 있습니다. 예를 들어, 주기적으로 반복되는 작업이나 예약된 작업을 일정에 등록하여 자동으로 실행할 수 있습니다.
PostgreSQL 버전(9.5 이상)부터는 cron 스타일의 스케줄링 기능이 내장되었으므로 별도의 확장 모듈을 설치할 필요 없이 pg_cron과 비슷한 스케줄 작업을 설정할 수 있게 되었습니다.
예(PostgreSQL 버전 9.5 이상):
pgAgent를 사용하여 스케줄 작업을 설정할 수 있습니다. pgAgent는 PostgreSQL과 함께 제공되는 스케줄링 도구입니다. 매일 오전 1시에 스크립트를 실행하는 스케줄 작업을 설정하는 예시입니다.
-- 스케줄 작업 생성 INSERT INTO pgagent.pga_jobagent (jobagentid, jobagentname, jobhostagent, jobdesc) VALUES (1, 'My Job Agent', '', 'My Job Agent'); INSERT INTO pgagent.pga_jobstep (jstid, jstjobid, jstname, jstdesc, jstenabled, jstkind, jstcode) VALUES (1, 1, 'My Job Step', '', TRUE, 's', 'SELECT my_function();'); INSERT INTO pgagent.pga_schedule (jscid, jscjobid, jscname, jscdesc, jscenabled, jscstart, jscend, jscminutes, jschours, jscweekdays, jscmonthdays, jscmonths) VALUES (1, 1, 'My Schedule', '', TRUE, '2000-01-01 01:00:00', NULL, '{0}', '{1}', '{0,1,2,3,4,5,6}', '{-1}', '{0}');
 
예(PostgreSQL 버전 9.5 이전):
pg_cron을 사용하여 스케쥴을 설정할 수 있습니다. pg_cron을 사용하려면 별도의 확장 모듈 설치가 필요합니다. my_function()이라는 사용자 정의 함수를 매일 오전 1시에 실행하는 스케줄 작업을 설정하는 예시입니다.
-- pg_cron 확장 모듈 설치 CREATE EXTENSION pg_cron; -- 스케줄 작업 생성 SELECT cron.schedule('0 1 * * *', 'SELECT my_function()');
 

암호화와 XML 처리

PostgreSQL은 기본적으로 데이터 암호화를 위한 내장 기능을 제공하지 않습니다. 암호화를 구현하기 위해서는 확장 모듈이나 외부 라이브러리를 사용해야 합니다.
예를 들어, pgcrypto 확장 모듈을 사용하여 데이터를 암호화하고 복호화할 수 있습니다.
암호화 예:
위의 예시에서는 pgp_sym_encrypt() 함수를 사용하여 텍스트를 암호화하고, pgp_sym_decrypt() 함수를 사용하여 암호화된 텍스트를 복호화합니다. 암호화에는 비밀 키(암호화에 사용되는 비밀번호)가 필요합니다.
-- pgcrypto 확장 모듈 활성화 CREATE EXTENSION IF NOT EXISTS pgcrypto; -- 텍스트 암호화 SELECT pgp_sym_encrypt('mytext', 'mysecretpassword'); -- 암호화된 텍스트 복호화 SELECT pgp_sym_decrypt('\xc36cf9...', 'mysecretpassword');
 
PostgreSQL은 XML 데이터를 별도의 데이터 유형으로 지원합니다. XML 데이터 유형을 사용하여 XML 데이터를 저장하고, XPath 쿼리와 XML 함수를 사용하여 XML 데이터를 쿼리하고 처리할 수 있습니다. PostgreSQL은 XML 데이터를 더 직접적으로 다룰 수 있는 기능을 제공합니다.
XML 처리 예:
books 테이블에 XML 데이터를 저장하고, XPath 쿼리를 사용하여 특정 조건을 충족하는 XML 데이터를 검색합니다. 또한, xml_modify() 함수를 사용하여 XML 데이터를 업데이트합니다.
XML 처리는 XML 데이터를 저장하고 쿼리하기 위해 사용되며, XML 문서의 특정 부분을 선택하거나 수정할 수 있습니다.
-- XML 데이터 저장 CREATE TABLE books ( id SERIAL PRIMARY KEY, data XML ); INSERT INTO books (data) VALUES ('<book><title>Book 1</title><author>Author 1</author></book>'); -- XML 데이터 쿼리 SELECT data FROM books WHERE xpath_exists('/book/author[text()="Author 1"]', data); -- XML 데이터 업데이트 UPDATE books SET data = xml_modify(data, '/book/author[text()="Author 1"]/text()', 'New Author') WHERE xpath_exists('/book/author[text()="Author 1"]', data);
 

외부 데이터 연결(Foreign Data Wrappers, FDW)

외부 데이터 연결(Foreign Data Wrappers): PostgreSQL은 외부 데이터 소스와의 연결을 위한 Foreign Data Wrapper(FDW)를 제공합니다. FDW를 사용하여 외부 데이터 소스(다른 데이터베이스, 웹 서비스 등)를 PostgreSQL에서 테이블처럼 접근하고 쿼리할 수 있습니다.
아래에서 PostgreSQL의 샤딩 관련하여 설명할 때 한번 더 언급됩니다.
 

트리거(Trigger), 외래 키(Foreign Key), 뷰(View)

트리거는 데이터베이스에서 특정 이벤트가 발생할 때 자동으로 실행되는 저장 프로시저입니다. 특정 테이블에 대한 데이터 변경 작업(insert, update, delete)이 발생할 때 트리거가 실행되어 추가적인 작업을 수행할 수 있습니다.
트리거 예:
CREATE FUNCTION update_inventory() RETURNS TRIGGER AS $$ BEGIN IF NEW.quantity < OLD.quantity THEN -- 재고 감소에 따른 추가 작업 수행 -- ... END IF; RETURN NEW; END; $$ LANGUAGE plpgsql; CREATE TRIGGER inventory_trigger AFTER UPDATE ON products FOR EACH ROW EXECUTE FUNCTION update_inventory();
위의 예시에서는 "products" 테이블의 업데이트 작업이 발생할 때 트리거가 실행됩니다. 새로운 데이터와 이전 데이터를 비교하여 재고 수량이 감소했을 경우 추가적인 작업을 수행할 수 있습니다.
외래 키는 한 테이블의 컬럼이 다른 테이블의 기본 키를 참조하는 제약 조건입니다. 이를 통해 데이터 간의 관계를 유지하고 데이터 무결성을 보장할 수 있습니다.
외래 키 예:
CREATE TABLE orders ( order_id SERIAL PRIMARY KEY, customer_id INT, -- ... FOREIGN KEY (customer_id) REFERENCES customers (customer_id) );
위의 예시에서는 "orders" 테이블의 "customer_id" 컬럼이 "customers" 테이블의 "customer_id" 컬럼을 참조하는 외래 키 제약 조건이 설정되어 있습니다. 이를 통해 "orders" 테이블의 주문은 "customers" 테이블의 고객과 관련된 데이터만 참조할 수 있습니다.
 

복제(Replication)

PostgreSQL은 기본적으로 내장된 복제 기능을 지원하며, 이는 데이터의 내구성과 가용성을 향상시키는 데 사용됩니다. PostgreSQL은 기본적으로 마스터-슬레이브 구조의 비동기 복제를 지원합니다.
  1. 물리적 복제(Physical Replication)
    1. 이 방식은 바이트 단위로 데이터를 복제합니다. PostgreSQL은 Write-Ahead Logging (WAL) 방식을 사용하여 Master의 모든 변경 사항을 Slave에 복제합니다. 이 방식은 거의 실시간으로 일어나며, 주로 재해 복구와 가용성 향상을 목적으로 사용됩니다.
  1. 논리적 복제(Logical Replication)
    1. PostgreSQL 10 이후 버전부터는 Logical Replication이라는 기능이 도입되었습니다. 이 방식은 특정 데이터베이스 또는 테이블을 복제하는 데 사용됩니다. Logical Replication은 데이터의 일부만 복제하거나, 다른 PostgreSQL 버전 또는 다른 시스템으로의 복제를 지원합니다.
또한, PostgreSQL 커뮤니티에서는 여러 복제 솔루션과 확장 기능을 제공하고 있습니다. 예를 들어, Pgpool-II, Slony, BDR(Bi-Directional Replication) 등의 도구와 솔루션은 PostgreSQL의 복제 기능을 확장하거나 향상시키는 데 사용될 수 있습니다.
따라서 PostgreSQL은 MySQL과 마찬가지로 높은 가용성, 데이터 보호, 부하 분산 등의 목적으로 복제 기능을 활용할 수 있습니다.
 

샤딩(Sharding)

PostgreSQL 자체는 내장 샤딩 기능을 제공하지 않지만, Citus와 같은 PostgreSQL 확장을 사용하여 샤딩을 구현할 수 있습니다.
Citus는 PostgreSQL을 분산 데이터베이스로 변환합니다.
Citus는 데이터를 여러 노드에 샤드화하고 쿼리를 병렬로 실행하여 데이터베이스의 확장성을 향상시킵니다.
또한, PostgreSQL은 Foreign Data Wrapper(FDW)라는 기능을 지원하는데, 이를 이용해 데이터베이스 간의 데이터를 연결하고 질의할 수 있습니다. 이는 샤딩과 비슷한 목적을 수행할 수 있습니다.
Foreign Data Wrapper(FDW)
FDW는 PostgreSQL에서 외부 데이터 소스를 연결하고 쿼리하는 데 사용되는 기능입니다. 이는 SQL/MED(SQL Management of External Data) 표준의 일부로 PostgreSQL에 구현되었습니다.
  • FDW를 사용하면, 외부 데이터 소스를 로컬 PostgreSQL 테이블처럼 사용할 수 있습니다. 이 외부 데이터 소스는 다른 PostgreSQL 데이터베이스일 수도 있고, 완전히 다른 유형의 데이터베이스(MySQL, Oracle 등)이거나, CSV 파일이나 스프레드시트와 같은 완전히 다른 유형의 데이터 소스일 수도 있습니다. 이런 방식으로, PostgreSQL은 하나의 통합된 인터페이스를 제공하여 다양한 데이터 소스에 걸쳐 쿼리를 실행할 수 있게 합니다.
  • FDW는 PostgreSQL에서 "서버"라는 개념을 통해 구현되며, 이 서버는 특정한 외부 데이터 소스를 나타냅니다. 각 FDW는 특정 유형의 데이터 소스와 상호 작용하는 방법을 알고 있으며, 이는 PostgreSQL이 FDW를 통해 해당 데이터 소스와 통신하게 합니다. 예를 들어, PostgreSQL에는 PostgreSQL 서버에 연결하기 위한 postgres_fdw, MySQL 서버에 연결하기 위한 mysql_fdw, CSV 파일을 처리하기 위한 file_fdw 등 다양한 FDW가 있습니다.
따라서, PostgreSQL은 MySQL과 유사하게 복제 및 샤딩 기능을 제공하며, 특히 확장 및 커뮤니티 도구를 이용하면 이러한 기능을 더욱 강화하고 커스터마이징할 수 있습니다.
 

파티셔닝(Partitioning)

PostgreSQL은 테이블 파티셔닝을 지원합니다. 이는 큰 테이블을 더 작은, 더 쉽게 관리할 수 있는 부분(파티션)으로 나누는 것을 의미합니다. 이러한 파티션은 분리된 테이블로서 각각 자체적으로 인덱스를 가질 수 있으며, 데이터는 파티션 키라고 불리는 특정 열의 값에 따라 해당 파티션에 저장됩니다. 파티셔닝은 쿼리 성능을 향상시키고, 관리를 용이하게 하며, 데이터를 여러 물리적 위치에 분산시킬 수 있습니다.
PostgreSQL 파티셔닝 유형
1. 범위 파티셔닝(Range Partitioning)
범위 파티셔닝은 파티션 키의 연속적인 값 범위를 사용하여 데이터를 분배합니다. 예를 들어, 날짜 또는 시간으로 테이블을 파티션하는 경우 범위 파티셔닝이 적용될 수 있습니다.
2. 목록 파티셔닝(List Partitioning)
목록 파티셔닝은 파티션 키의 개별 값들을 기준으로 데이터를 분배합니다. 각 파티션은 파티션 키 값의 목록을 가지며, 테이블에 삽입되는 행의 파티션 키 값이 해당 파티션의 목록에 있으면 해당 파티션에 저장됩니다.
3. 해시 파티셔닝(Hash Partitioning)
PostgreSQL 11부터 지원하는 해시 파티셔닝은 특정 해시 함수를 사용하여 행을 파티션으로 분배합니다. 이는 데이터를 균일하게 분포시키는 데 유용할 수 있습니다.
파티셔닝은 대용량 테이블의 데이터를 더 빠르게 쿼리할 수 있도록 돕습니다. 특정 파티션에 대한 쿼리를 실행하면, PostgreSQL은 다른 모든 파티션을 무시하고 해당 파티션만 스캔할 수 있기 때문입니다. 이를 '파티션 프루닝'이라고 합니다. 또한, 개별 파티션에 대해 특정 작업(예: 인덱싱, 백업, 삭제 등)을 수행할 수 있습니다.
 

클러스터링(Clustering)

PostgreSQL은 클러스터링을 위한 내장 기능을 제공하지 않지만, 여러 오픈 소스 도구와 확장을 사용하여 PostgreSQL 클러스터를 구성할 수 있습니다.
  1. PostgreSQL Automatic Failover (PAF)
    1. PostgreSQL 클러스터에서 자동 실패 복구를 제공하는 Pacemaker 리소스 에이전트입니다.
  1. Patroni
    1. PostgreSQL에 대한 템플릿화된 클러스터링 솔루션을 제공하는 오픈 소스 프로젝트입니다.
  1. Pgpool-II
    1. 여러 PostgreSQL 서버 사이에서 연결 및 쿼리를 분산하며, 고가용성, 로드 밸런싱, 자동 실패 복구 등을 제공하는 중간 계층입니다.
따라서, PostgreSQL에서는 복제 및 클러스터링을 통해 데이터베이스의 가용성과 성능을 향상시킬 수 있습니다. 하지만, 이러한 방식은 복잡성을 증가시킬 수 있으므로, 각 방식의 장단점을 이해하고 적절히 적용해야 합니다.
 
 

 

참고링크