đ PostgreSQL â Installation, SQL & Administration
Guide complet IDEOâLab pour maĂźtriser le SGBD objet-relationnel, de l'installation Ă la rĂ©plication.
Vue d'ensemble
SGBD Objet-Relationnel, ACID, extensible.
SGBD-OR ACID ExtensibleArchitecture
Processus (Postmaster), MVCC, WAL.
MVCC WAL ProcessusInstallation Linux
Ubuntu/Debian & RHEL/CentOS (DépÎts PG).
apt dnf postgresql.orgInstall (Win/Docker)
Installeur EDB, conteneur Docker (reco).
Windows Docker EDBClient psql
CLI, méta-commandes (\l, \dt, \c).
psql \l \dtRĂŽles & Authentification
CREATE ROLE, pg_hba.conf.
Gestion des BDD
CREATE DATABASE, \l, \c.
Gestion des Schemas
Schema 'public', search_path, isolation.
Types de Données Av.
JSONB, ARRAY, UUID, HSTORE.
DDL : CREATE TABLE
SERIAL, IDENTITY, Contraintes.
DML : INSERT (RETURNING)
INSERT...RETURNING, UPDATE, DELETE.
DQL : SELECT & JOIN
SELECT, INNER/LEFT JOIN.
DQL : Agrégats
GROUP BY, COUNT, FILTER, HAVING.
Transactions (ACID)
BEGIN, COMMIT, ROLLBACK.
Index (EXPLAIN)
EXPLAIN ANALYZE, B-Tree, GIN, GiST.
Fonctions & Triggers
pl/pgsql, CREATE FUNCTION, TRIGGER.
Vues & Vues Mat.
CREATE VIEW, Vues Matérialisées.
Backup (pg_dump)
Dump logique (SQL) vs Binaire (Custom).
pg_dump pg_dumpallRestauration
psql (SQL) ou pg_restore (Custom).
Réplication (Streaming)
Hot Standby, Read Replica, WAL.
Replication Hot StandbyCheat-sheet psql
Commandes psql et SQL fréquentes.
Le SGBD Open-Source le plus avancé
PostgreSQL (souvent "Postgres") est un **SGBD Objet-Relationnel (SGBD-OR)**. Il est réputé pour sa robustesse, sa conformité stricte aux standards SQL, et son ensemble de fonctionnalités avancées.
Il est 100% open-source (licence PostgreSQL, similaire à BSD/MIT) et n'est contrÎlé par aucune entreprise (contrairement à MySQL/MariaDB), mais par une communauté mondiale.
Caractéristiques Clés
- Conformité ACID : Garantie totale des propriétés (Atomicité, Cohérence, Isolation, Durabilité).
- Extensibilité : Vous pouvez créer vos propres types de données, fonctions, opérateurs et index.
- Types de données riches : Support natif pour
JSONB(binaire),ARRAY(tableaux),UUID, types géospatiaux (PostGIS). - Concurrence : Gérée via **MVCC** (Multi-Version Concurrency Control), permettant aux lecteurs de ne pas bloquer les scripteurs (et vice-versa).
Postgres vs. MySQL/MariaDB
Choix trÚs courant, voici les différences philosophiques :
| CritĂšre | PostgreSQL | MySQL / MariaDB |
|---|---|---|
| ModĂšle | Objet-Relationnel (plus strict) | Relationnel (plus permissif) |
| ACID | Stricte. Ne sacrifie jamais l'intĂ©gritĂ©. | Strict (avec InnoDB), mais peut ĂȘtre plus laxiste. |
| Cas d'usage | Données complexes, applications "sérieuses", GIS, data warehousing. | Applications Web, CMS (WordPress), "backend" simple. |
| Types | JSONB, ARRAY, UUID natifs et performants. | JSON (texte, moins performant), pas d'ARRAY. |
| ExtensibilitĂ© | ExtrĂȘme (PostGIS, TimescaleDB). | LimitĂ©e (Moteurs de stockage). |
Analogie : MySQL/MariaDB est une voiture de sport rapide et simple. PostgreSQL est un "char d'assaut" : plus complexe, mais incroyablement robuste, fiable et capable de tout faire.
Architecture Processus (Pas de Threads)
Contrairement Ă MySQL, Postgres utilise un modĂšle "processus par connexion".
+------------------------------------------------------+ | SERVEUR POSTGRESQL | | | | +------------------+ MĂ©moire PartagĂ©e (Cache) | | | Postmaster | <--> [Shared Buffers] | | | (Processus PĂšre) | <--> [WAL Buffers] | | +------------------+ | | | (fork) | (fork) | | ⌠⌠| | +---------+ +---------+ (Processus "Backend") | | | postgres| | postgres| ... 1 par client | | | (Client 1)| (Client 2)| | | +---------+ +---------+ | | | | | | ⌠⌠| | +---------+ +---------+ (Processus "Workers") | | | Autovacuum| | WAL Writer| (BGWriter, Checkpointer)| | +---------+ +---------+ | | | +------------------------------------------------------+
- Postmaster : Le "pÚre" de tous les processus. Il écoute les connexions.
- Backend (
postgres) : Quand un client se connecte, le Postmaster "fork" un nouveau processuspostgresdédié à ce client. - Mémoire Partagée : (
shared_buffers) Le cache principal (RAM) partagé par tous les processus. - Workers : Processus d'arriÚre-plan (
autovacuum,wal_writer...).
MVCC (Multi-Version Concurrency Control)
C'est le concept fondamental de Postgres pour gérer la concurrence. Au lieu de verrouiller les lignes, Postgres crée de nouvelles "versions" des lignes.
Quand vous faites un UPDATE :
- Postgres ne modifie pas la ligne originale.
- Il copie la ligne, effectue la modification sur la copie, et l'insĂšre comme une nouvelle version de la ligne.
- Il marque l'ancienne version comme "morte" (visible uniquement par les transactions qui ont commencé *avant* l'UPDATE).
Table "users" (Ătat T1) ID | nom | xmin | xmax ---|-------|------|------ 1 | Alice | 10 | inf -- Client 1 (Transaction 15): UPDATE users SET nom = 'Alicia' WHERE id = 1; Table "users" (Ătat T2) ID | nom | xmin | xmax <-- (Transaction 12 voit encore ça) ---|-------|------|------ 1 | Alice | 10 | 15 (Morte, tuĂ©e par TX 15) 1 | Alicia| 15 | inf (Nouvelle version, créée par TX 15)
- Avantage : Les
SELECT(lecteurs) ne bloquent **jamais** lesUPDATE(scripteurs), et vice-versa. - Inconvénient : Les "lignes mortes" s'accumulent (gonflement/bloat).
- Solution : Le processus
AUTOVACUUMtourne en permanence pour nettoyer ces lignes mortes.
WAL (Write-Ahead Logging)
C'est le mécanisme qui garantit la **Durabilité (le D de ACID)** et permet la réplication.
Avant d'écrire *quoi que ce soit* dans les fichiers de données (lents), Postgres écrit *d'abord* la modification dans un journal de transactions (le WAL).
[Client: COMMIT;]
|
âŒ
1. Ăcriture dans [WAL Buffer] (RAM)
|
âŒ
2. 'fsync' (écrit sur disque) -> [Fichiers WAL (/pg_wal/)]
|
âŒ
3. [Réponse "OK" au Client]
|
| (Plus tard, en arriĂšre-plan...)
âŒ
4. Ăcriture dans [Shared Buffers] (RAM)
|
âŒ
5. (Checkpoint) Ăcriture dans [Fichiers de donnĂ©es] (Disque)
- Garantie : Si le serveur crash à l'étape 4, au redémarrage, Postgres lit le WAL (étape 2) et "rejoue" les transactions qui n'étaient pas encore dans les fichiers de données.
- Réplication : Le serveur "Slave" reçoit le flux du WAL (étape 2) et le rejoue sur ses propres données.
Ubuntu 22.04+ / Debian 11+
Fortement recommandé : N'utilisez pas les dépÎts de votre OS (souvent obsolÚtes). Utilisez les dépÎts officiels de PostgreSQL.
# 1. Créer le fichier de dépÎt sudo sh -c 'echo "deb http://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list' # 2. Ajouter la clé GPG wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add - # 3. Installer (Exemple: Postgres 16) sudo apt-get update sudo apt-get -y install postgresql-16 postgresql-client-16
RHEL / CentOS 8+ / Fedora
# 1. Installer le RPM du dépÎt (Ex: PG 16) sudo dnf install -y https://download.postgresql.org/pub/repos/yum/reporpms/EL-9-x86_64/pgdg-redhat-repo-latest.noarch.rpm # 2. Désactiver le module PG natif (si nécessaire) sudo dnf -qy module disable postgresql # 3. Installer sudo dnf install -y postgresql16-server postgresql16
Initialisation du Cluster (initdb)
Sur Debian/Ubuntu, l'installation exécute initdb automatiquement et démarre le service.
Sur RHEL/CentOS, vous devez le faire manuellement :
(RHEL/CentOS seulement) # 1. Initialiser la BDD (crée le 'datadir') sudo /usr/pgsql-16/bin/postgresql-16-setup initdb # 2. Démarrer et activer sudo systemctl enable --now postgresql-16
Authentification peer (Linux)
Par défaut, l'installation crée un super-utilisateur de BDD nommé postgres.
L'authentification est réglée sur peer, ce qui signifie que seul l'utilisateur systÚme postgres peut se connecter.
# Devenez l'utilisateur systÚme 'postgres' sudo -i -u postgres # Lancez psql (connexion réussie) psql postgres=# \q exit
Vous ne pouvez pas vous connecter avec psql -u postgres depuis votre compte normal. Voir la section 3.1 (pg_hba.conf) pour changer cela.
Option 1 : Installeur Windows (EDB)
L'installeur officiel pour Windows est fourni par EDB (EnterpriseDB).
- Allez sur postgresql.org/download/windows/
- Téléchargez l'installeur EDB.
- Exécutez l'installeur.
- Ătape clĂ© : DĂ©finissez un mot de passe pour le super-utilisateur
postgres. - Laissez le port (
5432). - Choisissez la "Locale" (ex:
fr_FR).
L'installeur installe Postgres en tant que service Windows et ajoute psql Ă votre PATH.
Il installe aussi pgAdmin (un client GUI populaire).
(Dans cmd ou PowerShell) psql -U postgres Password for user postgres: [votre-mot-de-passe]
Option 2 : Docker (Recommandé pour le Dev)
La méthode la plus propre, la plus rapide et la plus isolée pour le développement.
# Lancer un conteneur Postgres docker run -d \ --name pg-local \ -e POSTGRES_PASSWORD=mon_pass_secret \ -p 5432:5432 \ -v pg-data:/var/lib/postgresql/data \ postgres:16-alpine
-d: Détaché.-e POSTGRES_PASSWORD: Définit le mot de passe pour l'utilisateurpostgres.-p 5432:5432: Lie le port 5432 de votre PC au port 5432 du conteneur.-v pg-data...: Crée un volume Docker "pg-data" pour la persistance des données.postgres:16-alpine: Image officielle, version 16 (légÚre).
# Se connecter (depuis votre PC) psql -h localhost -U postgres
Connexion psql
psql est le client interactif. Il est plus puissant que mysql car il possÚde des "méta-commandes" (commençant par \) qui ne sont pas du SQL.
# Syntaxe psql -h [HOST] -U [USER] -p [PORT] -d [DATABASE] # Connexion locale (compte 'postgres') sudo -u postgres psql # Connexion locale (votre compte) Ă une BDD psql -U mon_user -d ideo_lab_crm # Connexion distante psql -h db.ideolab.com -U mon_user -d ideo_lab_prod
Le Prompt
Le prompt psql vous donne des informations :
ideo_lab_prod=#
(Connecté à 'ideo_lab_prod' en tant que super-utilisateur #)
ideo_lab_prod=>
(Connecté à 'ideo_lab_prod' en tant qu'utilisateur normal >)
ideo_lab_prod-(
(Dans une transaction BEGIN; non terminée)
Méta-commandes (Cheat-sheet)
C'est ce qui rend psql génial. (Pas besoin de ;)
| Commande | Description |
|---|---|
\q | Quitter psql. |
\l ou \list | Lister toutes les bases de données. |
\c [nom_db] | Se Connecter Ă une autre base. |
\dt | Décrire les Tables (du schema actuel). |
\d [nom_table] | Décrire une table (colonnes, index...). |
\dn | Décrire les Schemas. |
\df | Décrire les Fonctions. |
\du | Décrire les RÎles (utilisateurs). |
\conninfo | Infos sur la Connexion actuelle. |
\timing | Active/DĂ©sactive l'affichage du temps d'exĂ©cution des requĂȘtes. |
\e | Ouvre la requĂȘte actuelle dans l'Ă©diteur ($EDITOR). |
\? | Aide sur les méta-commandes. |
Concept : RĂŽles (Utilisateurs et Groupes)
Postgres a un concept unifiĂ© : les RĂŽles. Un RĂŽle peut ĂȘtre un utilisateur, un groupe, ou les deux.
- Un RĂŽle avec l'attribut
LOGINest un "Utilisateur" (peut se connecter). - Un RĂŽle sans l'attribut
LOGINest un "Groupe".
On peut ensuite "GRANTer" un RÎle-Groupe à un RÎle-Utilisateur (héritage).
[ROLE "groupe_lecture"] (NOLOGIN)
(GRANT SELECT ON ALL TABLES...)
^
| (GRANT)
|
[ROLE "alice"] (LOGIN)
[ROLE "bob"] (LOGIN)
Création de RÎles (Utilisateurs)
-- Crée un rÎle qui peut se connecter (un utilisateur)
CREATE ROLE ideo_app WITH
LOGIN
PASSWORD 'pass_tres_fort';
-- Crée un super-utilisateur (NE PAS FAIRE en prod app)
CREATE ROLE admin_dev WITH
LOGIN
SUPERUSER
PASSWORD 'admin_pass';
-- Crée un rÎle 'groupe'
CREATE ROLE readonly_group NOLOGIN;Gestion des PrivilĂšges (GRANT)
Les privilÚges sont gérés par objet (BDD, Schema, Table...).
-- 1. Donner le droit de se connecter à une BDD GRANT CONNECT ON DATABASE ideo_lab_crm TO ideo_app; -- 2. Donner le droit d'utiliser un schema GRANT USAGE ON SCHEMA public TO ideo_app; -- 3. Donner des droits sur les tables GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO ideo_app; -- Gérer l'héritage (groupes) GRANT readonly_group TO ideo_app;
Fichier pg_hba.conf (Host-Based Authentication)
C'est l'étape la plus importante (et la plus confuse pour les débutants).
Ce fichier (situé dans le datadir) est le **portier** de Postgres. Il décide QUI (IP, User) peut se connecter et QUELLE méthode d'authentification utiliser.
Il est lu de haut en bas. La premiÚre rÚgle qui correspond est utilisée.
# Fichier: /etc/postgresql/16/main/pg_hba.conf # TYPE DATABASE USER ADDRESS METHOD #--------------------------------------------------------- # Connexions locales UNIX (ex: sudo -u postgres psql) local all postgres peer local all all peer # Connexions locales TCP/IP (ex: localhost, 127.0.0.1) host all all 127.0.0.1/32 scram-sha-256 # Connexions réseau (Ex: DBeaver, App Web) host all all 192.168.1.0/24 scram-sha-256 # Connexion pour la réplication host replication repl_user 192.168.1.10/32 scram-sha-256
| Méthode | Description |
|---|---|
peer | (Socket local) Fait confiance si le nom d'utilisateur systĂšme correspond au nom d'utilisateur BDD. (sudo -u postgres psql). |
scram-sha-256 | Recommandé. Mot de passe chiffré. |
md5 | Ancien standard de mot de passe. OK, mais scram est mieux. |
trust | Dangereux. Connexion sans mot de passe. (Ă n'utiliser *jamais* sauf en dev local). |
Toute modification de pg_hba.conf nécessite un rechargement (sudo systemctl reload postgresql) ou redémarrage.
Isolation
Dans Postgres, les BDD sont des conteneurs totalement isolés. Une connexion est liée à UNE seule BDD. Vous ne pouvez pas faire de JOIN entre BDD (contrairement à MySQL).
(Pour cela, on utilise les Schemas, voir 3.3).
Créer une BDD (SQL)
-- Syntaxe
CREATE DATABASE nom_db
WITH
OWNER = role_proprietaire
ENCODING = 'UTF8'
LC_COLLATE = 'fr_FR.UTF-8'
LC_CTYPE = 'fr_FR.UTF-8'
TEMPLATE = template0;
-- Exemple simple (suffisant 99% du temps)
CREATE DATABASE ideo_lab_crm OWNER ideo_app;Créer une BDD (CLI)
(Exécuté depuis le shell bash, pas psql)
sudo -u postgres createdb -O ideo_app ideo_lab_crm
Lister & Gérer (psql)
postgres=# \l
-- (ou \list) Liste toutes les BDD
List of databases
Name | Owner | Encoding | Collate | Ctype | ...
------------------+----------+----------+-------------+-------------+-----
ideo_lab_crm | ideo_app | UTF8 | fr_FR.UTF-8 | fr_FR.UTF-8 |
postgres | postgres | UTF8 | fr_FR.UTF-8 | fr_FR.UTF-8 |
template0 | postgres | UTF8 | fr_FR.UTF-8 | fr_FR.UTF-8 |
template1 | postgres | UTF8 | fr_FR.UTF-8 | fr_FR.UTF-8 |template0 et template1 sont les modÚles utilisés par CREATE DATABASE. Ne pas y toucher.
Se connecter (psql)
postgres=# \c ideo_lab_crm You are now connected to database "ideo_lab_crm" as user "postgres". ideo_lab_crm=#
Supprimer une BDD
-- SQL DROP DATABASE ideo_lab_crm; -- CLI (bash) sudo -u postgres dropdb ideo_lab_crm
Schema : Un "dossier" dans votre BDD
Si une BDD est un "Projet", un Schema est un "dossier" dans ce projet. Il permet d'organiser les tables logiquement.
C'est ce qui permet à Postgres de gérer des applications multi-tenant ou complexes dans une seule BDD.
BDD "ideo_lab_main"
âââ Schema: public (DĂ©faut)
â âââ Table: utilisateurs
â âââ Table: entreprises
â
âââ Schema: crm
â âââ Table: clients (public.entreprises)
â âââ Table: contacts
â
âââ Schema: compta
âââ Table: factures
âââ Table: lignes_factureLe schema public
Toute nouvelle BDD contient un schema public. Si vous faites CREATE TABLE users, Postgres crée en fait public.users.
search_path (Le "PATH" de Postgres)
Comment Postgres sait-il oĂč chercher (public, crm...) quand vous Ă©crivez SELECT * FROM clients ?
Il utilise le search_path.
-- Voir le search_path actuel SHOW search_path; -- Résultat: "$user", public -- (Il cherche d'abord un schema à votre nom, puis 'public') -- Changer le search_path pour la session SET search_path TO crm, public; -- Maintenant, 'SELECT * FROM clients' va chercher 'crm.clients' -- 'SELECT * FROM utilisateurs' va chercher 'public.utilisateurs'
Utilisation
-- Créer un schema
CREATE SCHEMA crm;
-- Créer une table dans un schema
CREATE TABLE crm.contacts (
id INT PRIMARY KEY,
nom VARCHAR(100)
);
-- Lister les schemas (psql)
\dnTypes Standard
(Similaires Ă MariaDB, mais avec des noms plus stricts)
| Type | Alias | Description |
|---|---|---|
| TEXT | Texte de longueur illimitée. (Il n'y a pas de VARCHAR vs TEXT en performance dans Postgres. Utilisez TEXT). | |
| VARCHAR(n) | Limite la longueur Ă N caractĂšres (contrainte). | |
| INTEGER | INT | Entier 4 octets. |
| BIGINT | Entier 8 octets. | |
| SMALLINT | Entier 2 octets. | |
| NUMERIC(p, s) | DECIMAL | Nombre à précision exacte (finance). |
| DOUBLE PRECISION | FLOAT8 | Virgule flottante 8 octets. |
| BOOLEAN | BOOL | true ou false. |
| TIMESTAMP | Date et heure (sans fuseau). | |
| TIMESTAMPTZ | Recommandé. Timestamp avec fuseau horaire (stocké en UTC). | |
| DATE | Date seule. |
Types Auto-Incrément (Clés Primaires)
Il y a deux façons de créer un ID auto-incrémenté :
1. SERIAL (Ancienne méthode)
SERIAL est un pseudo-type. C'est un alias qui crée un INTEGER et une SEQUENCE.
CREATE TABLE old_way (
id SERIAL PRIMARY KEY,
nom TEXT
);2. IDENTITY (Méthode SQL standard, recommandée)
Depuis SQL:2003, la méthode standard est GENERATED AS IDENTITY.
CREATE TABLE new_way (
id INT PRIMARY KEY
GENERATED ALWAYS AS IDENTITY,
-- (ou GENERATED BY DEFAULT AS IDENTITY)
nom TEXT
);GENERATED ALWAYS: Refuse unINSERTmanuel de l'ID (INSERT INTO new_way(id, nom) VALUES(100, 'Test')-> Erreur). C'est plus strict et plus sûr.GENERATED BY DEFAULT: Autorise l'insertion manuelle de l'ID.
Types Avancés (La force de Postgres)
| Type | Description | Exemple d'utilisation |
|---|---|---|
| UUID | Identifiant unique universel (128 bits). | Clés primaires (évite les conflits en distribué). DEFAULT gen_random_uuid() (nécessite CREATE EXTENSION "pgcrypto"). |
| JSONB | Stockage Binaire de JSON. C'est la version "intelligente" de JSON (qui est textuel). | Stockage de mĂ©tadonnĂ©es, documents NoSQL. Peut ĂȘtre indexĂ© (GIN). |
| ARRAY | Tableau d'un autre type. Ex: TEXT[] ou INT[]. | Tags (TEXT[]), listes de permissions. |
| HSTORE | Stockage Clé-Valeur simple (texte). (Nécessite CREATE EXTENSION "hstore"). | Moins utilisé depuis JSONB, mais trÚs rapide pour des paires clé-valeur simples. |
| (PostGIS) | Types géospatiaux (Points, Lignes, Polygones). (Nécessite CREATE EXTENSION "postgis"). | Cartographie, GIS. |
CREATE TABLE produits (
id INT PRIMARY KEY GENERATED ALWAYS AS IDENTITY,
ref UUID DEFAULT gen_random_uuid(),
nom TEXT NOT NULL,
tags TEXT[],
specs JSONB
);Contraintes de Colonne
CREATE TABLE utilisateurs (
id INT PRIMARY KEY GENERATED ALWAYS AS IDENTITY,
email TEXT NOT NULL
CONSTRAINT email_unique UNIQUE, -- Contrainte nommée
nom TEXT NOT NULL,
date_naissance DATE
CHECK (date_naissance > '1900-01-01'), -- Contrainte CHECK
statut TEXT DEFAULT 'actif'
CHECK (statut IN ('actif', 'inactif', 'archive')),
cree_le TIMESTAMPTZ DEFAULT NOW()
);Contraintes de Table (ClĂ©s ĂtrangĂšres)
Définit la relation entre commandes et utilisateurs.
CREATE TABLE commandes (
id INT PRIMARY KEY GENERATED ALWAYS AS IDENTITY,
utilisateur_id INT NOT NULL,
montant NUMERIC(10, 2) NOT NULL CHECK (montant > 0),
-- Contrainte de ClĂ© ĂtrangĂšre
CONSTRAINT fk_utilisateur
FOREIGN KEY(utilisateur_id)
REFERENCES utilisateurs(id)
ON DELETE RESTRICT -- (Quoi faire si l'utilisateur est supprimé)
);Comportement ON DELETE
ON DELETE RESTRICT(DĂ©faut) : Refuse de supprimer un utilisateur s'il a encore des commandes. (SĂ»r).ON DELETE CASCADE: Si on supprime un utilisateur, supprime automatiquement toutes ses commandes. (Dangereux, mais utile).ON DELETE SET NULL: Si on supprime un utilisateur, metutilisateur_idĂNULLdans ses commandes.
INSERT ... RETURNING
La clause RETURNING est une fonctionnalité trÚs puissante de Postgres. Elle permet de retourner des valeurs (comme l'ID) juste aprÚs l'insertion.
-- (Table 'utilisateurs' de l'exemple 4.2)
INSERT INTO utilisateurs (nom, email)
VALUES ('Jean Dupont', 'jean.dupont@mail.com')
RETURNING id, cree_le;
-- Résultat (trÚs utile pour les ORMs):
-- id | cree_le
-- ---|-------------------------------
-- 5 | 2025-11-01 22:30:00.12345+01INSERT (JSONB & ARRAY)
INSERT INTO produits (nom, tags, specs)
VALUES (
'Clavier Pro',
ARRAY['mecanique', 'rgb', 'usb-c'],
'{"poids": 500, "switch": "blue"}'::jsonb
);UPDATE
(WHERE est obligatoire !)
UPDATE utilisateurs
SET
nom = 'Jean Martin',
statut = 'inactif'
WHERE email = 'jean.dupont@mail.com'
RETURNING id; -- (RETURNING marche aussi ici)DELETE
(WHERE est obligatoire !)
DELETE FROM utilisateurs WHERE statut = 'archive' RETURNING email; -- (Retourne les emails supprimés)
TRUNCATE
-- Vider une table (rapide) TRUNCATE TABLE logs; -- Vider plusieurs tables (ex: dépendantes) TRUNCATE TABLE utilisateurs, commandes RESTART IDENTITY CASCADE; -- RESTART IDENTITY: Réinitialise les 'SERIAL' -- CASCADE: Vide aussi les tables liées (commandes)
Le SQL DQL (SELECT) de Postgres est standard et trĂšs similaire Ă celui de MariaDB (cf. sections 5.2, 6.1, 6.2 du guide MariaDB). Les concepts de SELECT, WHERE, ORDER BY, LIMIT, INNER JOIN, LEFT JOIN sont identiques.
RequĂȘte sur JSONB
La vraie différence réside dans l'interrogation des types avancés.
-- (Table 'produits' de l'exemple 4.3) -- Sélectionner un champ JSONB (opérateur '->>') SELECT nom, specs->>'switch' AS type_switch FROM produits WHERE specs->>'poids' = '500'; -- Filtrer si une clé JSONB existe (opérateur '?') SELECT nom FROM produits WHERE specs ? 'switch'; -- Filtrer sur un ARRAY (opérateur '@>') -- (Trouve les produits qui ont (au moins) 'rgb' ET 'usb-c') SELECT nom FROM produits WHERE tags @> ARRAY['rgb', 'usb-c'];
Les agrégats (COUNT, SUM, AVG, MAX, MIN) et GROUP BY / HAVING sont standards.
Agrégats avancés (FILTER)
Postgres permet de filtrer un agrĂ©gat (sans filtrer toute la requĂȘte).
-- Compter le total, ET compter juste les actifs, en 1 passe
SELECT
COUNT(id) AS total_utilisateurs,
COUNT(id) FILTER (WHERE statut = 'actif') AS nb_actifs,
COUNT(id) FILTER (WHERE statut = 'inactif') AS nb_inactifs
FROM utilisateurs;Agrégats de chaßne/JSON
-- Regrouper tous les noms dans un seul texte
SELECT STRING_AGG(nom, ', ') FROM utilisateurs;
-- 'Jean Dupont, Marie Martin, ...'
-- Regrouper tous les noms dans un tableau
SELECT ARRAY_AGG(nom) FROM utilisateurs;
-- '{ "Jean Dupont", "Marie Martin", ... }'
-- Regrouper les résultats en un JSON
SELECT JSONB_AGG(
JSONB_BUILD_OBJECT('id', id, 'nom', nom)
)
FROM utilisateurs;Garantie ACID
Postgres est transactionnel par dĂ©faut. Chaque requĂȘte SQL est exĂ©cutĂ©e dans sa propre transaction (auto-commit).
Pour des opérations complexes (ex: virement bancaire), vous devez les envelopper dans une transaction manuelle (BEGIN) pour garantir l'Atomicité (Tout ou Rien).
Scénario : Virement bancaire
-- Client 1 (Alice) a 100⏠-- Client 2 (Bob) a 50⏠-- Démarrer la transaction BEGIN; -- 1. Débiter Alice de 30⏠UPDATE comptes SET solde = solde - 30 WHERE client_id = 1; -- 2. Créditer Bob de 30⏠UPDATE comptes SET solde = solde + 30 WHERE client_id = 2; -- (Si le serveur crash ici, rien n'est sauvegardé -- au redémarrage, car le COMMIT n'a pas eu lieu) -- 3. Valider (Appliquer les 2 changements d'un coup) COMMIT;
ROLLBACK (Annulation)
Si une erreur survient (ex: le solde d'Alice devient négatif), l'application doit annuler toute la transaction.
BEGIN; -- 1. DĂ©biter Alice (Solde: 100âŹ) de 500⏠UPDATE comptes SET solde = solde - 500 WHERE client_id = 1; -- (Le solde est maintenant -400âŹ) -- (L'application (ou un CHECK) dĂ©tecte l'erreur) -- 2. Annuler toute la transaction ROLLBACK; -- (Le solde d'Alice revient Ă 100âŹ, comme si -- rien ne s'Ă©tait passĂ©.)
SAVEPOINT (Points de sauvegarde)
BEGIN;
INSERT INTO users (nom) VALUES ('A');
SAVEPOINT point_a;
INSERT INTO users (nom) VALUES ('B');
-- Annule juste B, garde A
ROLLBACK TO SAVEPOINT point_a;
COMMIT; -- (Valide A)EXPLAIN (ANALYZE, BUFFERS)
EXPLAIN (comme MariaDB) montre le plan. EXPLAIN ANALYZE **exĂ©cute** la requĂȘte et montre le plan + le temps rĂ©el et les lignes rĂ©elles. C'est l'outil N°1 d'optimisation Postgres.
EXPLAIN (ANALYZE, BUFFERS) SELECT * FROM utilisateurs WHERE id = 123;
Résultat (Bon : Index Scan)
Index Scan using utilisateurs_pkey on utilisateurs (cost=0.43..8.45 rows=1) (actual time=0.020..0.021 rows=1) Index Cond: (id = 123) Buffers: shared hit=3 Planning Time: 0.100 ms Execution Time: 0.030 ms
Index Scan, actual time=0.021ms. Instantané.
EXPLAIN (ANALYZE, BUFFERS) SELECT * FROM utilisateurs WHERE nom = 'Durand'; -- (Sans index sur 'nom')
Résultat (Mauvais : Seq Scan)
Seq Scan on utilisateurs (cost=0.00..4333.00 rows=15) (actual time=0.015..35.400 rows=15) Filter: (nom = 'Durand'::text) Rows Removed by Filter: 149985 Buffers: shared hit=1833 Planning Time: 0.080 ms Execution Time: 35.420 ms
Seq Scan (Full Table Scan), actual time=35.4ms. Lent.
Index B-Tree (Défaut)
L'index standard, utilisé pour 99% des cas. Idéal pour les opérateurs =, >, <, BETWEEN, LIKE 'prefixe%', et ORDER BY.
-- Index simple (pour WHERE nom = ...) CREATE INDEX idx_utilisateurs_nom ON utilisateurs(nom); -- Index composite (pour WHERE nom = ... AND prenom = ...) CREATE INDEX idx_utilisateurs_nom_prenom ON utilisateurs(nom, prenom); -- Index unique CREATE UNIQUE INDEX idx_utilisateurs_email_unique ON utilisateurs(LOWER(email)); -- (Index sur l'email en minuscule pour éviter les doublons)
Index Avancés (GIN & GiST)
C'est là que Postgres brille : des index pour les types de données complexes.
GIN (Generalized Inverted Index)
Idéal pour les types "composites" (qui contiennent plusieurs choses). Pensez "recherche inversée".
JSONB: (Pour?,@>).ARRAY: (Pour@>).HSTORE- Texte plein (FTS)
-- (Table 'produits' de l'exemple 4.3)
-- Indexer les clés/valeurs du JSONB
CREATE INDEX idx_produits_specs_gin ON produits USING GIN (specs);
-- (AccélÚre: WHERE specs @> '{"switch": "blue"}')
-- Indexer les éléments du tableau
CREATE INDEX idx_produits_tags_gin ON produits USING GIN (tags);
-- (AccélÚre: WHERE tags @> ARRAY['rgb'])GiST (Generalized Search Tree)
Idéal pour les données "spatiales" ou "complexes" (chevauchement).
- PostGIS : (Géométrie, "trouver les points dans ce polygone").
- Types natifs (
point,box).
Fonctions (pl/pgsql)
Postgres permet d'écrire une logique complexe (procédures stockées) directement dans la BDD. Le langage par défaut est pl/pgsql (similaire au PL/SQL d'Oracle).
CREATE FUNCTION get_total_ca(date_debut DATE, date_fin DATE)
RETURNS NUMERIC AS $$
DECLARE
total_ca NUMERIC := 0;
BEGIN
SELECT SUM(montant)
INTO total_ca
FROM commandes
WHERE date_commande BETWEEN date_debut AND date_fin;
RETURN total_ca;
END;
$$ LANGUAGE plpgsql;
-- Utilisation:
SELECT get_total_ca('2025-01-01', '2025-01-31');Triggers
Un Trigger exécute une Fonction automatiquement avant ou aprÚs un événement (INSERT, UPDATE, DELETE).
Ex: Mettre Ă jour modifie_le Ă chaque UPDATE.
-- 1. La Fonction (qui retourne un TRIGGER)
CREATE FUNCTION update_modifie_le_col()
RETURNS TRIGGER AS $$
BEGIN
NEW.modifie_le = NOW(); -- 'NEW' est la ligne en cours d'insertion/maj
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
-- 2. Le Trigger (lié à la table)
CREATE TRIGGER trg_update_modifie_le
BEFORE UPDATE ON utilisateurs -- 'BEFORE' ou 'AFTER'
FOR EACH ROW -- (Pour chaque ligne modifiée)
EXECUTE FUNCTION update_modifie_le_col();Vues (VIEW)
Une Vue est une "requĂȘte SELECT stockĂ©e" qui agit comme une table virtuelle. Elle n'existe pas physiquement et est rĂ©-exĂ©cutĂ©e Ă chaque appel.
Utile pour simplifier des requĂȘtes complexes ou restreindre l'accĂšs aux colonnes.
-- Vue qui joint utilisateurs et commandes
CREATE VIEW vue_commandes_clients AS
SELECT
u.email,
u.nom,
c.id AS commande_id,
c.montant
FROM utilisateurs u
JOIN commandes c ON u.id = c.utilisateur_id;
-- Utilisation (comme une table)
SELECT * FROM vue_commandes_clients
WHERE montant > 100;Vues Matérialisées (MATERIALIZED VIEW)
Une Vue MatĂ©rialisĂ©e **exĂ©cute** la requĂȘte et stocke le rĂ©sultat **physiquement** sur le disque (un "snapshot").
Avantage : La lecture est instantanée (c'est une table).
InconvĂ©nient : Les donnĂ©es ne sont pas Ă jour. Elles doivent ĂȘtre rafraĂźchies manuellement.
IdĂ©al pour les rapports (BI) lourds qui n'ont pas besoin d'ĂȘtre en temps rĂ©el.
-- Créer la vue (coûteux)
CREATE MATERIALIZED VIEW mv_rapport_ca_par_jour AS
SELECT
date_commande::DATE AS jour,
SUM(montant) AS ca_total,
COUNT(id) AS nb_commandes
FROM commandes
GROUP BY jour;
-- Lire la vue (instantané)
SELECT * FROM mv_rapport_ca_par_jour;
-- Rafraßchir les données (coûteux)
REFRESH MATERIALIZED VIEW mv_rapport_ca_par_jour;pg_dump (Backup Logique)
pg_dump est l'outil CLI pour sauvegarder **UNE** base de données. Il se connecte à la BDD (comme psql) et génÚre un fichier de dump. Il ne bloque pas les lectures/écritures (grùce à MVCC).
Option 1: Format SQL (Texte)
GénÚre un gros fichier .sql lisible. Simple, portable, mais lent à restaurer.
pg_dump -U [USER] -h [HOST] -W [NOM_DB] > backup.sql # -W force la demande de mot de passe
Option 2: Format "Custom" (Binaire)
RecommandĂ©. GĂ©nĂšre un fichier binaire .dump, compressĂ©, qui peut ĂȘtre restaurĂ© en parallĂšle (multi-thread) avec pg_restore.
pg_dump -U [USER] -h [HOST] -W -F c [NOM_DB] > backup.dump # -F c = Format Custom
pg_dumpall (Roles & Global)
pg_dump ne sauvegarde **PAS** les RĂŽles (utilisateurs) ni les Tablespaces (objets globaux).
pg_dumpall sauvegarde **toutes** les BDD *ET* les objets globaux (roles, etc.) dans un seul fichier SQL.
# Sauvegarde globale (structure + rĂŽles) pg_dumpall -U postgres --globals-only > roles_et_globaux.sql # Sauvegarde globale (tout) pg_dumpall -U postgres > full_cluster_dump.sql
Stratégie de Backup
- Faire un
pg_dumpall --globals-only(une fois par jour). - Faire un
pg_dump -F csur chaque BDD applicative (toutes les heures).
Restaurer un Dump SQL (Texte)
On utilise psql pour "exécuter" le fichier SQL.
# 1. Créer la BDD vide # (Le dump SQL ne contient pas CREATE DATABASE) createdb -U postgres -O ideo_app ideo_lab_crm_restored # 2. Importer le dump psql -U postgres -d ideo_lab_crm_restored < backup.sql
Restaurer un Dump "Custom" (Binaire)
On doit utiliser pg_restore. C'est plus puissant et permet la restauration parallĂšle (-j).
# 1. Créer la BDD vide createdb -U postgres ideo_lab_crm_restored # 2. Importer avec pg_restore # -d (database), -j (jobs/threads) pg_restore -U postgres -d ideo_lab_crm_restored -j 4 backup.dump
Restauration (pg_dumpall)
Un dump de pg_dumpall (SQL) se restaure simplement avec psql. (Il contient les CREATE DATABASE et CREATE ROLE).
psql -U postgres -f full_cluster_dump.sql
Réplication "Streaming"
Postgres utilise son systÚme de WAL (cf 1.2) pour la réplication. Le serveur Secondaire ("Slave" ou "Replica") se connecte au Primaire ("Master") et "stream" les fichiers WAL dÚs qu'ils sont écrits.
Le Secondaire "rejoue" ce journal en continu, ce qui en fait une copie (presque) temps réel.
Hot Standby (Read Replica)
Si hot_standby = on, le serveur Secondaire autorise les connexions en lecture seule (SELECT) pendant qu'il réplique. C'est ce qu'on appelle une "Read Replica".
[Applications (Ăcriture)]
|
| INSERT, UPDATE
âŒ
+-----------------------+
| MASTER (Primaire) |
| (wal_level = replica) |
+-----------------------+
|
| Streaming des fichiers WAL (via réseau)
âŒ
+-----------------------+
| SLAVE (Hot Standby) |
| (read_only = on) |
+-----------------------+
|
| SELECT (Reporting, BI)
âŒ
[Applications (Lecture)]
1. Configuration Primaire (Master)
Fichiers Ă modifier : postgresql.conf et pg_hba.conf.
postgresql.conf
# /etc/postgresql/16/main/postgresql.conf # Active le streaming wal_level = replica # Garde X segments de WAL pour le slave (ex: 64) max_wal_senders = 10 # (Combien de slaves) min_wal_size = 1G max_wal_size = 2G
pg_hba.conf
# /etc/postgresql/16/main/pg_hba.conf # Autoriser l'utilisateur 'repl_user' à se connecter # depuis l'IP du Slave (192.168.1.51) # 'replication' est un type de BDD spécial host replication repl_user 192.168.1.51/32 scram-sha-256
-- SQL: Créer l'utilisateur de réplication CREATE ROLE repl_user WITH REPLICATION LOGIN PASSWORD 'pass_repl'; -- Redémarrer Postgres sudo systemctl restart postgresql
2. Configuration Secondaire (Slave / Replica)
Le Slave doit ĂȘtre une **copie binaire exacte** du Master. On utilise pg_basebackup pour cloner.
# 1. ArrĂȘter Postgres sur le Slave
sudo systemctl stop postgresql
# 2. Vider le datadir
sudo -u postgres rm -rf /var/lib/postgresql/16/main/*
# 3. Cloner le Master (en tant que user 'postgres')
sudo -u postgres pg_basebackup \
-h [IP_DU_MASTER] \
-U repl_user \
-p 5432 \
-D /var/lib/postgresql/16/main/ \
-Fp -Xs -R
# -R : Crée le fichier 'standby.signal' et la config de réplication
# 4. Modifier postgresql.conf sur le Slave
# (Assurez-vous que hot_standby est activé)
# hot_standby = on
# 5. Démarrer le Slave
sudo systemctl start postgresqlLe Slave va démarrer, se connecter au Master, et commencer à "streamer" les WALs. Vous pouvez le vérifier avec \l sur le Master (il sera en lecture seule).
psql & SQLpsql (Dans le client interactif)
-- CONNEXION / SORTIE \q -- Quitter psql \l -- Lister les BDD \c [nom_db] [user] -- Se connecter Ă une autre BDD/user -- INSPECTION (OBJETS) \dt [schema.*] -- Lister les tables (du schema) \ds -- Lister les sequences \dv -- Lister les vues \df -- Lister les fonctions \dn -- Lister les schemas \d [nom_objet] -- DĂ©crire un objet (table, vue, index...) \d+ [nom_table] -- DĂ©crire (plus de dĂ©tails) -- INSPECTION (RĂLES) \du -- Lister les rĂŽles (utilisateurs) \dp [nom_table] -- Lister les permissions de la table (ACL) -- AIDE & CONFIG \? -- Aide psql \h [COMMANDE_SQL] -- Aide SQL (ex: \h CREATE TABLE) \timing -- Activer le timer \conninfo -- Infos connexion (host, port, user)
CLI (Commandes Shell Bash)
# Connexion psql -h [host] -U [user] -W -d [db] # Connexion locale (compte 'postgres') sudo -u postgres psql # Créer/Supprimer une BDD sudo -u postgres createdb [nom_db] sudo -u postgres dropdb [nom_db] # Exécuter une commande rapide psql -U [user] -d [db] -c "SELECT COUNT(*) FROM users" # Exécuter un fichier SQL psql -U [user] -d [db] -f script.sql # Backup (Custom format) pg_dump -U [user] -W -F c [db] > backup.dump # Backup (Global / Roles) pg_dumpall -U postgres --globals-only > roles.sql # Restore (Custom format) pg_restore -U [user] -W -d [db_vide] backup.dump # Restore (SQL format) psql -U [user] -W -d [db_vide] < backup.sql
SQL (Gestion & RĂŽles)
-- GESTION DES RĂLES CREATE ROLE nom_role LOGIN PASSWORD 'pass'; ALTER ROLE nom_role WITH SUPERUSER; DROP ROLE nom_role; ALTER ROLE nom_role RENAME TO nouveau_nom; -- GESTION DES PRIVILĂGES GRANT CONNECT ON DATABASE nom_db TO nom_role; GRANT USAGE ON SCHEMA nom_schema TO nom_role; GRANT SELECT, INSERT, UPDATE, DELETE ON table TO nom_role; GRANT ALL PRIVILEGES ON DATABASE nom_db TO nom_role; REVOKE SELECT ON table FROM nom_role; -- GESTION DES SCHEMAS CREATE SCHEMA nom_schema; DROP SCHEMA nom_schema; ALTER SCHEMA nom_schema RENAME TO nouveau_nom; SHOW search_path; SET search_path TO nom_schema, public; -- GESTION DES INDEX CREATE INDEX idx_nom ON table (colonne); CREATE INDEX idx_jsonb ON table USING GIN (jsonb_col); DROP INDEX idx_nom; -- ANALYSE EXPLAIN (ANALYZE, BUFFERS) SELECT ...;
