Terjemahan disediakan oleh mesin penerjemah. Jika konten terjemahan yang diberikan bertentangan dengan versi bahasa Inggris aslinya, utamakan versi bahasa Inggris.
Mengelola pertentangan TOAST OID di
TOAST (The Oversized-Attribute Storage Technique) adalah fitur PostgreSQL yang dirancang untuk menangani nilai data besar yang melebihi ukuran blok database 8KB yang khas. PostgreSQL tidak mengizinkan baris fisik menjangkau beberapa blok. Ukuran blok bertindak sebagai batas atas pada ukuran baris. TOAST mengatasi batasan ini dengan membagi nilai bidang besar menjadi potongan yang lebih kecil. Ini menyimpannya secara terpisah dalam tabel TOAST khusus yang terhubung ke tabel utama. Untuk informasi selengkapnya, lihat mekanisme penyimpanan PostgreSQL TOAST
Memahami operasi TOAST
TOAST melakukan kompresi dan menyimpan nilai bidang besar di luar jalur. TOAST memberikan OID unik (Object Identifier) untuk setiap potongan data besar yang disimpan dalam tabel TOAST. Tabel utama menyimpan ID nilai TOAST dan ID relasi pada halaman untuk mereferensikan baris yang sesuai dalam tabel TOAST. Hal ini memungkinkan PostgreSQL untuk secara efisien menemukan dan mengelola potongan TOAST ini. Namun, seiring bertambahnya tabel TOAST, sistem berisiko melelahkan tersedia OIDs, yang menyebabkan penurunan kinerja dan potensi waktu henti karena penipisan OID.
Pengidentifikasi objek di TOAST
Object Identifier (OID) adalah pengidentifikasi unik seluruh sistem yang digunakan oleh PostgreSQL untuk referensi objek database seperti tabel, indeks, dan fungsi. Pengidentifikasi ini memainkan peran penting dalam operasi internal PostgreSQL, memungkinkan database untuk secara efisien menemukan dan mengelola objek.
Untuk tabel dengan kumpulan data yang memenuhi syarat untuk pemanggangan, PostgreSQL OIDs menetapkan untuk mengidentifikasi secara unik setiap potongan data berukuran besar yang disimpan dalam tabel TOAST terkait. Sistem mengaitkan setiap potongan dengan achunk_id, yang membantu PostgreSQL mengatur dan menemukan potongan ini secara efisien dalam tabel TOAST.
Mengidentifikasi tantangan kinerja
Manajemen OID PostgreSQL bergantung pada penghitung 32-bit global sehingga membungkus setelah menghasilkan 4 miliar nilai unik. Sementara cluster database berbagi penghitung ini, alokasi OID melibatkan dua langkah selama operasi TOAST:
-
Penghitung global untuk alokasi - Penghitung global memberikan OID baru di seluruh cluster.
-
Pencarian lokal untuk konflik - Tabel TOAST memastikan OID baru tidak bertentangan dengan yang OIDs sudah ada yang sudah digunakan dalam tabel tertentu.
Degradasi kinerja dapat terjadi ketika:
-
Tabel TOAST memiliki fragmentasi tinggi atau penggunaan OID padat, yang menyebabkan keterlambatan dalam menetapkan OID.
-
Sistem sering mengalokasikan dan menggunakan kembali OIDs di lingkungan dengan churn data tinggi atau tabel lebar yang menggunakan TOAST secara ekstensif.
Untuk informasi selengkapnya, lihat batas ukuran tabel PostgreSQL TOAST
Penghitung global menghasilkan OIDs dan membungkus sekitar setiap 4 miliar nilai, sehingga dari waktu ke waktu, sistem menghasilkan nilai yang sudah digunakan lagi. PostgreSQL mendeteksi itu dan mencoba lagi dengan OID berikutnya. INSERT yang lambat dapat terjadi jika ada nilai OID bekas yang sangat lama tanpa celah di tabel TOAST. Tantangan ini menjadi lebih terasa saat ruang OID terisi, yang mengarah ke penyisipan dan pembaruan yang lebih lambat.
Mengidentifikasi masalah
-
INSERTPernyataan sederhana membutuhkan waktu lebih lama dari biasanya dengan cara yang tidak konsisten dan acak. -
Penundaan hanya terjadi untuk
INSERTdanUPDATEpernyataan yang melibatkan operasi TOAST. -
Entri log berikut muncul di log PostgreSQL ketika sistem berjuang untuk menemukan tersedia di tabel TOAST: OIDs
LOG: still searching for an unused OID in relation "pg_toast_20815" DETAIL: OID candidates have been checked 1000000 times, but no unused OID has been found yet. -
Performance Insights menunjukkan tingginya jumlah sesi aktif rata-rata (AAS) yang terkait dengan
LWLock:buffer_iodan acaraLWLock:OidGenLocktunggu.Anda dapat menjalankan kueri SQL berikut untuk mengidentifikasi transaksi INSERT yang berjalan lama dengan peristiwa tunggu:
SELECT datname AS database_name, usename AS database_user, pid, now() - pg_stat_activity.xact_start AS transaction_duration, concat(wait_event_type, ':', wait_event) AS wait_event, substr(query, 1, 30) AS TRANSACTION, state FROM pg_stat_activity WHERE (now() - pg_stat_activity.xact_start) > INTERVAL '60 seconds' AND state IN ('active', 'idle in transaction', 'idle in transaction (aborted)', 'fastpath function call', 'disabled') AND pid <> pg_backend_pid() AND lower(query) LIKE '%insert%' ORDER BY transaction_duration DESC;Contoh hasil kueri yang menampilkan operasi INSERT dengan waktu tunggu yang diperpanjang:
database_name | database_user | pid | transaction_duration | wait_event | transaction | state ---------------+-----------------+-------+----------------------+---------------------+--------------------------------+-------- postgres | db_admin_user| 70965 | 00:10:19.484061 | LWLock:buffer_io | INSERT INTO "products" (......... | active postgres | db_admin_user| 69878 | 00:06:14.976037 | LWLock:buffer_io | INSERT INTO "products" (......... | active postgres | db_admin_user| 68937 | 00:05:13.942847 | : | INSERT INTO "products" (......... | active
Mengisolasi masalah
-
Uji sisipan kecil — Masukkan catatan yang lebih kecil dari
toast_tuple_targetambang batas. Ingat bahwa kompresi diterapkan sebelum penyimpanan TOAST. Jika ini beroperasi tanpa masalah kinerja, masalahnya terkait dengan operasi TOAST. -
Uji tabel baru - Buat tabel baru dengan struktur yang sama dan masukkan catatan yang lebih besar dari
toast_tuple_target. Jika ini berfungsi tanpa masalah, masalah dilokalkan ke alokasi OID tabel asli.
Rekomendasi
Pendekatan berikut dapat membantu menyelesaikan masalah pertentangan TOAST OID.
-
Pembersihan dan arsip data - Tinjau dan hapus data usang atau tidak perlu untuk dikosongkan untuk penggunaan di OIDs masa mendatang, atau mengarsipkan data. Pertimbangkan batasan berikut:
-
Skalabilitas terbatas, karena pembersihan di masa depan mungkin tidak selalu memungkinkan.
-
Kemungkinan operasi VACUUM yang berjalan lama untuk menghilangkan tupel mati yang dihasilkan.
-
-
Menulis ke tabel baru - Buat tabel baru untuk sisipan future dan gunakan
UNION ALLtampilan untuk menggabungkan data lama dan baru untuk kueri. Tampilan ini menyajikan data gabungan dari tabel lama dan baru, yang memungkinkan kueri untuk mengaksesnya sebagai satu tabel. Pertimbangkan batasan berikut:-
Pembaruan pada tabel lama mungkin masih menyebabkan kelelahan OID.
-
-
Partisi atau Shard - Partisi data tabel atau pecahan untuk skalabilitas dan kinerja yang lebih baik. Pertimbangkan batasan berikut:
-
Peningkatan kompleksitas dalam logika kueri dan pemeliharaan, potensi kebutuhan untuk perubahan aplikasi untuk menangani data yang dipartisi dengan benar.
-
Memantau
Menggunakan tabel sistem
Anda dapat menggunakan tabel sistem PostgreSQL untuk memantau pertumbuhan penggunaan OID.
Awas
Tergantung pada jumlah OIDs dalam tabel TOAST, mungkin perlu waktu untuk menyelesaikannya. Kami menyarankan Anda menjadwalkan pemantauan selama jam kerja untuk meminimalkan dampak.
Blok anonim berikut menghitung jumlah berbeda yang OIDs digunakan di setiap tabel TOAST dan menampilkan informasi tabel induk:
DO $$ DECLARE r record; o bigint; parent_table text; parent_schema text; BEGIN SET LOCAL client_min_messages TO notice; FOR r IN SELECT c.oid, c.oid::regclass AS toast_table FROM pg_class c WHERE c.relkind = 't' AND c.relowner != 10 LOOP -- Fetch the number of distinct used OIDs (chunk IDs) from the TOAST table EXECUTE 'SELECT COUNT(DISTINCT chunk_id) FROM ' || r.toast_table INTO o; -- If there are used OIDs, find the associated parent table and its schema IF o <> 0 THEN SELECT n.nspname, c.relname INTO parent_schema, parent_table FROM pg_class c JOIN pg_namespace n ON c.relnamespace = n.oid WHERE c.reltoastrelid = r.oid; -- Raise a concise NOTICE message RAISE NOTICE 'Parent schema: % | Parent table: % | Toast table: % | Number of used OIDs: %', parent_schema, parent_table, r.toast_table, TO_CHAR(o, 'FM9,999,999,999,999'); END IF; END LOOP; END $$;
Contoh output yang menampilkan statistik penggunaan OID dengan tabel TOAST:
NOTICE: Parent schema: public | Parent table: my_table | Toast table: pg_toast.pg_toast_16559 | Number of used OIDs: 45,623,317 NOTICE: Parent schema: public | Parent table: my_table1 | Toast table: pg_toast.pg_toast_45639925 | Number of used OIDs: 10,000 NOTICE: Parent schema: public | Parent table: my_table2 | Toast table: pg_toast.pg_toast_45649931 | Number of used OIDs: 1,000,000 DO
Blok anonim berikut mengambil OID maksimum yang ditetapkan untuk setiap tabel TOAST yang tidak kosong:
DO $$ DECLARE r record; o bigint; parent_table text; parent_schema text; BEGIN SET LOCAL client_min_messages TO notice; FOR r IN SELECT c.oid, c.oid::regclass AS toast_table FROM pg_class c WHERE c.relkind = 't' AND c.relowner != 10 LOOP -- Fetch the max(chunk_id) from the TOAST table EXECUTE 'SELECT max(chunk_id) FROM ' || r.toast_table INTO o; -- If there's at least one TOASTed chunk, find the associated parent table and its schema IF o IS NOT NULL THEN SELECT n.nspname, c.relname INTO parent_schema, parent_table FROM pg_class c JOIN pg_namespace n ON c.relnamespace = n.oid WHERE c.reltoastrelid = r.oid; -- Raise a concise NOTICE message RAISE NOTICE 'Parent schema: % | Parent table: % | Toast table: % | Max chunk_id: %', parent_schema, parent_table, r.toast_table, TO_CHAR(o, 'FM9,999,999,999,999'); END IF; END LOOP; END $$;
Contoh output menampilkan potongan maksimum IDs untuk tabel TOAST:
NOTICE: Parent schema: public | Parent table: my_table | Toast table: pg_toast.pg_toast_16559 | Max chunk_id: 45,639,907 NOTICE: Parent schema: public | Parent table: my_table1 | Toast table: pg_toast.pg_toast_45639925 | Max chunk_id: 45,649,929 NOTICE: Parent schema: public | Parent table: my_table2 | Toast table: pg_toast.pg_toast_45649931 | Max chunk_id: 46,649,935 DO
Menggunakan Performance Insights
Peristiwa tunggu LWLock:buffer_io dan LWLock:OidGenLock muncul di Performance Insights selama operasi yang memerlukan penetapan Object Identifiers () baru. OIDs Sesi Aktif Rata-Rata Tinggi (AAS) untuk acara ini biasanya menunjukkan pertengkaran selama penugasan OID dan manajemen sumber daya. Ini sangat umum di lingkungan dengan churn data tinggi, penggunaan data besar yang ekstensif, atau pembuatan objek yang sering.
LWLock:buffer_io
LWLock:buffer_ioadalah acara tunggu yang terjadi ketika sesi PostgreSQL I/O menunggu operasi pada buffer bersama selesai. Ini biasanya terjadi ketika database membaca data dari disk ke memori atau menulis halaman yang dimodifikasi dari memori ke disk. Peristiwa BufferIO tunggu memastikan konsistensi dengan mencegah beberapa proses mengakses atau memodifikasi buffer yang sama saat I/O operasi sedang berlangsung. Kejadian tinggi dari peristiwa tunggu ini dapat mengindikasikan kemacetan disk atau I/O aktivitas berlebihan dalam beban kerja database.
Selama operasi TOAST:
-
PostgreSQL OIDs mengalokasikan untuk objek besar dan memastikan keunikannya dengan memindai indeks tabel TOAST.
-
Indeks TOAST yang besar mungkin memerlukan akses beberapa halaman untuk memverifikasi keunikan OID. Ini menghasilkan peningkatan I/O disk, terutama ketika kumpulan buffer tidak dapat menyimpan semua halaman yang diperlukan.
Ukuran indeks secara langsung mempengaruhi jumlah halaman buffer yang perlu diakses selama operasi ini. Bahkan jika indeks tidak membengkak, ukurannya yang tipis dapat meningkatkan buffer I/O, terutama di lingkungan dengan konkurensi tinggi atau churn tinggi. Untuk informasi lebih lanjut, lihat:Bufferio LWLock wait event troubleshooting guide.
LWLock:OidGenLock
OidGenLockadalah peristiwa tunggu yang terjadi ketika sesi PostgreSQL sedang menunggu untuk mengalokasikan pengenal objek baru (OID). Kunci ini memastikan bahwa OIDs dihasilkan secara berurutan dan aman, memungkinkan hanya satu proses untuk menghasilkan OIDs pada satu waktu.
Selama operasi TOAST:
-
Alokasi OID untuk potongan dalam tabel TOAST - PostgreSQL menetapkan potongan dalam tabel OIDs TOAST saat mengelola catatan data besar. Setiap OID harus unik untuk mencegah konflik dalam katalog sistem.
-
Konkurensi tinggi — Karena akses ke generator OID berurutan, ketika beberapa sesi secara bersamaan membuat objek yang membutuhkan OIDs, pertengkaran dapat terjadi.
OidGenLockIni meningkatkan kemungkinan sesi menunggu alokasi OID selesai. -
Ketergantungan pada akses katalog sistem — Mengalokasikan OIDs memerlukan pembaruan ke tabel katalog sistem bersama seperti dan.
pg_classpg_typeJika tabel ini mengalami aktivitas berat (karena operasi DDL yang sering), itu dapat meningkatkan pertentangan kunci untuk.OidGenLock -
Permintaan alokasi OID yang tinggi - TOAST beban kerja yang berat dengan catatan data yang besar memerlukan alokasi OID yang konstan, meningkatkan perselisihan.
Faktor tambahan yang meningkatkan pertentangan OID:
-
Pembuatan objek yang sering - Beban kerja yang sering membuat dan menjatuhkan objek, seperti tabel sementara, memperkuat pertentangan pada penghitung OID global.
-
Penguncian penghitung global - Penghitung OID global diakses secara serial untuk memastikan keunikan, menciptakan satu titik pertikaian di lingkungan konkurensi tinggi.