PostgreSQL
 sql >> Base de données >  >> RDS >> PostgreSQL

PostgreSQL fonctionne lentement ? Trucs et astuces pour aller à la source

En tant qu'administrateur de base de données PostgreSQL, il y a des attentes quotidiennes pour vérifier les sauvegardes, appliquer les modifications DDL, s'assurer que les journaux ne contiennent pas d'erreurs de rupture de jeu et répondre aux appels paniqués des développeurs dont les rapports s'exécutent deux fois plus longtemps que la normale et ils rendez-vous dans dix minutes.

Même avec une bonne compréhension de la santé des bases de données gérées, il y aura toujours de nouveaux cas et de nouveaux problèmes liés aux performances et à la « sensation » de la base de données. Qu'il s'agisse d'un e-mail paniqué ou d'un ticket ouvert pour "la base de données semble lente", cette tâche courante peut généralement être suivie de quelques étapes pour vérifier s'il y a ou non un problème avec PostgreSQL, et quel peut être ce problème.

Ce n'est en aucun cas un guide exhaustif, et les étapes ne doivent pas être effectuées dans un ordre spécifique. Mais il s'agit plutôt d'un ensemble de mesures initiales qui peuvent être prises pour aider à trouver rapidement les délinquants courants, ainsi qu'à mieux comprendre le problème. Un développeur peut savoir comment l'application agit et répond, mais l'administrateur de la base de données sait comment la base de données agit et répond à l'application, et ensemble, le problème peut être trouvé.

REMARQUE : Les requêtes à exécuter doivent être effectuées en tant que superutilisateur, tel que "postgres" ou tout utilisateur de base de données disposant des autorisations de superutilisateur. Les utilisateurs limités seront soit refusés, soit leurs données seront omises.

Étape 0 - Collecte d'informations

Obtenez autant d'informations que possible de celui qui dit que la base de données semble lente; requêtes spécifiques, applications connectées, délais de ralentissement des performances, etc. Plus ils donnent d'informations, plus il sera facile de trouver le problème.

Étape 1 – Vérifiez pg_stat_activity

La demande peut prendre de nombreuses formes différentes, mais si la "lenteur" est le problème général, vérifier pg_stat_activity est la première étape pour comprendre exactement ce qui se passe. La vue pg_stat_activity (la documentation de chaque colonne de cette vue peut être trouvée ici) contient une ligne pour chaque processus serveur/connexion à la base de données à partir d'un client. Il y a une poignée d'informations utiles dans cette vue qui peuvent vous aider.

REMARQUE : pg_stat_activity est connu pour changer de structure au fil du temps, affinant les données qu'il présente. La compréhension des colonnes elles-mêmes aidera à créer des requêtes dynamiquement selon les besoins à l'avenir.

