Docs of Jace-Lab

PostgreSql

PostgreSql

접속

psql을 사용해 로컬 또는 원격 호스트(Server)에 접속할 때는 접속 옵션 플래그를 지정하는 방식과 접속 URI(Connection String)를 사용하는 방식 두 가지를 주로 사용합니다.

상황에 맞는 접속 방법과 주요 옵션들을 자세히 정리해 드립니다.


1. 기본 옵션 플래그 형식 (가장 많이 사용)

가장 직관적인 방법으로, 각 접속 정보를 플래그(-h, -p, -U, -d)로 지정하여 접속합니다.

psql -h [호스트주소] -p [포트번호] -U [사용자명] -d [데이터베이스명]

💡 주요 플래그 설명

  • -h (host): 접속할 서버의 IP 주소 또는 도메인 (예: 127.0.0.1, localhost, db.example.com)
  • -p (port): PostgreSQL 포트 번호 (기본값은 5432)
  • -U (username): 데이터베이스 접속 계정명 (기본값은 현재 OS 로그인 사용자 이름)
  • -d (dbname): 최초로 연결할 데이터베이스 이름 (기본값은 사용자명과 동일)

📝 실제 사용 예시

# 원격 서버(IP: 192.168.1.50)의 5432 포트, postgres 계정으로 mydb 데이터베이스에 접속
psql -h 192.168.1.50 -p 5432 -U postgres -d mydb
  • 명령어를 실행하면 비밀번호(Password for user postgres:)를 묻는 프롬프트가 나타납니다. 비밀번호를 입력할 때는 보안상 화면에 글자가 표시되지 않으므로, 당황하지 않고 타이핑 후 Enter를 누르면 됩니다.

2. 접속 URI 형식 (URL 방식)

웹 주소처럼 하나의 문자열로 모든 접속 정보를 표현하는 방식입니다. 클라우드 서비스(Supabase, AWS RDS 등)에서 제공하는 Connection String을 그대로 복사해서 붙여넣을 때 유용합니다.

psql "postgresql://[사용자명]:[비밀번호]@[호스트주소]:[포트번호]/[데이터베이스명]?옵션"

📝 실제 사용 예시

# 비밀번호가 mypassword123인 경우 예시 (전체 문자열을 따옴표로 감싸는 것이 안전합니다)
psql "postgresql://postgres:mypassword123@192.168.1.50:5432/mydb"

# SSL 연결이 필수인 클라우드 DB 접속 시 (예: Supabase 등)
psql "postgresql://postgres:password@db.supabase.co:5432/postgres?sslmode=require"

3. 비밀번호 입력 없이 편하게 접속하는 방법

매번 긴 명령어와 비밀번호를 입력하는 것이 번거롭다면 아래의 방법들을 활용할 수 있습니다.

방법 A. .pgpass 파일 활용 (가장 권장됨)

사용자의 홈 디렉토리에 .pgpass 파일을 만들어 접속 정보를 저장해두면, psql 실행 시 비밀번호 입력을 자동으로 건너뜁니다.

  1. 홈 디렉토리에 파일 생성 및 작성 형식:
# 형식: 호스트주소:포트번호:데이터베이스명:사용자명:비밀번호
192.168.1.50:5432:mydb:postgres:mypassword123
  1. 보안 권한 설정 (필수): 이 파일은 소유자만 읽을 수 있어야 psql이 인식합니다.
chmod 0600 ~/.pgpass
  1. 이제 명령어에서 비밀번호 프롬프트 없이 바로 접속됩니다.
psql -h 192.168.1.50 -U postgres -d mydb

방법 B. 환경 변수(PGPASSWORD) 사용 (임시 활용)

셸 환경 변수에 비밀번호를 미리 선언하는 방법입니다. 터미널 기록에 비밀번호가 남을 수 있으므로 일회성 스크립트 등에서 제한적으로 사용하는 것이 좋습니다.

export PGPASSWORD='mypassword123'
psql -h 192.168.1.50 -U postgres -d mydb

