Database
 sql >> Teknologi Basis Data >  >> RDS >> Database

Sifat ACID dari Laporan &Transaksi

[ Lihat indeks untuk keseluruhan seri ]

Setiap programmer akan memberi tahu Anda bahwa menulis kode multi-utas yang aman bisa jadi sulit. Ini membutuhkan perhatian besar dan pemahaman yang baik tentang masalah teknis yang terlibat. Sebagai orang database, Anda mungkin berpikir bahwa kesulitan dan komplikasi semacam ini tidak berlaku saat menulis T-SQL. Jadi, mungkin agak mengejutkan untuk menyadari bahwa kode T-SQL juga rentan terhadap jenis kondisi balapan dan risiko integritas data lainnya yang paling sering dikaitkan dengan pemrograman multi-utas. Ini benar apakah kita berbicara tentang satu pernyataan T-SQL, atau sekelompok pernyataan yang terlampir dalam transaksi eksplisit.

Inti masalahnya adalah fakta bahwa sistem basis data memungkinkan banyak transaksi untuk dieksekusi pada saat yang bersamaan. Ini adalah keadaan yang terkenal (dan sangat diinginkan), namun banyak kode T-SQL produksi masih diam-diam mengasumsikan bahwa data yang mendasarinya tidak berubah selama pelaksanaan transaksi atau pernyataan DML tunggal seperti SELECT , INSERT , UPDATE , DELETE , atau MERGE .

Bahkan ketika pembuat kode menyadari kemungkinan efek dari perubahan data bersamaan, penggunaan transaksi eksplisit terlalu sering dianggap memberikan perlindungan lebih dari yang sebenarnya dibenarkan. Asumsi dan kesalahpahaman ini bisa jadi tidak kentara, dan tentu saja mampu menyesatkan bahkan praktisi database yang berpengalaman.

Sekarang, ada kasus di mana masalah ini tidak terlalu penting dalam arti praktis. Misalnya, database mungkin hanya-baca, atau mungkin ada jaminan asli . lainnya bahwa tidak ada orang lain yang akan mengubah data yang mendasarinya saat kami bekerja dengannya. Demikian pula, operasi yang dimaksud mungkin tidak memerlukan hasil yang persis benar; konsumen data kami mungkin sangat senang dengan hasil perkiraan (bahkan yang tidak mewakili status komitmen basis data di apa pun titik waktu).

Masalah Konkurensi

Pertanyaan tentang interferensi antara tugas-tugas yang dijalankan secara bersamaan adalah masalah yang umum bagi pengembang aplikasi yang bekerja dalam bahasa pemrograman seperti C# atau Java. Solusinya banyak dan beragam, tetapi umumnya melibatkan penggunaan operasi atom atau mendapatkan sumber daya yang saling eksklusif (seperti kunci ) saat operasi sensitif sedang berlangsung. Jika tindakan pencegahan yang tepat tidak dilakukan, kemungkinan hasilnya adalah data yang rusak, kesalahan, atau bahkan crash total.

Banyak konsep yang sama (misalnya operasi atom dan kunci) ada di dunia basis data, tetapi sayangnya mereka sering memiliki perbedaan arti yang penting . Kebanyakan orang database mengetahui sifat ACID dari transaksi database, di mana A adalah singkatan dari atomik . SQL Server juga menggunakan kunci (dan perangkat pengecualian bersama lainnya secara internal). Tak satu pun dari istilah-istilah ini cukup berarti seperti yang diharapkan oleh seorang programmer C# atau Java yang berpengalaman, dan banyak profesional database memiliki pemahaman yang membingungkan tentang topik ini juga (seperti pencarian cepat menggunakan mesin pencari favorit Anda akan bersaksi).

Untuk mengulangi, kadang-kadang masalah ini tidak akan menjadi perhatian praktis. Jika Anda menulis kueri untuk menghitung jumlah pesanan aktif dalam sistem basis data, seberapa penting jika hitungannya sedikit meleset? Atau apakah itu mencerminkan keadaan basis data di waktu lain?

