Ne zaman / neden basamaklı SQL Server'da kullanılır?


149

SQL Server'da yabancı anahtarlar kurarken, hangi koşullar altında silme veya güncellemede basamaklandırmanız gerekir ve bunun ardındaki neden nedir?

Bu muhtemelen diğer veritabanları için de geçerlidir.

En önemlisi her bir senaryonun somut örneklerini arıyorum, tercihen bunları başarılı bir şekilde kullanan birinden.


4
Bu soru kesinlikle SQL Server ile ilgili görünmüyor ve daha çok teorik, genel bir soruya benziyor. sql-serverEtiketi kaldırırsanız topluluk için daha yararlı olur .
clapas

4
@clapas Dürüst olmak gerekirse, bugün soracak olsaydım konu dışı olurdu. Topluma değer verdiğini gösteren yüksek görüşler / oylar için değilse, sadece silebilirdim.
Joel Coehoorn

6
@JoelCoehoorn - Açıkçası bu tür soruların değeri var. Bu değer zaman geçtikçe dağılmaz. Aklımdaki soru, bugün bu tür sorulara izin vermeyerek ne kadar değer kaybediyoruz?
P.Brian.Mackey

2
@ P.Brian.Mackey İşte, İşte! Gördüğüm en iyi soruların / cevapların bazıları, aşağı oylanan veya konu dışı olarak boyanmış olanlardır ... ancak BÜYÜK oylarla birçok kişinin aynı soruyu sorduğunu söyleyebilirsiniz!
Anthony Griggs

Basamaklı eylemler serileştirilebilir kilitler alır.
Mitch Wheat

Yanıtlar:


126

Şimdiye kadar gördüklerimin özeti:

  • Bazı insanlar basamaklı olmayı hiç sevmezler.

Basamakla Sil

  • Basamaklı Silme, ilişkinin anlambiliminin münhasır "açıklamanın bir parçası " tanımını içerebilmesi mantıklı olabilir . Örneğin, OrderLine kaydı üst siparişinin bir parçasıdır ve OrderLines hiçbir zaman birden fazla sipariş arasında paylaşılmaz. Sipariş ortadan kalkacak olsaydı, OrderLine da sipariş etmeli ve siparişi olmayan bir satır sorun olurdu.
  • Basamaklı Sil için kurallı örnek SomeObject ve SomeObjectItems'tir, burada bir öğe kaydının karşılık gelen bir ana kayıt olmadan var olması mantıklı değildir.
  • Sen gerektiğini değil sen geçmişini koruyarak ya kullanıyorsanız Sil Cascade kullandığı bir "yumuşak / mantıksal silme" Eğer sadece 1 / true silinmiş bir bit sütun başladığı an.

Art arda Güncelleme

  • Basamaklı Güncelleştirme, tablolar arasında bir yedek anahtar (kimlik / otomatik bağlama sütunu) yerine gerçek bir anahtar kullandığınızda anlamlı olabilir.
  • Basamaklı Güncelleştirme'nin standart örneği, değiştirilebilen bir kullanıcı adı gibi değiştirilebilir bir yabancı anahtarınız olduğu zamandır.
  • Sen gerektiğini değil Kimlik / autoincrement sütunlardır tuşlarıyla Cascade Update kullanan.
  • Kademeli Güncelleme en iyi, benzersiz bir kısıtlama ile birlikte kullanılır.

Basamaklı Ne Zaman Kullanılmalı

  • Bir işlemin basamaklandırılmasına izin vermeden önce kullanıcıdan ekstra güçlü bir onay almak isteyebilirsiniz, ancak bu durum uygulamanıza bağlıdır.
  • Yabancı anahtarlarınızı yanlış ayarlarsanız kademeli olarak başınız derde girebilir. Ama bunu doğru yaparsan iyi olmalısın.
  • Tamamen anlamadan önce basamaklı kullanmak akıllıca değildir. Bununla birlikte, kullanışlı bir özelliktir ve bu nedenle anlaşılması için zaman ayırmaya değer.

3
Kademeli güncellemelerin "sözde" doğal anahtarların bu gerçek etkili benzersiz anahtarlar gibi görünmediği yerlerde de sıklıkla kullanıldığını unutmayın. Aslında, kademeli güncellemelerin sadece zayıf normalleştirilmiş veritabanı modelleri ile gerekli olduğuna ikna oldum ve dağınık tablolara ve dağınık kodlara açık bir kapı.
Philippe Grondier

1
Önemli bir noktayı kaçırıyorsunuz, çok sayıda çocuk kaydı varsa basamaklı büyük performans sorunları oluşturabilir.
HLGEM