4. 접속 문제 해결 (Troubleshooting)

만약 위 명령어를 올바르게 입력했는데도 접속이 안 된다면 원격 서버의 PostgreSQL 설정이나 방화벽 문제일 확률이 높습니다.

  • Connection refused 에러가 나는 경우:
  • 서버의 postgresql.conf 파일에서 외부 접속이 허용되어 있는지 확인해야 합니다.
# postgresql.conf
listen_addresses = '*'  # 기본값인 'localhost' 대신 '*'로 되어 있어야 외부 접속 가능
  • no pg_hba.conf entry for host 에러가 나는 경우:
  • 서버의 pg_hba.conf 파일에 클라이언트 IP(본인 PC)의 접근 권한이 추가되어 있는지 확인해야 합니다.
# pg_hba.conf 예시 (모든 IP 호스트에 대해 md5/scram-sha-256 인증 허용)
host    all             all             0.0.0.0/0               scram-sha-256
  • 설정을 변경한 후에는 반드시 PostgreSQL 서비스를 재시작(sudo systemctl restart postgresql 등)해야 적용됩니다.



psql

PostgreSQL CLI(psql)에서 자주 사용하는 기본 명령어 정리입니다.

psql 명령어는 크게 역슬래시(\)로 시작하는 메타 명령어일반 SQL 문으로 나뉩니다. 메타 명령어는 세미콜론(;)이 필요 없지만, SQL 문은 반드시 끝에 ;을 붙여야 실행됩니다.


1. 연결 및 종료

명령어설명
\qpsql 접속 종료 (Quit)
\c [데이터베이스명] [사용자명]다른 데이터베이스 또는 사용자로 전환 (Connect)
\conninfo현재 연결된 데이터베이스, 사용자, 포트 정보 확인

2. 데이터베이스 및 스키마 조회

명령어설명
\l 또는 \list전체 데이터베이스 목록 조회
\dn현재 데이터베이스의 스키마 목록 조회
\dn+스키마 목록 및 권한/설명 상세 조회

3. 테이블 및 데이터 객체 조회 (d 계열)

뒤에 +를 붙이면 (예: \dt+) 물리적 크기 및 설명이 포함된 상세 정보가 나옵니다.

명령어설명
\dt현재 스키마의 테이블 목록 조회 (Table)
\dt *.테이블명모든 스키마에서 특정 테이블 검색
\d [테이블명]특정 테이블의 컬럼 구조, 타입, 인덱스, 제약조건 상세 조회
\dv뷰(View) 목록 조회
\di인덱스(Index) 목록 조회
\df함수/프로시저(Function) 목록 조회
\dy트리거(Trigger) 목록 조회
\ds시퀀스(Sequence) 목록 조회

4. 권한 및 사용자 관리

명령어설명
\du역할(Role) 및 사용자(User) 목록, 권한 조회
\z [테이블명]특정 테이블의 접근 권한(Grant/Revoke 상태) 조회

5. 쿼리 결과 및 화면 설정

명령어설명
\x확장 디스플레이 모드 토글 (컬럼이 많을 때 가로가 아닌 세로 행 형태로 출력)
\timing쿼리 실행 시간을 밀리초(ms) 단위로 표시 토글
\a정렬되지 않은 출력 모드 전환 (CSV 내보내기 등에 유용)
\HHTML 출력 형식 토글

6. 외부 파일 실행 및 저장

명령어설명
\i [파일패스]외부 SQL 스크립트 파일을 불러와서 실행 (Input)
\o [파일패스]이후 실행되는 쿼리의 결과를 화면이 아닌 파일로 저장 (Output)

(원상 복구하려면 파일 패스 없이 \o만 입력) | | \copy [테이블명] to '[경로]/file.csv' csv header | 특정 테이블 데이터를 CSV 파일로 내보내기 (서버 권한 필요 없음) | | \copy [테이블명] from '[경로]/file.csv' csv header | CSV 파일 데이터를 테이블로 가져오기 |


