İnsanlar neden SQL imleçlerinden bu kadar nefret ediyor? [kapalı]


127

Ek yük ve rahatsızlıktan dolayı bir imleç kullanmaktan kaçınmak istemeyi anlayabiliyorum, ancak insanların kullanmak zorunda kalmamak için büyük çaba sarf ettikleri bazı ciddi imleç-fobi-mani var gibi görünüyor.

Örneğin, bir soru, bir imleçle açıkça önemsiz bir şeyin nasıl yapılacağını sordu ve özyinelemeli bir özel işlevle ortak bir tablo ifadesi (CTE) özyinelemeli sorgu kullanılarak önerilen kabul edilen yanıt, bu işlem yapılabilecek satır sayısını 32 ile sınırlasa bile (sql sunucusundaki özyinelemeli işlev çağrı sınırı nedeniyle). Bu, basit bir imleç kullanmaktan kaçınmak için muazzam bir çabadan bahsetmek yerine, sistemin uzun ömürlülüğü için korkunç bir çözüm olarak beni şaşırtıyor.

Bu kadar çılgınca nefretin sebebi nedir? Bazı 'tanınmış otorite' imleçlere karşı fetva yayınladı mı? Çocukların ahlakını bozan imleçlerin kalbinde, ağza alınmayacak bir kötülük falan mı gizleniyor?

Wiki sorusu, temsilciden çok cevapla ilgileniyor.

İlgili Bilgiler:

SQL Server Hızlı İletme İmleçleri

DÜZENLEME: daha kesin olalım: Normal ilişkisel işlemler yerine imleçlerin kullanılmaması gerektiğini anlıyorum ; bu bir beyinsizdir. Anlamadığım şey, bir imleç daha basit ve / veya daha verimli bir çözüm olsa bile, insanların çürükleri varmış gibi imleçlerden kaçınmak için kendi yollarından vazgeçmeleri. Beni şaşırtan, apaçık teknik verimlilikler değil, mantıksız nefret.


1
Sanırım Düzenlemeniz her şeyi anlatıyor ... Hemen hemen tüm durumlarda (karşılaştığım) bir imleci daha iyi performans gösteren küme tabanlı bir durumla değiştirmenin bir yolu var. Zahmetsiz diyorsunuz ama farkı anlıyorsunuz.
StingyJack

7
Bu sorudaki etiketleri seviyorum!
sep332

2
Özyinelemeli CTE sınırlarının varlığı ile ilgili 32kısım saçmadır. Muhtemelen sen özyinelemeli tetikleyici düşünme ve maksimum edilir @@NESTLEVELait 32. OPTION (MAXRECURSION N)Varsayılan 100ve 0sınırsız anlamına gelen sorguda ayarlanabilir .
Martin Smith

@MartinSmith: varsayılan sınır şu anda 100 ve maksimum 32 bin sql-server-helper.com/error-messages/msg-310.aspx
Steven

Hayır, yorumumu yaptığımda ve SQL Server'ın özyinelemeli CTE'leri destekleyen tüm sürümlerinde tam olarak aynı. Bağlantınız "0 belirtildiğinde, sınır uygulanmaz" dediği gibi.
Martin Smith

Yanıtlar:


74

İmleçlerle "ek yük" yalnızca API'nin bir parçasıdır. İmleçler, RDBMS'nin parçalarının başlık altında nasıl çalıştığıdır. Genellikle CREATE TABLEve INSERTsahip SELECTekstreleri ve uygulama bariz iç imleç uygulamasıdır.

Daha üst düzey "küme tabanlı operatörler" kullanmak, imleç sonuçlarını tek bir sonuç kümesinde bir araya getirir, bu da daha az API ileri geri anlamına gelir.

İmleçler, birinci sınıf koleksiyonlar sağlayan modern dillerden öncedir. Eski C, COBOL, Fortran vb. Sıraları teker teker işlemek zorundaydı çünkü yaygın olarak kullanılabilecek "koleksiyon" kavramı yoktu. Java, C #, Python vb., Sonuç kümelerini içeren birinci sınıf liste yapılarına sahiptir.

