Fiche mémo PostgreSQL : guide de référence rapide pour les développeurs
Rappel rapide de PostgreSQL
Une référence rapide pour le travail PostgreSQL quotidien : connexions, syntaxe SQL, commandes méta psql, performance, JSON, fonctions de fenêtre, et bien plus.
Si vous souhaitez un rafraîchissement concis inter-bases de données avant de plonger dans les spécificités de Postgres, cette fiche de triche SQL avec les commandes SQL les plus utiles est un compagnon pratique.

Connexion & Bases
# Connexion
psql -h HOST -p 5432 -U USER -d DB
psql $DATABASE_URL
# Dans psql
\conninfo -- afficher la connexion
\l[+] -- lister les bases de données
\c DB -- se connecter à la base DB
\dt[+] [schema.]pat -- lister les tables
\dv[+] -- lister les vues
\ds[+] -- lister les séquences
\df[+] [pat] -- lister les fonctions
\d[S+] name -- décrire table/vue/séquence
\dn[+] -- lister les schémas
\du[+] -- lister les rôles
\timing -- activer/désactiver le temps de requête
\x -- affichage étendu
\e -- éditer le buffer dans $EDITOR
\i file.sql -- exécuter le fichier
\copy ... -- COPY côté client
\! shell_cmd -- exécuter une commande shell
Types de données (courants)
- Numériques :
smallint,integer,bigint,decimal(p,s),numeric,real,double precision,serial,bigserial - Texte :
text,varchar(n),char(n) - Booléen :
boolean - Temporels :
timestamp [with/without time zone],date,time,interval - UUID :
uuid - JSON :
json,jsonb(recommandé) - Tableau :
type[]par ex.text[] - Réseau :
inet,cidr,macaddr - Géométriques :
point,line,polygon, etc.
Vérifier la version PostgreSQL
SELECT version();
Version du serveur PostgreSQL :
pg_config --version
Version du client PostgreSQL :
psql --version
DDL (Création / Modification)
-- Création du schéma et de la table
CREATE SCHEMA IF NOT EXISTS app;
CREATE TABLE app.users (
id bigserial PRIMARY KEY,
email text NOT NULL UNIQUE,
name text,
active boolean NOT NULL DEFAULT true,
created_at timestamptz NOT NULL DEFAULT now(),
profile jsonb,
tags text[]
);
-- Modification
ALTER TABLE app.users ADD COLUMN last_login timestamptz;
ALTER TABLE app.users ALTER COLUMN name SET NOT NULL;
ALTER TABLE app.users DROP COLUMN tags;
-- Contraintes
ALTER TABLE app.users ADD CONSTRAINT email_lower_uk UNIQUE (lower(email));
-- Index
CREATE INDEX ON app.users (email);
CREATE UNIQUE INDEX CONCURRENTLY users_email_uidx ON app.users (lower(email));
CREATE INDEX users_profile_gin ON app.users USING gin (profile);
CREATE INDEX users_created_at_idx ON app.users (created_at DESC);
DML (Insertion / Mise à jour / Upsert / Suppression)
INSERT INTO app.users (email, name) VALUES
('a@x.com','A'), ('b@x.com','B')
RETURNING id;
-- Upsert (ON CONFLICT)
INSERT INTO app.users (email, name)
VALUES ('a@x.com','Alice')
ON CONFLICT (email)
DO UPDATE SET name = EXCLUDED.name, updated_at = now();
UPDATE app.users SET active = false WHERE last_login < now() - interval '1 year';
DELETE FROM app.users WHERE active = false AND last_login IS NULL;
Éléments essentiels des requêtes
SELECT * FROM app.users ORDER BY created_at DESC LIMIT 20 OFFSET 40; -- pagination
-- Filtrage
SELECT * FROM app.users WHERE email ILIKE '%@example.%' AND active;
-- Agrégats & GROUP BY
SELECT active, count(*) AS n
FROM app.users
GROUP BY active
HAVING count(*) > 10;
-- Jointures
SELECT o.id, u.email, o.total
FROM app.orders o
JOIN app.users u ON u.id = o.user_id
LEFT JOIN app.discounts d ON d.id = o.discount_id;
-- DISTINCT ON (spécifique à Postgres)
SELECT DISTINCT ON (user_id) user_id, status, created_at
FROM app.events
ORDER BY user_id, created_at DESC;
-- CTE (Common Table Expressions)
WITH recent AS (
SELECT * FROM app.orders WHERE created_at > now() - interval '30 days'
)
SELECT count(*) FROM recent;
-- CTE récursif
WITH RECURSIVE t(n) AS (
SELECT 1
UNION ALL
SELECT n+1 FROM t WHERE n < 10
)
SELECT sum(n) FROM t;
Fonctions de fenêtre
SELECT
user_id,
created_at,
sum(total) OVER (PARTITION BY user_id ORDER BY created_at) AS running_total,
row_number() OVER (PARTITION BY user_id ORDER BY created_at) AS rn,
lag(total, 1) OVER (PARTITION BY user_id ORDER BY created_at) AS prev_total
FROM app.orders;
JSON / JSONB
-- Extraction
SELECT profile->>'company' AS company FROM app.users;
SELECT profile->'address'->>'city' FROM app.users;
-- Index pour les requêtes jsonb
CREATE INDEX users_profile_company_gin ON app.users USING gin ((profile->>'company'));
-- Existence / Contenance
SELECT * FROM app.users WHERE profile ? 'company'; -- la clé existe
SELECT * FROM app.users WHERE profile @> '{"role":"admin"}'; -- contient
-- Mise à jour jsonb
UPDATE app.users
SET profile = jsonb_set(COALESCE(profile,'{}'::jsonb), '{prefs,theme}', '"dark"', true);
Tableaux
-- appartenance et contenance
SELECT * FROM app.users WHERE 'vip' = ANY(tags);
SELECT * FROM app.users WHERE tags @> ARRAY['beta'];
-- ajout
UPDATE app.users SET tags = array_distinct(tags || ARRAY['vip']);
Heures et Dates
SELECT now() AT TIME ZONE 'Australia/Melbourne';
SELECT date_trunc('day', created_at) AS d, count(*)
FROM app.users GROUP BY d ORDER BY d;
-- Intervalles
SELECT now() - interval '7 days';
Transactions & Verrous
BEGIN;
UPDATE app.accounts SET balance = balance - 100 WHERE id = 1;
UPDATE app.accounts SET balance = balance + 100 WHERE id = 2;
COMMIT; -- ou ROLLBACK
-- Niveau d'isolation
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
-- Vérifier les verrous
SELECT * FROM pg_locks l JOIN pg_stat_activity a USING (pid);
Rôles & Permissions
-- Création de rôle/utilisateur
CREATE ROLE app_user LOGIN PASSWORD 'secret';
GRANT USAGE ON SCHEMA app TO app_user;
GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA app TO app_user;
ALTER DEFAULT PRIVILEGES IN SCHEMA app GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO app_user;
Import / Export
-- Côté serveur (nécessite superutilisateur ou permissions appropriées)
COPY app.users TO '/tmp/users.csv' CSV HEADER;
COPY app.users(email,name) FROM '/tmp/users.csv' CSV HEADER;
-- Côté client (psql)
\copy app.users TO 'users.csv' CSV HEADER
\copy app.users(email,name) FROM 'users.csv' CSV HEADER
Performance & Observabilité
EXPLAIN (ANALYZE, BUFFERS, VERBOSE) SELECT ...; -- temps d'exécution réel
-- Vues de statistiques
SELECT * FROM pg_stat_user_tables;
SELECT * FROM pg_stat_statements ORDER BY total_time DESC LIMIT 20; -- nécessite l'extension
-- Maintenance
VACUUM [FULL] [VERBOSE] table_name;
ANALYZE table_name;
REINDEX TABLE table_name;
Pour une vue d’ensemble plus large des outils de développement essentiels, y compris Docker, Git et PostgreSQL, consultez Outils de développement : Le guide complet des flux de travail modernes.
Activez les extensions selon les besoins :
CREATE EXTENSION IF NOT EXISTS pg_stat_statements;
CREATE EXTENSION IF NOT EXISTS btree_gin;
CREATE EXTENSION IF NOT EXISTS pg_trgm; -- recherche de trigrammes
Recherche plein texte (rapide)
ALTER TABLE app.docs ADD COLUMN tsv tsvector;
UPDATE app.docs SET tsv = to_tsvector('english', coalesce(title,'') || ' ' || coalesce(body,''));
CREATE INDEX docs_tsv_idx ON app.docs USING gin(tsv);
SELECT id FROM app.docs WHERE tsv @@ plainto_tsquery('english', 'quick brown fox');
Si vous décidez quand la recherche native de Postgres est suffisante par rapport à l’installation d’une pile de recherche séparée, cette comparaison entre la recherche plein texte PostgreSQL et Elasticsearch couvre en profondeur les compromis.
Paramètres psql utiles
\pset pager off -- désactiver le pager
\pset null '∅'
\pset format aligned -- autre : unaligned, csv
\set ON_ERROR_STOP on
\timing on
Requêtes de catalogue pratiques
-- Taille des tables
SELECT relname, pg_size_pretty(pg_total_relation_size(relid)) AS size
FROM pg_catalog.pg_statio_user_tables ORDER BY pg_total_relation_size(relid) DESC;
-- Enflure des index (approximatif)
SELECT schemaname, relname, indexrelname, idx_scan
FROM pg_stat_user_indexes ORDER BY idx_scan ASC NULLS FIRST LIMIT 20;
Sauvegarde / Restauration
# Dump logique
pg_dump -h HOST -U USER -d DB -F c -f db.dump # format personnalisé
pg_restore -h HOST -U USER -d NEW_DB -j 4 db.dump
# SQL brut
pg_dump -h HOST -U USER -d DB > dump.sql
psql -h HOST -U USER -d DB -f dump.sql
Pour les outils de gestion de bases de données graphiques, consultez DBeaver vs Beekeeper - Outils de gestion de bases de données SQL et Installer DBeaver sur linux - tutoriel.
Pour un exemple concret de l’utilisation de pg_dump/psql aux côtés des sauvegardes de dépôt et de fichiers, consultez Sauvegarde et restauration du serveur Gitea.
Réplication (vue d’ensemble)
- Les fichiers WAL sont diffusés depuis primaire → secondaire
- Paramètres clés :
wal_level,max_wal_senders,hot_standby,primary_conninfo - Outils :
pg_basebackup,standby.signal(PG ≥12)
Pièges & Astuces
- Utilisez toujours
jsonb, et nonjson, pour l’indexation et les opérateurs. - Privilégiez
timestamptz(prise en charge de la fuseau horaire). DISTINCT ONest un atout précieux de Postgres pour les “top-N par groupe”.- Utilisez
GENERATED ALWAYS AS IDENTITYau lieu deserial. - Évitez
SELECT *dans les requêtes de production. - Créez des index pour les filtres sélectifs et les clés de jointure.
- Mesurez avec
EXPLAIN (ANALYZE)avant d’optimiser.
Avantages spécifiques aux versions (≥v12+)
-- Identité générée
CREATE TABLE t (id bigINT GENERATED ALWAYS AS IDENTITY, ...);
-- UPSERT avec index partiel
CREATE UNIQUE INDEX ON t (key) WHERE is_active;