💡 유용한 팁

  • 명령어 도움말: \?를 입력하면 psql 내에서 사용할 수 있는 모든 메타 명령어 요약본을 볼 수 있습니다.
  • SQL 도움말: \h [SQL명령어] (예: \h CREATE TABLE)를 입력하면 해당 SQL 문의 문법 구문을 안내해 줍니다.
  • 이전 쿼리 편집: \e를 입력하면 시스템 기본 에디터(Vim, Nano 등)가 열리며, 작성 중이던 버퍼나 직전 쿼리를 편하게 편집한 후 저장하고 나와서 실행할 수 있습니다.

데이터베이스(DB) 관리 명령어

PostgreSQL에서 데이터베이스(DB)를 새로 만들고, 권한을 부여하며, 유지보수 및 관리하는 전체적인 흐름을 psql 명령어와 SQL 문 위주로 정리해 드립니다.


1. 데이터베이스(DB) 생성 및 삭제

새로운 프로젝트를 시작할 때 DB와 해당 DB를 관리할 전용 사용자를 만드는 과정입니다.

⚠️ 주의: DB 생성, 사용자 생성, 삭제 등은 대개 최고 관리자 권한(postgres 계정 등)이 필요합니다.

데이터베이스 생성 (CREATE)

-- 1. 전용 사용자(Role) 생성 (비밀번호 포함)
CREATE USER jace_user WITH PASSWORD 'secure_password_123';

-- 2. 데이터베이스 생성 (소유자를 위에서 만든 사용자로 지정)
CREATE DATABASE my_project_db OWNER jace_user;

데이터베이스 삭제 (DROP)

-- 데이터베이스 삭제 (연결된 세션이 없어야 함)
DROP DATABASE my_project_db;

-- 만약 다른 프로세스가 접속 중이라 삭제가 안 된다면, 강제 접속 종료 후 삭제
DROP DATABASE my_project_db WITH (FORCE);

2. 사용자 권한 관리 (Privileges)

보안과 협업을 위해 특정 스키마나 테이블에 대한 접근 권한을 제어합니다.

권한 부여 (GRANT)

-- 특정 사용자에게 해당 데이터베이스의 모든 권한 부여
GRANT ALL PRIVILEGES ON DATABASE my_project_db TO jace_user;

-- 특정 스키마(예: public) 내의 테이블 조회/수정 권한만 부여할 때
GRANT USAGE ON SCHEMA public TO jace_user;
GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO jace_user;

권한 회수 (REVOKE)

-- 특정 테이블의 권한을 회수
REVOKE INSERT, UPDATE ON TABLE users FROM jace_user;

3. 구조 변경 및 관리 (DDL)

생성된 데이터베이스 내에서 테이블 구조를 변경하거나 인덱스를 관리하는 방법입니다.

테이블 구조 변경 (ALTER TABLE)

-- 새 컬럼 추가
ALTER TABLE users ADD COLUMN phone_number VARCHAR(20);

-- 컬럼 데이터 타입 변경
ALTER TABLE users ALTER COLUMN phone_number TYPE VARCHAR(30);

-- 컬럼 이름 변경
ALTER TABLE users RENAME COLUMN phone_number TO phone;

-- 컬럼 삭제
ALTER TABLE users DROP COLUMN phone;

인덱스 관리 (Index)

조회 성능 최적화를 위해 자주 검색 조건(WHERE)이나 조인(JOIN)에 사용되는 컬럼에 인덱스를 생성합니다.

-- 인덱스 생성 (Non-blocking 방식으로 운영 중인 서비스에 영향 없이 생성)
CREATE INDEX CONCURRENTLY idx_users_email ON users(email);

-- 인덱스 삭제
DROP INDEX CONCURRENTLY idx_users_email;

4. 백업 및 복구 (Dump & Restore)

데이터베이스를 안전하게 이관하거나 백업할 때는 psql 내부가 아닌 터미널(셸) 환경에서 다음 도구들을 사용합니다.

백업하기 (pg_dump)

# 특정 데이터베이스를 SQL 스크립트 파일로 백업
pg_dump -h localhost -U postgres -d my_project_db > backup.sql

# 압축된 커스텀 포맷으로 백업 (대용량 DB 추천, 복구가 빠름)
pg_dump -h localhost -U postgres -F c -d my_project_db -f backup.dump

복구하기 (psql 또는 pg_restore)

# 1. SQL 스크립트 파일(.sql)로 복구할 때
psql -h localhost -U postgres -d new_project_db -f backup.sql

# 2. 커스텀 포맷 파일(.dump)로 복구할 때
pg_restore -h localhost -U postgres -d new_project_db -v backup.dump

5. 성능 최적화 및 유지보수 (Maintenance)

PostgreSQL은 MVCC(Multi-Version Concurrency Control) 모델을 사용하므로, 데이터를 수정(UPDATE)하거나 삭제(DELETE)하면 물리적 공간에 쓰레기 데이터(Dead Tuples)가 남습니다. 이를 주기적으로 정리해 주어야 성능이 유지됩니다.

불필요한 영역 정리 및 통계 갱신 (VACUUM)

-- 1. 쓰레기 데이터를 정리하고 성능 통계를 최적화 (운영 중 사용 가능)
VACUUM ANALYZE users;

-- 2. 데이터베이스 전체를 대상으로 실행
VACUUM ANALYZE;

-- 3. 디스크 물리 공간까지 완전히 OS로 반환 (테이블에 락이 걸리므로 서비스 점검 시에만 사용)
VACUUM FULL users;

현재 실행 중인 쿼리 확인 및 강제 종료

DB가 느려지거나 락(Lock)이 걸렸을 때 원인을 찾고 해결하는 방법입니다.

-- 현재 실행 중인 활성 쿼리 및 실행 시간 확인
SELECT pid, age(clock_timestamp(), query_start), usename, query, state
FROM pg_stat_activity
WHERE state != 'idle' AND query NOT LIKE '%pg_stat_activity%';

-- 특정 프로세스(PID) 안전하게 종료 (실행 중인 쿼리만 취소)
SELECT pg_cancel_backend([확인한_PID]);

-- 특정 프로세스(PID) 강제 종료 (커넥션 자체를 끊음)
SELECT pg_terminate_backend([확인한_PID]);

용량 제한

결론부터 말씀드리면, PostgreSQL 자체에는 특정 데이터베이스(DB)의 용량을 제한하는 MAX_SIZE 같은 내장 설정이나 명령어가 없습니다. PostgreSQL 공식 제한 기준으로 DB 용량은 '무제한(디스크가 허용하는 만큼)'입니다.

하지만 멀티 테넌트(Multi-tenant) 환경이나 가상 서버를 운영할 때 DB별로 용량을 제한해야 하는 경우가 많죠. 이 경우 우회적인 방법을 사용하여 용량을 제한할 수 있습니다. 가장 많이 쓰이는 3가지 방법을 정리해 드립니다.


1. 운영체제(OS)의 Tablespace와 디스크 할당량(Quota) 활용

PostgreSQL의 테이블스페이스(Tablespace) 기능과 리눅스의 디스크 쿼터(Quota) 기능을 조합하는 가장 확실하고 정석적인 방법입니다.

  1. 별도의 디스크 볼륨 또는 파티션 생성: 가상으로 용량이 제한된 디스크 공간(예: 10GB 짜리 파티션이나 루프백 디바이스)을 만듭니다.
  2. OS 디렉토리 매핑: 해당 디스크를 리눅스 특정 경로(예: /mnt/db_limit_10g)에 마운트하고 소유권을 postgres로 바꿉니다.
  3. psql에서 테이블스페이스 생성:
CREATE TABLESPACE limited_space LOCATION '/mnt/db_limit_10g';
  1. DB 생성 시 테이블스페이스 지정:
