Jika saya memiliki UPDATE
pernyataan yang tidak benar-benar mengubah data apa pun (karena data sudah dalam keadaan diperbarui). Apakah ada manfaat kinerja dalam memberikan tanda centang pada WHERE
klausa untuk mencegah pembaruan?
Misalnya akan ada perbedaan dalam kecepatan eksekusi antara UPDATE 1 dan UPDATE 2 sebagai berikut:
CREATE TABLE MyTable (ID int PRIMARY KEY, Value int);
INSERT INTO MyTable (ID, Value)
VALUES
(1, 1),
(2, 2),
(3, 3);
-- UPDATE 1
UPDATE MyTable
SET
Value = 2
WHERE
ID = 2
AND Value <> 2;
SELECT @@ROWCOUNT;
-- UPDATE 2
UPDATE MyTable
SET
Value = 2
WHERE
ID = 2;
SELECT @@ROWCOUNT;
DROP TABLE MyTable;
Alasan saya bertanya adalah bahwa saya perlu jumlah baris untuk memasukkan baris yang tidak berubah jadi saya tahu apakah akan melakukan insert jika ID tidak ada. Karena itu saya menggunakan formulir UPDATE 2. Jika ada manfaat kinerja untuk menggunakan formulir UPDATE 1, apakah mungkin untuk mendapatkan jumlah baris yang saya butuhkan?
sql-server
query-performance
update
Martin Brown
sumber
sumber
Jawaban:
Pasti ada karena ada sedikit perbedaan kinerja karena UPDATE 1 :
Namun, berapa banyak perbedaan yang perlu diukur oleh Anda pada sistem Anda dengan skema Anda, dan data, dan beban sistem. Ada beberapa faktor yang berperan dalam seberapa besar dampak UPDATE yang tidak memperbarui:
UPDATE TableName SET Field1 = Field1
, maka Pemicu Pembaruan akan menyala dan menunjukkan bahwa bidang telah diperbarui (jika Anda memeriksa menggunakan fungsi UPDATE () atau COLUMNS_UPDATED ), dan bidang di keduanyaINSERTED
danDELETED
tabel adalah nilai yang sama.Juga, bagian ringkasan berikut ini ditemukan dalam artikel Paul White, Dampak Pembaruan yang Tidak Memperbarui (seperti dicatat oleh @spaghettidba dalam komentar atas jawabannya):
Harap diingat (terutama jika Anda tidak mengikuti tautan untuk melihat artikel lengkap Paul), dua hal berikut:
Pembaruan yang tidak memperbarui masih memiliki beberapa aktivitas log, menunjukkan bahwa suatu transaksi dimulai dan berakhir. Hanya saja tidak ada modifikasi data yang terjadi (yang masih merupakan penghematan yang baik).
Seperti yang saya nyatakan di atas, Anda perlu menguji pada sistem Anda. Gunakan pertanyaan penelitian yang sama yang digunakan Paulus dan lihat apakah Anda mendapatkan hasil yang sama. Saya melihat hasil yang sedikit berbeda pada sistem saya daripada apa yang ditampilkan dalam artikel. Masih tidak ada halaman kotor untuk ditulis, tetapi sedikit lebih banyak aktivitas log.
Secara sederhana, jika Anda hanya berurusan dengan satu baris, Anda dapat melakukan hal berikut:
Untuk beberapa baris, Anda bisa mendapatkan informasi yang diperlukan untuk membuat keputusan dengan menggunakan
OUTPUT
klausa. Dengan menangkap secara tepat baris apa yang diperbarui, maka Anda dapat mempersempit item untuk mencari tahu perbedaan antara tidak memperbarui baris yang tidak ada dan tidak memperbarui baris yang ada tetapi tidak perlu pembaruan.Saya menunjukkan implementasi dasar dalam jawaban berikut:
Bagaimana cara menghindari menggunakan permintaan Gabung saat memasang beberapa data menggunakan parameter xml?
Metode yang ditunjukkan dalam jawaban itu tidak menyaring baris yang ada namun tidak perlu diperbarui. Bagian itu dapat ditambahkan, tetapi pertama-tama Anda harus menunjukkan dengan tepat di mana Anda mendapatkan dataset yang Anda gabungkan
MyTable
. Apakah mereka datang dari meja sementara? Parameter bernilai tabel (TVP)?PEMBARUAN 1:
Saya akhirnya dapat melakukan beberapa pengujian dan inilah yang saya temukan mengenai log transaksi dan penguncian. Pertama, skema untuk tabel:
Selanjutnya, tes memperbarui bidang ke nilai yang sudah dimilikinya:
Hasil:
Akhirnya, tes yang memfilter pembaruan karena nilai tidak berubah:
Hasil:
Seperti yang Anda lihat, tidak ada yang tertulis pada Log Transaksi ketika memfilter baris, sebagai lawan dari dua entri yang menandai awal dan akhir dari Transaksi. Dan meskipun benar bahwa kedua entri itu hampir tidak ada, mereka tetap sesuatu.
Juga, mengunci PAGE dan sumber daya KUNCI kurang membatasi ketika menyaring baris yang belum berubah. Jika tidak ada proses lain yang berinteraksi dengan tabel ini maka itu mungkin bukan masalah (tapi seberapa besar kemungkinannya, benar-benar?). Perlu diingat bahwa pengujian yang ditampilkan di salah satu blog tertaut (dan bahkan pengujian saya) secara implisit mengasumsikan bahwa tidak ada pertengkaran di atas meja karena tidak pernah menjadi bagian dari pengujian. Mengatakan bahwa pembaruan yang tidak diperbarui begitu ringan sehingga tidak perlu melakukan penyaringan perlu diambil dengan sebutir garam karena pengujian telah dilakukan, lebih atau kurang, dalam ruang hampa udara. Namun dalam Produksi, tabel ini kemungkinan besar tidak terisolasi. Tentu saja, bisa jadi sedikit penebangan dan kunci yang lebih ketat tidak menghasilkan efisiensi yang kurang. Jadi sumber informasi yang paling dapat diandalkan untuk menjawab pertanyaan ini? SQL Server. Secara khusus:Anda SQL Server. Ini akan menunjukkan kepada Anda metode mana yang lebih baik untuk sistem Anda :-).
PEMBARUAN 2:
Jika operasi di mana nilai baru sama dengan nilai saat ini (yaitu tidak ada pembaruan) keluar nomor operasi di mana nilai baru berbeda dan pembaruan diperlukan, maka pola berikut mungkin terbukti lebih baik, terutama jika ada banyak pertengkaran di atas meja. Idenya adalah melakukan yang sederhana
SELECT
dulu untuk mendapatkan nilai saat ini. Jika Anda tidak mendapatkan nilai, maka Anda memiliki jawaban tentangINSERT
. Jika Anda memiliki nilai, Anda dapat melakukan yang sederhanaIF
danUPDATE
hanya mengeluarkannya jika diperlukan.Hasil:
Jadi hanya ada 2 kunci yang diperoleh alih-alih 3, dan kedua kunci ini adalah Intent Shared, bukan Intent eXclusive atau Intent Update ( Kompatibilitas Kunci ). Perlu diingat bahwa setiap kunci yang diperoleh juga akan dilepaskan, setiap kunci benar-benar 2 operasi, jadi metode baru ini total 4 operasi, bukan 6 operasi dalam metode yang diusulkan sebelumnya. Mempertimbangkan operasi ini berjalan sekali setiap 15 ms (kira-kira, seperti yang dinyatakan oleh OP), yaitu sekitar 66 kali per detik. Jadi proposal asli berjumlah 396 operasi kunci / buka per detik, sementara metode baru ini hanya berjumlah 264 operasi kunci / buka kunci per detik dari kunci yang bahkan lebih ringan. Ini bukan jaminan kinerja yang luar biasa, tetapi tentu saja layak diuji :-).
sumber
Perkecil sedikit dan pikirkan gambar yang lebih besar. Di dunia nyata, apakah pernyataan pembaruan Anda benar-benar akan terlihat seperti ini:
Atau akan terlihat seperti ini:
Karena di dunia nyata, tabel memiliki banyak kolom. Itu berarti Anda harus membuat banyak logika aplikasi dinamis yang kompleks untuk membangun string dinamis, ATAU Anda harus menentukan konten sebelum dan sesudah setiap bidang, setiap saat.
Jika Anda membuat pernyataan pembaruan ini secara dinamis untuk setiap tabel, hanya melewati bidang yang sedang diperbarui, Anda dapat dengan cepat mengalami masalah polusi cache paket yang mirip dengan masalah ukuran parameter NHibernate dari beberapa tahun yang lalu. Lebih buruk lagi, jika Anda membuat pernyataan pembaruan dalam SQL Server (seperti dalam prosedur tersimpan), maka Anda akan membakar siklus CPU yang berharga karena SQL Server tidak terlalu efisien untuk menggabungkan string bersama dalam skala.
Karena kerumitan itu, biasanya tidak masuk akal untuk melakukan perbandingan baris-per-baris, bidang-per-bidang seperti ini saat Anda melakukan pembaruan. Pikirkan operasi berbasis set sebagai gantinya.
sumber
Anda bisa melihat peningkatan kinerja dalam melewatkan baris yang tidak perlu diperbarui hanya ketika jumlah baris besar (lebih sedikit logging, lebih sedikit halaman kotor untuk ditulis ke disk).
Saat berurusan dengan pembaruan satu baris seperti dalam kasus Anda, perbedaan kinerja benar-benar dapat diabaikan. Jika memperbarui baris dalam semua kasus memudahkan Anda, lakukanlah.
Untuk informasi lebih lanjut tentang topik ini, lihat Pembaruan Tidak Memperbarui oleh Paul White
sumber
Anda dapat menggabungkan pembaruan dan menyisipkan ke dalam satu pernyataan. Pada SQL Server, Anda bisa menggunakan pernyataan MERGE untuk melakukan pembaruan dan menyisipkan jika tidak ditemukan. Untuk MySQL, Anda dapat menggunakan INSERT ON DUPLICATE KEY UPDATE .
sumber
Alih-alih memeriksa nilai semua bidang, tidak bisakah Anda mendapatkan nilai hash menggunakan kolom yang Anda minati lalu membandingkannya dengan hash yang disimpan terhadap baris dalam tabel?
sumber