Yavaş Sorun

Bazı çevrelerde, ilişkisel birleşimler bir gizemdir ve insanlar basit bir birleştirme yerine iç içe imleçler yazacaktır. Çok sayıda imleç olarak yazılmış gerçekten destansı iç içe döngü işlemleri gördüm. RDBMS optimizasyonunu yenmek. Ve gerçekten yavaş koşuyor.

İç içe geçmiş imleç döngülerini birleştirmelerle değiştirmek için basit SQL yeniden yazar ve tek, düz bir imleç döngüsü, programların 100. kez çalışmasını sağlayabilir. [Optimizasyon tanrısı olduğumu düşünüyorlardı. Tek yaptığım, iç içe geçmiş döngüleri birleşimlerle değiştirmekti. Hala imleçler kullanılıyor.]

Bu kafa karışıklığı çoğu zaman imleçlerin suçlanmasına yol açar. Ancak, bu imleç değil, sorun olan imlecin kötüye kullanılmasıdır.

Boyut Sorunu

Gerçekten destansı sonuç kümeleri için (yani, bir tabloyu bir dosyaya dökmek), imleçler gereklidir. Küme tabanlı işlemler, gerçekten büyük sonuç kümelerini bellekte tek bir koleksiyon olarak gerçekleştiremez.

Alternatifler

Mümkün olduğunca ORM katmanı kullanmaya çalışıyorum. Ancak bunun iki amacı var. İlk olarak, imleçler ORM bileşeni tarafından yönetilir. İkinci olarak, SQL uygulamadan bir yapılandırma dosyasına ayrılır. İmleçler kötü olduğundan değil. Tüm bu açılma, kapanma ve getirme işlemlerinin kodlanması katma değerli bir programlama değildir.


