PostgreSQL
La base de données relationnelle open-source de référence. Robuste, riche en fonctionnalités, capable de tenir la charge d'une application en production — et l'option par défaut dès que SQLite n'est plus suffisant.
À quoi ça sert
PostgreSQL (souvent abrégé Postgres) est une base de données SQL serveur : contrairement à SQLite qui est un simple fichier, Postgres tourne comme un processus séparé auquel plusieurs applications peuvent se connecter en même temps via le réseau.
Concrètement, on s'en sert pour :
- Stocker les données métier d'une API en production (utilisateurs, produits, commandes…).
- Servir plusieurs clients en parallèle — c'est précisément ce que SQLite ne sait pas bien faire.
- Persister des données complexes — Postgres gère nativement le JSON, les tableaux, les types géographiques (PostGIS), les recherches plein-texte, etc.
- Stocker le tracking MLflow — le serveur MLflow utilise typiquement Postgres comme backend store pour les runs, paramètres, métriques.
- Servir de base à Supabase — Supabase, c'est Postgres + une couche d'outils par-dessus.
SQLite = un fichier, parfait pour le développement ou les petites applis mono-utilisateur. PostgreSQL = un serveur SQL complet, le standard de production open-source. Supabase = du Postgres hébergé + auth + API REST auto-générée + storage. En MLOps, on prototype souvent en SQLite puis on passe en Postgres en production sans changer le code grâce à SQLAlchemy.
Un exemple d'usage
On lance un Postgres en local (via Docker), on crée une base, et on s'y connecte depuis une appli Python avec SQLAlchemy :
# Lancer un Postgres dans Docker en une commande
docker run -d --name pg \
-e POSTGRES_PASSWORD=secret \
-e POSTGRES_DB=appdb \
-p 5432:5432 \
postgres:16
# Se connecter avec psql (client en CLI)
docker exec -it pg psql -U postgres -d appdb
from sqlalchemy import create_engine, text
# Format : postgresql+psycopg://user:password@host:port/database
engine = create_engine("postgresql+psycopg://postgres:secret@localhost:5432/appdb")
with engine.connect() as conn:
conn.execute(text("CREATE TABLE IF NOT EXISTS users (id SERIAL, name TEXT)"))
conn.execute(text("INSERT INTO users (name) VALUES ('Alice')"))
conn.commit()
rows = conn.execute(text("SELECT * FROM users")).fetchall()
print(rows) # [(1, 'Alice')]
En quelques lignes, tu as un Postgres prêt, une connexion depuis Python, une table créée et un premier enregistrement. Le passage de SQLite à Postgres dans un projet existant se résume souvent à changer la connection string dans la config.
How-to : installer et utiliser PostgreSQL
-
Lancer un Postgres en local (Docker, recommandé)
L'image officielle
postgresest la façon la plus simple — pas besoin de l'installer sur ta machine, et chaque projet peut avoir sa propre version. Avec Docker :bashdocker run -d --name pg \ -e POSTGRES_USER=app \ -e POSTGRES_PASSWORD=secret \ -e POSTGRES_DB=appdb \ -p 5432:5432 \ -v pgdata:/var/lib/postgresql/data \ postgres:16Le
-v pgdata:/var/lib/postgresql/dataest important : il monte un volume Docker pour persister les données entre redémarrages du conteneur (sinon, tu perds tout à chaquedocker rm).docker-compose, encore mieuxEn pratique, on déclare la DB dans un
docker-compose.ymlaux côtés de l'API et des autres services.docker compose upet tout démarre ensemble — c'est le pattern standard d'un projet FastAPI + Postgres. -
Se connecter avec psql
psqlest le client SQL en ligne de commande de Postgres. Pour entrer dans la DB du conteneur :bashdocker exec -it pg psql -U app -d appdbUne fois dans
psql, quelques commandes utiles :sql\l -- lister les bases \c appdb -- se connecter à une base \dt -- lister les tables \d users -- décrire la table users \du -- lister les utilisateurs \q -- quitter -
Créer une base, un utilisateur, des droits
sql-- Connecté en tant que superuser (postgres) CREATE DATABASE projet_devia; CREATE USER devia WITH PASSWORD 'un_mdp_solide'; GRANT ALL PRIVILEGES ON DATABASE projet_devia TO devia; -- Droits plus fins (recommandé en prod) \c projet_devia GRANT USAGE ON SCHEMA public TO devia; GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO devia; -
Se connecter depuis Python
Le pilote moderne est
psycopg(v3). SQLAlchemy reste recommandé par-dessus, pour pouvoir changer de DB sans toucher au code.bashuv add "sqlalchemy[postgresql]" psycopgpythonfrom sqlalchemy import create_engine DATABASE_URL = "postgresql+psycopg://devia:un_mdp_solide@localhost:5432/projet_devia" engine = create_engine(DATABASE_URL)Connection string : à ne jamais commiterLe mot de passe ne doit jamais finir dans le code. Stocke-le dans un
.env(gitignoré) et lis-le via Pydantic Settings — c'est le pattern standard. -
Types Postgres utiles à connaître
Postgres a des types riches au-delà du SQL standard, qu'on utilise souvent en MLOps :
sqlCREATE TABLE predictions ( id SERIAL PRIMARY KEY, created_at TIMESTAMPTZ DEFAULT NOW(), user_id UUID NOT NULL, inputs JSONB, -- JSON indexable score NUMERIC(5, 3), -- précis (5 chiffres, 3 décimales) tags TEXT[] -- tableau de strings );JSONBest particulièrement utile pour stocker les inputs/outputs variables d'un modèle ML sans figer un schéma. -
Backup et restore
pg_dumpexporte une base entière (schéma + données) dans un fichier SQL.psqlpeut le rejouer.bash# Export docker exec pg pg_dump -U app appdb > backup.sql # Restore cat backup.sql | docker exec -i pg psql -U app -d appdb -
Migrations de schéma (Alembic)
En prod, on ne modifie jamais le schéma à la main : on utilise des migrations versionnées dans Git. Alembic (intégré à SQLAlchemy) gère ça :
bashuv add alembic uv run alembic init migrations uv run alembic revision --autogenerate -m "add users" uv run alembic upgrade headChaque commande crée un fichier de migration dans
migrations/versions/— versionné dans Git, rejouable en CI/CD pour mettre à jour la prod automatiquement. -
Optimiser : index et EXPLAIN
Quand une requête devient lente, on regarde son plan d'exécution avec
EXPLAIN ANALYZEpuis on ajoute un index si besoin :sqlEXPLAIN ANALYZE SELECT * FROM predictions WHERE user_id = '…'; -- Si l'on voit Seq Scan sur une grosse table, ajouter un index : CREATE INDEX idx_predictions_user_id ON predictions(user_id);
Aide-mémoire
docker run -d --name pg -e POSTGRES_PASSWORD=… -p 5432:5432 postgres:16
docker exec -it pg psql -U postgres
docker exec pg pg_dump -U app appdb > backup.sql
\l, \c db, \dt, \d table, \du, \q
\timing -- afficher le temps d'exécution
\x -- affichage vertical (utile pour wide rows)
postgresql+psycopg://user:password@host:port/dbname
-- Exemple local :
postgresql+psycopg://app:secret@localhost:5432/appdb
SERIAL, BIGSERIAL -- auto-increment
UUID -- identifiant unique
TIMESTAMPTZ -- date+heure avec fuseau
JSONB -- JSON binaire, indexable
TEXT[] -- tableau de strings
NUMERIC(p, s) -- précis (financier)
PostgreSQL et le reste de l'écosystème
- SQLAlchemy — la couche Python qu'on met systématiquement entre Postgres et le code. On écrit du Python, SQLAlchemy traduit en SQL Postgres. Permet aussi de basculer SQLite ↔ Postgres en changeant juste la connection string.
- SQLite — la base de poche utilisée pendant le développement et les tests. Postgres prend le relais en prod. Avec SQLAlchemy, le code reste identique.
- Supabase — du Postgres managé avec auth et API REST par-dessus. Si tu veux les bénéfices de Postgres sans gérer le serveur, c'est l'option.
- FastAPI — pile classique : FastAPI expose une API qui parle à Postgres via SQLAlchemy. Les modèles d'entrée/sortie sont validés par Pydantic.
- Docker / Kubernetes — Postgres tourne quasi toujours dans un conteneur en dev et en prod. L'image officielle est l'une des plus utilisées au monde.
-
MLflow — peut utiliser
Postgres comme tracking backend à la place de SQLite
(
--backend-store-uri postgresql+psycopg://...). Indispensable dès que plusieurs personnes loguent en même temps. - Prefect — utilise aussi Postgres comme base de métadonnées en self-hosted (suivi des flux, états des runs).
- Grafana — peut brancher Postgres comme source pour des dashboards SQL (à côté de Prometheus et Loki).
Si tu hésites pour ton projet final, choisis Postgres. C'est gratuit, open source, mature depuis 1996, et c'est ce que MLflow, Prefect, Supabase et la majorité des frameworks modernes attendent par défaut. Le seul vrai concurrent est SQLite, mais uniquement quand un seul processus écrit dans la base.
Pour aller plus loin
- Site officiel : postgresql.org
- Documentation officielle (référence) : postgresql.org/docs/current
- Image Docker officielle : hub.docker.com/_/postgres
- Alembic (migrations) : alembic.sqlalchemy.org
- « PostgreSQL Exercises » (tuto interactif) : pgexercises.com