Les colonnes notables dans pg_stat_activity sont :

  1. requête :une colonne de texte indiquant la requête en cours d'exécution, en attente d'exécution ou qui a été exécutée en dernier (selon l'état). Cela peut aider à identifier la ou les requêtes signalées par un développeur qui s'exécutent lentement.
  2. client_addr :l'adresse IP d'où proviennent cette connexion et cette requête. S'il est vide (ou Null), il provient de localhost.
  3. backend_start, xact_start, query_start :ces trois éléments fournissent respectivement un horodatage du démarrage de chacun. Backend_start représente le moment où la connexion à la base de données a été établie, xact_start correspond au démarrage de la transaction en cours et query_start correspond au démarrage de la requête actuelle (ou de la dernière).
  4. state :L'état de la connexion à la base de données. Actif signifie qu'il exécute actuellement une requête, "inactif" signifie qu'il attend d'autres entrées du client, "inactif dans la transaction" signifie qu'il attend d'autres entrées du client tout en maintenant une transaction ouverte. (Il en existe d'autres, mais leur probabilité est rare, consultez la documentation pour plus d'informations).
  5. datname :nom de la base de données à laquelle la connexion est actuellement connectée. Dans plusieurs clusters de bases de données, cela peut aider à isoler les connexions problématiques.
  6. wait_event_type et wait_event :ces colonnes seront nulles lorsqu'une requête n'attend pas, mais si elle attend, elles contiendront des informations sur la raison pour laquelle la requête attend, et l'exploration de pg_locks peut identifier ce qu'elle attend. (PostgreSQL 9.5 et versions antérieures n'ont qu'une colonne booléenne appelée "attente", true si en attente, false sinon.

1.1. La requête est-elle en attente/bloquée ?

S'il y a une requête spécifique ou des requêtes qui sont « lentes » ou « bloquées », vérifiez si elles attendent qu'une autre requête se termine. En raison du verrouillage des relations, d'autres requêtes peuvent verrouiller une table et empêcher d'autres requêtes d'accéder aux données ou de les modifier tant que cette requête ou transaction n'est pas terminée.

PostgreSQL 9.5 et versions antérieures :

SELECT * FROM pg_stat_activity WHERE waiting = TRUE;

PostgreSQL 9.6 :

SELECT * FROM pg_stat_activity WHERE wait_event IS NOT NULL;

PostgreSQL 10 et versions ultérieures (?) :

SELECT * FROM pg_stat_activity WHERE wait_event IS NOT NULL AND backend_type = 'client backend';

Les résultats de cette requête afficheront toutes les connexions actuellement en attente sur une autre connexion pour libérer les verrous sur une relation qui est nécessaire.

Si la requête est bloquée par une autre connexion, il existe plusieurs façons de savoir de quoi il s'agit. Dans PostgreSQL 9.6 et versions ultérieures, la fonction pg_blocking_pids() permet l'entrée d'un ID de processus qui est bloqué, et elle renverra un tableau d'ID de processus qui sont responsables de le bloquer.

PostgreSQL 9.6 et versions ultérieures :

SELECT * FROM pg_stat_activity 
WHERE pid IN (SELECT pg_blocking_pids(<pid of blocked query>));

PostgreSQL 9.5 et versions antérieures :

SELECT blocked_locks.pid     AS blocked_pid,
         blocked_activity.usename  AS blocked_user,
         blocking_locks.pid     AS blocking_pid,
         blocking_activity.usename AS blocking_user,
         blocked_activity.query    AS blocked_statement,
         blocking_activity.query   AS current_statement_in_blocking_process
   FROM  pg_catalog.pg_locks         blocked_locks
    JOIN pg_catalog.pg_stat_activity blocked_activity  ON blocked_activity.pid = blocked_locks.pid
    JOIN pg_catalog.pg_locks         blocking_locks 
        ON blocking_locks.locktype = blocked_locks.locktype
        AND blocking_locks.DATABASE IS NOT DISTINCT FROM blocked_locks.DATABASE
        AND blocking_locks.relation IS NOT DISTINCT FROM blocked_locks.relation
        AND blocking_locks.page IS NOT DISTINCT FROM blocked_locks.page
        AND blocking_locks.tuple IS NOT DISTINCT FROM blocked_locks.tuple
        AND blocking_locks.virtualxid IS NOT DISTINCT FROM blocked_locks.virtualxid
        AND blocking_locks.transactionid IS NOT DISTINCT FROM blocked_locks.transactionid
        AND blocking_locks.classid IS NOT DISTINCT FROM blocked_locks.classid
        AND blocking_locks.objid IS NOT DISTINCT FROM blocked_locks.objid
        AND blocking_locks.objsubid IS NOT DISTINCT FROM blocked_locks.objsubid
        AND blocking_locks.pid != blocked_locks.pid
    JOIN pg_catalog.pg_stat_activity blocking_activity ON blocking_activity.pid = blocking_locks.pid
   WHERE NOT blocked_locks.GRANTED;

(Disponible sur le Wiki PostgreSQL).

Ces requêtes pointeront vers tout ce qui bloque un PID spécifique fourni. Avec cela, une décision peut être prise de tuer la requête ou la connexion bloquante, ou de la laisser s'exécuter.

Étape 2 :Si les requêtes sont en cours d'exécution, pourquoi prennent-elles autant de temps ?

2.1. Le planificateur exécute-t-il les requêtes de manière efficace ?

Si une requête (ou un ensemble de requêtes) en question a le statut "active", alors elle est en cours d'exécution. Si la requête entière n'est pas disponible dans pg_stat_activity, récupérez-la auprès des développeurs ou du journal postgresql et commencez à explorer le planificateur de requêtes.

EXPLAIN SELECT * FROM postgres_stats.table_stats t JOIN hosts h ON (t.host_id = h.host_id) WHERE logged_date >= '2018-02-01' AND logged_date < '2018-02-04' AND t.india_romeo = 569;
Nested Loop  (cost=0.280..1328182.030 rows=2127135 width=335)
  ->  Index Scan using six on victor_oscar echo  (cost=0.280..8.290 rows=1 width=71)
          Index Cond: (india_romeo = 569)
  ->  Append  (cost=0.000..1306902.390 rows=2127135 width=264)
        ->  Seq Scan on india_echo romeo  (cost=0.000..0.000 rows=1 width=264)
                Filter: ((logged_date >= '2018-02-01'::timestamp with time zone) AND (logged_date < '2018-02-04'::timestamp with time zone) AND (india_romeo = 569))
        ->  Seq Scan on juliet victor_echo  (cost=0.000..437153.700 rows=711789 width=264)
                Filter: ((logged_date >= '2018-02-01'::timestamp with time zone) AND (logged_date < '2018-02-04'::timestamp with time zone) AND (india_romeo = 569))
        ->  Seq Scan on india_papa quebec_bravo  (cost=0.000..434936.960 rows=700197 width=264)
                Filter: ((logged_date >= '2018-02-01'::timestamp with time zone) AND (logged_date < '2018-02-04'::timestamp with time zone) AND (india_romeo = 569))
        ->  Seq Scan on two oscar  (cost=0.000..434811.720 rows=715148 width=264)
                Filter: ((logged_date >= '2018-02-01'::timestamp with time zone) AND (logged_date < '2018-02-04'::timestamp with time zone) AND (india_romeo = 569))

Cet exemple montre un plan de requête pour une jointure de deux tables qui touche également une table partitionnée. Nous recherchons tout ce qui peut ralentir la requête, et dans ce cas, le planificateur effectue plusieurs analyses séquentielles sur les partitions, suggérant qu'il leur manque des index. L'ajout d'index à ces tables pour la colonne "india_romeo" améliorera instantanément cette requête.

Les éléments à rechercher sont les analyses séquentielles, les boucles imbriquées, le tri coûteux, etc. Comprendre le planificateur de requêtes est essentiel pour s'assurer que les requêtes fonctionnent de la meilleure façon possible, la documentation officielle peut être lue pour plus d'informations ici.

2.2. Les tableaux concernés sont-ils gonflés ?

Si les requêtes semblent toujours lentes sans que le planificateur de requêtes ne pointe sur quelque chose d'évident, il est temps de vérifier la santé des tables impliquées. Sont-ils trop gros ? Sont-ils gonflés ?

SELECT n_live_tup, n_dead_tup from pg_stat_user_tables where relname = ‘mytable’;
n_live_tup  | n_dead_tup
------------+------------
      15677 |    8275431
(1 row)

Ici, nous voyons qu'il y a beaucoup plus de lignes mortes que de lignes actives, ce qui signifie que pour trouver les bonnes lignes, le moteur doit passer au crible des données qui ne sont même pas pertinentes pour trouver des données réelles. Un vide/vide plein sur cette table augmentera considérablement les performances.

Étape 3 - Vérifier les journaux

Si le problème ne peut toujours pas être trouvé, consultez les journaux pour trouver des indices.

Messages FATAUX/ERREUR :

Recherchez les messages susceptibles de causer des problèmes, tels que des blocages ou de longs délais d'attente avant d'obtenir un verrou.

Points de contrôle

Espérons que log_checkpoints soit activé, ce qui écrira des informations sur les points de contrôle dans les journaux. Il existe deux types de points de contrôle, chronométrés et demandés (forcés). Si des points de contrôle sont forcés, les tampons sales en mémoire doivent être écrits sur le disque avant de traiter davantage de requêtes, ce qui peut donner à un système de base de données une sensation générale de « lenteur ». L'augmentation de checkpoint_segments ou max_wal_size (selon la version de la base de données) donnera au pointeur de contrôle plus d'espace pour travailler, ainsi qu'aider le rédacteur en arrière-plan à prendre une partie de la charge d'écriture.

Étape 4 :Quel est l'état du système hôte ?

S'il n'y a aucun indice dans la base de données elle-même, l'hôte lui-même est peut-être surchargé ou rencontre des problèmes. Qu'il s'agisse d'un canal d'E/S surchargé, d'un débordement de mémoire pour l'échange ou même d'un disque défaillant, aucun de ces problèmes ne serait apparent avec tout ce que nous avons examiné auparavant. En supposant que la base de données fonctionne sur un système d'exploitation basé sur *nix, voici quelques éléments qui peuvent vous aider.

4.1. Charge du système

En utilisant 'top', regardez la charge moyenne pour l'hôte. Si le nombre approche ou dépasse le nombre de cœurs sur le système, il peut s'agir simplement d'un trop grand nombre de connexions simultanées frappant la base de données, ce qui l'amène à une exploration pour rattraper son retard.

load average: 3.43, 5.25, 4.85

4.2. Mémoire système et SWAP

En utilisant "gratuit", vérifiez si SWAP a été utilisé. Le débordement de mémoire vers SWAP dans un environnement de base de données PostgreSQL est extrêmement mauvais pour les performances, et de nombreux administrateurs de base de données élimineront même SWAP des hôtes de base de données, car une erreur de "mémoire insuffisante" est plus préférable qu'un système lent pour beaucoup.

Si SWAP est utilisé, un redémarrage du système l'effacera, et l'augmentation de la mémoire système totale ou la reconfiguration de l'utilisation de la mémoire pour PostgreSQL (comme la réduction de shared_buffers ou work_mem) peut être nécessaire.

[[email protected] ~]$ free -m
              total        used        free      shared  buff/cache   available
Mem:           7986         225        1297          12        6462        7473
Swap:          7987        2048        5939

4.3. Accès au disque

PostgreSQL tente de faire une grande partie de son travail en mémoire et d'étaler l'écriture sur le disque pour minimiser les goulots d'étranglement, mais sur un système surchargé avec une écriture lourde, il est facilement possible de voir des lectures et des écritures lourdes ralentir l'ensemble du système à mesure qu'il rattrape son retard. sur les demandes. Des disques plus rapides, plus de disques et de canaux d'E/S sont des moyens d'augmenter la quantité de travail pouvant être effectuée.

Des outils tels que "iostat" ou "iotop" peuvent aider à déterminer s'il existe un goulot d'étranglement sur le disque et d'où il peut provenir.

4.4. Vérifiez les journaux

Si tout le reste échoue, ou même si ce n'est pas le cas, les journaux doivent toujours être vérifiés pour voir si le système signale quelque chose qui ne va pas. Nous avons déjà discuté de la vérification des postgresql.logs, mais les journaux système peuvent fournir des informations sur des problèmes tels que des disques défaillants, une mémoire défaillante, des problèmes de réseau, etc. Chacun de ces problèmes peut entraîner un comportement lent et imprévisible de la base de données. d'une santé parfaite peut aider à trouver ces problèmes.

Téléchargez le livre blanc aujourd'hui PostgreSQL Management &Automation with ClusterControlDécouvrez ce que vous devez savoir pour déployer, surveiller, gérer et faire évoluer PostgreSQLTélécharger le livre blanc

Étape 5 :Quelque chose n'a toujours pas de sens ?

Même les administrateurs les plus chevronnés rencontreront quelque chose de nouveau qui n'a aucun sens. C'est là que la communauté mondiale PostgreSQL peut intervenir pour aider. Tout comme l'étape 0, plus les informations fournies à la communauté sont claires, plus il est facile pour elle d'aider.

5.1. Listes de diffusion PostgreSQL

Puisque PostgreSQL est développé et géré par la communauté open source, il y a des milliers de personnes qui parlent à travers les listes de diffusion pour discuter d'innombrables sujets, y compris les fonctionnalités, les erreurs et les problèmes de performances. Les listes de diffusion peuvent être trouvées ici, pgsql-admin et pgsql-performance étant les plus importants pour rechercher de l'aide sur les problèmes de performances.

5.2. CRI

Freenode héberge plusieurs canaux PostgreSQL avec des développeurs et des administrateurs du monde entier, et il n'est pas difficile de trouver une personne utile pour localiser l'origine des problèmes. Plus d'informations peuvent être trouvées sur la page IRC PostgreSQL.