Saya memiliki pertanyaan terkait kinerja. Katakanlah saya memiliki pengguna dengan nama depan Michael. Ambil kueri berikut:
UPDATE users
SET first_name = 'Michael'
WHERE users.id = 123
Apakah kueri benar-benar menjalankan pembaruan, meskipun sedang diperbarui dengan nilai yang sama? Jika demikian, bagaimana saya mencegahnya terjadi?
postgresql
performance
update
postgresql-performance
OneSneakyMofo
sumber
sumber
Jawaban:
Karena model MVCC Postgres, dan sesuai dengan aturan SQL, sebuah
UPDATE
menulis versi baris baru untuk setiap baris yang tidak dikecualikan dalamWHERE
klausa.Ini memang memiliki dampak yang lebih atau kurang substansial pada kinerja, secara langsung dan tidak langsung. "Pembaruan kosong" memiliki biaya per baris yang sama dengan pembaruan lainnya. Mereka mengaktifkan pemicu (jika ada) seperti pembaruan lainnya, mereka harus log-WAL dan mereka menghasilkan baris mati membengkak tabel dan menyebabkan lebih banyak pekerjaan untuk
VACUUM
nanti seperti pembaruan lainnya.Entri indeks dan kolom TOASTed di mana tidak ada kolom yang terlibat yang diubah dapat tetap sama, tetapi itu berlaku untuk setiap baris yang diperbarui. Terkait:
Ini hampir selalu merupakan ide yang baik untuk mengecualikan pembaruan kosong tersebut (ketika ada kemungkinan itu terjadi). Anda tidak memberikan definisi tabel dalam pertanyaan Anda (yang selalu merupakan ide bagus). Kita harus menganggap
first_name
bisa NULL (yang tidak akan mengejutkan untuk "nama depan"), oleh karena itu kueri harus menggunakan perbandingan NULL-aman :Jika
first_name IS NULL
sebelum pembaruan, pengujian dengan hanyafirst_name <> 'Michael'
akan mengevaluasi ke NULL dan dengan demikian mengecualikan baris dari pembaruan. Kesalahan licik. Jika kolom didefinisikanNOT NULL
, gunakan pemeriksaan kesetaraan sederhana, karena itu sedikit lebih murah.Terkait:
sumber
Indexes entries and TOASTed columns where none of the involved columns are changed can stay the same
Tetapi bukankah mereka harus diperbarui untuk menunjuk ke lokasi barisan yang baru?rollback
, penanganan snapshot, manajemen kunci, WAL, dan apa yang tidak ...ORM seperti Ruby on Rail's menawarkan eksekusi yang ditangguhkan yang menandai catatan sebagai diubah (atau tidak) dan kemudian ketika diperlukan atau dipanggil, kemudian kirimkan perubahan ke database.
PostgreSQL adalah database dan bukan ORM. Ini akan menurunkan kinerja jika perlu waktu untuk memeriksa apakah nilai baru sama dengan nilai yang diperbarui dalam kueri Anda.
Karena itu akan memperbarui nilai terlepas dari apakah itu sama dengan nilai baru atau tidak.
Jika Anda ingin mencegah ini, Anda bisa menggunakan kode seperti yang disarankan Max Vernon dalam jawabannya.
sumber
Anda cukup menambahkan
where
klausa:Jika
first_name
didefinisikan sebagaiNOT NULL
,OR first_name IS NULL
bagian dapat dihapus.Kondisi:
dapat juga ditulis lebih elegan seperti (dalam jawaban Erwin):
sumber
NULL
@erwinDari sudut pandang basis data
Jawaban atas pertanyaan Anda adalah ya. Pembaruan akan berlangsung. Basis data tidak memeriksa nilai sebelumnya, hanya menetapkan nilai baru.
Karena ini terjadi dalam memori (dan hanya akan ditulis ke file data setelah komit dikeluarkan) kinerja tidak akan menjadi masalah.
Dari perspektif ORM
Biasanya Anda akan memiliki Obyek yang mewakili satu baris database (bisa jauh lebih kompleks dari itu, tetapi mari kita tetap sederhana). Objek ini dikelola dalam memori (pada tingkat server aplikasi) dan hanya versi terbaru dari objek yang akan benar-benar membuatnya ke database pada titik tertentu.
Itu mungkin menjelaskan perilaku yang berbeda.
Sekarang, jangan membandingkan kapal kargo dengan printer 3D. Fakta bahwa Anda dapat mengirim printer 3D menggunakan kapal barang tidak berarti bahwa mungkin ada jenis perbandingan di antara mereka.
Nikmati!
Saya harap ini menjelaskan beberapa konsep.
sumber