Adalah umum bagi sistem nyata untuk membuat trade-off antara konkurensi dan konsistensi (bahkan jika perancang tidak menyadarinya pada saat itu – diinformasikan trade-off mungkin merupakan hewan yang lebih langka). Sistem nyata seringkali bekerja cukup baik , dengan anomali apa pun yang berumur pendek atau dianggap tidak penting. Pengguna yang melihat status yang tidak konsisten pada halaman web akan sering menyelesaikan masalah dengan menyegarkan halaman. Jika masalah dilaporkan, kemungkinan besar akan ditutup sebagai Tidak Dapat Direproduksi. Saya tidak mengatakan ini adalah keadaan yang diinginkan, hanya mengakui bahwa itu terjadi.

Namun demikian, sangat berguna untuk memahami masalah konkurensi pada tingkat mendasar. Menyadari mereka memungkinkan kita untuk menulis dengan benar (atau diinformasikan cukup benar) T-SQL sesuai kebutuhan. Lebih penting lagi, ini memungkinkan kita untuk menghindari penulisan T-SQL yang dapat membahayakan integritas logis data kita.

Tapi, SQL Server memberikan jaminan ACID!

Ya, memang, tetapi mereka tidak selalu seperti yang Anda harapkan, dan mereka tidak melindungi segalanya. Lebih sering daripada tidak, manusia membaca jauh lebih banyak tentang ACID daripada yang dibenarkan.

Komponen akronim ACID yang paling sering disalahpahami adalah kata-kata Atom, Konsisten, dan Terisolasi – kita akan membahasnya sebentar lagi. Yang lainnya, Tahan Lama , cukup intuitif selama Anda ingat itu hanya berlaku untuk persistent (dapat dipulihkan) pengguna data.

Dengan semua yang dikatakan, SQL Server 2014 mulai mengaburkan batas-batas properti Durable dengan pengenalan daya tahan tertunda umum dan daya tahan skema OLTP dalam memori saja. Saya menyebutkannya hanya untuk kelengkapan, kami tidak akan membahas fitur baru ini lebih lanjut. Mari kita beralih ke properti ACID yang lebih bermasalah:

Sifat Atom

Banyak bahasa pemrograman menyediakan operasi atom yang dapat digunakan untuk melindungi terhadap kondisi balapan dan efek konkurensi yang tidak diinginkan lainnya, di mana beberapa utas eksekusi dapat mengakses atau memodifikasi struktur data bersama. Untuk pengembang aplikasi, operasi atom dilengkapi dengan jaminan eksplisit isolasi lengkap dari efek pemrosesan bersamaan lainnya dalam program multi-utas.

Situasi analog muncul di dunia basis data, di mana beberapa kueri T-SQL secara bersamaan mengakses dan memodifikasi data bersama (yaitu basis data) dari utas yang berbeda. Perhatikan bahwa kita tidak berbicara tentang kueri paralel di sini; kueri utas tunggal biasa secara rutin dijadwalkan untuk dijalankan secara bersamaan dalam SQL Server pada utas pekerja terpisah.

Sayangnya, properti atom transaksi SQL hanya menjamin bahwa modifikasi data yang dilakukan dalam transaksi berhasil atau gagal sebagai satu unit . Tidak lebih dari itu. Jelas tidak ada jaminan isolasi penuh dari efek pemrosesan bersamaan lainnya. Perhatikan juga secara sepintas bahwa properti transaksi atom tidak mengatakan apa pun tentang jaminan apa pun tentang membaca data.

Pernyataan Tunggal

Juga tidak ada yang istimewa dari satu pernyataan di SQLServer. Di mana transaksi berisi eksplisit (BEGIN TRAN...COMMIT TRAN ) tidak ada, satu pernyataan DML masih dijalankan dalam transaksi komit otomatis. Jaminan ACID yang sama berlaku untuk satu pernyataan, dan batasan yang sama juga. Secara khusus, satu pernyataan datang tanpa jaminan khusus bahwa data tidak akan berubah saat sedang berlangsung.