3
"İmleçler, RDBMS'nin başlık altında nasıl çalıştığıdır." Özellikle SQL Server'ı kastediyorsanız, tamam, tamam, bundan habersizim. Ancak birden çok RDBMS'nin (ve ORDBMS'nin) (Stonebraker altında) dahili üzerinde çalıştım ve hiçbiri bunu yapmadı. Örneğin: Ingres, dahili olarak tuple'ların "sonuç kümeleri" ne kadarını kullanır.
Richard T

@Richard T: RDBMS kaynağı hakkında ikinci el bilgiler üzerinde çalışıyorum; İfadeyi değiştireceğim.
S.Lott

2
"Gerçekten çok ve çok sayıda imleç olarak yazılmış epik iç içe döngü işlemlerini gördüm." Ben de onları görüyorum. İnanması zor.
RussellH

41

İmleçler, insanların küme tabanlı bir ortama aşırı bir prosedürel zihniyet uygulamasına neden olur.

Ve onlar YAVAŞ !!!

Gönderen SQLTeam :

Lütfen imleçlerin SQL Server içindeki verilere erişmenin en yavaş yolu olduğunu unutmayın. , Yalnızca bir seferde bir satıra gerçekten erişmeniz gerektiğinde kullanılmalıdır. Bunun için düşünebildiğim tek neden, her satırda bir saklı yordamı çağırmaktır. In İmleç Performans makalesinde ben imleçleri olduğunu keşfetmiş üzerinde otuz kat daha yavaş kümesi tabanlı alternatiflerden daha .


6
bu makale 7 yaşında, bu arada işler değişmiş olabilir mi?
Steven

1
Ayrıca imleçlerin gerçekten yavaş olduğunu ve genel olarak kaçınılması gerektiğini düşünüyorum. Bununla birlikte, OP, olduğunu düşündüğüm soruyu ifade ediyorsa, o zaman bir imleç doğru çözümdü (bellek kısıtlamaları nedeniyle her seferinde bir kayıt akışı).
rmeador

güncellenen makale, göreceli hız ölçümlerini düzeltmez, ancak bazı iyi optimizasyonlar ve alternatifler sunar. Orijinal makalenin imleçlerin while döngülerinden 50 kat daha hızlı olduğunu söylediğine dikkat edin, bu ilginç
Steven A.Lowe

6
@BoltBait: Ben şahsen düşünüyorum yaparsanız o gerçekten eski :-P 45 yaş olamaz böyle battaniye iddialar
Steven A. Lowe

4
@BoltBait: Siz çocuklar çimlerimden inin!
Steven

19

Yukarıda "imleçler, SQL Server içindeki verilere erişmenin en yavaş yoludur ... imleçler, set tabanlı alternatiflere göre otuz kat daha yavaştır."

Bu ifade birçok durumda doğru olabilir, ancak genel bir ifade olarak sorunludur. Örneğin, sürekli üretim okumaları alan büyük bir tablonun birçok satırını etkileyen bir güncelleme veya silme işlemi gerçekleştirmek istediğim durumlarda imleçleri iyi kullandım. Bu güncellemeleri her seferinde bir satırda yapan bir saklı yordamı çalıştırmak, set tabanlı işlemlerden daha hızlı olur, çünkü set tabanlı işlem okuma işlemiyle çakışır ve korkunç kilitleme sorunlarına neden olur (ve üretim sistemini tamamen öldürebilir, en uç durumlarda).

Diğer veritabanı etkinliklerinin yokluğunda, set tabanlı işlemler evrensel olarak daha hızlıdır. Üretim sistemlerinde bağlıdır.


1
Kuralı kanıtlayan istisna gibi görünüyor.
Joel Coehoorn

6
@ [Joel Coehoorn]: Bunu hiç anlamadım.
Steven

2
@ [Steven A. Lowe] phrases.org.uk/meanings/exception-that-proves-the-rule.html istisnayı "dışarıda bırakılan" olarak anlayın ve buradaki kuralın "çoğu durumda imleçlerin kötü".
David Lay

1
@delm: Bağlantı için teşekkürler, şimdi cümleyi daha da az anlıyorum!
Steven A.Lowe

5
@ [Steven A. Lowe] Temel olarak, bir alt harfle "bir kuralı ihlal ederseniz", kırmak için genel bir kural olması gerektiğini, ergo bir kural olduğunu söylüyor. Örneğin Bağlantıdan: ("'Giriş Pazar günleri ücretsizdir' gibi bir ifademiz varsa, genel bir kural olarak girişin ücretlendirildiğini makul bir şekilde varsayabiliriz.")
Fry

9

İmleçler genellikle set tabanlı işlemlerin daha iyi olacağı yerlerde SQL geliştiricileri tarafından kullanılmaya başlandı. Özellikle insanlar geleneksel bir programlama dilini öğrendikten sonra SQL öğrendiklerinde, "bu kayıtların üzerinde yineleme" zihniyeti, insanları imleçleri uygunsuz bir şekilde kullanmaya yöneltme eğilimindedir.

En ciddi SQL kitapları, imleçlerin kullanımını emreden bir bölüm içerir; iyi yazılmış olanlar, imleçlerin bir yeri olduğunu, ancak küme tabanlı işlemler için kullanılmaması gerektiğini açıkça belirtir.

Açıkça, imleçlerin doğru seçim veya en azından A doğru seçim olduğu durumlar vardır.


9

Optimizer, bir imleç yöntemi kullanıldığında problemi dönüştürmek için genellikle ilişkisel cebiri kullanamaz. Genellikle bir imleç bir sorunu çözmek için harika bir yoldur, ancak SQL bildirimsel bir dildir ve veri tabanında kısıtlamalardan istatistiklere ve dizinlere kadar pek çok bilgi vardır, bu da optimize edicinin sorunu çözmek için birçok seçeneğe sahip olduğu anlamına gelir. sorun, oysa bir imleç çözümü hemen hemen açık bir şekilde yönlendirir.


8

Oracle PL / SQL imleçleri, tablo kilitlerine neden olmaz ve toplu toplama / toplu getirme kullanmak mümkündür.

Oracle 10'da sıklıkla kullanılan örtük imleç

  for x in (select ....) loop
    --do something 
  end loop;

bir seferde örtük olarak 100 satır getirir. Açıkça toplu toplama / toplu getirme de mümkündür.

Bununla birlikte, PL / SQL imleçleri son çare olabilir, küme tabanlı SQL ile bir sorunu çözemediğinizde bunları kullanın.

Diğer bir neden paralelleştirmedir, veritabanının büyük küme tabanlı ifadeleri sıraya göre zorunlu koda göre paralel hale getirmesi daha kolaydır. İşlevsel programlamanın giderek daha popüler hale gelmesinin (Haskell, F #, Lisp, C # LINQ, MapReduce ...) nedeniyle aynı nedenden dolayı işlevsel programlama paralelleştirmeyi kolaylaştırır. Bilgisayar başına CPU sayısı artıyor, bu nedenle paralelleştirme giderek daha fazla sorun haline geliyor.


6

Genel olarak, ilişkisel bir veritabanında, imleçleri kullanan kodun performansı, küme tabanlı işlemlerden daha kötü bir büyüklük sırasıdır.


bunun için bir kriteriniz veya referansınız var mı? Bu kadar ciddi bir performans düşüşü fark etmedim ... ama belki tablolarımın önemli olması için yeterli satır yok (genellikle bir milyon veya daha az)?
Steven A.Lowe

oh bekle ne demek istediğini anlıyorum - ama imleçleri set operasyonları içinde kullanmayı asla savunmam, sadece imleçlerden kaçınmak için aşırıya gitmem
Steven

3
SQL'i ilk yaptığım zamanı hatırlıyorum, bir ana bilgisayardan bir SQL Server veritabanına 50 bin günlük veri dosyası aktarmak zorunda kaldık ... Bir imleç kullandım ve içe aktarmanın imleci kullanarak yaklaşık 26 saat sürdüğünü keşfettim. Set tabanlı işlemlere geçtiğimde işlem 20 dakika sürdü.
Charles Bretana

6

Yukarıdaki cevaplar, kilitlemenin önemini yeterince vurgulamamıştır. İmleçlerin büyük bir hayranı değilim çünkü genellikle masa seviyesinde kilitlerle sonuçlanıyorlar.


1
Evet teşekkür ederim! Önleme seçenekleri olmadan (salt okunur, yalnızca iletme, vb.), Birkaç satır ve ardından birkaç satır satırı işgal etmeye devam eden herhangi bir (sql sunucusu) işlemi gibi kesinlikle yapacaklardır.
Steven A.Lowe

?? Bu, kilitleme stratejinizle ilgili bir problemdir, imleçler DEĞİL. Bir SELECT ifadesi bile okuma kilitleri ekleyecektir.
Adam

3

Ne olursa olsun, bir imlecin dışarıya çıkacağı "bir" yerin, küme tabanlı karşılığını gerçekleştireceği bir toplamda olduğunu okudum. Küçük bir tablo üzerinde, satırları sıra üzerinden sütunlara göre toplama hızı, küme tabanlı işlemi kolaylaştırır, ancak tablo satır boyutunda arttıkça, imleç daha hızlı hale gelecektir, çünkü çalışan toplam değeri basitçe bir sonraki geçişe taşıyabilir. döngü. Şimdi nerede Yapmanız gereken bir çalışan toplam farklı bir argüman olduğunu ...


1
"Toplamı çalıştırma" derken bir tür (min, maks, toplam) bir toplamayı kastediyorsanız, herhangi bir yetkin DBMS, yalnızca işlevin motorda gerçekleştirilmesi ve istemci <--> sunucu ek yükü yoktur. Belki SQL Server yetkin değil?
Richard T

1
@ [Richard T]: İstemci tarafı imleçleri değil, bir saklı yordamda olduğu gibi sunucu tarafı imleçleri tartışıyoruz; karışıklık için özür dilerim!
Steven A.Lowe


2

Performans (olmayan) sorunlarının dışında, imleçlerin en büyük başarısızlığının hata ayıklamanın acı verici olduğunu düşünüyorum. Özellikle hata ayıklamanın nispeten kolay olduğu ve dil özelliklerinin çok daha kolay olduğu çoğu istemci uygulamasındaki kodla karşılaştırıldığında. Aslında, SQL'de bir imleçle yapılan hemen hemen her şeyin muhtemelen istemci uygulamasında ilk etapta olması gerektiğini iddia ediyorum.


2
İmleçler olmadan bile SQL'de hata ayıklamak zahmetlidir. Visual Studio'daki MS SQL adım adım araçları benden hoşlanmıyor gibi görünüyor (çok takılıyorlar veya kesme noktalarına hiç takılmıyorlar), bu nedenle genellikle PRINT ifadelerine indirgeniyorum ;-)
Steven A. Lowe

1

Bu imleç örneğini veya soruya bağlantı gönderebilir misiniz? Muhtemelen özyinelemeli bir CTE'den daha iyi bir yol vardır.

Diğer yorumlara ek olarak, imleçler yanlış kullanıldığında (ki bu genellikle) gereksiz sayfa / satır kilitlerine neden olur.


1
daha iyi bir yol var - acayip bir imleç ;-)
Steven A. Lowe

