Terjemahan disediakan oleh mesin penerjemah. Jika konten terjemahan yang diberikan bertentangan dengan versi bahasa Inggris aslinya, utamakan versi bahasa Inggris.
IO: DataFileRead
Peristiwa IO:DataFileRead
terjadi saat koneksi menunggu proses backend untuk membaca halaman yang diperlukan dari penyimpanan karena halaman tidak tersedia dalam memori bersama.
Versi mesin yang didukung
Informasi peristiwa tunggu ini didukung untuk semua versi RDS for PostgreSQL.
Konteks
Semua kueri dan operasi manipulasi data (DML) mengakses halaman di pool buffer. Pernyataan yang dapat menimbulkan pembacaan mencakup SELECT
, UPDATE
, dan DELETE
. Misalnya, UPDATE
dapat membaca halaman dari tabel atau indeks. Jika halaman yang diminta atau diperbarui tidak berada dalam pool buffer bersama, pembacaan ini dapat mengarah ke peristiwa IO:DataFileRead
.
Karena bersifat terbatas, pool buffer bersama dapat menjadi penuh. Dalam hal ini, permintaan untuk halaman yang tidak berada dalam memori akan memaksa basis data untuk membaca blok dari disk. Jika peristiwa IO:DataFileRead
sering terjadi, pool buffer bersama mungkin terlalu kecil untuk mengakomodasi beban kerja Anda. Masalah ini bersifat akut untuk kueri
yang membaca sejumlah besar baris yang tidak dapat ditampung pool buffer. Untuk informasi selengkapnya tentang pool buffer, lihat Resource ConsumptionSELECT
Kemungkinan penyebab peningkatan peristiwa tunggu
Penyebab umum peristiwa IO:DataFileRead
mencakup:
- Lonjakan koneksi
-
Anda mungkin menemukan beberapa koneksi yang menghasilkan jumlah acara IO: DataFileRead wait yang sama. Dalam hal ini, lonjakan (peningkatan tiba-tiba dan besar) dalam peristiwa
IO:DataFileRead
dapat terjadi. - Pernyataan SELECT dan DML yang melakukan pemindaian berurutan
-
Aplikasi Anda mungkin melakukan operasi baru. Atau, operasi yang ada mungkin berubah karena rencana eksekusi baru. Dalam kasus ini, cari tabel (terutama tabel besar) yang memiliki nilai
seq_scan
yang lebih besar. Temukan tabel ini dengan membuat kueripg_stat_user_tables
. Untuk melacak kueri yang menghasilkan lebih banyak operasi baca, gunakan ekstensipg_stat_statements
. - CTAS dan CREATE INDEX untuk set data besar
-
CTAS adalah pernyataan
CREATE TABLE AS SELECT
. Jika Anda menjalankan CTAS menggunakan set data besar sebagai sumber, atau membuat indeks pada tabel besar, maka peristiwaIO:DataFileRead
dapat terjadi. Saat Anda membuat indeks, basis data mungkin perlu membaca seluruh objek menggunakan pemindaian berurutan. CTAS menghasilkan pembacaanIO:DataFile
saat halaman tidak ada dalam memori. - Beberapa pekerja vakum berjalan pada waktu yang sama
-
Pekerja vakum dapat dipicu secara manual atau otomatis. Sebaiknya adopsi strategi vakum yang agresif. Namun, saat tabel memiliki banyak baris yang diperbarui atau dihapus, peristiwa tunggu
IO:DataFileRead
bertambah. Setelah ruang diklaim kembali, waktu vakum yang dihabiskan padaIO:DataFileRead
berkurang. - Menyerap data dalam jumlah besar
-
Saat aplikasi Anda menyerap data dalam jumlah besar, operasi
ANALYZE
mungkin terjadi lebih sering. ProsesANALYZE
dapat dipicu oleh peluncur autovacuum atau diinvokasi secara manual.Operasi
ANALYZE
membaca subset tabel. Jumlah halaman yang harus dipindai dihitung dengan mengalikan 30 dengan nilaidefault_statistics_target
. Untuk informasi selengkapnya, lihat dokumentasi PostgreSQL. Parameter default_statistics_target
menerima nilai antara 1 hingga 10.000, dengan nilai default 100. - Kekurangan sumber daya
-
Jika bandwidth jaringan instans atau CPU dikonsumsi, peristiwa
IO:DataFileRead
mungkin terjadi lebih sering.
Tindakan
Kami merekomendasikan berbagai tindakan, tergantung pada penyebab peristiwa tunggu Anda.
Topik
Memeriksa filter predikat untuk kueri yang menghasilkan peristiwa tunggu
Asumsikan bahwa Anda mengidentifikasi kueri spesifik yang menghasilkan peristiwa tunggu IO:DataFileRead
. Anda mungkin mengidentifikasinya menggunakan teknik berikut:
-
Wawasan Performa
-
Tampilan katalog seperti yang disediakan oleh ekstensi
pg_stat_statements
-
Tampilan katalog
pg_stat_all_tables
, jika secara berkala menunjukkan peningkatan jumlah pembacaan fisik -
Tampilan
pg_statio_all_tables
, jika menunjukkan bahwa penghitung_read
meningkat
Sebaiknya Anda menentukan filter yang akan digunakan dalam predikat (klausa WHERE
) kueri ini. Ikuti pedoman berikut:
-
Jalankan perintah
EXPLAIN
. Pada output, identifikasi jenis pemindaian yang digunakan. Pemindaian berurutan tidak selalu menunjukkan adanya masalah. Kueri yang menggunakan pemindaian berurutan tentunya akan menghasilkan lebih banyak peristiwaIO:DataFileRead
jika dibandingkan dengan kueri yang menggunakan filter.Cari tahu apakah kolom yang tercantum dalam klausa
WHERE
diindeks. Jika tidak, coba buat indeks untuk kolom ini. Pendekatan ini mencegah pemindaian berurutan dan mengurangi peristiwaIO:DataFileRead
. Jika kueri memiliki filter yang bersifat membatasi dan masih menghasilkan pemindaian berurutan, evaluasi apakah indeks yang tepat sedang digunakan. -
Cari tahu apakah kueri mengakses tabel yang sangat besar. Dalam beberapa kasus, partisi tabel dapat meningkatkan performa, dengan memungkinkan kueri hanya membaca partisi yang diperlukan.
-
Periksa kardinalitas (jumlah total baris) dari operasi join Anda. Perhatikan seberapa membatasikah nilai yang Anda teruskan di filter untuk klausa
WHERE
Anda. Jika memungkinkan, setel kueri Anda untuk mengurangi jumlah baris yang diteruskan di setiap langkah rencana.
Minimalkan efek operasi pemeliharaan
Operasi pemeliharaan seperti VACUUM
dan ANALYZE
penting untuk dilakukan. Sebaiknya jangan dinonaktifkan karena peristiwa tunggu IO:DataFileRead
berkaitan dengan operasi pemeliharaan ini. Pendekatan berikut dapat meminimalkan efek operasi ini:
-
Jalankan operasi pemeliharaan secara manual di luar jam sibuk. Teknik ini mencegah basis data mencapai ambang batas untuk operasi otomatis.
-
Untuk tabel yang sangat besar, pertimbangkan untuk mempartisi tabel. Teknik ini mengurangi overhead operasi pemeliharaan. Basis data hanya mengakses partisi yang memerlukan pemeliharaan.
-
Saat Anda menyerap data dalam jumlah besar, coba nonaktifkan fitur analisis otomatis.
Fitur autovacuum secara otomatis dipicu untuk tabel saat rumus berikut benar.
pg_stat_user_tables.n_dead_tup > (pg_class.reltuples x autovacuum_vacuum_scale_factor) + autovacuum_vacuum_threshold
Tampilan pg_stat_user_tables
dan katalog pg_class
memiliki beberapa baris. Satu baris dapat sesuai dengan satu baris di tabel Anda. Rumus ini mengasumsikan bahwa reltuples
tersebut ditujukan untuk tabel tertentu. Parameter autovacuum_vacuum_scale_factor
(0.20 secara default) dan autovacuum_vacuum_threshold
(50 tuple secara default) biasanya diatur secara global untuk keseluruhan instans. Namun, Anda dapat menetapkan nilai berbeda untuk tabel tertentu.
Topik
Temukan tabel yang mengonsumsi ruang secara tidak perlu
Untuk menemukan tabel yang menghabiskan ruang secara tidak perlu, Anda dapat menggunakan fungsi dari ekstensi pgstattuple
PostgreSQL. Ekstensi (modul) ini tersedia secara default di semua instans DB RDS for PostgreSQL dan dapat diinstansiasi pada instans dengan perintah berikut.
CREATE EXTENSION pgstattuple;
Untuk informasi selengkapnya tentang ekstensi ini, lihat pgstattuple
Anda dapat memeriksa bloat tabel dan indeks di aplikasi Anda. Untuk informasi selengkapnya, lihat Mendiagnosis bloat tabel dan indeks.
Temukan tabel yang mengonsumsi ruang secara tidak perlu
Untuk menemukan indeks yang mengalami bloat dan memperkirakan jumlah ruang yang dikonsumsi secara tidak perlu pada tabel yang hak akses bacanya Anda miliki, Anda dapat menjalankan kueri berikut.
-- WARNING: rows with is_na = 't' are known to have bad statistics ("name" type is not supported). -- This query is compatible with PostgreSQL 8.2 and later. SELECT current_database(), nspname AS schemaname, tblname, idxname, bs*(relpages)::bigint AS real_size, bs*(relpages-est_pages)::bigint AS extra_size, 100 * (relpages-est_pages)::float / relpages AS extra_ratio, fillfactor, bs*(relpages-est_pages_ff) AS bloat_size, 100 * (relpages-est_pages_ff)::float / relpages AS bloat_ratio, is_na -- , 100-(sub.pst).avg_leaf_density, est_pages, index_tuple_hdr_bm, -- maxalign, pagehdr, nulldatawidth, nulldatahdrwidth, sub.reltuples, sub.relpages -- (DEBUG INFO) FROM ( SELECT coalesce(1 + ceil(reltuples/floor((bs-pageopqdata-pagehdr)/(4+nulldatahdrwidth)::float)), 0 -- ItemIdData size + computed avg size of a tuple (nulldatahdrwidth) ) AS est_pages, coalesce(1 + ceil(reltuples/floor((bs-pageopqdata-pagehdr)*fillfactor/(100*(4+nulldatahdrwidth)::float))), 0 ) AS est_pages_ff, bs, nspname, table_oid, tblname, idxname, relpages, fillfactor, is_na -- , stattuple.pgstatindex(quote_ident(nspname)||'.'||quote_ident(idxname)) AS pst, -- index_tuple_hdr_bm, maxalign, pagehdr, nulldatawidth, nulldatahdrwidth, reltuples -- (DEBUG INFO) FROM ( SELECT maxalign, bs, nspname, tblname, idxname, reltuples, relpages, relam, table_oid, fillfactor, ( index_tuple_hdr_bm + maxalign - CASE -- Add padding to the index tuple header to align on MAXALIGN WHEN index_tuple_hdr_bm%maxalign = 0 THEN maxalign ELSE index_tuple_hdr_bm%maxalign END + nulldatawidth + maxalign - CASE -- Add padding to the data to align on MAXALIGN WHEN nulldatawidth = 0 THEN 0 WHEN nulldatawidth::integer%maxalign = 0 THEN maxalign ELSE nulldatawidth::integer%maxalign END )::numeric AS nulldatahdrwidth, pagehdr, pageopqdata, is_na -- , index_tuple_hdr_bm, nulldatawidth -- (DEBUG INFO) FROM ( SELECT i.nspname, i.tblname, i.idxname, i.reltuples, i.relpages, i.relam, a.attrelid AS table_oid, current_setting('block_size')::numeric AS bs, fillfactor, CASE -- MAXALIGN: 4 on 32bits, 8 on 64bits (and mingw32 ?) WHEN version() ~ 'mingw32' OR version() ~ '64-bit|x86_64|ppc64|ia64|amd64' THEN 8 ELSE 4 END AS maxalign, /* per page header, fixed size: 20 for 7.X, 24 for others */ 24 AS pagehdr, /* per page btree opaque data */ 16 AS pageopqdata, /* per tuple header: add IndexAttributeBitMapData if some cols are null-able */ CASE WHEN max(coalesce(s.null_frac,0)) = 0 THEN 2 -- IndexTupleData size ELSE 2 + (( 32 + 8 - 1 ) / 8) -- IndexTupleData size + IndexAttributeBitMapData size ( max num filed per index + 8 - 1 /8) END AS index_tuple_hdr_bm, /* data len: we remove null values save space using it fractionnal part from stats */ sum( (1-coalesce(s.null_frac, 0)) * coalesce(s.avg_width, 1024)) AS nulldatawidth, max( CASE WHEN a.atttypid = 'pg_catalog.name'::regtype THEN 1 ELSE 0 END ) > 0 AS is_na FROM pg_attribute AS a JOIN ( SELECT nspname, tbl.relname AS tblname, idx.relname AS idxname, idx.reltuples, idx.relpages, idx.relam, indrelid, indexrelid, indkey::smallint[] AS attnum, coalesce(substring( array_to_string(idx.reloptions, ' ') from 'fillfactor=([0-9]+)')::smallint, 90) AS fillfactor FROM pg_index JOIN pg_class idx ON idx.oid=pg_index.indexrelid JOIN pg_class tbl ON tbl.oid=pg_index.indrelid JOIN pg_namespace ON pg_namespace.oid = idx.relnamespace WHERE pg_index.indisvalid AND tbl.relkind = 'r' AND idx.relpages > 0 ) AS i ON a.attrelid = i.indexrelid JOIN pg_stats AS s ON s.schemaname = i.nspname AND ((s.tablename = i.tblname AND s.attname = pg_catalog.pg_get_indexdef(a.attrelid, a.attnum, TRUE)) -- stats from tbl OR (s.tablename = i.idxname AND s.attname = a.attname)) -- stats from functional cols JOIN pg_type AS t ON a.atttypid = t.oid WHERE a.attnum > 0 GROUP BY 1, 2, 3, 4, 5, 6, 7, 8, 9 ) AS s1 ) AS s2 JOIN pg_am am ON s2.relam = am.oid WHERE am.amname = 'btree' ) AS sub -- WHERE NOT is_na ORDER BY 2,3,4;
Temukan tabel yang memenuhi syarat untuk di-autovacuum
Untuk menemukan tabel yang memenuhi syarat untuk di-autovacuum, jalankan kueri berikut.
--This query shows tables that need vacuuming and are eligible candidates. --The following query lists all tables that are due to be processed by autovacuum. -- During normal operation, this query should return very little. WITH vbt AS (SELECT setting AS autovacuum_vacuum_threshold FROM pg_settings WHERE name = 'autovacuum_vacuum_threshold') , vsf AS (SELECT setting AS autovacuum_vacuum_scale_factor FROM pg_settings WHERE name = 'autovacuum_vacuum_scale_factor') , fma AS (SELECT setting AS autovacuum_freeze_max_age FROM pg_settings WHERE name = 'autovacuum_freeze_max_age') , sto AS (SELECT opt_oid, split_part(setting, '=', 1) as param, split_part(setting, '=', 2) as value FROM (SELECT oid opt_oid, unnest(reloptions) setting FROM pg_class) opt) SELECT '"'||ns.nspname||'"."'||c.relname||'"' as relation , pg_size_pretty(pg_table_size(c.oid)) as table_size , age(relfrozenxid) as xid_age , coalesce(cfma.value::float, autovacuum_freeze_max_age::float) autovacuum_freeze_max_age , (coalesce(cvbt.value::float, autovacuum_vacuum_threshold::float) + coalesce(cvsf.value::float,autovacuum_vacuum_scale_factor::float) * c.reltuples) as autovacuum_vacuum_tuples , n_dead_tup as dead_tuples FROM pg_class c JOIN pg_namespace ns ON ns.oid = c.relnamespace JOIN pg_stat_all_tables stat ON stat.relid = c.oid JOIN vbt on (1=1) JOIN vsf ON (1=1) JOIN fma on (1=1) LEFT JOIN sto cvbt ON cvbt.param = 'autovacuum_vacuum_threshold' AND c.oid = cvbt.opt_oid LEFT JOIN sto cvsf ON cvsf.param = 'autovacuum_vacuum_scale_factor' AND c.oid = cvsf.opt_oid LEFT JOIN sto cfma ON cfma.param = 'autovacuum_freeze_max_age' AND c.oid = cfma.opt_oid WHERE c.relkind = 'r' AND nspname <> 'pg_catalog' AND ( age(relfrozenxid) >= coalesce(cfma.value::float, autovacuum_freeze_max_age::float) or coalesce(cvbt.value::float, autovacuum_vacuum_threshold::float) + coalesce(cvsf.value::float,autovacuum_vacuum_scale_factor::float) * c.reltuples <= n_dead_tup -- or 1 = 1 ) ORDER BY age(relfrozenxid) DESC;
Tangani jumlah koneksi yang tinggi
Saat Anda memantau Amazon CloudWatch, Anda mungkin menemukan bahwa DatabaseConnections
metrik melonjak. Peningkatan ini menunjukkan bertambahnya jumlah koneksi ke basis data Anda. Sebaiknya lakukan pendekatan berikut:
-
Batasi jumlah koneksi yang dapat dibuka aplikasi dengan setiap instans. Jika aplikasi Anda memiliki fitur pool koneksi tersemat, tetapkan jumlah koneksi yang wajar. Tentukan jumlahnya berdasarkan paralelisasi yang dapat secara efektif ditangani vCPU dalam instans Anda.
Jika aplikasi Anda tidak menggunakan fitur pool koneksi, coba gunakan Proksi Amazon RDS atau alternatifnya. Pendekatan ini memungkinkan aplikasi Anda membuka beberapa koneksi dengan penyeimbang beban. Penyeimbang selanjutnya dapat membuka jumlah koneksi yang terbatas dengan basis data. Karena lebih sedikit koneksi yang berjalan secara paralel, instans DB Anda melakukan lebih sedikit peralihan konteks di kernel. Kueri akan berjalan lebih cepat, sehingga mengurangi peristiwa tunggu. Untuk informasi selengkapnya, lihat Menggunakan Amazon RDS Proxy .
-
Jika memungkinkan, manfaatkan replika baca RDS for PostgreSQL. Saat aplikasi Anda menjalankan operasi hanya-baca, kirim permintaan ini ke replika pembaca. Teknik ini mengurangi tekanan I/O pada simpul primer (penulis).
-
Coba naikkan skala instans DB Anda. Kelas instans berkapasitas lebih tinggi memberikan memori lebih banyak, yang memberi RDS for PostgreSQL pool buffer bersama yang lebih besar untuk menampung halaman. Ukuran lebih besar juga memberikan instans DB lebih banyak vCPU untuk menangani koneksi. Lebih banyak vCPU akan sangat membantu saat operasi yang menghasilkan peristiwa tunggu
IO:DataFileRead
adalah operasi tulis.