

Terjemahan disediakan oleh mesin penerjemah. Jika konten terjemahan yang diberikan bertentangan dengan versi bahasa Inggris aslinya, utamakan versi bahasa Inggris.

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

Peristiwa `LWLock:SubtransSLRU` dan `LWLock:SubtransBuffer` tunggu menunjukkan bahwa sesi sedang menunggu untuk mengakses cache sederhana yang paling tidak baru digunakan (SLRU) untuk informasi subtransaksi. Ini terjadi ketika menentukan visibilitas transaksi dan hubungan orang tua-anak.
+ `LWLock:SubtransSLRU`: Sebuah proses sedang menunggu untuk mengakses cache sederhana yang paling tidak baru digunakan (SLRU) untuk subtransaksi. Dalam RDS untuk PostgreSQL sebelum versi 13, acara tunggu ini dipanggil. `SubtransControlLock`
+ `LWLock:SubtransBuffer`: Sebuah proses I/O sedang menunggu buffer sederhana yang paling tidak baru digunakan (SLRU) untuk subtransaksi. Dalam RDS untuk PostgreSQL sebelum versi 13, acara tunggu ini dipanggil. `subtrans`

**Topics**
+ [Versi mesin yang didukung](#wait-event.lwlocksubtransslru.supported)
+ [Konteks](#wait-event.lwlocksubtransslru.context)
+ [Kemungkinan penyebab peningkatan peristiwa tunggu](#wait-event.lwlocksubtransslru.causes)
+ [Tindakan](#wait-event.lwlocksubtransslru.actions)

## Versi mesin yang didukung
<a name="wait-event.lwlocksubtransslru.supported"></a>

Informasi peristiwa tunggu ini didukung untuk semua versi RDS for PostgreSQL.

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

**Memahami subtransaksi** — Subtransaksi adalah transaksi dalam transaksi di PostgreSQL. Ini juga dikenal sebagai transaksi bersarang.

Subtransaksi biasanya dibuat saat Anda menggunakan:
+ `SAVEPOINT`perintah
+ Blok pengecualian (`BEGIN/EXCEPTION/END`)

Subtransaksi memungkinkan Anda memutar kembali bagian transaksi tanpa mempengaruhi seluruh transaksi. Ini memberi Anda kontrol halus atas manajemen transaksi.

**Detail implementasi** - PostgreSQL mengimplementasikan subtransaksi sebagai struktur bersarang dalam transaksi utama. Setiap subtransaksi mendapatkan ID transaksinya sendiri.

Aspek implementasi kunci:
+ ID transaksi dilacak di `pg_xact`
+ Parent-child hubungan disimpan dalam `pg_subtrans` subdirektori di bawah `PGDATA`
+ Setiap sesi database dapat mempertahankan hingga `64` subtransaksi aktif
+ Melebihi batas ini menyebabkan luapan subtransaksi, yang mengharuskan mengakses cache sederhana yang paling tidak baru digunakan (SLRU) untuk informasi subtransaksi

## Kemungkinan penyebab peningkatan peristiwa tunggu
<a name="wait-event.lwlocksubtransslru.causes"></a>

Penyebab umum pertengkaran SLRU subtransaksi meliputi:
+ **Penggunaan berlebihan penanganan SAVEPOINT dan EXCEPTION** — PL/pgSQL prosedur dengan `EXCEPTION` handler secara otomatis membuat savepoint implisit, terlepas dari apakah pengecualian terjadi. Masing-masing `SAVEPOINT` memulai subtransaksi baru. Ketika satu transaksi mengakumulasi lebih dari 64 subtransaksi, itu memicu overflow SLRU subtransaksi.
+ **Konfigurasi driver dan ORM** — `SAVEPOINT` penggunaan dapat eksplisit dalam kode aplikasi atau implisit melalui konfigurasi driver. Banyak alat ORM dan kerangka kerja aplikasi yang umum digunakan mendukung transaksi bersarang secara native. Berikut adalah beberapa contoh umum:
  + Parameter driver JDBC`autosave`, jika disetel ke `always` atau`conservative`, menghasilkan savepoint sebelum setiap kueri.
  + Definisi transaksi Spring Framework saat disetel ke`propagation_nested`.
  + Rel saat `requires_new: true` diatur.
  + SQLAlchemy saat `session.begin_nested` digunakan.
  + Django ketika `atomic()` blok bersarang digunakan.
  + GORM saat `Savepoint` digunakan.
  + psqlodbc ketika pengaturan tingkat rollback diatur ke rollback tingkat pernyataan (misalnya,). `PROTOCOL=7.4-2`
+ **Beban kerja bersamaan yang tinggi dengan transaksi dan subtransaksi yang berjalan lama — Ketika overflow SLRU subtransaksi terjadi selama beban kerja** bersamaan yang tinggi dan transaksi serta subtransaksi yang berjalan lama, PostgreSQL mengalami peningkatan pertengkaran. Ini bermanifestasi sebagai peristiwa menunggu `LWLock:SubtransBuffer` dan `LWLock:SubtransSLRU` mengunci yang tinggi.

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

Kami merekomendasikan berbagai tindakan, tergantung pada penyebab peristiwa tunggu Anda. Beberapa tindakan memberikan bantuan segera, sementara yang lain memerlukan penyelidikan dan koreksi jangka panjang.

**Topics**
+ [Memantau penggunaan subtransaksi](#wait-event.lwlocksubtransslru.actions.monitor)
+ [Mengkonfigurasi parameter memori](#wait-event.lwlocksubtransslru.actions.memory)
+ [Long-term tindakan](#wait-event.lwlocksubtransslru.actions.longterm)

### Memantau penggunaan subtransaksi
<a name="wait-event.lwlocksubtransslru.actions.monitor"></a>

Untuk PostgreSQL versi 16.1 dan yang lebih baru, gunakan kueri berikut untuk memantau jumlah subtransaksi dan status overflow per backend. Kueri ini menggabungkan statistik backend dengan informasi aktivitas untuk menunjukkan proses mana yang menggunakan subtransaksi:

```
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;
```

Untuk PostgreSQL versi 13.3 dan yang lebih baru, pantau `pg_stat_slru` tampilan untuk tekanan cache subtransaction. Kueri SQL berikut mengambil statistik cache SLRU untuk komponen Subtrans:

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

`blks_read`Nilai yang meningkat secara konsisten menunjukkan akses disk yang sering untuk subtransaksi yang tidak di-cache, menandakan potensi tekanan cache SLRU.

### Mengkonfigurasi parameter memori
<a name="wait-event.lwlocksubtransslru.actions.memory"></a>

Untuk PostgreSQL 17.1 dan yang lebih baru, Anda dapat mengonfigurasi ukuran cache SLRU subtransaksi menggunakan parameter. `subtransaction_buffers` Contoh konfigurasi berikut menunjukkan cara mengatur parameter buffer subtransaction:

```
subtransaction_buffers = 128
```

Parameter ini menentukan jumlah memori bersama yang digunakan untuk cache konten subtransaksi ()`pg_subtrans`. Ketika ditentukan tanpa unit, nilai mewakili blok `BLCKSZ` byte, biasanya 8KB masing-masing. Misalnya, mengatur nilai ke 128 mengalokasikan 1MB (128 \* 8kB) memori untuk cache subtransaksi.

**catatan**  
Anda dapat mengatur parameter ini di tingkat cluster sehingga semua instance tetap konsisten. Uji dan sesuaikan nilainya agar sesuai dengan persyaratan beban kerja spesifik dan kelas instance Anda. Anda harus me-reboot instance writer agar perubahan parameter diterapkan.

### Long-term tindakan
<a name="wait-event.lwlocksubtransslru.actions.longterm"></a>
+ **Periksa kode dan konfigurasi aplikasi** — Tinjau kode aplikasi dan konfigurasi driver database Anda untuk penggunaan eksplisit dan implisit serta `SAVEPOINT` penggunaan subtransaksi secara umum. Identifikasi transaksi yang berpotensi menghasilkan lebih dari 64 subtransaksi.
+ **Kurangi penggunaan savepoint** — Minimalkan penggunaan savepoint dalam transaksi Anda:
  + Tinjau PL/pgSQL prosedur dan fungsi dengan blok EXCEPTION. Blok EXCEPTION secara otomatis membuat savepoint implisit, yang dapat berkontribusi pada overflow subtransaksi. Setiap klausa EXCEPTION membuat subtransaksi, terlepas dari apakah pengecualian benar-benar terjadi selama eksekusi.  
**Example**  

    Contoh 1: Penggunaan blok PENGECUALIAN yang bermasalah

    Contoh kode berikut menunjukkan penggunaan blok EXCEPTION bermasalah yang menciptakan beberapa subtransaksi:

    ```
    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;
    ```

    Contoh kode yang ditingkatkan berikut mengurangi penggunaan subtransaksi dengan menggunakan UPSERT alih-alih penanganan pengecualian:

    ```
    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**  

    Contoh 2: Penangan pengecualian KETAT

    Contoh kode berikut menunjukkan penanganan EXCEPTION bermasalah dengan 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;
    ```

    Contoh kode yang ditingkatkan berikut menghindari subtransaksi dengan menggunakan IF NOT FOUND alih-alih penanganan pengecualian:

    ```
    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;
    ```
  + Driver JDBC — `autosave` Parameter, jika diatur ke `always` atau`conservative`, menghasilkan savepoint sebelum setiap kueri. Evaluasi apakah `never` pengaturan akan dapat diterima untuk aplikasi Anda.
  + Driver PostgreSQL ODBC (psqlodBC) - Pengaturan level rollback (untuk rollback tingkat pernyataan) menciptakan savepoint implisit untuk mengaktifkan fungsionalitas rollback pernyataan. Evaluasi apakah tingkat transaksi atau tidak ada rollback dapat diterima untuk aplikasi Anda. 
  + Periksa konfigurasi transaksi ORM
  + Pertimbangkan strategi penanganan kesalahan alternatif yang tidak memerlukan savepoint
+ **Optimalkan desain transaksi** — Merestrukturisasi transaksi untuk menghindari penyarangan yang berlebihan dan mengurangi kemungkinan kondisi overflow subtransaksi.
+ **Mengurangi transaksi jangka panjang** — Long-running transaksi dapat memperburuk masalah subtransaksi dengan memegang informasi subtransaksi lebih lama. Pantau metrik Performance Insights dan konfigurasikan `idle_in_transaction_session_timeout` parameter untuk menghentikan transaksi idle secara otomatis.
+ Monitor Metrik Performance Insights — Melacak metrik termasuk `idle_in_transaction_count` (jumlah sesi dalam keadaan idle dalam keadaan transaksi) dan `idle_in_transaction_max_time` (durasi transaksi idle yang berjalan paling lama) untuk mendeteksi transaksi yang berjalan lama.
+ Konfigurasi `idle_in_transaction_session_timeout` - Tetapkan parameter ini di grup parameter Anda untuk secara otomatis menghentikan transaksi idle setelah durasi yang ditentukan.
+ Pemantauan proaktif — Memantau kejadian tinggi `LWLock:SubtransBuffer` dan `LWLock:SubtransSLRU` menunggu peristiwa untuk mendeteksi pertikaian terkait subtransaksi sebelum menjadi kritis.