Pertimbangkan kueri AdventureWorks mainan berikut:

SELECT
    TH.TransactionID,
    TH.ProductID,
    TH.ReferenceOrderID,
    TH.ReferenceOrderLineID,
    TH.TransactionDate,
    TH.TransactionType,
    TH.Quantity,
    TH.ActualCost
FROM Production.TransactionHistory AS TH
WHERE TH.ReferenceOrderID =
(
    SELECT TOP (1) 
        TH2.ReferenceOrderID
    FROM Production.TransactionHistory AS TH2
    WHERE TH2.TransactionType = N'P'
    ORDER BY 
        TH2.Quantity DESC,
        TH2.ReferenceOrderID ASC
);

Query tersebut dimaksudkan untuk menampilkan informasi tentang Order yang menduduki peringkat pertama berdasarkan Quantity. Rencana eksekusi adalah sebagai berikut:

Operasi utama dalam rencana ini adalah:

  1. Pindai tabel untuk menemukan baris dengan jenis transaksi yang diperlukan
  2. Temukan Order ID yang diurutkan paling tinggi menurut spesifikasi di subquery
  3. Temukan baris (dalam tabel yang sama) dengan ID Pesanan yang dipilih menggunakan indeks nonclustered
  4. Cari data kolom yang tersisa menggunakan indeks berkerumun

Sekarang bayangkan bahwa pengguna bersamaan memodifikasi Order 495, mengubah Jenis Transaksinya dari P ke W, dan melakukan perubahan itu ke database. Untungnya, modifikasi ini berjalan saat kueri kami melakukan operasi pengurutan (langkah 2).

Ketika pengurutan selesai, pencarian indeks pada langkah 3 menemukan baris dengan ID Pesanan yang dipilih (yang kebetulan adalah 495) dan Pencarian Kunci pada langkah 4 mengambil kolom yang tersisa dari tabel dasar (di mana Jenis Transaksi sekarang adalah W) .

Urutan peristiwa ini berarti kueri kami menghasilkan hasil yang tampaknya mustahil:

Alih-alih menemukan pesanan dengan jenis transaksi P sebagai kueri yang ditentukan, hasilnya menunjukkan jenis transaksi W.

Akar penyebabnya jelas:kueri kami secara implisit mengasumsikan data tidak dapat berubah saat kueri pernyataan tunggal kami sedang berlangsung. Jendela peluang dalam kasus ini relatif besar karena jenis pemblokiran, tetapi kondisi balapan yang sama dapat terjadi pada setiap tahap eksekusi kueri, secara umum. Tentu, risikonya biasanya lebih tinggi dengan peningkatan tingkat modifikasi bersamaan, tabel yang lebih besar, dan di mana operator pemblokiran muncul dalam rencana kueri.

Mitos persisten lainnya di area umum yang sama adalah bahwa MERGE lebih disukai daripada INSERT separate yang terpisah , UPDATE dan DELETE pernyataan karena pernyataan tunggal MERGE adalah atom. Itu omong kosong, tentu saja. Kami akan kembali ke penalaran semacam ini nanti di seri ini.

Pesan umum pada titik ini adalah bahwa kecuali langkah-langkah eksplisit diambil untuk memastikan sebaliknya, baris data dan entri indeks dapat berubah, berpindah posisi, atau hilang seluruhnya setiap saat selama proses eksekusi. Gambaran mental tentang perubahan konstan dan acak dalam database adalah gambaran yang baik untuk diingat saat menulis kueri T-SQL.

Properti Konsistensi

Kata kedua dari akronim ACID juga memiliki berbagai kemungkinan interpretasi. Dalam database SQL Server, Konsistensi berarti hanya bahwa transaksi meninggalkan database dalam keadaan yang tidak melanggar batasan aktif apa pun. Penting untuk sepenuhnya memahami betapa terbatasnya pernyataan itu:Satu-satunya jaminan ACID untuk integritas data dan konsistensi logis adalah yang disediakan oleh batasan aktif.

