

Les traductions sont fournies par des outils de traduction automatique. En cas de conflit entre le contenu d'une traduction et celui de la version originale en anglais, la version anglaise prévaudra.

# LWLock:SubtransSLRU (LWLock:SubtransControlLock)
<a name="wait-event.lwlocksubtransslru"></a>

Les événements `LWLock:SubtransSLRU` and `LWLock:SubtransBuffer` wait indiquent qu'une session attend d'accéder au cache simple le moins récemment utilisé (SLRU) pour les informations relatives aux sous-transactions. Cela se produit lors de la détermination de la visibilité des transactions et des relations parent-enfant.
+ `LWLock:SubtransSLRU`: un processus attend d'accéder au cache simple le moins récemment utilisé (SLRU) pour une sous-transaction. Dans RDS pour PostgreSQL avant la version 13, cet événement d'attente est appelé. `SubtransControlLock`
+ `LWLock:SubtransBuffer`: Un processus attend I/O une sous-transaction dans une mémoire tampon simple la moins récemment utilisée (SLRU). Dans RDS pour PostgreSQL avant la version 13, cet événement d'attente est appelé. `subtrans`

**Topics**
+ [Versions de moteur prises en charge](#wait-event.lwlocksubtransslru.supported)
+ [Contexte](#wait-event.lwlocksubtransslru.context)
+ [Causes probables de l’augmentation du nombre d’événements d’attente](#wait-event.lwlocksubtransslru.causes)
+ [Actions](#wait-event.lwlocksubtransslru.actions)

## Versions de moteur prises en charge
<a name="wait-event.lwlocksubtransslru.supported"></a>

Ces informations sur les événements d’attente sont prises en charge pour toutes les versions de RDS pour PostgreSQL.

## Contexte
<a name="wait-event.lwlocksubtransslru.context"></a>

**Comprendre les sous-transactions** — Une sous-transaction est une transaction au sein d'une transaction dans PostgreSQL. Elle est également connue sous le nom de transaction imbriquée.

Les sous-transactions sont généralement créées lorsque vous utilisez :
+ Commandes de l’`SAVEPOINT`
+ Blocs d'exception (`BEGIN/EXCEPTION/END`)

Les sous-transactions vous permettent d'annuler certaines parties d'une transaction sans affecter l'ensemble de la transaction. Cela vous donne un contrôle précis sur la gestion des transactions.

**Détails de mise en œuvre** — PostgreSQL implémente les sous-transactions sous forme de structures imbriquées dans les transactions principales. Chaque sous-transaction reçoit son propre identifiant de transaction.

Principaux aspects de mise en œuvre :
+ Les numéros de transaction sont suivis dans `pg_xact`
+ Parent-child les relations sont stockées dans le `pg_subtrans` sous-répertoire sous `PGDATA`
+ Chaque session de base de données peut gérer jusqu'à des `64` sous-transactions actives
+ Le dépassement de cette limite entraîne un débordement des sous-transactions, ce qui nécessite d'accéder au cache simple utilisé le moins récemment (SLRU) pour les informations relatives aux sous-transactions

## Causes probables de l’augmentation du nombre d’événements d’attente
<a name="wait-event.lwlocksubtransslru.causes"></a>

Les causes courantes de contention du SLRU lié aux sous-transactions sont les suivantes :
+ **Utilisation excessive de SAVEPOINT et de gestion des EXCEPTIONS** : PL/pgSQL les procédures dotées de `EXCEPTION` gestionnaires créent automatiquement des points de sauvegarde implicites, que des exceptions se produisent ou non. Chacune `SAVEPOINT` initie une nouvelle sous-transaction. Lorsqu'une seule transaction accumule plus de 64 sous-transactions, elle déclenche un dépassement du SLRU des sous-transactions.
+ **Configurations du pilote et de l'ORM** : `SAVEPOINT` l'utilisation peut être explicite dans le code de l'application ou implicite dans les configurations du pilote. De nombreux outils ORM et frameworks d'applications couramment utilisés prennent en charge les transactions imbriquées de manière native. Voici quelques exemples courants :
  + Le paramètre du pilote JDBC`autosave`, s'il est défini sur `always` ou`conservative`, génère des points de sauvegarde avant chaque requête.
  + Définitions de transactions Spring Framework lorsqu'elles sont définies sur`propagation_nested`.
  + Rails quand `requires_new: true` c'est réglé.
  + SQLAlchemy lorsqu'il `session.begin_nested` est utilisé.
  + Django lorsque des `atomic()` blocs imbriqués sont utilisés.
  + GORM lorsqu'il `Savepoint` est utilisé.
  + PSQLodBC lorsque le paramètre de niveau d'annulation est défini sur Annulation au niveau de l'instruction (par exemple,). `PROTOCOL=7.4-2`
+ **Charges de travail simultanées élevées associées à des transactions et sous-transactions de longue durée : lorsque le nombre de sous-transactions** SLRU déborde lors de charges de travail simultanées élevées et de transactions et sous-transactions de longue durée, PostgreSQL est confronté à une augmentation des contentions. Cela se traduit par des temps d'attente élevés `LWLock:SubtransBuffer` et des `LWLock:SubtransSLRU` blocages.

## Actions
<a name="wait-event.lwlocksubtransslru.actions"></a>

Nous vous recommandons différentes actions en fonction des causes de votre événement d’attente. Certaines actions apportent un soulagement immédiat, tandis que d'autres nécessitent une enquête et une correction à long terme.

**Topics**
+ [Surveillance de l'utilisation des sous-transactions](#wait-event.lwlocksubtransslru.actions.monitor)
+ [Configuration des paramètres de mémoire](#wait-event.lwlocksubtransslru.actions.memory)
+ [Long-term actions](#wait-event.lwlocksubtransslru.actions.longterm)

### Surveillance de l'utilisation des sous-transactions
<a name="wait-event.lwlocksubtransslru.actions.monitor"></a>

Pour les versions 16.1 et ultérieures de PostgreSQL, utilisez la requête suivante pour surveiller le nombre de sous-transactions et l'état des dépassements par backend. Cette requête associe les statistiques du backend aux informations d'activité pour indiquer quels processus utilisent des sous-transactions :

```
SELECT a.pid, usename, query, state, wait_event_type,
       wait_event, subxact_count, subxact_overflowed
FROM (SELECT id, pg_stat_get_backend_pid(id) pid, subxact_count, subxact_overflowed
      FROM pg_stat_get_backend_idset() id
           JOIN LATERAL pg_stat_get_backend_subxact(id) AS s ON true
     ) a
JOIN pg_stat_activity b ON a.pid = b.pid;
```

Pour les versions 13.3 et ultérieures de PostgreSQL, surveillez la vue pour détecter la pression `pg_stat_slru` du cache des sous-transactions. La requête SQL suivante extrait les statistiques du cache SLRU pour le composant Subtrans :

```
SELECT * FROM pg_stat_slru WHERE name = 'Subtrans';
```

Une `blks_read` valeur en augmentation constante indique un accès fréquent au disque pour les sous-transactions non mises en cache, ce qui indique une pression potentielle sur le cache du SLRU.

### Configuration des paramètres de mémoire
<a name="wait-event.lwlocksubtransslru.actions.memory"></a>

Pour PostgreSQL 17.1 et versions ultérieures, vous pouvez configurer la taille du cache SLRU des sous-transactions à l'aide du paramètre. `subtransaction_buffers` L'exemple de configuration suivant montre comment définir le paramètre du tampon de sous-transactions :

```
subtransaction_buffers = 128
```

Ce paramètre indique la quantité de mémoire partagée utilisée pour mettre en cache le contenu des sous-transactions (`pg_subtrans`). Lorsqu'elle est spécifiée sans unités, la valeur représente des blocs d'`BLCKSZ`octets, généralement de 8 Ko chacun. Par exemple, définir la valeur sur 128 alloue 1 Mo (128 x 8 Ko) de mémoire au cache de sous-transactions.

**Note**  
Vous pouvez définir ce paramètre au niveau du cluster afin que toutes les instances restent cohérentes. Testez et ajustez la valeur en fonction de vos exigences spécifiques en matière de charge de travail et de classe d'instance. Vous devez redémarrer l'instance du rédacteur pour que les modifications des paramètres soient prises en compte.

### Long-term actions
<a name="wait-event.lwlocksubtransslru.actions.longterm"></a>
+ **Examinez le code et les configurations de l'**application : passez en revue les configurations du code de votre application et du pilote de base de données pour en déterminer `SAVEPOINT` l'utilisation explicite et implicite et l'utilisation des sous-transactions en général. Identifiez les transactions susceptibles de générer plus de 64 sous-transactions.
+ **Réduisez l'utilisation des points de sauvegarde** — Minimisez l'utilisation de points de sauvegarde dans vos transactions :
  + Passez en revue PL/pgSQL les procédures et les fonctions à l'aide de blocs EXCEPTION. Les blocs EXCEPTION créent automatiquement des points de sauvegarde implicites, ce qui peut contribuer au dépassement des sous-transactions. Chaque clause EXCEPTION crée une sous-transaction, qu'une exception se produise ou non pendant l'exécution.  
**Example**  

    Exemple 1 : utilisation problématique du bloc EXCEPTION

    L'exemple de code suivant montre l'utilisation problématique du bloc EXCEPTION qui crée plusieurs sous-transactions :

    ```
    CREATE OR REPLACE FUNCTION process_user_data()
    RETURNS void AS $$
    DECLARE
        user_record RECORD;
    BEGIN
        FOR user_record IN SELECT * FROM users LOOP
            BEGIN
                -- This creates a subtransaction for each iteration
                INSERT INTO user_audit (user_id, action, timestamp)
                VALUES (user_record.id, 'processed', NOW());
                
                UPDATE users 
                SET last_processed = NOW() 
                WHERE id = user_record.id;
                
            EXCEPTION
                WHEN unique_violation THEN
                    -- Handle duplicate audit entries
                    UPDATE user_audit 
                    SET timestamp = NOW() 
                    WHERE user_id = user_record.id AND action = 'processed';
            END;
        END LOOP;
    END;
    $$ LANGUAGE plpgsql;
    ```

    L'exemple de code amélioré suivant réduit l'utilisation des sous-transactions en utilisant UPSERT au lieu de la gestion des exceptions :

    ```
    CREATE OR REPLACE FUNCTION process_user_data()
    RETURNS void AS $$
    DECLARE
        user_record RECORD;
    BEGIN
        FOR user_record IN SELECT * FROM users LOOP
            -- Use UPSERT to avoid exception handling
            INSERT INTO user_audit (user_id, action, timestamp)
            VALUES (user_record.id, 'processed', NOW())
            ON CONFLICT (user_id, action) 
            DO UPDATE SET timestamp = NOW();
            
            UPDATE users 
            SET last_processed = NOW() 
            WHERE id = user_record.id;
        END LOOP;
    END;
    $$ LANGUAGE plpgsql;
    ```  
**Example**  

    Exemple 2 : gestionnaire d'exceptions STRICT

    L'exemple de code suivant montre la gestion problématique des EXCEPTIONS avec NO\_DATA\_FOUND :

    ```
    CREATE OR REPLACE FUNCTION get_user_email(p_user_id INTEGER)
    RETURNS TEXT AS $$
    DECLARE
        user_email TEXT;
    BEGIN
        BEGIN
            -- STRICT causes an exception if no rows or multiple rows found
            SELECT email INTO STRICT user_email 
            FROM users 
            WHERE id = p_user_id;
            
            RETURN user_email;
            
        EXCEPTION
            WHEN NO_DATA_FOUND THEN
                RETURN 'Email not found';
        END;
    END;
    $$ LANGUAGE plpgsql;
    ```

    L'exemple de code amélioré suivant évite les sous-transactions en utilisant IF NOT FOUND au lieu de la gestion des exceptions :

    ```
    CREATE OR REPLACE FUNCTION get_user_email(p_user_id INTEGER)
    RETURNS TEXT AS $$
    DECLARE
        user_email TEXT;
    BEGIN
         SELECT email INTO user_email 
         FROM users 
         WHERE id = p_user_id;
            
         IF NOT FOUND THEN
             RETURN 'Email not found';
         ELSE
             RETURN user_email;
         END IF;
    END;
    $$ LANGUAGE plpgsql;
    ```
  + Pilote JDBC — Le `autosave` paramètre, s'il est défini sur `always` ou`conservative`, génère des points de sauvegarde avant chaque requête. Évaluez si le `never` paramètre est acceptable pour votre application.
  + Pilote ODBC PostgreSQL (PSQLodBC) : le paramètre du niveau de restauration (pour la restauration au niveau des instructions) crée des points de sauvegarde implicites pour activer la fonctionnalité de restauration des instructions. Déterminez si une annulation au niveau de la transaction serait acceptable pour votre application. 
  + Examiner les configurations de transactions ORM
  + Envisagez d'autres stratégies de gestion des erreurs qui ne nécessitent pas de points de sauvegarde
+ **Optimisez la conception** des transactions : restructurez les transactions pour éviter une imbrication excessive et réduire le risque de débordement des sous-transactions.
+ **Réduisez les transactions de longue durée : les** Long-running transactions peuvent exacerber les problèmes liés aux sous-transactions en conservant plus longtemps les informations relatives aux sous-transactions. Surveillez les métriques Performance Insights et configurez le `idle_in_transaction_session_timeout` paramètre pour mettre fin automatiquement aux transactions inactives.
+ Surveillez les indicateurs de Performance Insights : suivez des indicateurs tels que `idle_in_transaction_count` (nombre de sessions inactives dans l'état de transaction) et `idle_in_transaction_max_time` (durée de la transaction inactive la plus longue) pour détecter les transactions de longue durée.
+ Configurer `idle_in_transaction_session_timeout` : définissez ce paramètre dans votre groupe de paramètres pour mettre fin automatiquement aux transactions inactives après une durée spécifiée.
+ Surveillance proactive : surveillez les occurrences élevées d'événements `LWLock:SubtransBuffer` et `LWLock:SubtransSLRU` attendez afin de détecter les litiges liés aux sous-transactions avant qu'ils ne deviennent critiques.