1

İnsanları sadece sizden farklı bir bakış açısına sahip oldukları için "deli" olarak adlandırmak yerine, başka türlü yaptıkları gibi hissetmek için çok iyi bir nedeni olabilecek profesyonellerle alay etmeye çalışmak yerine, muhtemelen sorunuzu ikinci paragraftan sonra bitirebilirsiniz.

Sorunuza gelince, kesinlikle bir imlecin çağrılabileceği durumlar varken, benim deneyimime göre geliştiriciler bir imlecin gerçekte olduğundan daha sık "FAR" kullanılması gerektiğine karar veriyorlar. Bence birisinin çok fazla imleç kullanması yerine onları kullanmaması konusunda hata yapma şansı ÇOK daha yüksek.


8
lütfen daha dikkatli okuyun, Tom - tam ifade "çılgın nefret" idi; "Nefret edilen", "deli" sıfatının nesnesiydi, "insanlar" değil. İngilizce bazen biraz zor olabilir ;-)
Steven A. Lowe

0

temelde aynı şeyi yapan 2 blok kod. belki biraz tuhaf bir örnek ama asıl noktayı kanıtlıyor. SQL Server 2005:

SELECT * INTO #temp FROM master..spt_values
DECLARE @startTime DATETIME

BEGIN TRAN 

