Ini telah muncul beberapa kali baru-baru ini, baik di SO maupun di milis PostgreSQL.
TL;DR untuk dua poin terakhir Anda:
(a) Shared_buffers yang lebih besar mungkin menjadi alasan mengapa TRUNCATE lebih lambat di server CI. Konfigurasi fsync yang berbeda atau penggunaan media rotasi alih-alih SSD juga bisa menjadi penyebabnya.
(b) TRUNCATE
memiliki biaya tetap, tetapi tidak harus lebih lambat dari DELETE
, ditambah itu bekerja lebih banyak. Simak penjelasan detailnya berikut ini.
PERBARUI: Diskusi signifikan tentang kinerja pgsql muncul dari posting ini. Lihat utas ini.
PEMBARUAN 2: Perbaikan telah ditambahkan ke 9.2beta3 yang akan membantu dengan ini, lihat posting ini.
Penjelasan mendetail tentang TRUNCATE
vs DELETE FROM
:
Meskipun bukan ahli dalam topik tersebut, pemahaman saya adalah bahwa TRUNCATE
memiliki biaya per tabel yang hampir tetap, sedangkan DELETE
setidaknya O(n) untuk n baris; lebih buruk jika ada kunci asing yang merujuk ke tabel yang dihapus.
Saya selalu berasumsi bahwa biaya tetap dari TRUNCATE
lebih rendah dari biaya DELETE
di meja yang hampir kosong, tapi ini tidak benar sama sekali.
TRUNCATE table;
melakukan lebih dari DELETE FROM table;
Status database setelah TRUNCATE table
hampir sama seperti jika Anda menjalankan:
DELETE FROM table;
VACCUUM (FULL, ANALYZE) table;
(9.0+ saja, lihat catatan kaki)
... meskipun tentu saja TRUNCATE
tidak benar-benar mencapai efeknya dengan DELETE
dan VACUUM
.
Intinya DELETE
dan TRUNCATE
lakukan hal yang berbeda, jadi Anda tidak hanya membandingkan dua perintah dengan hasil yang sama.
A DELETE FROM table;
memungkinkan baris mati dan mengasapi tetap ada, memungkinkan indeks membawa entri mati, tidak memperbarui statistik tabel yang digunakan oleh perencana kueri, dll.
Sebuah TRUNCATE
memberi Anda tabel dan indeks yang benar-benar baru seolah-olah hanya CREATE
ed. Ini seperti Anda menghapus semua catatan, mengindeks ulang tabel dan melakukan VACUUM FULL
.
Jika Anda tidak peduli jika ada sisa makanan di tabel karena Anda akan pergi dan mengisinya kembali, Anda mungkin lebih baik menggunakan DELETE FROM table;
.
Karena Anda tidak menjalankan VACUUM
Anda akan menemukan bahwa baris mati dan entri indeks terakumulasi sebagai mengasapi yang harus dipindai kemudian diabaikan; ini memperlambat semua pertanyaan Anda. Jika pengujian Anda tidak benar-benar membuat dan menghapus banyak data yang mungkin tidak Anda perhatikan atau pedulikan, dan Anda selalu dapat melakukan VACUUM
atau dua setengah jalan melalui uji coba Anda jika Anda melakukannya. Lebih baik, biarkan pengaturan autovacuum yang agresif memastikan bahwa autovacuum melakukannya untuk Anda di latar belakang.
Anda masih dapat TRUNCATE
semua tabel Anda setelah whole test suite berjalan untuk memastikan tidak ada efek yang menumpuk di banyak proses. Pada 9.0 dan yang lebih baru, VACUUM (FULL, ANALYZE) table;
global di atas meja setidaknya sama baiknya jika tidak lebih baik, dan itu jauh lebih mudah.
IIRC Pg memiliki beberapa optimasi yang berarti mungkin menyadari ketika transaksi Anda adalah satu-satunya yang dapat melihat tabel dan segera menandai blok sebagai bebas. Dalam pengujian, ketika saya ingin membuat mengasapi, saya harus memiliki lebih dari satu koneksi bersamaan untuk melakukannya. Saya tidak akan mengandalkan ini.
DELETE FROM table;
sangat murah untuk meja kecil tanpa referensi f/k
Untuk DELETE
semua catatan dari tabel tanpa referensi kunci asing, semua Pg harus melakukan pemindaian tabel berurutan dan mengatur xmax
dari tupel yang ditemui. Ini adalah operasi yang sangat murah - pada dasarnya membaca linier dan menulis semi-linear. AFAIK tidak harus menyentuh indeks; mereka terus menunjuk ke tupel mati sampai mereka dibersihkan oleh VACUUM
nanti yang juga menandai blok dalam tabel yang hanya berisi tupel mati sebagai bebas.
DELETE
hanya menjadi mahal jika ada banyak catatan, jika ada banyak referensi kunci asing yang harus diperiksa, atau jika Anda menghitung tabel VACUUM (FULL, ANALYZE) table;
diperlukan untuk mencocokkan TRUNCATE
's dalam biaya DELETE
. Anda .
Dalam pengujian saya di sini, tabel DELETE FROM table;
biasanya 4x lebih cepat dari TRUNCATE
pada 0.5ms vs 2ms. Itu adalah DB pengujian pada SSD, berjalan dengan fsync=off
karena saya tidak peduli jika saya kehilangan semua data ini. Tentu saja, DELETE FROM table;
tidak melakukan semua pekerjaan yang sama, dan jika saya menindaklanjuti dengan tabel VACUUM (FULL, ANALYZE) table;
itu jauh lebih mahal 21ms, jadi DELETE
hanya sebuah kemenangan jika saya tidak benar-benar membutuhkan meja yang murni.
TRUNCATE table;
melakukan lebih banyak pekerjaan dengan biaya tetap dan tata graha daripada DELETE
Sebaliknya, sebuah TRUNCATE
harus melakukan banyak pekerjaan. Itu harus mengalokasikan file baru untuk tabel, tabel TOAST-nya jika ada, dan setiap indeks yang dimiliki tabel. Header harus ditulis ke dalam file-file itu dan katalog sistem mungkin perlu diperbarui juga (tidak yakin tentang hal itu, belum diperiksa). Itu kemudian harus mengganti file lama dengan yang baru atau menghapus yang lama, dan harus memastikan sistem file telah mengikuti perubahan dengan operasi sinkronisasi - fsync() atau serupa - yang biasanya mem-flush semua buffer ke disk . Saya tidak yakin apakah sinkronisasi dilewati jika Anda menjalankan dengan opsi (pemakan data) fsync=off
.
Baru-baru ini saya mengetahui bahwa TRUNCATE
juga harus membersihkan semua buffer PostgreSQL yang terkait dengan tabel lama. Ini bisa memakan banyak waktu dengan shared_buffers
yang besar . Saya menduga inilah mengapa ini lebih lambat di server CI Anda.
Saldo
Bagaimanapun, Anda dapat melihat bahwa TRUNCATE
tabel yang memiliki tabel TOAST terkait (sebagian besar dilakukan) dan beberapa indeks dapat memakan waktu beberapa saat. Tidak panjang, tapi lebih dari DELETE
dari meja yang hampir kosong.
Akibatnya, Anda mungkin lebih baik melakukan DELETE FROM table;
.
--
Catatan:pada DB sebelum 9.0, CLUSTER table_id_seq ON table; ANALYZE table;
atau VACUUM FULL ANALYZE table; REINDEX table;
akan menjadi setara lebih dekat dengan TRUNCATE
. VACUUM FULL
impl diubah menjadi yang jauh lebih baik di 9.0.