Sorunun geçmişi:
Standart SQL, baştan itibaren klasik programlama unsurları (döngüler, dallanmalar, doğrudan geçiş) olmayan bir deklaratif dil olarak tasarlanmıştır; ancak T-SQL/PLSQL gibi uzantılar ile WHILE, CASE gibi yapılar ve hatta GOTO taklidi gibi yapılar kullanılabilir hale gelmiştir.
Sorun:
Yinelemeli işlemler (tek kayıt üzerinde döngüsel işleme) genellikle, büyük hacimlerin işlenmesinde işin yavaşlamasına neden olur; bunun yerine "set-based" (küme tabanlı) bir yaklaşım benimsenmelidir. Dallanmalar, CASE, IF - çok kullanışlıdır, ancak aşırı iç içe geçme, kodun okunabilirliği ve tahmin edilebilirliğini zedeler.
Çözüm:
Kontrol yapılarının kullanımı, yalnızca toplu (bulk/set) işlemlerle yapılamayacaksa haklı çıkarılmalıdır! Karmaşık hesaplamalar için - küçük bir döngü, tetikleyici veya CASE kabul edilebilir. Toplu işleme için - pencere fonksiyonları veya alt sorgu ile UPDATE kullanmak daha iyidir.
Kod örneği (T-SQL):
DECLARE @i INT = 1 WHILE (@i <= 5) BEGIN IF @i % 2 = 0 PRINT CONCAT('Çift: ', @i) ELSE PRINT CONCAT('Tek: ', @i) SET @i = @i + 1 END
CASE ifadesi:
SELECT num, CASE WHEN num % 2 = 0 THEN 'çift' ELSE 'tek' END AS parity FROM numbers
Anahtar özellikler:
CASE, WHERE gibi satırları filtrelemek için kullanılabilir mi?
Hayır! CASE farklı değerler döndürüyor, ancak satırları filtrelemiyor. Sık yapılan bir hata - CASE ile filtrelemek yerine WHERE kullanmak, sonuç yanlış olacaktır.
WHILE ile CURSOR arasındaki fark nedir - aynı mı?
WHILE, kullanıcı tarafından yönetilen değişken ile temel bir döngüdür; CURSOR, tablo kayıtları üzerinde çalışır, satır referansı tutar. CURSOR, daha fazla kaynak gerektirir ve genellikle büyük veriler için çok daha yavaş çalışır.
Toplu işleme için hangi yaklaşım daha hızlıdır: WHILE ile UPDATE döngüsü veya bir set-based UPDATE?
%99 durumunda bir set-based UPDATE (veya INSERT) tek başına, bir kayıt üzerinde döngüden çok daha hızlıdır (veya bu "daha esnek" gibi görünse bile).
-- Yanlış yaklaşım DECLARE @id INT = 1 WHILE (@id <= 100000) BEGIN UPDATE t SET flag=1 WHERE id=@id SET @id = @id + 1 END -- Doğru UPDATE t SET flag=1 WHERE id BETWEEN 1 AND 100000
Bir projede, bir milyon siparişin durumunu güncellemek için her id için bir UPDATE ile döngü yazmışlardı. İşleme ~8 saat sürdü. Yarıda çökme durumunda - her şeyi kaybettiler, manuel olarak düzeltmek zorunda kaldılar.
Artılar:
Eksiler:
Tek bir ifade ile set-based UPDATE'e geçtirdik. Çalışma süresi 6 dakikaya düştü, işlem atomiktir.
Artılar:
Eksiler: