Saudações. Nesse artigo e tutorial vou apresentar o PostgreSQL (PSQL ou PGSQL) visando ajudar quem precisa instalá-lo de maneira clara e bem documentada.
Pré-requisitos (constam em outros artigos aqui do blog):
- Instalação do Linux (Debian);
- Obter terminal (shell) como usuário root;
1 – Instalação no HOST (direto no Debian)
Instalar direto no Linux é uma forma de montar servidores dedicados para banco de dados.
Instalando
# Atualizar sistema:
apt-get -y update;
apt-get -y upgrade;
apt-get -y dist-upgrade;
# Ferramentas basicas:
apt-get -y install sudo;
apt-get -y install curl wget;
apt-get -y install ca-certificates;
# Instalar base de scripts comuns do PG (não é o PostgreSQL em si)
apt-get -y install postgresql-common;
# a UNIT /lib/systemd/system/postgresql.service nao faz nada!
# Instalar repositorio oficial PostgreSQL:
/usr/share/postgresql-common/pgdg/apt.postgresql.org.sh;
# tecle ENTER para continuar
# Com o repositorio presente, podemos instalar a versão desejada
# Versoes:
# - 18.0
# - 17.6
# - 16.10
# - 15.14
# - 14.19
# - 13.22
apt-get -y install postgresql-18;
apt-get -y install postgresql-client-18;
# table-space padrao.: /var/lib/postgresql/18/main
# configuracao.......: /etc/postgresql/18/main/postgresql.conf
# Controle do servico:
# - Verificar status:
systemctl status postgresql;
# - Parar/Iniciar (reiniciar):
systemctl stop postgresql;
systemctl start postgresql;
systemctl restart postgresql;
# - Verificar processos:
ps ax | grep postgres;
# 194155 ? Ss 0:00 /usr/lib/postgresql/18/bin/postgres -D
# /var/lib/postgresql/18/main -c
# config_file=/etc/postgresql/18/main/postgresql.conf
# 194156 ? Ss 0:00 postgres: 18/main: io worker 0
# 194157 ? Ss 0:00 postgres: 18/main: io worker 1
# 194158 ? Ss 0:00 postgres: 18/main: io worker 2
# 194159 ? Ss 0:00 postgres: 18/main: checkpointer
# 194160 ? Ss 0:00 postgres: 18/main: background writer
# 194162 ? Ss 0:00 postgres: 18/main: walwriter
# 194163 ? Ss 0:00 postgres: 18/main: autovacuum launcher
# 194164 ? Ss 0:00 postgres: 18/main: logical replication launcher
# 194177 pts/1 S+ 0:00 grep post
Acesso
Formas de entrar via terminal no shell do Postgres:
# Primeiro acesse como postgres
sudo -u postgres psql;
Nota: em linguagem SQL, comentários são definidos com “–“. Comentários com “#” são aceitos mas não recomendados.
Dentro do shell (psql), execute:
-- Alterar senha do usuario padrao "postgres":
ALTER USER postgres WITH PASSWORD 'tulipasql'; -- comentario pos-comando
-- Crie um novo superusuário "root" (opcional, nao confundir com root do linux):
CREATE USER root WITH SUPERUSER PASSWORD 'tulipasql';
-- Sair do psql:
\q
Conectando pelo terminal do Linux usando senha e usuários diferentes:
# Tente conectar com senha
psql -U postgres -h localhost -W
# Password: tulipasql
2 – Comandos rápidos do terminal PSQL
Comandos do shell do PostgreSQL:
\l -- Listar bancos de dados
\c nome_db -- Conectar em um banco de dados
\c nome_db usuario -- Conectar em um DB com usuário específico
\conninfo -- Informacoes da conexao atual
\d* -- Lista todos os objetos
\dt -- Listar tabelas do banco conectado
\dt+ -- Listar tabelas com detalhes
\d nome_da_tabela -- Descreve a estrutura da tabela
\d+ nome_da_tabela -- Descreve a estrutura da tabela detalhada
\d nome_index_vw -- Descreve índice ou view
\dn -- Lista todos os esquemas
\du -- Lista usuários/roles
\q -- Sair da conexão PGSQL
\? -- Ajuda geral dos comandos psql
\h -- Lista de todos os comandos
\h SELECT -- Ajuda para usar o comando SELECT
\h CREATE TABLE -- Ajuda para criar tabela
\h comando_aqui -- Ajuda para o comando desejado
\l -- Listar bancos de dados
\l+ -- Listar bancos de dados com detalhes
\dt -- Lista tabelas do schema atual
\dt+ -- Lista tabelas com detalhes
\dt schema.* -- Lista tabelas de um schema específico
\dt *.nome_tabela -- Lista a tabela específica em todos os schemas
\dp -- Lista privilégios de tabelas
\dp+ -- Lista privilégios de tabelas com detalhes
\dn -- Lista esquemas
\dn+ -- Lista esquemas com detalhes
\di -- Lista índices
\di+ -- Lista índices com detalhes
\df -- Lista funções
\df+ -- Lista funções com detalhes
\df nome_funcao -- Lista função específica
\dy -- Lista triggers de eventos
\dv -- Lista views
\dv+ -- Lista views com detalhes
\dm -- Apenas materialized views
\ds -- Lista sequências
\ds -- Lista sequências com detalhes
\db -- Lista tablespaces
\db+ -- Lista tablespaces com detalhes
\dE -- Lista encodings disponíveis
\dC -- Lista collations
\dD -- Lista domains
\dc -- Lista conversões
\do -- Lista operadores
\do+ -- Lista operadores com detalhes
\da -- Lista funções de agregação
\dT -- Lista tipos de dados
\dT+ -- Lista tipos de dados com detalhes
\e -- Abre editor para último comando
\e script.sql -- Abre arquivo informado no editor
\ef nome_funcao -- Abre o editor para editar a função informada
\s -- Mostra histórico de comandos
\s output.txt -- Salva histórico no arquivo informado
\w output.sql -- Salva o último comando no arquivo informado
\x -- Liga/desliga modo expandido (alterna)
\x on -- Liga modo expandido (padrão, chato)
\x off -- Desliga modo expandido (bom!)
\a -- Alternar exibição entre alinhado/não alinhado
\t -- Alternar exibição de cabeçalhos das consultas
\f -- Mostrar separador atual (ascii de exibição)
\f '|' -- Definir caracter pipe "|" como separador
\f '\t' -- Define um TAB como separador
\H -- Liga/desliga modo de saída HTML (alterna)
\T 'Titulo X' -- Define um título para as próximas consultas
\T -- Remove título das consultas
\C 'Titulo Y' -- Define um título só para a próxima consulta
\pset border 2 -- Define bordas das consultas
\pset format wrapped -- Formato com quebra de linha das consultas
\pset null '(NULL)' -- Define como exibir colunas com valor NULL
\pset footer off -- Remove rodapé das tabelas
\timing -- Liga/desliga cronômetro de consultas
\timing on -- Liga cronômetro de consultas
\timing on -- Desliga cronômetro de consultas
\! -- Abre shell para o sistema onde o PG está rodando
\! COMMAND -- Executa um comando específico no shell do sistema
\cd -- Alterna para o diretório HOME no sistema
\cd FOLDER_PATH -- Alterna para um diretório específico no sistema
\setenv VN VLE -- Define uma variável de ambiente VN com valor VLE
BEGIN -- Iniciar transação
\begin -- Iniciar transação (apelido de BEGIN)
COMMIT -- Finaliza a transação e executa
\commit -- Finaliza a transação e executa (apelido de COMMIG)
ROLLBACK -- Desfaz transação
\rollback -- Desfaz transação (equivale a ROLLBACK)
\i arquivo_sql -- Executa todos os comandos do arquivo (/pasta/…)
\o arquivo_saida -- Redireciona a saída da tela para o arquivo
SELECT 1\g out.txt -- Executa a SELECT e salva no arquivo out.txt
-- Importe o arquivo file.csv para a tabela escolhida
\copy tabela FROM 'file.csv' CSV HEADER;
-- Exportar a tabela escolhida para um arquivo CSV
\copy tabela TO 'file.csv' CSV HEADER;
SELECT count(*) FROM tabela \watch 5 -- Executa a SELECT a cada 5 segundos
\watch -- Para a repetição
-- Executa e mostra em formato expandido
SELECT * FROM tabela \gx
-- Exibir em formato de tabela cruzada
SELECT c1, c2 FROM tabela \crosstabview
3 – Instalando em container Docker
Usar o PG em container se tornou um novo padrão para aplicações em stacks.
Nota: não vou publicar o serviço para a Internet mapeando a porta 5432, faça isso por sua conta e risco usando o argumento -p 5432:5432 no docker run.
Usando docker run (simples)
# Criar rede de containers para banco de dados
# - Rede de containers somente ipv4
docker network create -d bridge network_db;
# Criando container 'postgres-18':
docker run \
-d \
--restart=always \
--name postgres-18 \
--network network_db \
\
-e "POSTGRES_PASSWORD=tulipasql" \
\
-v pg18_data:/var/lib/postgresql/data \
\
postgres:18 \
postgres --max_connections=8192;
# Entrar no shell do Postgres:
docker exec -it --user=postgres postgres-18 psql;
# \q para sair
# Remover o container (nao apaga os dados do volume pg18_data)
docker rm -f postgres-18;
Usando docker run (versão com todos os atributos de tuning)
# Criar rede de containers para banco de dados
# - Rede de containers somente ipv4
docker network create -d bridge \
-o "com.docker.network.bridge.name"="br-net-db" \
-o "com.docker.network.bridge.enable_icc"="true" \
-o "com.docker.network.bridge.enable_ip_masquerade"="true" \
--subnet 10.251.0.0/16 \
--gateway 10.251.0.254 \
network_db;
# Obter imagem da versao 18 (opcional, docker run ja faz isso)
docker pull postgres:18;
# Criando container 'postgres-18':
docker run \
-d \
--restart=always \
--name postgres-18 \
-h postgres-18.intranet.br \
--network network_db \
--ip=10.251.0.201 \
--memory=2g \
--memory-swap=2g \
--shm-size=256m \
\
--tmpfs /tmp:rw,noexec,nosuid,size=512m \
--tmpfs /run/postgresql:rw,noexec,nosuid,size=128m \
\
-e "TZ=America/Sao_Paulo" \
-e "POSTGRES_PASSWORD=tulipasql" \
-e POSTGRES_INITDB_ARGS="--auth-host=scram-sha-256 --data-checksums" \
\
-v pg18_data:/var/lib/postgresql/data \
-v pg18_logs:/var/log/postgresql \
\
postgres:18 \
postgres \
-c max_connections=8192 \
-c shared_buffers=512MB \
-c effective_cache_size=1536MB \
-c maintenance_work_mem=128MB \
-c checkpoint_completion_target=0.9 \
-c wal_buffers=16MB \
-c default_statistics_target=100 \
-c random_page_cost=1.1 \
-c effective_io_concurrency=200 \
-c work_mem=2621kB \
-c huge_pages=off \
-c min_wal_size=1GB \
-c max_wal_size=4GB \
-c max_worker_processes=4 \
-c max_parallel_workers_per_gather=2 \
-c max_parallel_workers=4 \
-c max_parallel_maintenance_workers=2 \
-c log_timezone='America/Sao_Paulo' \
-c timezone='America/Sao_Paulo';
# Entrar no shell do Postgres:
docker exec -it --user=postgres postgres-18 psql;
# \q para sair
# Remover o container (nao apaga os dados do volume pg18_data)
docker rm -f postgres-18;
Usando stack (simples)
version: '3.8'
services:
postgres-18:
image: postgres:18
container_name: postgres-18
restart: always
networks:
- network_db
environment:
- POSTGRES_PASSWORD=tulipasql
volumes:
- pg18_data:/var/lib/postgresql/data
command: postgres --max_connections=8192
networks:
network_db:
driver: bridge
driver_opts:
com.docker.network.enable_ipv6: "false"
volumes:
pg18_data:
driver: local
Usando stack (versão com todos os atributos de tuning)
version: '3.8'
networks:
network_db:
driver: bridge
driver_opts:
com.docker.network.bridge.name: "br-net-db"
com.docker.network.bridge.enable_icc: "true"
com.docker.network.bridge.enable_ip_masquerade: "true"
ipam:
config:
- subnet: 10.251.0.0/16
gateway: 10.251.0.254
volumes:
pg18_data:
driver: local
pg18_logs:
driver: local
services:
postgres-18:
image: postgres:18
container_name: postgres-18
hostname: postgres-18.intranet.br
restart: always
networks:
network_db:
ipv4_address: 10.251.0.201
deploy:
resources:
limits:
memory: 2G
reservations:
memory: 2G
shm_size: 256m
tmpfs:
- /tmp:rw,noexec,nosuid,size=512m
- /run/postgresql:rw,noexec,nosuid,size=128m
environment:
- TZ=America/Sao_Paulo
- POSTGRES_PASSWORD=tulipasql
- POSTGRES_INITDB_ARGS=--auth-host=scram-sha-256 --data-checksums
volumes:
- pg18_data:/var/lib/postgresql/data
- pg18_logs:/var/log/postgresql
command:
- postgres
- -c
- max_connections=8192
- -c
- shared_buffers=512MB
- -c
- effective_cache_size=1536MB
- -c
- maintenance_work_mem=128MB
- -c
- checkpoint_completion_target=0.9
- -c
- wal_buffers=16MB
- -c
- default_statistics_target=100
- -c
- random_page_cost=1.1
- -c
- effective_io_concurrency=200
- -c
- work_mem=2621kB
- -c
- huge_pages=off
- -c
- min_wal_size=1GB
- -c
- max_wal_size=4GB
- -c
- max_worker_processes=4
- -c
- max_parallel_workers_per_gather=2
- -c
- max_parallel_workers=4
- -c
- max_parallel_maintenance_workers=2
- -c
- log_timezone=America/Sao_Paulo
- -c
- timezone=America/Sao_Paulo
Para entrar no shell do PG pelo terminal do Portainer, obtenha shell para /bin/bash com o usuário postgresql, em seguida execute o comando psql.
5 – Tuning básico
Considerando uma instância do PostgreSQL limitado a 2G de RAM, os valores recomendados de tuning são:
Parâmetro | Valor | Descrição |
---|---|---|
shared_buffers | 512MB | 25% da RAM total |
effective_cache_size | 1536MB | 75% da RAM total |
maintenance_work_mem | 128MB | Para VACUUM, CREATE INDEX |
work_mem | 2621kB | RAM / (max_connections * 4) |
wal_buffers | 16MB | Para write-ahead logs |
Para um I/O eficiente, evite discos SATA/SAS e opte por SSD ou NVME.
Para operações rápidas, opte por processadores modernos, clock de 3GHz ou superior com muita memória Cache L3 (128MB ou mais), memória DDR5 com ECC.
6 – Sistemas de gerenciamento visual
Segue alguns sistemas para administrar o PG visualmente:
- pgAdmin – https://www.pgadmin.org/download/
- DBeaver – https://dbeaver.io/
- DbVisualizer (DbVis) – https://www.dbvis.com/
- HeidiSQL – https://www.heidisql.com/
- NaviCat – https://www.navicat.com/
- DataGrip – https://www.jetbrains.com/datagrip/
- TablePlus – https://tableplus.com/
- Postico – https://eggerapps.at/postico2/
- Luna Modeler – https://www.datensen.com/
Recomendo o pgAdmin por ser um sistema que roda em Docker e pode compor sua stack.
Usando docker run
Altere o usuário (env PGADMIN_DEFAULT_EMAIL) e senha (env PGADMIN_DEFAULT_PASSWORD) nas variáveis de ambiente abaixo:
# Criar rede de containers para banco de dados
# - Rede de containers somente ipv4
docker network create -d bridge network_db;
# Criando container 'postgres-18':
docker run \
-d \
--restart=always \
--name pgadmin4 \
--network network_db \
\
-p 15080:80 \
\
-e PGADMIN_DEFAULT_EMAIL=root@intranet.br \
-e PGADMIN_DEFAULT_PASSWORD=pgadmin_2025 \
\
-v pgadmin:/var/lib/pgadmin \
\
dpage/pgadmin4;
Usando stack
version: '3.8'
networks:
network_db:
driver: bridge
external: true
volumes:
pgadmin:
driver: local
services:
pgadmin4:
image: dpage/pgadmin4
container_name: pgadmin4
restart: always
networks:
- network_db
ports:
- "15080:80"
environment:
- PGADMIN_DEFAULT_EMAIL=root@intranet.br
- PGADMIN_DEFAULT_PASSWORD=pgadmin_2025
volumes:
- pgadmin:/var/lib/pgadmin
Acesse o IP do servidor na porta 15080 (http://ip-do-servidor:1580) para acessar o pgAdmin. Ele pode demorar até 2 minutos para carregar totalmente.
7 – Acesso remoto via shell PSQL
Para acessar via linha de comando um servidor Postgres cujo IP e porta TCP sejam alcançáveis, use alguma dessas técnicas:
Via cliente psql de um servidor para o outro
# Acesso remoto na porta exposta do container PG (postgres-main)
psql -h 45.255.128.2 -p 5432 -U postgres;
# ou
psql -h 45.255.128.2 -p 5432 -U postgres -d DB_NAME_AQUI;
# ou URL do schema postgresql:
psql postgresql://postgres:tulipa_pgsql@45.255.128.2:5432;
psql postgresql://postgres:tulipa_pgsql@45.255.128.2:5432/DB_NAME_AQUI;
Via SSH com comando remoto
Esse método permite com um único comando SSH executar o psql para acesso:
# SSH para o servidor
# - use o Termius, SecureCRT, Putty ou seu software favorito
# - troque 45.255.128.2 e 22 pelo ip e porta desejado
ssh root@45.255.128.2 -p 22;
# Rodar comando psql dentro do container (exit ou \q para sair):
docker exec -it --user=postgres psql postgres-18 -U postgres;
docker exec -it --user=postgres psql postgres-18 -U postgres -d DB_NAME_AQUI;
# Método reunido:
# Rodar o SSH ordenando execução de comando remoto:
ssh root@45.255.128.2 -p 22 -t \
docker exec -it --user=postgres postgres-18 psql;
Usando SSH-Tuneling para mapeamento de porta local em servidor remoto
Nesse método o primeiro comando abre um port-forward para o IP do servidor, o que resulta na abertura de uma porta local enquanto o comando ssh estiver rodando.
Essa porta local aberta garante um túnel TCP até a porta TCP do PostgreSQL:
# Criar túnel TCP
# - conecta-se ao servidor 45.255.128.2 -p 22
# - abre a porta 9991 no ip de loopback (127.0.0.1)
# - qualquer aplicativo pode ser conectar na porta 9991 local que
# dará acesso ao IP 10.249.255.121 porta 5432
# Opção 1: Somente criar o túnel (com o -N):
ssh root@45.255.128.2 -p 22 -N -L 127.0.0.1:9991:10.249.255.121:5432
# Agora conecte-se ao postegresql (psql) no ip localhost 127.0.0.1 porta 9991
psql -h 127.0.0.1 -p 9991 -U postgres;
# ou
psql -h 127.0.0.1 -p 9991 -U postgres -d DB_NAME_AQUI;
Terminamos por hoje!
Patrick Brandão, patrickbrandao@gmail.com