13
@HLGEM - Alaka düzeyini görmüyorum. Bir kademeli işlemler yavaşlamaya neden olursa, eşdeğer manuel işlem ya aynı yavaşlamaya neden olur ya da işlemin geri alınması gerektiğinde doğru şekilde korunmaz.
Joel Coehoorn

3
Bir KİMLİK veya otomatik artış sütununda kademeli bir güncelleme olması neden önemlidir? Bunlar olmazdı neden görebilirsiniz gerekli o (keyfi) değerleri değiştirmek gerekmez, çünkü ancak bunlardan biri eğer yaptığımız değişiklik, en azından bilgi tutarlılığı sağlam olurdu.
Kenny Evitt

3
10 Mermi mi? Şimdi Joel'in bir tabanca ateşlemediğini biliyoruz.
Neil N

68

Yabancı anahtarlar, bir veritabanının başvuru bütünlüğünü sağlamanın en iyi yoludur. Sihir olduğu için kaskadlardan kaçınmak derleme içindeki her şeyi yazmak gibidir, çünkü derleyicilerin arkasındaki sihire güvenmezsiniz.

Kötü olan, yabancı anahtarların yanlış kullanılmasıdır, örneğin geriye doğru oluşturmak gibi.

Juan Manuel'in örneği kanonik örnektir, eğer kod kullanırsanız, veritabanında size gelip ısırmak için sahte DocumentItems bırakma şansı daha vardır.

Basamaklı güncellemeler, örneğin verilere değişebilecek bir şeyle referansınız olduğunda faydalıdır, bir kullanıcı tablosunun birincil anahtarının ad, soyadı birleşimi olduğunu varsayalım. Ardından, bu kombinasyondaki değişikliklerin başvurulan her yere yayılmasını istersiniz.

@Aidan, Bahsettiğiniz bu netlik yüksek bir maliyetle geliyor, veritabanınızda sahte veri bırakma şansı yok, ki bu küçük değil . Bana göre, genellikle DB'ye aşinalık eksikliği ve bu korkuyu besleyen DB ile çalışmadan önce hangi FK'lerin yerinde olduğunu bulamama. Ya bu, ya da sürekli olarak kötüye kullanımı, varlıkların kavramsal olarak ilişkili olmadığı ya da tarihi korumanız gereken yerlerde kullanmak.


7
Bu tür bir 'doğal' birincil anahtar kullanmak ilk etapta gerçekten kötü bir fikirdir.
Nick Johnson

4
RE: Aidan'a yönelik yorum. Hayır, CASCADE'i bir FK üzerinde bırakmak sahte verileri bırakma şansını arttırmaz. Bir komuttan beklenenden daha fazla verinin etkilenme şansını azaltır ve kodu arttırır. FK'ları bırakmak tamamen sahte veri şansı bırakıyor.
Shannon Severance

5
Kariyerimde en az iki kez yanlış anlaşılmış bir çağlayan silme işleminin tehdit edici sonuçlarını gördüm. Her iki durumda da, gerçekten tutulması gereken, ancak tutulmayan bir kaskatın sonucu veriler silinmişti ve normal yedekleme döngüsü kolay bir geri yükleme olasılığını kaybetene kadar eksik olmadığı tespit edilmedi. Vinko tamamen mantıklı bir bakış açısından doğrudur, ancak basamaklı kullanan gerçek dünyada insanın yanıltıcılığına ve öngörülemeyen sonuçlara istediğimden daha fazla maruz kalmaktadır.
Cruachan

1
Aslında kullanıcıların basitçe kullanıcıyı düşünmeye zorlamak için ana silmeden önce tüm çocukları bir ana ayrıntıda açıkça silmek zorunda kalacağı bir yönetim kararının verildiği sistemleri kodladım. Mantıksal olarak bir kaskad kullanmamak benzer bir ateş böceği gibidir.
Cruachan

6
@Cruachan: Bence kural basit. Veriler, üst veriler olmadan işe yaramayacak kadar güçlü bir şekilde ilişkili değilse, basamaklı bir ilişki gerektirmez. Bu cevabımın son cümlesinde ele almaya çalıştığım ben.
Vinko Vrsalovic

17

Asla basamaklı silme kullanmıyorum.

Bir şey veritabanından kaldırılmasını istiyorsanız açıkça veritabanına ne almak istiyorum söylemek istiyorum.

Tabii ki bunlar veritabanında bulunan bir işlevdir ve bunları kullanmanın uygun olduğu zamanlar olabilir, örneğin bir 'sipariş' tablonuz ve bir 'orderItem' tablonuz varsa, sipariş.

