Résumé PostgreSQL : Référence rapide pour les développeurs

Référence rapide pour PostgreSQL

Sommaire
Une référence rapide pour le travail quotidien
PostgreSQL
connexions, syntaxe SQL, méta-commandes psql, performance, JSON, fonctions analytiques et plus encore.

Si vous souhaitez un rappel concis couvrant plusieurs bases de données avant de plonger dans les spécificités de Postgres, ce barème SQL contenant les commandes SQL les plus utiles est un compagnon pratique.

logo postgresql

Connexion et bases

# Connexion
psql -h HÔTE -p 5432 -U UTILISATEUR -d SDB
psql $DATABASE_URL

# À l'intérieur de psql
\conninfo             -- afficher la connexion
\l[+]                 -- lister les bases de données
\c SDB                 -- se connecter à SDB
\dt[+] [schéma.]motif   -- lister les tables
\dv[+]                -- lister les vues
\ds[+]                -- lister les séquences
\df[+] [motif]          -- lister les fonctions
\d[S+] nom           -- décrire table/vue/séquence
\dn[+]                -- lister les schémas
\du[+]                -- lister les rôles
\timing               -- basculer le minutage des requêtes
\x                    -- affichage étendu
\e                    -- éditer le tampon dans $EDITOR
\i fichier.sql           -- exécuter le fichier
\copy ...             -- COPY côté client
\! commande_shell          -- 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
  • Temporel : timestamp [with/without time zone], date, time, interval
  • UUID : uuid
  • JSON : json, jsonb (recommandé)
  • Tableau : type[] par exemple text[]
  • Réseau : inet, cidr, macaddr
  • Géométrique : 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éer / Modifier)

-- Créer schéma et 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[]
);

-- Modifier
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 (Insérer / Mettre à jour / Upsert / Supprimer)

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;

Essentiels de requêtage

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 et 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écursive
WITH RECURSIVE t(n) AS (
  SELECT 1
  UNION ALL
  SELECT n+1 FROM t WHERE n < 10
)
SELECT sum(n) FROM t;

Fonctions analytiques (Window Functions)

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 / containment
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 (Arrays)

-- appartenance et containment
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']);

Temps 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 et 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'isolement
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;

-- Vérifier les verrous
SELECT * FROM pg_locks l JOIN pg_stat_activity a USING (pid);

Rôles et permissions

-- Créer un 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 un superutilisateur ou des privilèges appropriés)
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 et 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 une extension

-- Maintenance
VACUUM [FULL] [VERBOSE] nom_table;
ANALYZE nom_table;
REINDEX TABLE nom_table;

Pour une vue d’ensemble plus large des outils essentiels pour les développeurs, y compris Docker, Git et PostgreSQL, consultez Outils pour développeurs : Le guide complet des flux de travail de développement 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 par trigrammes

Recherche full-text (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 hésitez entre une recherche native Postgres et une pile de recherche séparée, cette comparaison entre la recherche full-text PostgreSQL et Elasticsearch détaille les compromis.


Paramètres psql utiles

\pset pager off       -- désactiver le pagin
\pset null '∅'
\pset format aligned  -- autres : unaligned, csv
\set ON_ERROR_STOP on
\timing on

Requêtes utiles sur le catalogue

-- 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;

-- Gonflement 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 HÔTE -U UTILISATEUR -d SDB -F c -f db.dump        # format personnalisé
pg_restore -h HÔTE -U UTILISATEUR -d NEW_DB -j 4 db.dump

# SQL brut
pg_dump -h HÔTE -U UTILISATEUR -d SDB > dump.sql
psql -h HÔTE -U UTILISATEUR -d SDB -f dump.sql

Pour les outils de gestion de base de données avec interface graphique, consultez DBeaver vs Beekeeper - Outils de gestion de base de données SQL et Installer DBeaver sur Linux - Tutoriel.


Réplication (vue d’ensemble)

  • Les fichiers WAL sont diffusés du primaire vers le standby
  • Paramètres clés : wal_level, max_wal_senders, hot_standby, primary_conninfo
  • Outils : pg_basebackup, standby.signal (PG ≥12)

Pièges et astuces

  • Utilisez toujours jsonb et non json pour l’indexation et les opérateurs.
  • Préférez timestamptz (prise en charge de la fuseau horaire).
  • DISTINCT ON est la solution idéale de Postgres pour le “top-N par groupe”.
  • Utilisez GENERATED ALWAYS AS IDENTITY au lieu de serial.
  • É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.

Petites touches spécifiques à la version (≥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;

Liens utiles

S'abonner

Recevez de nouveaux articles sur les systèmes, l'infrastructure et l'ingénierie IA.