SELECT @startTime = GETDATE()
UPDATE #temp
SET number = 0
select DATEDIFF(ms, @startTime, GETDATE())

ROLLBACK 

BEGIN TRAN 
DECLARE @name VARCHAR

DECLARE tempCursor CURSOR
    FOR SELECT name FROM #temp

OPEN tempCursor

FETCH NEXT FROM tempCursor 
INTO @name

SELECT @startTime = GETDATE()
WHILE @@FETCH_STATUS = 0
BEGIN

    UPDATE #temp SET number = 0 WHERE NAME = @name
    FETCH NEXT FROM tempCursor 
    INTO @name

END 
select DATEDIFF(ms, @startTime, GETDATE())
CLOSE tempCursor
DEALLOCATE tempCursor

ROLLBACK 
DROP TABLE #temp

imleç 2016 ms sürerken tek güncelleme 156 ms sürer.


3
evet, bunun bir imleç kullanmanın gerçekten aptalca bir yolu olduğunu kanıtlıyor! ama ya her satırın güncellenmesi tarih sırasına göre önceki satırın değerine bağlıysa?
Steven A. Lowe

BEGIN TRAN SELECT TOP 1 baseval from tablodan zaman damgasına göre SİPARİŞ TESLİMAT INSERT tablo (alanlar) DEĞERLER (önceki kayıttan türetilen değer dahil vals) COMMIT TRAN
dkretz

@doofledorfer: son satıra tarih sırasına göre bir satır ekler, her satırı tarih sırasına göre önceki satırından bir değere göre güncellemez
Steven

İmleci gerçekten kullanmak için güncellemede WHERE CURRENT
OF'ı
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.