De quoi EXPLAIN se tait-il, et comment le faire parler

Une question classique que les dĂ©veloppeurs posent presque toujours Ă  leur DBA ou au consultant PostgreSQL est : « Pourquoi les requĂȘtes prennent-elles autant de temps Ă  s'exĂ©cuter ? »

Un ensemble traditionnel de raisons :

  • un algorithme inefficace
    lorsque vous essayez de faire un JOIN entre plusieurs CTE avec des dizaines de milliers d'enregistrements
  • Ce point est particuliĂšrement important pour PostgreSQL, lorsque vous avez « dĂ©versĂ© » un grand ensemble de donnĂ©es sur le serveur, vous faites une requĂȘte — et celui-ci effectue une « scan sĂ©quentielle » sur la table. Parce qu'hier, il y avait 10 enregistrements, et aujourd'hui 10 millions, mais PostgreSQL n'est pas encore au courant, et il faut le lui signaler. [
    si la distribution réelle des données dans la table diffÚre fortement de celle analysée par ANALYZE la derniÚre fois
  • Vous avez installĂ© une grande base de donnĂ©es lourde sur un serveur faible, manquant d'espace disque, de mĂ©moire et de puissance processeur. Et voilà
 Il y a un seuil de performance au-delĂ  duquel vous ne pouvez plus sauter.
    et si les capacités de calcul CPU dédiées ne suffisent plus, que des gigaoctets de mémoire sont constamment sollicités ou que le disque ne peut pas suivre toutes les « demandes » de la base de données
  • de blocage en raison de processus concurrents

Et si les blocages sont assez difficiles Ă  capturer et Ă  analyser, pour tout le reste, il nous suffit du plan de requĂȘte, que l'on peut obtenir en utilisant l'instruction EXPLAIN (idĂ©alement, utilisez EXPLAIN (ANALYZE, BUFFERS) 
) ou le module auto_explain.

Cependant, comme le dit la documentation,

« Comprendre le plan est un art, et pour le maĂźtriser, une certaine expĂ©rience est nĂ©cessaire, 
 »

Mais on peut s'en passer si l'on utilise un outil approprié !

À quoi ressemble gĂ©nĂ©ralement un plan de requĂȘte ? En quelque sorte comme cela :

Index Scan using pg_class_relname_nsp_index on pg_class (actual time=0.049..0.050 rows=1 loops=1)
  Index Cond: (relname = $1)
  Filter: (oid = $0)
  Buffers: shared hit=4
  InitPlan 1 (returns $0,$1)
    ->  Limit (actual time=0.019..0.020 rows=1 loops=1)
          Buffers: shared hit=1
          ->  Seq Scan on pg_class pg_class_1 (actual time=0.015..0.015 rows=1 loops=1)
                Filter: (relkind = 'r'::"char")
                Rows Removed by Filter: 5
                Buffers: shared hit=1

ou comme ça :

"Append  (cost=868.60..878.95 rows=2 width=233) (actual time=0.024..0.144 rows=2 loops=1)"
"  Buffers: shared hit=3"
"  CTE cl"
"    ->  Seq Scan on pg_class  (cost=0.00..868.60 rows=9972 width=537) (actual time=0.016..0.042 rows=101 loops=1)"
"          Buffers: shared hit=3"
"  ->  Limit  (cost=0.00..0.10 rows=1 width=233) (actual time=0.023..0.024 rows=1 loops=1)"
"        Buffers: shared hit=1"
"        ->  CTE Scan on cl  (cost=0.00..997.20 rows=9972 width=233) (actual time=0.021..0.021 rows=1 loops=1)"
"              Buffers: shared hit=1"
"  ->  Limit  (cost=10.00..10.10 rows=1 width=233) (actual time=0.117..0.118 rows=1 loops=1)"
"        Buffers: shared hit=2"
"        ->  CTE Scan on cl cl_1  (cost=0.00..997.20 rows=9972 width=233) (actual time=0.001..0.104 rows=101 loops=1)"
"              Buffers: shared hit=2"
"Planning Time: 0.634 ms"
"Execution Time: 0.248 ms"

Mais lire le plan textuellement « à la volée » est trÚs difficile et peu clair :

  • dans le nƓud, est affichĂ© la somme des ressources de l'arbre sous-jacent
    c'est-Ă -dire que pour comprendre combien de temps a Ă©tĂ© utilisĂ© pour exĂ©cuter un nƓud spĂ©cifique, ou combien de donnĂ©es ont Ă©tĂ© effectivement rĂ©cupĂ©rĂ©es de la table — il faut soustraire une valeur d'une autre
  • le temps du nƓud doit ĂȘtre multipliĂ© par les loops
    Oui, la soustraction n'est pas l'opĂ©ration la plus difficile Ă  faire « mentalement » — en effet, le temps d'exĂ©cution est indiquĂ© en moyenne pour un seul nƓud, alors qu'il peut y en avoir des centaines.
  • Eh bien, tout cela complique la rĂ©ponse Ă  la question principale — alors, qui est-ce ? « Le maillon le plus faible »?