SQL Server menyediakan batasan batasan untuk menegakkan integritas logis, termasuk PRIMARY KEY , FOREIGN KEY , CHECK , UNIQUE , dan NOT NULL . Ini semua dijamin akan terpenuhi pada saat transaksi dilakukan. Selain itu, SQL Server menjamin fisik integritas database setiap saat, tentu saja.

Kendala bawaan tidak selalu cukup untuk menegakkan semua bisnis dan aturan integritas data yang kita inginkan. Sangat mungkin untuk berkreasi dengan fasilitas standar, tetapi fasilitas ini dengan cepat menjadi kompleks dan dapat mengakibatkan penyimpanan data duplikat.

Akibatnya, sebagian besar database nyata berisi setidaknya beberapa rutinitas T-SQL yang ditulis untuk menegakkan aturan tambahan, misalnya dalam prosedur dan pemicu tersimpan. Tanggung jawab untuk memastikan kode ini berfungsi dengan benar sepenuhnya berada di tangan pembuatnya – properti Consistency tidak memberikan perlindungan khusus.

Untuk menekankan poin ini, batasan semu yang ditulis dalam T-SQL harus bekerja dengan benar tidak peduli modifikasi konkuren apa yang mungkin terjadi. Pengembang aplikasi mungkin melindungi operasi sensitif seperti itu dengan pernyataan kunci. Hal terdekat yang dimiliki programmer T-SQL dengan fasilitas untuk prosedur tersimpan yang berisiko dan kode pemicu adalah sp_getapplock yang relatif jarang digunakan. prosedur tersimpan sistem. Itu tidak berarti bahwa itu adalah satu-satunya, atau bahkan pilihan yang lebih disukai, hanya saja itu ada dan dapat menjadi pilihan yang tepat dalam beberapa keadaan.

Properti Isolasi

Ini adalah sifat transaksi ACID yang paling sering disalahpahami.

Pada prinsipnya, benar-benar terisolasi transaksi dijalankan sebagai satu-satunya tugas yang dijalankan terhadap database selama masa pakainya. Transaksi lain hanya dapat dimulai setelah transaksi saat ini benar-benar selesai (yaitu berkomitmen atau dibatalkan). Dieksekusi dengan cara ini, sebuah transaksi akan benar-benar menjadi operasi atom , dalam arti yang ketat bahwa orang non-database akan menganggap frasa tersebut.

Dalam praktiknya, transaksi basis data beroperasi dengan tingkat isolasi ditentukan oleh tingkat isolasi transaksi yang efektif saat ini (yang berlaku sama untuk pernyataan yang berdiri sendiri, ingat). Kompromi ini (derajat isolasi) adalah konsekuensi praktis dari pertukaran antara konkurensi dan kebenaran yang disebutkan sebelumnya. Sebuah sistem yang benar-benar memproses transaksi satu per satu, tanpa tumpang tindih waktu, akan memberikan isolasi lengkap tetapi throughput sistem secara keseluruhan kemungkinan akan buruk.

Lain kali

Bagian selanjutnya dalam seri ini akan melanjutkan pemeriksaan masalah konkurensi, properti ACID, dan isolasi transaksi dengan tampilan mendetail pada tingkat isolasi serial, contoh lain dari sesuatu yang mungkin tidak seperti yang Anda pikirkan.

[ Lihat indeks untuk keseluruhan seri ]


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Masukkan DML Dengan Variabel Bind:MENGGUNAKAN Klausul Eksekusi Pernyataan Segera

  2. Tantangannya aktif! Panggilan komunitas untuk membuat generator seri nomor tercepat

  3. Periksa Batasan dalam SQL

  4. Manajemen Indeks Otomatis di Azure SQL Database

  5. Panduan analisis data:Saatnya untuk unggul dengan menggunakan Excel!