Ben 'sihir' oluyor yerine kod (veya saklı yordam) yaparak netlik seviyorum.

Aynı nedenle ben de tetikleyici hayranı değilim.

Dikkat edilmesi gereken bir şey, bir 'siparişi' silerseniz, basamaklı silme 50 'orderItem'i kaldırmış olsa bile' 1 satırdan etkilenmiş 'raporunu geri alacağınızdır.


34
Neden birincil anahtarlardan da kurtulmuyorsunuz? Kodunuzda benzersiz değerler sağlamanın netliğini elde edersiniz.
MusiGenesis

4
@MusiGenesis, Aidan, FK'nin kaldırılmasını savunmuyordu. FK hala verileri korur, ancak CASCADE ON olmadan ... beklenmedik sihir olmaz.
Shannon Severance

7
@Vinko: Sil ve güncelle iyi tanımlanmış varsayılan anlambilime sahiptir. Davranışı bir basamaklı veya tetikleyici aracılığıyla daha fazla iş yapmak için değiştirmek, beklenenden daha fazla şans bıraktı. Hayır, test yapmadan çalışmıyorum ve evet veritabanlarım belgeleniyor. Ancak kod yazarken her belgeyi hatırlıyor muyum? Ebeveynleri ve çocukları silme gibi daha üst düzey anlambilim istersem, bunu yapmak için bir SP yazacağım ve kullanacağım.
Shannon Severance

3
@Vinko. sihir sorunu yetkin geliştiriciler veya DBA'lar ile değil, 5 yıl sonra Joe interen ile DBA tatildeyken 'basit' bakım görevi verilen ve daha sonra hiç kimse fark etmeden kurumsal verileri bertaraf eden kişidir. Kaskadların yeri vardır, ancak dağıtmadan önce insan faktörleri de dahil olmak üzere tüm koşulları dikkate almak önemlidir.
Cruachan

5
@Vinko: Neden 'Gasp' SP'leri? SP'ler, veritabanının kritik bir kurumsal varlık olduğu yere gitmenin yoludur. SP'lere tüm veri erişimini veya en azından Select hariç tüm veri erişimini kısıtlamak gibi durumlarda güçlü bir argüman var . Cevabımı stackoverflow.com/questions/1171769/…
Cruachan

13

Basamaklı silmelerle çok çalışıyorum.

Veritabanına karşı çalışan kimsenin asla istenmeyen veri bırakmayacağını bilmek iyi hissettirir. Bağımlılıklar artarsa, sadece Management Studio'daki şemadaki kısıtlamaları değiştiririm ve sp veya dataacces'i değiştirmek zorunda değilim.

Bununla birlikte, basamaklı silme ve bu dairesel referanslarla ilgili 1 sorunum var. Bu genellikle veritabanının basamaklı silinmesi olmayan bölümlerine yol açar.


1
Bunun çok eski olduğunu biliyorum, ancak CASCADE DELETE ile ilgili dairesel referans sorunundan bahsettiği için +1.
Maverick

2
Noob sorusunu affedin: dairesel bir referans alırsanız gerçekte ne olur?
Tim Lovell-Smith

10

Ben veritabanı iş bir sürü yapmak ve nadiren yararlı basamaklı siler bulabilirsiniz. Onları etkili bir şekilde kullandığım zaman, bir gece işi tarafından güncellenen bir raporlama veritabanında. Son içe aktarmadan bu yana değişen üst düzey kayıtları silerek değiştirilen verilerin doğru bir şekilde içe aktarıldığından emin olurum, sonra değiştirilen kayıtları ve bunlarla ilgili her şeyi yeniden içe aktarırım. Beni veritabanımın altından üst kısmına bakan bir sürü karmaşık silme işlemi yazmaktan kurtarıyor.

Art arda gelen silmelerin yalnızca verileri sildikleri kadar tetikleyiciler kadar kötü olduğunu düşünmüyorum, tetikleyiciler içinde her türlü kötü şey olabilir.

Genel olarak gerçek silmeleri tamamen önler ve bunun yerine mantıksal silmeleri (yani isDeleted adında bir bit sütununa sahip olarak ayarlanır.


2
Biraz daha öğrenmemi merak ettin. Neden mantıksal silmeleri şiddetle tercih ediyorsunuz? Üzerinde çalıştığınız verilerin onunla bir ilgisi var mı?
Tim Lovell-Smith

9

Örnekler arasında varlıklar arasında bağımlılık olduğunda ... yani: Belge -> Belge Öğeleri (Belgeyi sildiğinizde, Belge Öğelerinin var olma nedeni yoktur)


5

Yönlendiren PK kaydı kaldırılmışsa FK ile kaydın kaldırılmasını istediğiniz basamaklı silmeyi kullanın. Başka bir deyişle, referans kaydı olmadan kaydın anlamsız olduğu yerlerde.

Ölü istisnalara neden olmak yerine ölü referansların varsayılan olarak kaldırılmasını sağlamak için basamaklı silme işleminin yararlı olduğunu düşünüyorum.


5

AÇIK Kaskat Sil:

İstediğiniz zaman çocuk tablosundaki satırlar Silinecek Eğer gelen satır silinir ana tablodaki.

Eğer silme basamaklandığında bir hata için yükseltilir sonra kullanılmaz tutarlılığı .

ON Güncelleme Kaskadı:

Birincil anahtardaki değişikliğin yabancı anahtarda güncellenmesini istediğinizde


5

Tamamen kötü deneyimler nedeniyle "On Delete Cascade" (ve diğerleri) kullanımını yasaklayan DBA'ları ve / veya "Şirket Politikası" nı duydum. Bir durumda, bir adam birbirini çağıran üç tetikleyici yazdı. İyileşmek için üç gün, hepsi bir idjitin eylemleri nedeniyle tetikleyicileri tamamen yasakladı.

Tabii ki bazen, bazı alt verilerin korunması gerektiğinde olduğu gibi, "On Delete cascade" yerine Tetikleyiciler gerekir. Ancak diğer durumlarda, Silme işleminde basamaklı yöntemini kullanmak tamamen geçerlidir. "On Delete cascade" nin önemli bir avantajı TÜM çocukları yakalamasıdır; özel olarak yazılmış bir tetikleyici / saklama yordamı doğru kodlanmazsa kullanılamaz.

Geliştiricinin, geliştirmenin ne olduğuna ve spesifikasyonun söylediklerine dayanarak karar vermesine izin verilmesi gerektiğine inanıyorum. Kötü bir deneyime dayanan halı yasağı kriterler olmamalıdır; "Asla kullanma" düşünce süreci en iyi ihtimalle acımasızdır. Her seferinde bir karar çağrısı yapılması ve iş modeli değiştikçe değişiklik yapılması gerekmektedir.

Gelişmenin konusu bu değil mi?


Ben her şeyi sileceğini sanmıyordum ... yani özellik aslında ne diyorsa onu yapıyor? ...
Joel Coehoorn

3

Art arda silme işleminin bir nedenini (kodda yapmak yerine) performansı artırmaktır.

Durum 1: Bir basamaklı silme ile

 DELETE FROM table WHERE SomeDate < 7 years ago;

Durum 2: Kademeli silme olmadan

 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

İkinci olarak, basamaklı silmeyle ekstra bir alt tablo eklediğinizde, Durum 1'deki kod çalışmaya devam eder.

Sadece ilişkinin anlambiliminin "parçası" olduğu bir çağlayan koyardım. Aksi takdirde, bazı aptallar veritabanınızın yarısını sildiğinizde silecektir:

DELETE FROM CURRENCY WHERE CurrencyCode = 'USD'

5
Hangi datbase'i kullandığınızı bilmeden, manuel silme işleminizin, temelli olarak ayarlanmadığı için basamaklı silme işleminden daha kötü performans gösterdiğini öneririm. Çoğu veri tabanında, başka bir tabloya birleştirmeye dayalı olarak silebilirsiniz ve bu nedenle kayıtlar arasında döngüden çok daha hızlı bir set tabanlı silme işlemine sahip olabilirsiniz.
HLGEM

2

SQL sunucusunda açıkça istemediğim silme veya güncellemelerden kaçınmaya çalışıyorum.

Ya basamaklı olarak ya da tetikleyicileri kullanarak. Bir hatayı izlemeye çalışırken veya performans sorunlarını teşhis ederken sizi kıçından bir süre ısırmaya eğilimlidirler.

Onları kullanacağım yer, çok fazla çaba sarf etmemek için tutarlılığı garanti etmektir. Aynı etkiyi elde etmek için saklı yordamları kullanmanız gerekir.


2

Buradaki herkes gibi, basamaklı silmelerin gerçekten sadece marjinal olarak yararlı olduğunu görüyorum (diğer tablolardaki referanslı verileri silmek için o kadar çok iş değil - çok fazla tablo varsa, bunu bir komut dosyasıyla otomatikleştirin) ama gerçekten sinir bozucu Birisi yanlışlıkla art arda sıralandığında, geri yüklenmesi zor olan bazı önemli verileri siler.

Kullanacağım tek durum, tablo tablosundaki verilerin yüksek denetimli (örn. Sınırlı izinler) olması ve yalnızca doğrulanmış denetimli bir işlemle (yazılım güncellemesi gibi) güncellenmiş veya silinmiş olmasıdır.


1

Bazı R gruplarında bulunan yabancı anahtar değerini kaldıran S'nin silinmesi veya güncellenmesi üç yoldan biriyle gerçekleştirilebilir:

  1. ret
  2. Yayılma
  3. sıfırlanması.

Yayılım basamaklı olarak adlandırılır.

İki durum söz konusudur:

S S içindeki bir demet silindiyse, ona karşılık gelen R demetlerini silin.

S S içindeki bir demet güncellendi ise, R demetlerindeki değeri referans alarak güncelleyin.


0

Farklı sürümlerde birçok farklı modüle sahip bir sistem üzerinde çalışıyorsanız, basamaklı silinen öğelerin PK sahibinin bir parçası olması / sahip olması çok yararlı olabilir. Aksi takdirde, tüm modüller, PK sahibini silmeden önce bağımlı öğelerini temizlemek için derhal yamalar gerektirir veya yabancı anahtar ilişkisi tamamen atlanır ve temizleme doğru şekilde yapılmazsa sistemde tonlarca çöp bırakılır.

Kaskad silme oldukça uzun bir süre için kaldırıldıktan sonra, zaten var olan iki tablo (yalnızca silmek için kavşak) arasında yeni bir kavşak tablosu için basamaklı silme işlemini yeni başlattım. Verilerin kaybolması da çok kötü değil.

Ancak, enum benzeri liste tablolarında kötü bir şeydir: biri giriş 13 - tablo "renkler" sarı siler ve veritabanındaki tüm sarı öğeler silinir. Ayrıca, bunlar bazen tümünü sil-hepsini ekle biçiminde güncellenerek referans bütünlüğünün tamamen atlanmasına neden olur. Tabii ki yanlış, ama gerçek referans bütünlüğünün ortaya çıkması beklenmedik yan etkiler riski altında olan karmaşık bir yazılımı yıllardır nasıl değiştireceksiniz?

Başka bir sorun, birincil yabancı anahtar değerlerinin birincil anahtar silindikten sonra bile saklanmasıdır. Orijinal FK için bir kaldırıldı olarak işaretleme sütunu ve ON DELETE SET NULL seçeneği oluşturulabilir, ancak bu, gereksiz (PK silme hariç) anahtar değerini korumak için tetikler veya özel kod gerektirir.


0

Basamaklı silmeler, fiziksel bir veritabanında mantıksal süper tür ve alt tür varlıklar uygulanırken son derece yararlıdır.

Süper tiplerin / alt tiplerin fiziksel olarak uygulanması için ayrı süper tip ve alt tip tablolar kullanıldığında (tüm alt tip niteliklerini tek bir fiziksel süper tip tabloya yuvarlamanın aksine), bire bir -bu tablolar ve sorun arasındaki bir ilişki daha sonra birincil anahtarları bu tablolar arasında senkronize% 100 tutmak olur.

Art arda silmeler aşağıdakiler için çok yararlı bir araç olabilir:

1) Bir süper tip kaydın silinmesinin aynı zamanda tek bir alt tip kaydın da silindiğinden emin olun.

2) Alt tür kayıtlarının silinmesinin süper tür kaydı da sildiğinden emin olun. Bu, karşılık gelen süper-tip kaydı giden ve silen alt-tip tablosuna bir "yerine-" silme tetikleyicisi uygulanarak elde edilir, bu da kaskat alt-tip kaydı siler.

Basamaklı silmeleri bu şekilde kullanmak, önce süper tür kaydı veya alt tür kaydı silip silmediğinize bakılmaksızın, hiçbir öksüz süper tür veya alt tür kaydın bulunmamasını sağlar.


İyi örnek. JPA'da, InheritanceStrategy Katıldı Tablosu. 1 için): Normalde, birleştirilmiş bir varlığın önce birleştirilmiş parçayı, ardından süper parçayı silmesi için silinen diziyi uygulayan bir kalıcılık katmanı çerçevesi (EclipseLink, Hibernate, ...) kullanıyorsunuz. Ancak, içe aktarma veya arşivleme işi gibi daha temel bir yazılımınız varsa, üst kısımda bir silme yayınlayarak varlığı silebilirsiniz. 2): kabul edin, ancak bu durumda müşteri, işletmenin birleştirilmiş / alt kısmı üzerinde çalıştığının farkında olmalıdır.
leo
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.