[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"article-deep-evm-27-performance-postgresql-index-vacuum":3},{"article":4,"author":55},{"id":5,"category_id":6,"title":7,"slug":8,"excerpt":9,"content_md":10,"content_html":11,"locale":12,"author_id":13,"published":14,"published_at":15,"meta_title":16,"meta_description":17,"focus_keyword":18,"og_image":19,"canonical_url":19,"robots_meta":20,"created_at":15,"updated_at":15,"tags":21,"category_name":24,"related_articles":35},"d6000000-0000-0000-0000-000000000127","a0000000-0000-0000-0000-000000000065","Deep EVM #27 : Performance PostgreSQL à grande échelle — Index, VACUUM et optimisation de requêtes","deep-evm-27-performance-postgresql-index-vacuum","Maîtrisez le réglage de performance PostgreSQL avec les index partiels, les index couvrants, BRIN pour les séries temporelles, la configuration d'autovacuum et l'interprétation d'EXPLAIN ANALYZE.","## PostgreSQL à grande échelle\n\nPostgreSQL est remarquablement rapide par défaut, mais à grande échelle vous devez comprendre ses mécanismes internes pour maintenir les performances. Cet article couvre les trois piliers : les index, VACUUM et l'optimisation de requêtes.\n\n## Index : au-delà du B-tree basique\n\n### Index partiels\n\nIndexez uniquement les lignes qui comptent :\n\n```sql\n-- Au lieu d'indexer toute la table\nCREATE INDEX idx_orders_status ON orders(status);\n\n-- Indexez seulement les commandes actives (5% de la table)\nCREATE INDEX idx_orders_active ON orders(created_at)\n    WHERE status = 'active';\n```\n\nL'index partiel est 20x plus petit, 20x plus rapide à maintenir, et couvre 95 % des requêtes.\n\n### Index couvrants (covering indexes)\n\n```sql\n-- La requête lit seulement account_id et balance\n-- Un index couvrant évite de toucher la table (index-only scan)\nCREATE INDEX idx_accounts_covering ON accounts(account_id)\n    INCLUDE (balance, updated_at);\n```\n\n### BRIN pour les séries temporelles\n\nBlock Range INdex — idéal pour les données naturellement ordonnées :\n\n```sql\n-- 1000x plus petit qu'un B-tree pour les données temporelles\nCREATE INDEX idx_events_time ON events USING BRIN (created_at)\n    WITH (pages_per_range = 32);\n```\n\nBRIN stocke les valeurs min\u002Fmax par groupe de pages. Pour les données insérées chronologiquement, il est extrêmement efficace.\n\n## VACUUM : comprendre le MVCC\n\nPostgreSQL utilise le MVCC (Multi-Version Concurrency Control). Chaque UPDATE crée une nouvelle version de la ligne ; l'ancienne version (dead tuple) reste jusqu'à ce que VACUUM la nettoie.\n\n### Pourquoi VACUUM est critique\n\nSans VACUUM :\n- La table grossit indéfiniment (bloat)\n- Les index pointent vers des dead tuples\n- Les requêtes scannent des pages mortes\n- Les statistiques deviennent obsolètes\n\n### Configuration d'autovacuum\n\n```sql\n-- Pour les tables à fort débit d'écriture\nALTER TABLE transactions SET (\n    autovacuum_vacuum_scale_factor = 0.01,     -- Déclencher à 1% de dead tuples\n    autovacuum_vacuum_cost_delay = 2,           -- 2ms entre les I\u002FO\n    autovacuum_vacuum_cost_limit = 1000          -- Budget d'I\u002FO élevé\n);\n```\n\n### Monitoring du bloat\n\n```sql\nSELECT\n    schemaname, tablename,\n    n_dead_tup,\n    n_live_tup,\n    round(n_dead_tup::numeric \u002F greatest(n_live_tup, 1) * 100, 1) AS dead_pct,\n    last_autovacuum\nFROM pg_stat_user_tables\nORDER BY n_dead_tup DESC;\n```\n\n## EXPLAIN ANALYZE\n\n```sql\nEXPLAIN (ANALYZE, BUFFERS, FORMAT TEXT)\nSELECT * FROM transactions\nWHERE account_id = 42 AND created_at > '2024-01-01';\n```\n\nPoints clés à lire :\n- **Actual time** vs **estimated time** — Un écart important indique des statistiques obsolètes\n- **Buffers: shared hit vs read** — Hit = en cache, read = disque\n- **Rows Removed by Filter** — Beaucoup de lignes filtrées = index manquant\n- **Seq Scan** sur une grande table — Probablement un index manquant\n\n## Anti-patterns courants\n\n1. **SELECT *** — Lisez seulement les colonnes nécessaires\n2. **Fonctions sur les colonnes indexées** — `WHERE YEAR(created_at) = 2024` ne peut pas utiliser l'index\n3. **OR dans WHERE** — Souvent empêche l'utilisation de l'index ; utilisez UNION\n4. **Pas de LIMIT** — Toujours limiter les résultats en production\n5. **Transactions longues** — Bloquent VACUUM et accumulent les dead tuples\n\n## Conclusion\n\nLa performance PostgreSQL à grande échelle repose sur trois piliers : des index ciblés (partiels, couvrants, BRIN), un VACUUM bien configuré (autovacuum agressif pour les tables à fort débit), et l'interprétation méthodique d'EXPLAIN ANALYZE pour identifier et corriger les problèmes.","\u003Ch2 id=\"postgresql-grande-chelle\">PostgreSQL à grande échelle\u003C\u002Fh2>\n\u003Cp>PostgreSQL est remarquablement rapide par défaut, mais à grande échelle vous devez comprendre ses mécanismes internes pour maintenir les performances. Cet article couvre les trois piliers : les index, VACUUM et l’optimisation de requêtes.\u003C\u002Fp>\n\u003Ch2 id=\"index-au-del-du-b-tree-basique\">Index : au-delà du B-tree basique\u003C\u002Fh2>\n\u003Ch3>Index partiels\u003C\u002Fh3>\n\u003Cp>Indexez uniquement les lignes qui comptent :\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-sql\">-- Au lieu d'indexer toute la table\nCREATE INDEX idx_orders_status ON orders(status);\n\n-- Indexez seulement les commandes actives (5% de la table)\nCREATE INDEX idx_orders_active ON orders(created_at)\n    WHERE status = 'active';\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>L’index partiel est 20x plus petit, 20x plus rapide à maintenir, et couvre 95 % des requêtes.\u003C\u002Fp>\n\u003Ch3>Index couvrants (covering indexes)\u003C\u002Fh3>\n\u003Cpre>\u003Ccode class=\"language-sql\">-- La requête lit seulement account_id et balance\n-- Un index couvrant évite de toucher la table (index-only scan)\nCREATE INDEX idx_accounts_covering ON accounts(account_id)\n    INCLUDE (balance, updated_at);\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch3>BRIN pour les séries temporelles\u003C\u002Fh3>\n\u003Cp>Block Range INdex — idéal pour les données naturellement ordonnées :\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-sql\">-- 1000x plus petit qu'un B-tree pour les données temporelles\nCREATE INDEX idx_events_time ON events USING BRIN (created_at)\n    WITH (pages_per_range = 32);\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>BRIN stocke les valeurs min\u002Fmax par groupe de pages. Pour les données insérées chronologiquement, il est extrêmement efficace.\u003C\u002Fp>\n\u003Ch2 id=\"vacuum-comprendre-le-mvcc\">VACUUM : comprendre le MVCC\u003C\u002Fh2>\n\u003Cp>PostgreSQL utilise le MVCC (Multi-Version Concurrency Control). Chaque UPDATE crée une nouvelle version de la ligne ; l’ancienne version (dead tuple) reste jusqu’à ce que VACUUM la nettoie.\u003C\u002Fp>\n\u003Ch3>Pourquoi VACUUM est critique\u003C\u002Fh3>\n\u003Cp>Sans VACUUM :\u003C\u002Fp>\n\u003Cul>\n\u003Cli>La table grossit indéfiniment (bloat)\u003C\u002Fli>\n\u003Cli>Les index pointent vers des dead tuples\u003C\u002Fli>\n\u003Cli>Les requêtes scannent des pages mortes\u003C\u002Fli>\n\u003Cli>Les statistiques deviennent obsolètes\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Ch3>Configuration d’autovacuum\u003C\u002Fh3>\n\u003Cpre>\u003Ccode class=\"language-sql\">-- Pour les tables à fort débit d'écriture\nALTER TABLE transactions SET (\n    autovacuum_vacuum_scale_factor = 0.01,     -- Déclencher à 1% de dead tuples\n    autovacuum_vacuum_cost_delay = 2,           -- 2ms entre les I\u002FO\n    autovacuum_vacuum_cost_limit = 1000          -- Budget d'I\u002FO élevé\n);\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch3>Monitoring du bloat\u003C\u002Fh3>\n\u003Cpre>\u003Ccode class=\"language-sql\">SELECT\n    schemaname, tablename,\n    n_dead_tup,\n    n_live_tup,\n    round(n_dead_tup::numeric \u002F greatest(n_live_tup, 1) * 100, 1) AS dead_pct,\n    last_autovacuum\nFROM pg_stat_user_tables\nORDER BY n_dead_tup DESC;\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch2 id=\"explain-analyze\">EXPLAIN ANALYZE\u003C\u002Fh2>\n\u003Cpre>\u003Ccode class=\"language-sql\">EXPLAIN (ANALYZE, BUFFERS, FORMAT TEXT)\nSELECT * FROM transactions\nWHERE account_id = 42 AND created_at &gt; '2024-01-01';\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Points clés à lire :\u003C\u002Fp>\n\u003Cul>\n\u003Cli>\u003Cstrong>Actual time\u003C\u002Fstrong> vs \u003Cstrong>estimated time\u003C\u002Fstrong> — Un écart important indique des statistiques obsolètes\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Buffers: shared hit vs read\u003C\u002Fstrong> — Hit = en cache, read = disque\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Rows Removed by Filter\u003C\u002Fstrong> — Beaucoup de lignes filtrées = index manquant\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Seq Scan\u003C\u002Fstrong> sur une grande table — Probablement un index manquant\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Ch2 id=\"anti-patterns-courants\">Anti-patterns courants\u003C\u002Fh2>\n\u003Col>\n\u003Cli>**SELECT *** — Lisez seulement les colonnes nécessaires\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Fonctions sur les colonnes indexées\u003C\u002Fstrong> — \u003Ccode>WHERE YEAR(created_at) = 2024\u003C\u002Fcode> ne peut pas utiliser l’index\u003C\u002Fli>\n\u003Cli>\u003Cstrong>OR dans WHERE\u003C\u002Fstrong> — Souvent empêche l’utilisation de l’index ; utilisez UNION\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Pas de LIMIT\u003C\u002Fstrong> — Toujours limiter les résultats en production\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Transactions longues\u003C\u002Fstrong> — Bloquent VACUUM et accumulent les dead tuples\u003C\u002Fli>\n\u003C\u002Fol>\n\u003Ch2 id=\"conclusion\">Conclusion\u003C\u002Fh2>\n\u003Cp>La performance PostgreSQL à grande échelle repose sur trois piliers : des index ciblés (partiels, couvrants, BRIN), un VACUUM bien configuré (autovacuum agressif pour les tables à fort débit), et l’interprétation méthodique d’EXPLAIN ANALYZE pour identifier et corriger les problèmes.\u003C\u002Fp>\n","fr","b0000000-0000-0000-0000-000000000001",true,"2026-03-28T10:44:29.348303Z","Performance PostgreSQL à grande échelle — Index, VACUUM et optimisation de requêtes","Réglage de performance PostgreSQL : index partiels, BRIN, configuration autovacuum, lecture EXPLAIN ANALYZE et anti-patterns courants.","performance postgresql optimisation",null,"index, follow",[22,27,31],{"id":23,"name":24,"slug":25,"created_at":26},"c0000000-0000-0000-0000-000000000012","DevOps","devops","2026-03-28T10:44:21.513630Z",{"id":28,"name":29,"slug":30,"created_at":26},"c0000000-0000-0000-0000-000000000022","Performance","performance",{"id":32,"name":33,"slug":34,"created_at":26},"c0000000-0000-0000-0000-000000000005","PostgreSQL","postgresql",[36,43,49],{"id":37,"title":38,"slug":39,"excerpt":40,"locale":12,"category_name":41,"published_at":42},"d0000000-0000-0000-0000-000000000677","Pourquoi Bali devient le hub impact-tech d'Asie du Sud-Est en 2026","pourquoi-bali-devient-hub-impact-tech-asie-sud-est-2026","Bali se classe 16e parmi les écosystèmes startups d'Asie du Sud-Est. Avec une concentration croissante de bâtisseurs Web3, de startups IA durables et d'entreprises eco-travel tech, l'île se forge une identité de capitale impact-tech de la région.","Ingénierie","2026-03-28T10:44:49.517126Z",{"id":44,"title":45,"slug":46,"excerpt":47,"locale":12,"category_name":41,"published_at":48},"d0000000-0000-0000-0000-000000000676","Le patchwork de la protection des données ASEAN : checklist de conformité pour les développeurs","patchwork-protection-donnees-asean-checklist-conformite-developpeurs","Sept pays de l'ASEAN disposent désormais de lois complètes sur la protection des données, chacune avec des modèles de consentement, des exigences de localisation et des structures de sanctions différents. Voici une checklist pratique de conformité pour les développeurs.","2026-03-28T10:44:49.504560Z",{"id":50,"title":51,"slug":52,"excerpt":53,"locale":12,"category_name":41,"published_at":54},"d0000000-0000-0000-0000-000000000675","La transformation numérique de 29 milliards de dollars d'Indonesia : opportunités pour les éditeurs de logiciels","transformation-numerique-29-milliards-dollars-indonesia-opportunites-editeurs-logiciels","Le marché des services informatiques d'Indonesia devrait atteindre 29,03 milliards de dollars en 2026, contre 24,37 milliards en 2025. L'infrastructure cloud, l'IA, le e-commerce et les centres de données tirent la croissance la plus rapide d'Asie du Sud-Est.","2026-03-28T10:44:49.469231Z",{"id":13,"name":56,"slug":57,"bio":58,"photo_url":19,"linkedin":19,"role":59,"created_at":60,"updated_at":60},"Open Soft Team","open-soft-team","The engineering team at Open Soft, building premium software solutions from Bali, Indonesia.","Engineering Team","2026-03-28T08:31:22.226811Z"]