Lorsque nous avons essayé d'expliquer tout cela à plusieurs centaines de nos développeurs, nous avons réalisé que de l'extérieur, cela ressemblait à peu prÚs à cela :

De quoi EXPLAIN se tait-il, et comment le faire parler

Alors, nous avons besoin de


Outil

Dans celui-ci, nous avons essayé de rassembler toutes les mécaniques clés qui aident à comprendre, en fonction du plan et de la demande, « qui est responsable et que faire ». Et aussi, de partager une partie de notre expérience avec la communauté.
Faites connaissance et utilisez — explain.tensor.ru

Clarté des plans

Est-il facile de comprendre un plan lorsqu'il ressemble Ă  cela ?

Seq Scan on pg_class (temps réel=0.009..1.304 lignes=6609 boucles=1)
  Buffers : partagés hit=263
Temps de planification : 0.108 ms
Temps d'exécution : 1.800 ms

Pas vraiment.

Mais ainsi, dans une version abrĂ©gĂ©e, lorsque les indicateurs clĂ©s sont sĂ©parĂ©s — c'est dĂ©jĂ  beaucoup plus clair :

De quoi EXPLAIN se tait-il, et comment le faire parler

Mais si le plan est plus complexe — un diagramme à secteurs de distribution du temps par nƓuds :

De quoi EXPLAIN se tait-il, et comment le faire parler

Eh bien, pour les cas les plus complexes, le diagramme d'exécution:

De quoi EXPLAIN se tait-il, et comment le faire parler

Par exemple, il existe des situations suffisamment non triviales oĂč un plan peut avoir plus d'une racine rĂ©elle :

De quoi EXPLAIN se tait-il, et comment le faire parlerDe quoi EXPLAIN se tait-il, et comment le faire parler

Conseils structurels

Eh bien, si toute la structure du plan et ses points faibles sont dĂ©jĂ  Ă©tablis et visibles — pourquoi ne pas les mettre en Ă©vidence pour le dĂ©veloppeur, et expliquer « en termes simples » ?

De quoi EXPLAIN se tait-il, et comment le faire parlerNous avons déjà rassemblé une bonne dizaine de ces modÚles de recommandations.

Profilage ligne par ligne de la requĂȘte

Maintenant, si vous appliquez la requĂȘte d'origine au plan analysĂ©, vous pouvez voir combien de temps chaque opĂ©rateur individuel a pris — Ă  peu prĂšs comme cela :

De quoi EXPLAIN se tait-il, et comment le faire parler


 ou mĂȘme comme ça :

De quoi EXPLAIN se tait-il, et comment le faire parler

Substitution de paramĂštres dans la requĂȘte

Si vous avez « attachĂ© » au plan non seulement la requĂȘte, mais aussi ses paramĂštres depuis la ligne DETAIL du journal, vous pouvez la copier de maniĂšre supplĂ©mentaire dans l'une des variantes :

  • avec substitution des valeurs dans la requĂȘte
    pour une exécution immédiate sur votre propre base et un profilage ultérieur
    SELECT 'const', 'param'::text;
  • avec substitution des valeurs via PREPARE/EXECUTE
    pour simuler le fonctionnement du planificateur, lorsque la partie paramĂ©trique peut ĂȘtre ignorĂ©e — par exemple, lors de l'utilisation de tables partitionnĂ©es
    DEALLOCATE ALL;
    PREPARE q(text) AS SELECT 'const', $1::text;
    EXECUTE q('param'::text);
    

Archives des plans

Insérez, analysez, partagez avec vos collÚgues ! Les plans resteront archivés, et vous pourrez y revenir plus tard : explain.tensor.ru/archive

Mais si vous ne voulez pas que votre plan soit vu par d'autres, n'oubliez pas de cocher la case « ne pas publier dans l'archive ».

Dans les prochains articles, je parlerai des difficultés et des solutions qui surgissent lors de l'analyse des plans.

Source : habr.com

Acheter un hĂ©bergement fiable pour les sites avec protection DDoS, serveurs VPS VDS đŸ”„ Acheter un hĂ©bergement fiable pour les sites avec protection DDoS, serveurs VPS VDS | ProHoster