Pengantar
Baru-baru ini, seorang kolega saya datang kepada saya dengan putus asa karena dia telah mengeluarkan pernyataan pembaruan tanpa klausa WHERE pada tabel aplikasi utama. Implikasinya di ujung depan akan mengerikan, jadi dia datang kepada saya secara langsung karena dia sangat membutuhkan bantuan untuk membalikkan situasi dengan cara apa pun sebelum email dan eskalasi mulai mengalir.
Ketika kami melihat situasinya, kami menemukan bahwa perubahan belum diterapkan di database sekunder. Dalam kebanyakan kasus, jeda antara database primer dan sekunder kami adalah dua puluh menit (kami memiliki sedikit keterkejutan untuk menghindari masalah kinerja). Karena rekan saya meminta bantuan segera setelah menyadari kesalahan, kami dapat memulihkan data dari database sekunder. Saya menjelaskan nilai penundaan seperti itu di artikel ini .
Tinjauan Skenario
Skenario yang saya jelaskan di atas bukanlah hal yang aneh. Salah satu alasan mengapa ini terjadi pada pengguna SQL Server biasa adalah karena SQL Server menggunakan apa yang disebut Transaksi Implisit. Transaksi Implisit dimatikan secara default, yang berarti SQL Server tidak mengharapkan Anda untuk mengeluarkan pernyataan COMMIT TRANSACTION di akhir setiap pernyataan. Akibatnya, setiap pernyataan dilakukan secara otomatis. Ini nyaman dan membantu menghindari situasi di mana sesi yang belum dilakukan akhirnya mengunci sumber daya dan memengaruhi kinerja. Brent Ozar memberikan rincian lebih lanjut tentang implikasi kinerja dari TRANSAKSI IMPLISIT =AKTIF.
Namun, kelemahan kecil dari konfigurasi ini (IMPLICIT TRANSACTIONS =OFF) adalah bahwa pengguna tidak memiliki kesempatan untuk memikirkan kembali pernyataan dan mengeluarkan ROLLBACK yang sangat umum di Oracle. Gambar 1 menunjukkan opsi kueri ANSI yang tersedia di SQL Server Management Studio.
Gbr. 1 Default ANSI di SQL Server Management Studio
Menggunakan Transaksi Implisit
Intinya, masalah yang kami hadapi dalam konfigurasi default ini atau alat klien kami yang paling diinginkan adalah bahwa kami tidak dapat ROLLBACK setelah kami mengeksekusi pernyataan SQL. Kami dapat menghindari ini dengan mengaktifkan TRANSAKSI IMPLISIT di sesi kami. Ini akan memberi kita kesempatan untuk melakukan ROLLBACK transaksi jika kita perlu. Gbr. 2 dan Gbr. 4 menunjukkan kepada kita bahwa kita dapat mengaktifkan pengaturan ini hanya untuk satu sesi, meskipun ini tidak menghilangkan risiko sesi pengguna memblokir sesi lain jika ROLLBACK atau COMMIT tidak dikeluarkan.
Gbr. 2 TRANSAKSI IMPLISIT DALAM Satu Sesi
-- Listing 1: UPDATE Table TAB2 with IMPLICIT_TRANSACTIONS ON SET IMPLICIT_TRANSACTIONS ON DECLARE @IMPLICIT_TRANSACTIONS VARCHAR(3) = 'OFF'; IF ( (2 & @@OPTIONS) = 2 ) SET @IMPLICIT_TRANSACTIONS = 'ON'; SELECT @IMPLICIT_TRANSACTIONS AS IMPLICIT_TRANSACTIONS; USE KTrain GO SELECT * FROM Tab2; GO UPDATE TAB2 SET countryCode='SA' -- WHERE fname='Joyce'; GO SELECT * FROM Tab2; GO
Gbr. 3 Semua Baris Diperbarui
Untuk mengilustrasikan solusi yang dijelaskan di sini, mari kita lihat kode SQL di Daftar 1. Mari kita asumsikan bahwa pengguna SQL Server biasa, pengembang junior, telah diberikan satu set skrip untuk dieksekusi dalam kondisi tertentu . Dalam skrip, klausa WHERE telah dikomentari karena diharapkan setiap kali mereka mengeksekusi skrip ini, mereka harus mengubah predikat. Tentu saja, ini adalah kasus penggunaan yang sederhana dan risikonya dapat diatasi dengan beberapa cara, tetapi kami hanya ingin menunjukkan kemungkinan melakukan ROLLBACK.
Ingat bahwa kita telah mengaktifkan TRANSAKSI IMPLIKIT, jadi ketika kita menjalankan pernyataan ini, SQL Server akan mengharapkan kita untuk melakukan COMMIT atau ROLLBACK transaksi. Niat pengembang adalah untuk memperbarui kode negara Joyce Afam ke 'SA' karena dia berimigrasi ke Afrika Selatan. Gambar 3 menunjukkan kepada kita bahwa pengembang ketika mencoba melakukan ini, secara tidak sengaja memperbarui semua baris dengan nilai SA sebagai kode negara . Mereka memperhatikan ini dan mengeluarkan ROLLBACK.
Gbr. 4 Mengeluarkan ROLLBACK
Gbr. 5 TRANSAKSI IMPLISIT DI Sesi Lain
Namun, di sesi lain di mana kami belum mengaktifkan TRANSAKSI IMPLISIT, kami menemukan bahwa pengembang tidak dapat memulihkan dari kesalahan mereka. Mereka tidak berhasil mengeluarkan ROLLBACK dalam kasus ini. Pemulihan kemudian akan memerlukan pemulihan data.
Gbr. 6 ROLLBACK tidak Mungkin tanpa TRANSAKSI IMPLIS ON
Menggunakan Transaksi Eksplisit
Pendekatan lain untuk mencapai efek yang sama adalah dengan menyertakan DML dalam transaksi dengan secara eksplisit menyatakan BEGIN TRAN. Sekali lagi, sangat penting untuk menyelesaikan transaksi – dengan menggunakan COMMIT atau ROLLBACK. Dalam konteks diskusi ini, kami mengeluarkan ROLLBACK karena kami menyadari bahwa ada kesalahan dalam kode.
-- Listing 2: UPDATE Table TAB2 with Explicit Transaction BEGIN TRAN GO USE KTrain GO SELECT * FROM Tab2; GO UPDATE TAB2 SET countryCode='GH' -- WHERE fname='Joyce'; GO SELECT * FROM Tab2; GO ROLLBACK; SELECT * FROM Tab2; GO - Listing 3: Corrected UPDATE Statement BEGIN TRAN GO USE KTrain GO SELECT * FROM Tab2; GO UPDATE TAB2 SET countryCode='SA' WHERE fname='Joyce'; GO SELECT * FROM Tab2; GO
Kesimpulan
Dalam artikel ini, kami telah membahas secara singkat solusi yang baik untuk menciptakan peluang ROLLBACK dan dengan demikian mengurangi kesalahan pengguna akibat DML yang salah. Kami juga telah menyoroti risiko utama dari pendekatan ini, yaitu pemblokiran yang tidak disengaja. DBA dapat memulai penyelidikan tentang kemungkinan adanya risiko ini dengan menanyakan sys.dm_tran_session_transactions, sys.dm_tran_locks , dan objek manajemen dinamis serupa.
Referensi
Memperbaiki Kehilangan Data Menggunakan Pengiriman Log dengan Pemulihan Tertunda
Tetapkan Transaksi Implisit
Menetapkan Transaksi Implisit sebagai Ide Buruk
DMV untuk Transaksi