Kapan / Mengapa menggunakan Cascading di SQL Server?

149

Saat mengatur kunci asing di SQL Server, dalam keadaan apa Anda harus membuatnya jatuh pada menghapus atau memperbarui, dan apa alasan di baliknya?

Ini mungkin berlaku untuk database lain juga.

Saya terutama mencari contoh konkret dari setiap skenario, lebih disukai dari seseorang yang telah menggunakannya dengan sukses.

Joel Coehoorn
sumber
4
Pertanyaan ini tampaknya tidak terkait erat dengan SQL Server dan lebih mirip pertanyaan umum teoretis. Akan lebih bermanfaat bagi komunitas jika Anda menghapus sql-servertag.
clapas
4
@clapas Jujur, jika saya bertanya hari ini akan keluar dari topik. Jika bukan karena tampilan / suara tinggi yang menunjukkan nilai untuk komunitas, saya hanya akan menghapusnya.
Joel Coehoorn
6
@ JoelCoehoorn - Jelas jenis pertanyaan ini memiliki nilai. Nilai ini tidak hilang karena berlalunya waktu. Pertanyaan yang ada di benak saya adalah berapa banyak nilai yang kita kehilangan dengan menolak pertanyaan seperti itu hari ini?
P.Brian.Mackey
2
@ P.Brian.Mackey Di Sini, Di Sini! Beberapa pertanyaan / jawaban terbaik yang pernah saya lihat adalah pertanyaan yang tidak dipilih atau dilukis sebagai topik yang tidak umum ... tetapi Anda dapat mengetahui dari jumlah suara BESAR yang naik bahwa banyak yang memiliki pertanyaan yang sama persis!
Anthony Griggs
Tindakan Cascading mengambil kunci serial.
Mitch Wheat

Jawaban:

126

Ringkasan dari apa yang saya lihat sejauh ini:

  • Beberapa orang tidak suka kaskade sama sekali.

Hapus Cascade

  • Hapus Cascade mungkin masuk akal ketika semantik hubungan dapat melibatkan deskripsi " bagian dari " eksklusif . Misalnya, catatan OrderLine adalah bagian dari pesanan induknya, dan OrderLines tidak akan pernah dibagikan di antara banyak pesanan. Jika Order menghilang, OrderLine juga, dan garis tanpa Order akan menjadi masalah.
  • Contoh kanonik untuk Cascade Delete adalah SomeObject dan SomeObjectItems, di mana tidak masuk akal untuk catatan item yang pernah ada tanpa catatan utama yang sesuai.
  • Anda tidak boleh menggunakan Cascade Delete jika Anda menyimpan histori atau menggunakan "penghapusan lunak / logis" di mana Anda hanya mengatur kolom bit yang dihapus ke 1 / true.

Pembaruan Cascade

  • Pembaruan kaskade mungkin masuk akal ketika Anda menggunakan kunci nyata daripada kunci pengganti (kolom identitas / autoincrement) di seluruh tabel.
  • Contoh kanonik untuk Pembaruan Cascade adalah ketika Anda memiliki kunci asing yang bisa berubah, seperti nama pengguna yang dapat diubah.
  • Anda tidak boleh menggunakan Pembaruan Cascade dengan kunci yang merupakan kolom Identitas / peningkatan otomatis.
  • Pembaruan Cascade paling baik digunakan bersama dengan kendala unik.

Kapan Menggunakan Cascading

  • Anda mungkin ingin mendapatkan konfirmasi yang sangat kuat kembali dari pengguna sebelum mengizinkan operasi untuk mengalir, tetapi tergantung pada aplikasi Anda.
  • Cascading dapat membuat Anda mendapat masalah jika Anda salah mengatur kunci asing Anda. Tetapi Anda harus baik-baik saja jika Anda melakukannya dengan benar.
  • Tidak bijaksana menggunakan kaskade sebelum Anda memahaminya secara menyeluruh. Namun, ini adalah fitur yang berguna dan karenanya perlu meluangkan waktu untuk memahami.
Joel Coehoorn
sumber
3
Perhatikan bahwa pembaruan kaskade juga sering digunakan di mana kunci alami "yang disebut" tampaknya bukan kunci unik yang sangat efektif ini. Bahkan saya yakin bahwa pembaruan kaskade diperlukan hanya dengan model database yang dinormalkan dengan buruk, dan mereka adalah gerbang terbuka untuk tabel berantakan dan kode berantakan.
Philippe Grondier
1
Anda kehilangan satu poin penting, berjenjang dapat menciptakan masalah kinerja besar jika ada banyak catatan anak.
HLGEM
13
@ HLGEM - Saya tidak melihat relevansinya. Jika operasi kaskade menyebabkan pelambatan, proses manual yang setara akan menyebabkan perlambatan yang sama atau tidak dilindungi dengan benar jika transaksi perlu dibatalkan.
Joel Coehoorn
3
Mengapa penting apakah ada pembaruan kaskade pada IDENTITY atau kolom kenaikan otomatis? Saya bisa melihat mengapa hal itu tidak akan diperlukan karena Anda tidak perlu mengubah nilai-nilai (sewenang-wenang), tetapi jika salah satu dari mereka melakukan perubahan, setidaknya integritas referensial akan utuh.
Kenny Evitt
3
10 peluru? Nah sekarang kita tahu Joel tidak menembakkan revolver.
Neil N
68

Kunci asing adalah cara terbaik untuk memastikan integritas referensial dari database. Menghindari kaskade karena menjadi sihir seperti menulis segala sesuatu dalam kumpulan karena Anda tidak percaya keajaiban di balik kompiler.

Apa yang buruk adalah penggunaan kunci asing yang salah, seperti membuatnya mundur, misalnya.

Contoh Juan Manuel adalah contoh kanonik, jika Anda menggunakan kode, ada lebih banyak peluang untuk meninggalkan DocumentItems palsu dalam database yang akan datang dan menggigit Anda.

Pembaruan berjenjang berguna, misalnya, ketika Anda memiliki referensi ke data dengan sesuatu yang dapat berubah, katakanlah kunci utama tabel pengguna adalah nama, kombinasi nama belakang. Maka Anda ingin perubahan dalam kombinasi itu menyebar ke mana pun mereka direferensikan.

@ Aidan, Kejelasan yang Anda rujuk datang dengan biaya tinggi, kesempatan meninggalkan data palsu di database Anda, yang tidak kecil . Bagi saya, biasanya hanya kurang terbiasa dengan DB dan ketidakmampuan untuk menemukan FK mana yang ada sebelum bekerja dengan DB yang menumbuhkan ketakutan itu. Entah itu, atau penyalahgunaan kaskade konstan, menggunakannya di mana entitas tidak terkait secara konseptual, atau di mana Anda harus melestarikan sejarah.

Vinko Vrsalovic
sumber
7
Menggunakan kunci primer 'alami' semacam itu adalah ide yang sangat buruk.
Nick Johnson
4
RE: Komentar diarahkan ke Aidan. Tidak, meninggalkan CASCADE pada FK tidak meningkatkan peluang untuk meninggalkan data palsu. Ini mengurangi kemungkinan bahwa lebih banyak data akan dipengaruhi oleh perintah daripada yang diharapkan dan meningkatkan kode. Membiarkan FK sepenuhnya meninggalkan peluang data palsu.
Shannon Severance
5
Setelah setidaknya dua kali dalam karir saya melihat konsekuensi yang mengancam bisnis dari penghapusan kaskade yang disalahpahami, saya sangat enggan menggunakannya sendiri dalam semua kecuali kasus yang paling jelas. Dalam kedua kasus, data telah dihapus sebagai akibat dari kaskade yang benar-benar seharusnya dipertahankan tetapi tidak - dan bahwa itu hilang tidak terdeteksi sampai siklus cadangan normal telah kehilangan kemungkinan pemulihan yang mudah. Vinko benar dari sudut pandang yang murni logis, namun di dunia nyata menggunakan kaskade memaparkan seseorang pada falibilitas manusia dan konsekuensi yang tidak terduga lebih dari yang saya inginkan.
Cruachan
1
Saya benar-benar mengkodekan sistem di mana keputusan manajemen telah dibuat bahwa pengguna harus menghapus secara eksplisit semua anak dalam detail-master sebelum mereka dapat menghapus master hanya untuk memaksa pengguna untuk berpikir. Tidak menggunakan kaskade ketika secara logis orang bisa adalah sejenis pemecah api yang serupa.
Cruachan
6
@Cruachan: Aturannya, dalam pandangan saya, sederhana. Jika data tidak terkait kuat sehingga tidak berguna tanpa data induk, maka itu tidak menjamin hubungan kaskade. Inilah yang saya coba sampaikan dalam frasa terakhir pada jawaban saya.
Vinko Vrsalovic
17

Saya tidak pernah menggunakan penghapusan cascading.

Jika saya ingin sesuatu dihapus dari database saya ingin secara eksplisit memberi tahu database apa yang ingin saya ambil.

Tentu saja mereka adalah fungsi yang tersedia dalam database dan mungkin ada saat-saat ketika tidak masalah untuk menggunakannya, misalnya jika Anda memiliki tabel 'pesanan' dan tabel 'pesananItem' Anda mungkin ingin menghapus item ketika Anda menghapus memesan.

Saya suka kejelasan yang saya dapatkan dari melakukannya dalam kode (atau prosedur tersimpan) daripada 'ajaib' terjadi.

Untuk alasan yang sama, saya juga bukan penggemar pemicu.

Yang perlu diperhatikan adalah bahwa jika Anda menghapus 'pesanan', Anda akan mendapatkan laporan '1 baris yang terpengaruh' kembali bahkan jika penghapusan bertingkat telah menghapus 50 'orderItem.

Loofer
sumber
34
Mengapa tidak menyingkirkan kunci primer juga? Anda akan mendapatkan kejelasan dalam memastikan nilai unik dalam kode Anda.
MusiGenesis
4
@MusiGenesis, Aidan tidak menganjurkan penghapusan FK. FK masih melindungi data, tetapi tanpa CASCADE ON .... keajaiban tak terduga tidak terjadi.
Shannon Severance
7
@ Vinko: Hapus dan perbarui memiliki semantik default yang didefinisikan dengan baik. Mengubah perilaku melalui kaskade atau pemicu untuk melakukan lebih banyak pekerjaan meninggalkan kesempatan lebih banyak dilakukan daripada yang dimaksudkan. Tidak, saya tidak bekerja tanpa pengujian dan ya database saya didokumentasikan. Tetapi apakah saya ingat setiap bagian dokumentasi saat menulis kode? Jika saya ingin semantik tingkat yang lebih tinggi, seperti menghapus orang tua & anak-anak, daripada saya akan menulis dan menggunakan SP untuk melakukan itu.
Shannon Severance
3
@ Vinko. masalah sulap bukan pada pengembang yang kompeten atau DBA, melainkan dengan Joe interen 5 tahun kemudian siapa yang diberi tugas pemeliharaan sederhana ketika DBA sedang berlibur dan yang kemudian mengacaukan data perusahaan tanpa ada yang menyadarinya. Cascades memiliki tempat mereka, tetapi penting untuk mempertimbangkan keadaan penuh, termasuk faktor manusia, sebelum menempatkan mereka.
Cruachan
5
@ Vinko: Mengapa SP Terkesiap? SP menantang cara untuk pergi ke mana database merupakan aset perusahaan yang penting. Ada argumen kuat dalam situasi yang sedang dibicarakan untuk membatasi semua akses data ke SP, atau paling tidak semua kecuali Select. Lihat jawaban saya di bawah stackoverflow.com/questions/1171769/...
Cruachan
13

Saya banyak bekerja dengan menghapus cascading.

Senang rasanya mengetahui siapa pun yang bekerja melawan database mungkin tidak akan pernah meninggalkan data yang tidak diinginkan. Jika ketergantungan tumbuh saya hanya mengubah kendala dalam diagram di Studio Manajemen dan saya tidak perlu mengubah sp atau dataacces.

Yang mengatakan, saya punya 1 masalah dengan penghapusan cascading dan thats referensi melingkar. Ini sering mengarah ke bagian-bagian dari database yang tidak memiliki penghapusan cascading.

Mathias F
sumber
1
Saya tahu ini sangat lama, tetapi +1 untuk menyebutkan masalah referensi melingkar dengan CASCADE DELETE.
Code Maverick
2
Maafkan pertanyaan noob: apa yang sebenarnya terjadi jika Anda mendapatkan referensi melingkar?
Tim Lovell-Smith
10

Saya melakukan banyak pekerjaan basis data dan jarang menemukan penghapusan kaskade bermanfaat. Satu kali saya menggunakannya secara efektif adalah dalam database pelaporan yang diperbarui oleh pekerjaan malam. Saya memastikan bahwa setiap data yang diubah diimpor dengan benar dengan menghapus semua catatan tingkat atas yang telah berubah sejak impor terakhir, kemudian mengimpor kembali catatan yang dimodifikasi dan apa pun yang berkaitan dengan mereka. Ini menyelamatkan saya dari keharusan menulis banyak penghapusan rumit yang terlihat dari bawah ke atas database saya.

Saya tidak menganggap penghapusan kaskade seburuk pemicu karena mereka hanya menghapus data, pemicu dapat memiliki semua jenis hal-hal buruk di dalamnya.

Secara umum saya menghindari Hapus nyata sama sekali dan menggunakan penghapusan logis (mis. Memiliki kolom bit bernama isDeleted yang akan disetel ke true) sebagai gantinya.

Martynnw
sumber
2
Anda membuat saya penasaran untuk belajar lebih banyak. Mengapa Anda lebih suka penghapusan logis? Apakah data yang Anda kerjakan ada hubungannya dengan itu?
Tim Lovell-Smith
9

Salah satu contoh adalah ketika Anda memiliki dependensi antara entitas ... yaitu: Dokumen -> DocumentItems (ketika Anda menghapus Dokumen, DocumentItems tidak memiliki alasan untuk ada)

juan
sumber
5

Gunakan penghapusan kaskade di mana Anda ingin catatan dengan FK dihapus jika catatan PK rujukannya dihapus. Dengan kata lain, di mana catatan tidak ada artinya tanpa catatan referensi.

Saya menemukan penghapusan kaskade berguna untuk memastikan bahwa referensi mati dihapus secara default daripada menyebabkan pengecualian nol.

testpattern
sumber
5

ON Hapus Cascade:

Saat Anda ingin baris dalam tabel anak dihapus Jika baris terkait dihapus di tabel induk.

Jika pada penghapusan kaskade tidak digunakan maka kesalahan akan dinaikkan untuk integritas referensial .

ON Update Cascade:

Ketika Anda ingin perubahan kunci utama diperbarui di kunci asing

Durai Amuthan.H
sumber
5

Saya telah mendengar tentang DBA dan / atau "Kebijakan Perusahaan" yang melarang penggunaan "On Delete Cascade" (dan yang lainnya) murni karena pengalaman buruk di masa lalu. Dalam satu kasus seorang pria menulis tiga pemicu yang akhirnya memanggil satu sama lain. Tiga hari untuk pulih menghasilkan larangan total pada pemicu, semua karena tindakan satu idjit.

Tentu saja kadang-kadang Pemicu diperlukan daripada "On Delete cascade", seperti ketika beberapa data anak perlu disimpan. Tetapi dalam kasus lain, sangat valid untuk menggunakan metode kasir On Delete. Keuntungan utama dari "On Delete cascade" adalah ia menangkap SEMUA anak-anak; prosedur pemicu / penyimpanan tertulis khusus mungkin tidak jika tidak dikodekan dengan benar.

Saya percaya Pengembang harus diizinkan untuk membuat keputusan berdasarkan apa pengembangan itu dan apa yang dikatakan oleh spec. Larangan karpet berdasarkan pengalaman buruk seharusnya tidak menjadi kriteria; proses berpikir "Jangan pernah gunakan" itu kejam. Panggilan penilaian perlu dilakukan setiap waktu, dan perubahan dibuat saat model bisnis berubah.

Bukankah ini yang dimaksud dengan pengembangan?

BrianBurkill
sumber
Saya tidak berpikir itu akan menghapus semuanya ... maksud Anda fitur itu benar-benar melakukan apa yang dikatakannya? ...
Joel Coehoorn
3

Salah satu alasan untuk menghapus kaskade (daripada melakukannya dalam kode) adalah untuk meningkatkan kinerja.

Kasus 1: Dengan penghapusan kaskade

 DELETE FROM table WHERE SomeDate < 7 years ago;

Kasus 2: Tanpa penghapusan kaskade

 FOR EACH R IN (SELECT FROM table WHERE SomeDate < 7 years ago) LOOP
   DELETE FROM ChildTable WHERE tableId = R.tableId;
   DELETE FROM table WHERE tableId = R.tableid;
   /* More child tables here */
 NEXT

Kedua, ketika Anda menambahkan tabel anak tambahan dengan penghapusan kaskade, kode dalam Kasus 1 tetap berfungsi.

Saya hanya akan menempatkan kaskade di mana semantik hubungan adalah "bagian dari". Kalau tidak, beberapa idiot akan menghapus setengah dari database Anda ketika Anda melakukannya:

DELETE FROM CURRENCY WHERE CurrencyCode = 'USD'
WW.
sumber
5
Tidak tahu basis data mana yang Anda gunakan, saya akan menyarankan bahwa penghapusan manual Anda berkinerja lebih buruk daripada penghapusan Cascading karena tidak ditetapkan berdasarkan. Di sebagian besar basis data, Anda dapat menghapus berdasarkan gabungan ke tabel lain dan memiliki penghapusan berbasis set, jauh lebih cepat daripada perulangan melalui catatan.
HLGEM
2

Saya mencoba untuk menghindari penghapusan atau pembaruan yang saya tidak minta secara eksplisit di SQL server.

Baik melalui cascading atau melalui penggunaan pemicu. Mereka cenderung menggigit Anda di pantat beberapa saat, baik ketika mencoba melacak bug atau ketika mendiagnosis masalah kinerja.

Di mana saya akan menggunakannya dalam menjamin konsistensi untuk tidak terlalu banyak usaha. Untuk mendapatkan efek yang sama Anda harus menggunakan prosedur tersimpan.

pauliephonic
sumber
2

Saya, seperti orang lain di sini, menemukan bahwa penghapusan kaskade benar-benar hanya sedikit membantu (itu benar-benar tidak banyak bekerja untuk menghapus data yang direferensikan di tabel lain - jika ada banyak tabel, Anda cukup mengotomatisasi ini dengan skrip) tetapi sangat menjengkelkan ketika seseorang secara tidak sengaja kaskade menghapus beberapa data penting yang sulit untuk dipulihkan.

Satu-satunya kasus di mana saya menggunakan adalah jika data dalam tabel tabel sangat terkontrol (misalnya, izin terbatas) dan hanya diperbarui atau dihapus dari melalui proses terkontrol (seperti pembaruan perangkat lunak) yang telah diverifikasi.

Jen A
sumber
1

Penghapusan atau pembaruan ke S yang menghilangkan nilai kunci asing yang ditemukan di beberapa tuple R dapat ditangani dengan salah satu dari tiga cara berikut:

  1. Penolakan
  2. Perambatan
  3. pembatalan.

Propagasi disebut cascading.

Ada dua kasus:

‣ Jika sebuah tuple dalam S telah dihapus, hapus R tuple yang merujuk padanya.

‣ Jika sebuah tuple dalam S telah diperbarui, perbarui nilai dalam tuple R yang merujuk padanya.

Mayank Chopra
sumber
0

Jika Anda bekerja pada sistem dengan banyak modul berbeda dalam versi yang berbeda, itu bisa sangat membantu, jika item kaskade yang dihapus adalah bagian dari / dimiliki oleh pemegang PK. Selain itu, semua modul akan memerlukan tambalan segera untuk membersihkan item dependen mereka sebelum menghapus pemilik PK, atau hubungan kunci asing akan dihilangkan sepenuhnya, mungkin meninggalkan banyak sampah dalam sistem jika pembersihan tidak dilakukan dengan benar.

Saya baru saja memperkenalkan penghapusan kaskade untuk tabel persimpangan baru antara dua tabel yang sudah ada (persimpangan untuk menghapus saja), setelah penghapusan kaskade telah berkecil hati untuk beberapa waktu. Ini juga tidak terlalu buruk jika data hilang.

Namun, itu adalah hal yang buruk pada tabel daftar enum-like: seseorang menghapus entri 13 - kuning dari tabel "warna", dan semua item kuning dalam database bisa dihapus. Juga, ini kadang-kadang diperbarui dengan cara delete-all-insert-all, yang mengarah ke integritas referensial yang sama sekali dihilangkan. Tentu saja itu salah, tetapi bagaimana Anda akan mengubah perangkat lunak yang kompleks yang telah berjalan selama bertahun-tahun, dengan pengenalan integritas referensial yang benar berada pada risiko efek samping yang tidak terduga?

Masalah lain adalah ketika nilai kunci asing asli harus disimpan bahkan setelah kunci primer telah dihapus. Seseorang dapat membuat kolom batu nisan dan opsi HAPUS SET NULL untuk FK asli, tetapi ini lagi membutuhkan pemicu atau kode tertentu untuk mempertahankan nilai kunci redundan (kecuali setelah penghapusan PK).

Erik Hart
sumber
0

Penghapusan Cascade sangat berguna ketika mengimplementasikan entitas tipe-super dan sub-tipe logis dalam database fisik.

Ketika tabel tipe-super dan sub-tipe yang terpisah digunakan untuk secara fisik mengimplementasikan tipe-super / sub-tipe (sebagai lawan untuk menggulung semua atribut sub-tipe ke dalam tabel tipe-super fisik tunggal), ada satu-ke-satu -satu hubungan antara tabel ini dan masalah kemudian menjadi bagaimana menjaga kunci utama 100% sinkron antara tabel-tabel ini.

Penghapusan kaskade dapat menjadi alat yang sangat berguna untuk:

1) Pastikan bahwa menghapus catatan tipe-super juga menghapus catatan sub-jenis tunggal yang sesuai.

2) Pastikan bahwa setiap penghapusan catatan jenis sub juga menghapus catatan tipe super. Ini dicapai dengan menerapkan pemicu hapus "bukan-pada" pada tabel sub-tipe yang berjalan dan menghapus catatan tipe super yang sesuai, yang, pada gilirannya, kaskade menghapus catatan sub-jenis.

Menggunakan penghapusan kaskade dengan cara ini memastikan bahwa tidak ada catatan tipe atau sub-tipe anak yatim super yang pernah ada, terlepas dari apakah Anda menghapus catatan tipe super terlebih dahulu atau catatan sub-tipe terlebih dahulu.

Mark Allen
sumber
Contoh yang baik. Di JPA, itu InheritanceStrategy Bergabung Tabel. Untuk 1): Biasanya, Anda menggunakan kerangka lapisan kegigihan (EclipseLink, Hibernate, ...), yang mengimplementasikan urutan yang dihapus untuk entitas yang bergabung untuk pertama-tama menghapus bagian yang bergabung, kemudian bagian super. Tetapi jika Anda memiliki lebih banyak perangkat lunak dasar, seperti pekerjaan impor atau arsip, akan lebih mudah untuk hanya menghapus entitas dengan mengeluarkan penghapusan pada bagian super. Mengenai 2): setuju, tetapi dalam hal itu klien harus sudah menyadari bahwa ia sedang mengerjakan bagian / sub entitas yang tergabung.
leo