CREATE DATABASE restricted_db TABLESPACE limited_space;
  • 결과: 해당 DB에 쌓이는 모든 데이터는 지정한 파티션에만 저장되므로, 디스크 공간이 가득 차면 더 이상 INSERT가 불가능해지며 자연스럽게 용량이 제한됩니다.

2. Trigger(트리거)를 활용한 소프트 제한 (용량 체크)

정확한 물리적 제한은 아니지만, 데이터가 삽입/수정될 때마다 현재 DB 용량을 체크하여 지정한 용량을 넘어서면 에러를 발생시키는 방식입니다.

-- 1. 현재 DB의 용량이 5GB(5120MB)를 넘었는지 확인하는 함수 생성
CREATE OR REPLACE FUNCTION check_db_size_limit() 
RETURNS TRIGGER AS $$
DECLARE
    current_db_size_mb NUMERIC;
    limit_size_mb NUMERIC := 5120; -- 제한하고 싶은 용량 (MB 단위)
BEGIN
    -- 현재 접속 중인 DB의 용량 계산
    SELECT pg_database_size(current_database()) / 1024 / 1024 INTO current_db_size_mb;

    IF current_db_size_mb > limit_size_mb THEN
        RAISE EXCEPTION '데이터베이스 용량 제한(%MB)을 초과하여 데이터를 추가할 수 없습니다.', limit_size_mb;
    END IF;
    
    RETURN NEW;
END;
$$ LANGUAGE plpgsql;

-- 2. 용량이 크게 늘어날 수 있는 주요 테이블에 트리거 적용
CREATE TRIGGER trg_limit_size
BEFORE INSERT OR UPDATE ON heavy_table
FOR EACH ROW EXECUTE FUNCTION check_db_size_limit();
  • 장점: 별도의 인프라 작업 없이 SQL만으로 제어가 가능합니다.
  • 단점: 모든 테이블에 일일이 걸어주기 번거롭고, 데이터가 들어올 때마다 용량을 계산하는 쿼리가 돌기 때문에 약간의 성능 저하가 발생할 수 있습니다.

3. 외부 스크립트(Cron Job) 환경에서 Connection 제한

리눅스 크론탭(Crontab)을 이용해 5분이나 10분 주기로 DB 용량을 체크하는 셸 스크립트를 실행하는 방식입니다. 용량이 초과되면 사용자의 쓰기 권한을 박탈하거나 접속을 막아버립니다.

예시 스크립트 흐름 (check_size.sh)

#!/bin/bash
# 현재 DB 용량(Byte)을 가져와 기준치(예: 10GB = 10737418240)와 비교
CURRENT_SIZE=$(psql -At -c "SELECT pg_database_size('my_db');")
LIMIT_SIZE=10737418240

if [ "$CURRENT_SIZE" -gt "$LIMIT_SIZE" ]; then
    # 용량 초과 시, 해당 DB를 읽기 전용(Connection 제한 등)으로 변경하거나 일반 유저의 INSERT 권한 회수
    psql -c "ALTER DATABASE my_db CONNECTION LIMIT 0;"
    # 또는 특정 유저의 권한 박탈
    # psql -d my_db -c "REVOKE INSERT, UPDATE ON ALL TABLES IN SCHEMA public FROM jace_user;"
fi
  • 장점: 실시간 서비스 성능에 전혀 영향을 주지 않습니다.
  • 단점: 크론탭 주기 사이(예: 5분 사이)에 대량의 데이터가 인입되면 일시적으로 제한 용량을 넘길 수 있습니다.

📌 요약 및 추천

  • 인프라를 직접 제어할 수 있는 독립 서버 환경(AWS EC2, 전용 서버 등)이라면 1번(Tablespace) 방식을 가장 추천합니다. 안정적이고 깔끔합니다.
  • Supabase 같은 Managed 클라우드 DB를 사용 중이라면 플랫폼 자체 제공 쿼터 설정을 이용해야 하며, 내부에서 구현해야 한다면 관리 목적용으로 3번(스크립트 감시) 방식을 조합하는 것이 일반적입니다.

On this page