7 puan yazan GN⁺ 2024-09-26 | 2 yorum | WhatsApp'ta paylaş
  • Veri analizi işlerinde sık kullanılan SQL yazma alışkanlıkları ve sorgu kalıplarını derleyen bir liste; bunların tüm RDBMS’lere aynı şekilde uygulanmayabileceği varsayımıyla sunuluyor
  • Okunabilirlik açısından önden virgül, WHERE 1=1, girintileme, CTE, yorumlar ve USING ile sorguları okumayı ve değiştirmeyi kolaylaştıran yaklaşımlar öneriliyor
  • Veri işlemede anti-join, QUALIFY, GROUP BY ROLLUP, EXCEPT gibi pratikte sonuç filtreleme, toplam üretme ve tablo farklarını kontrol etmede kullanılan söz dizimleri örneklerle ele alınıyor
  • Performans ve doğruluk açısından NULL içeren NOT IN, örtük tür dönüşümü ve hesaplanmış alan alias çakışmaları sorgu sonuçlarını veya hızını bozabilir
  • Karmaşık sorgularda yürütme sırası, dokümantasyonu kontrol etme, sütun kaynağını belirtme ve kayıtlı sorgu adı gibi temel alışkanlıklar hata ayıklamayı ve yeniden kullanılabilirliği artırmada önemlidir

SQL yazımında okunabilirliği artıran alışkanlıklar

  • Bu depo, yıllar içinde öğrenilen SQL ipuçları ve püf noktalarını derleyen bir listedir; veri analistlerinin günlük işlerinde faydalı olanlara ve SQL’e ilk başladığında bilinmesi iyi olacak konulara odaklanır
  • Bazı ipuçları tüm RDBMS’lere uygun olmayabilir
  • Önden virgül ve önden AND

    • SELECT bölümünde alanları ayırmak için sondan virgül yerine önden virgül kullanılması önerilir
    • Yeni bir sütun mu yoksa satıra bölünmüş kod mu olduğu daha net görünür
    • Satır uzunlukları farklı olsa bile eksik virgül olup olmadığını bulmak kolaylaşır
    • Aynı nedenle WHERE bölümündeki koşulların önüne de önden AND konabilir
  • WHERE 1=1 ile koşulları kolay test etme

    • WHERE bölümüne sahte koşul 1=1 eklemek, test sırasında koşulları yorum satırına alsanız bile sorgunun bozulmamasını sağlar
    • Tüm koşullar yorum satırına alınsa bile 1=1 kaldığı için sorgu çalışmaya devam edebilir
  • Girintileme ve formatter’lar

    • Girintileme, iş arkadaşlarınızın ve gelecekteki sizin sorguyu daha kolay okumasını sağlar
    • Ekip veya şirket yönergesi varsa onu izlemek, yoksa size uygun yöntemi kullanmak daha iyidir
    • Çevrimiçi formatter poorsql veya linter sqlfluff kullanılabilir
  • Karmaşık sorgularda CTE’yi değerlendirin

    • inline view’lar 2–3 seviyeden fazla iç içe geçtiğinde, birkaç hafta sonra tekrar bakıldığında anlaşılması zor sorgulara dönüşmeye yatkındır
    • CTE, uzun sorguları daha düzenli hale getiren, yeniden kullanılabilirliğe ve hata ayıklamaya yardımcı olan bir yöntem olarak sunulur
  • Yorumlar “neden”i açıklasın

    • Zaman geçtikten sonra belirli bir işlemin neden yapıldığını hatırlamak zor olabilir
    • Yorumlar genellikle kodun “nasıl” çalıştığından çok, bunun neden yapıldığını açıklamalıdır
    • Örnekte, yeni CMS archive video formatını işleyemediği için archive içerikleri hariç tutan koşula yorum eklenir
  • Aynı adlı sütunlarla join için USING

    • İki tabloda aynı ada sahip sütunla join yapılırken USING kullanmak, join’i ON’a göre daha sade ifade edebilir
    • USING, ortak sütunu sonuçta tekilleştirir ve yalnızca bir kez döndürür
    • ON kullanırken ortak sütun açıkça belirtilmezse ambiguous column name hatası oluşabilir

Veri işlemede yararlı söz dizimleri

  • anti-join ile başka tabloda bulunmayan satırları bulma

    • anti-join, bir tabloda bulunan ama diğer tabloda eşleşmeyen satırları döndürmek için kullanılır
    • Örnek, archive edilmemiş içeriklerin yalnızca video_id değerlerini alma durumunu ele alır
    • Birden fazla uygulama yöntemi vardır
    • LEFT JOIN sonrasında eşleşen tablonun anahtarı NULL olan satırları filtreleme
    • NOT IN ve alt sorgu kullanma
    • NOT EXISTS ve ilişkili alt sorgu kullanma
    • NOT IN, NULL değerleri nedeniyle amaçlandığı gibi çalışmayabileceğinden önerilmez
  • QUALIFY ile pencere fonksiyonu sonuçlarını filtreleme

    • QUALIFY, sorgu sonuçlarını pencere fonksiyonu sonuçlarına göre filtrelemeyi sağlar
    • inline view olmadan filtreleme yapılabildiği için kod satırı sayısını azaltabilir
    • Örnekte ürün başına en iyi 10 pazar DENSE_RANK() ile seçilir ve ardından QUALIFY ile filtrelenir
    • QUALIFY için, yalnızca Snowflake, Amazon Redshift, Google BigQuery gibi büyük veri ambarlarında sağlanıyor göründüğü yönünde bir sınırlama vardır
  • Sütun konumuna dayalı GROUP BY ve ORDER BY

    • Sütun adı yerine sütun konumuyla GROUP BY 1, ORDER BY 2 gibi yazılabilir
    • Geçici veya tek seferlik sorgular için yararlı olabilir
    • Prodüksiyon kodunda her zaman doğrudan sütun adlarına referans verilmesi önerilir
  • GROUP BY ROLLUP ile toplam oluşturma

    • GROUP BY ROLLUP, ara toplam ve genel toplam oluşturmak için kullanılabilir
    • Örnek, departman bazında maaş toplamını hesaplarken genel maaş toplamı satırını da oluşturur
    • Transact-SQL dokümantasyonu, ROLLUP’ın sütun ifadeleri kombinasyonları için gruplar oluşturduğunu, grupların sayısını sağdan sola azalttığını ve ara toplamlarla genel toplamlar ürettiğini açıklar
    • COALESCE uygulanırsa genel toplam satırı Total gibi gösterilebilir
    • Genel toplam satırının sonucun alt kısmında gelmesi için sıralama sütununa dikkat etmek gerekir
  • EXCEPT ile iki sonuç kümesi arasındaki farkı bulma

    • EXCEPT, ilk sorgu sonucunda olup ikinci sorgu sonucunda olmayan satırları döndürür
    • EXCEPT ve UNION ALL birlikte kullanılarak iki tablonun aynı veriye sahip olup olmadığı doğrulanabilir
    • Dönen satır yoksa iki tablo aynıdır
    • Dönen satır varsa farkı oluşturan neden bu satırlardır

Performansı ve doğruluğu bozan kalıplar

  • NULL alabilen sütunlarda NOT EXISTS, NOT IN’den daha iyidir

    • Karşılaştırılan sütun NULL kabul ediyorsa NOT IN genellikle NOT EXISTS’ten daha yavaş olabilir
    • Bu durum Snowflake’te yaşanmış; PostgreSQL Wiki’deki Don’t Do This, NOT IN (SELECT ...) ifadesinin iyi optimize edilmediğini belirtir
    • NOT IN, karşılaştırılan değerlerde NULL varsa amaçlandığı gibi çalışmaz
    • Bir sütunun NULL kabul etmesi, gerçekten NULL değer bulunduğu anlamına gelmez; ancak değiştiremeyeceğiniz tablolarla çalışırken NOT EXISTS hız iyileştirmesine yardımcı olabilir
  • Örtük tür dönüşümü yavaşlayabilir veya başarısız olabilir

    • Bir sütundan farklı veri türündeki bir değer koşula konduğunda veritabanı örtük tür dönüşümü denemesi yapabilir
    • Örnek, string türündeki video_id sütununu integer 200050 ile karşılaştırma durumunu ele alır
    • Örtük tür dönüşümüne güvenmek sorunlara yol açabilir
    • Dönüştürülemeyen değerler varsa hata oluşabilir
    • Her değeri belirtilen türe dönüştürmek için ek çalışma gerektiğinden sorgu yavaşlayabilir
    • Sütunla aynı veri türünü kullanmak veya hatalardan kaçınmak için Snowflake’in TRY_TO_NUMBER gibi fonksiyonları kullanılabilir
    • Hıza etkisi, işlenen veri kümesinin boyutuna göre değişir

Sık yapılan hatalar

  • NOT IN ve NULL

    • NOT IN, karşılaştırılan değerlerde NULL varsa çalışmaz
    • NULL, Unknown’ı temsil ettiği için SQL motoru kontrol edilen değerin listede olmadığını doğrulayamaz
    • Bu durumda NOT EXISTS kullanmak bir alternatiftir
  • Hesaplanmış alan alias çakışması

    • Hesaplanmış alanın adını mevcut bir sütunla aynı yapmak beklenmeyen davranışlara yol açabilir
    • Snowflake’in GROUP BY dokümantasyonu, GROUP BY bölümündeki bir ad hem sütun adıyla hem alias ile eşleşirse sütun adının kullanılacağını belirtir
    • Örnekte LEFT(product, 1) AS product ile alias oluşturup GROUP BY product yazıldığında, ilk harfe göre değil özgün product sütununa göre gruplama yapılır ve 3 satır döner
    • İki çözüm vardır
    • product_letter gibi benzersiz alias kullanmak
    • GROUP BY LEFT(product, 1) gibi ifadeyi açıkça belirtmek
    • Pencere fonksiyonlarında da alias sorunu oluşabilir
    • Örnekte CASE ile Robot gelirini 0’a çevirir, ancak bu pencere fonksiyonu çalıştıktan sonra uygulandığı için sıralama beklenenden farklı çıkar
    • Mümkünse benzersiz alias kullanmak veya pencere fonksiyonunun ORDER BY içinde hesaplamayı doğrudan yazmak gerekir
  • Sütunun hangi tabloya ait olduğunu belirtin

    • Birden fazla join içeren karmaşık sorgularda değer sorunlarını kaynak tabloya kadar izleyebilmek gerekir
    • İki tablo aynı sütun adını paylaştığında sütunun ait olduğu yer belirtilmezse RDBMS hata verebilir
    • Örnekte vc.video_id, metadata.season gibi tablo alias’ları eklenerek sütun kaynağı netleştirilir

Yürütme sırası, dokümantasyon ve kayıt adı

  • SQL yürütme sırasını anlama

    • SQL öğrenenler için en önemli tavsiyelerden biri olarak bölümlerin yürütme sırasını anlamak gösterilir
    • Yürütme sırasını bilmek sorgu yazma biçimini ciddi ölçüde değiştirebilir
    • Referans olarak A beginner’s guide to the true order of SQL operations sunulur
  • Dokümantasyonu sonuna kadar okuyun

    • Snowflake’te birden fazla tarih sütunu arasından en güncel tarihi döndürmek için GREATEST() kullanılan bir örnek vardır
    • GREATEST(), argümanlarından biri NULL ise NULL döndürür
    • Dokümantasyon daha fazla okunsaydı COALESCE(GREATEST(...), ...) yerine GREATEST_IGNORE_NULLS() kullanılabilirdi
    • Çoğu durumda dokümantasyona göz atmak 1 dakikadan az sürer ve beklenenden farklı davranışın nedenini arama zahmetini azaltabilir
  • Kayıtlı sorgular için açıklayıcı adlar kullanın

    • Yeniden çalıştırılması veya referans alınması gereken sorguyu bulamama durumundan kaçınmak için açıklayıcı adlarla kaydetmek daha iyidir
    • Kayıt adlarında genellikle sorgu konusu, çalıştırma ayı ve talep eden kişinin adı yer alır
    • Örnek biçim Lapsed users analysis - 2023-09-01 - Olivia Roberts şeklindedir

2 yorum

 
hiyama 2024-09-26

Baştaki virgüller bu gönderide tamamen sondaki virgüller olarak yazılmış. Orijinal metinde başta olacak şekilde girilmiş.

-- Good:  
SELECT   
timeslot_date  
, timeslot_channel   
, overnight_fta_share  
, IFF(DATEDIFF(DAY, timeslot_date, CURRENT_DATE()) > 7, -- First argument of IFF.  
	LAG(overnight_fta_share, 1) OVER (PARTITION BY timeslot_date, timeslot_channel ORDER BY timeslot_activity), -- Second argument of IFF.  
		NULL) AS C7_fta_share -- Third argument of IFF.  
, IFF(DATEDIFF(DAY, timeslot_date, CURRENT_DATE()) >= 29,   
		LAG(overnight_fta_share, 2) OVER (PARTITION BY timeslot_date, timeslot_channel ORDER BY timeslot_activity),   
			NULL) AS C28_fta_share  
FROM timeslot_data  
;  
 
GN⁺ 2024-09-26
Hacker News yorumları
  • Benim ekleyeceğim ipucu şu: DB sunucusunu düzgünce öğrenmek ve execution plan’leri sık sık kontrol etmek gerekir. Beklenmedik sonuçlar çıkabileceği için ayarlayıp yeniden kontrol etmek iyi olur.
    Genelde EXISTS, IN’den daha hızlıdır; NOT EXISTS ise NULL işlemede EXCEPT’ten farklı davranır. Tabloları join ettikten sonra satırları DISTINCT gibi şeylerle elemek yerine, SELECT listesindeki alt sorgu sütunlarını kullanmak bazen çok daha hızlı olabilir. Aynı tablodan 10’dan fazla değer getirseniz bile böyle olabilir; DB sunucusu lateral join desteklese de durum aynı kalabilir. Ancak alt sorgu en fazla tek satır döndürmelidir.
    Tek seferlik olmayan sorguların tüm tablo taraması yapmamasını sağlamak gerekir. Bugünün tablo taraması yarının kesintisine dönüşebileceğinden indeks eklenmelidir. GROUP BY ifadesinin genellikle indeks kullanımını belirlediğini de hatırlamak gerekir.
    Bir ifadeye göre filtreleme yapmanız gerekiyorsa, örneğin bir alt dizgenin belirli bir değere eşit olup olmadığını kontrol etmeniz gerekiyorsa, hesaplanmış bir sütun ekleyip ona indeks koyabilirsiniz. Bazı DB’ler ifade indekslerini doğrudan destekler. OR yerine UNION ALL kullanmak, karmaşık sorgularda veya çok sayıda OR koşulunda çoğu zaman çok daha hızlı olabilir.
    DB filtreleme sırasını akıllıca belirleyemediğinde, sırayı zorlamak için alt sorguyu JOIN etmek de işe yarar.

    • En yararlısı DBMS’in kendisini öğrenmektir. Her DB’nin performans ve izolasyon seviyeleriyle ilgili kendine özgü noktaları var; ek özellikleri de farklı olduğu için bundan kaçış yok.
      Postgres’te ilginç bulduğum şey, başka DB’lerde de böyle olma ihtimali var, INSERT (SELECT ...) işlemini CPU çekirdeği sayısına göre elle shard ederseniz neredeyse doğrusal şekilde hızlanabilmesiydi. Yaklaşık 10 join olsa bile mümkündü. Önce EXPLAIN ile en içteki ya da en dıştaki join’i bulup, ardından her satır aralığı için ayrı paralel sorgular (id >= start AND id < end) çalıştırmak yeterli. 6 yıl önce yaptığım bir işte tuhaf bir nedenle bu yöntemi çok kullandım. Postgres 10+’a paralellik eklendi, ama bildiğim kadarıyla hâlâ bu kadar ileri düzeyde değil.
    • SELECT listesinde alt sorgu “sütunu” kullanmakla tam olarak ne kastedildiğini bilmiyorum.
      Örneğin SELECT column1, (SELECT column2, column3, ... FROM table_b WHERE table_a.id = table_b.a_id) FROM table_a çalıştırınca beklendiği gibi “subquery must return only one column” hatası geliyor. Birden çok sütunu kayıt/kompozit tip olarak döndürmek mi kastediliyor?
      GROUP BY ifadesinin genellikle indeks kullanımını neden belirlediği bana hemen anlaşılır gelmemişti; merak edenler için bu yazı adım adım iyi açıklıyor: https://www.brentozar.com/archive/2015/06/indexing-for-group...
    • Katılıyorum. EXPLAIN kullanmalı ve tercih ettiğiniz araçla onu yorumlamayı öğrenmelisiniz. Sorguları da izlemek gerekir.
      Önceki startup’ta PgHero kurmuştuk; performans optimizasyonu ve önceliklendirme konusunda gerçekten çok yardımcı oldu.
    • İyi tasarlanmış sorgular bile çoğu zaman beklenenden farklı davranır. Sütun istatistiklerinin güncellenmemiş olması veya büyük tablolarda verinin parçalanmış olması tipik örneklerdir. Örneğin rastgele birincil anahtar ekleme gibi.
    • “Tek seferlik olmayan sorgular tüm tablo taraması yapmamalı. Bugünün tablo taraması yarının kesintisine dönüşebilir” ifadesine katılmıyorum.
      Tüm tablo taraması bazı sorgular için en verimli erişim stratejisidir. Genelde tüm tabloyu okuyan analiz/toplama sorguları böyledir; bazen tüm satırların yalnızca %50’sini getiren durumlarda bile tablo taraması daha iyidir.
      Salt okunur bir tablo taramasının nasıl kesintiye yol açtığını da pek bilmiyorum. Çünkü eşzamanlı erişimi engellemez. Tek dezavantajı I/O yükünün büyük olmasıdır; sunucu bunu kaldıramıyorsa zaten baştan ciddi şekilde düşük özellikli demektir.
  • “Okunabilirlik” bölümündeki 3 örnek tuhaf. İlk 2’si yazmayı kolaylaştırmak için kelimenin tam anlamıyla okunabilirlikten fedakârlık ediyor; sonuncusu ise girintilemeyle bile pek kurtarılamayan, okunması zor, canavar gibi bir biçim.

    • Baştaki virgül biçiminin okunabilirlik dışında da avantajları var. Örneğin sürüm kontrol sisteminde argüman başına bir satır + başta virgül biçimi, argüman değişikliğini yalnızca tek satırlık fark olarak gösterir.
      Geliştiricilerin gerçek kaynak kod kadar commit geçmişine de baktığını düşünüyorum.
    • İlk iki konvansiyonun görünümünü çok sevdiğim söylenemez, ama gerçek SQL yazan insanların gerçekten kullandığı konvansiyonlar bunlar. Neden var olduklarını da anlayabiliyorum.
      Yeterince sık gördüğüm için artık pek gözüme batmıyor.
    • Alternatif olarak, üç yaşında bir çocuk MSPaint’i ilk kez keşfetmiş gibi SQL’i karmakarışık yazıp sonra “beautifier” düğmesine basabilir ve erken öğle yemeğine çıkabilirsiniz.
    • Neden daha kötü olduğunu düşündüğünüzü bilmiyorum.
      Bir sorun da görmüyorum.
      Yanlış bir şey var gibi de görünmüyor.
    • SELECT bloğunda sütunları satır satır ayırırken 150 karakterlik satırı olduğu gibi bırakan kişi kim? Bu okunabilirliğin bozuk bir tanımı. Virgül meselesine hiç giremiyorum bile.
      Kod incelemesinde uzun satırları kimse doğru düzgün görmez. AngularJS’in en büyük sorunu buydu. Merge yanlış işlendi ve her şey bozuldu; çünkü 90. sütun civarına gelince gözler bulanıklaşıyor. Kod incelemesi olan yarım düzineden fazla ekip gördüm, hep aynıydı. Bu sorunun gayet farkında olup kaçınmaya çalışsam bile, ben de hâlâ başkalarının yaklaşık yarısı sıklığında hata yapıyorum.
      Biraz bölerek yazalım. Özellikle başkalarına örnek gösteriyorsanız bunu daha da çok yapmalısınız.
  • Karmaşık stored procedure’larla çalışırken ipuçları şöyle:

    1. Prosedürün başında kalıcı tabloyu hemen geçici bir tabloya kopyalayın; yalnızca gerekli satırları belirtin/sınırlayın/filtreleyin
    2. Ortada geçici tabloyu gerektiği gibi işleyin
    3. Sonda, bir transaction içinde kalıcı tabloyu güncelleyin. Hata tespit edilirse transaction’ı hemen rollback edip prosedürden çıkın. Bu üç adımı izlemek eşzamanlılığı artırır ve veri artıklarını elle temizlemek zorunda kalmadan prosedürü yeniden başlatabilmenizi sağlar
    4. Uzak tablolarla çalışırken son derece dikkatli olun. Uzak tablo mevcut RDBMS’in içinde olmadığından, o RDBMS’in istatistiklerinden veya indekslerinden büyük olasılıkla pek yararlanamazsınız. Çoğu durumda uzak tablonun tamamını geçici bir tabloya dump/kopya etmek ve sonra onun üzerinde çalışmak daha hızlıdır. Uzak tablodan bekleyebileceğiniz en fazla şey WHERE koşulunun çalıştırılmasıdır. JOIN ya da karmaşık işlemler denerseniz timeout alma olasılığınız yüksektir
    5. Execution plan’lar kolayca kafa karıştırır. Bazı durumlarda execution plan satır satır işlemeye düşüp performansı kilitleyebilir. Karmaşık stored procedure’ları geçici tablolar kullanan küçük adımlara bölmek çoğu zaman daha iyidir
    6. RDBMS’in gerçekte ne yaptığını görmek için her zaman execution plan’ı kontrol etmelisiniz
    • Gerekli olmadığı bir durumda 5. maddeyi uygulayan kodu geri alıp sorgu performansını ciddi şekilde iyileştirdiğim oldu. Bazen bir sorguyu birçok küçük sorguya bölmek, query optimizer’a tüm sorguyu verip en iyi yolu bulmasını sağlamaktan çok daha verimsizdir
      6. madde olmadan 5. maddeyi yaptıysanız, optimal olmayan bir şey yaptığınızı görememe ihtimaliniz yüksek. Benim tavsiyem erken optimizasyondan kaçınmak; önce en sezgisel şekilde yazıp yalnızca gerektiğinde optimize etmek. En önemlisi SQL’i prosedürel yazmamaktır. İstediğiniz veriyi tarif edersiniz; motora onu nasıl getireceğini emretmezsiniz
    • Bir sürü geçici tablo kullanmak zorunda kalmaktan hoşlanmıyorum ama query planner’a bırakırsanız asla bitmeyecek sorgularla sık sık karşılaşıyorum. Derleyicilerde olduğu gibi query planner’ın yetenekleri de ciddi biçimde abartılıyor
      Öte yandan Microsoft, query planner en iyisini bilir der gibi, onu tune etmeye çalışmamanız için sürekli uyarılar koyuyor
    • Bu kurallar bir vendor’ın DB’sinde tamamen doğru olabilir, ama başka DB’lerin öncelikleri, özellikleri ve trade-off’ları çok farklı olabilir
      DB sürümü de etkili olabilir
    • 1–3. maddeler, veri boyutunun makul olduğunu garanti edebiliyorsanız iyidir. Ancak veri donanımın kaldırabileceğinden fazla büyürse, büyük dataset’leri kopyalayıp sonra yine büyük dataset’leri güncellemek kayda değer bir overhead ekleyebilir
  • “Ne olur ne olmaz” diye geliştirme yapmayı sevmiyorum. Arayüzler için de böyle, where 1=1 gibi placeholder’lar için de
    Gerektiğinde yapın. Bir gün gelecekte gerekebilir diye yapmayın. Production kodu, geliştirme yardımcılarını geride bırakacağınız yer değildir. Geliştirme sırasında istediğinizi yapabilirsiniz ama production kodunda okunabilirlik ve açık niyet çok daha önemlidir

    • Tablo adı ve kolon adı referanslarının hepsini tam nitelikli olarak yazanlardan mısınız? Böyle yapmak çoğu zaman okunabilirliği bir basamak ya da daha fazla artırdı, ama kısa sürede çok laf kalabalığına dönüyor ve yazması inanılmaz derecede acı verici biçimde sıkıcı oluyor
  • “Anti join” konusunda bir şey daha. Başka bir büyük tabloda veya alt sorguda koşula uyan satırın var olup olmadığını kontrol etmek istiyorsanız IN ya da LEFT JOIN yerine EXISTS kullanmak daha iyidir
    EXISTS, eşleşen bir öğe bulur bulmaz true döndürür. LEFT JOIN ve IN durumunda motor, değerlendirmeden önce tüm sonuçları toplar

    • O kısım bana biraz kafa karıştırıcı geldi. Test ettiğim tüm durumlarda (NOT) EXISTS, (LEFT) JOIN ya da (NOT) IN’den daha iyi bir execution plan üretti ya da aynı planı üretti
      Üstelik niyeti de daha net gösteriyor
  • “Koda yorum yazın” ile ilgili olarak, en azından MSSQL’de yorumlarda -- yerine /**/ kullanılması sıkça önerilir. Query Store gibi özellikler sorguları çoğu zaman satır sonları olmadan sakladığından, oradan sorguyu aldığınızda IDE formatter’ını doğrudan kullanmak yerine her şeyi elle düzeltmeniz gerekir

    • Bu kulağa Query Store’un bug’ı gibi geliyor
    • XML’e cast edebilir misiniz? Ben bunu OBJECT_DEFINITION ile kullanıyorum
      select name,cast((select OBJECT_DEFINITION(object_id) for xml path('')) as xml) from sys.procedures
      Satır sonları korunduğu için düzenlemek daha kolay olabilir. Ancak > işaretinin > hâline gelmesi gibi diğer XML karakterleri bozulur. Bir diğer seçenek de VARBINARY ve onu geri açacak bir şey kullanmaktır
  • Herkes virgül önerisine takılmış durumda, ama WHERE koşulundaki 1=1 iyi bir fikir olarak mı görülüyor? Code review’da bunu görsem yazarı hakkında ne düşüneceğimi bilemem

    • Sondaki virgülle aynı gerekçeyle savunulabilir: WHERE ifadesindeki değişikliğin başka satırları etkilememesi, yani code review’u kolaylaştırması
      Ama gerekçe bu örnekteki gibi dinamik koşullar eklemekse, çalıştığım yerde bu kesinlikle işten kovulma sebebi olurdu
  • Veritabanı ayarlarıyla hız kazanma konusunda, neredeyse “satın alma”ya yakın bir yöntem ile fiilen elle uygulanan “inşa etme” arasındaki çizginin nereye çekilmesi gerektiğine dair genel yönergeler paylaşabilecek biri var mı? Sınırlı deneyimime göre yetkin DBA’ler çok daha yüksek ücretler alıp başka yerlerde çalıştığı için bu iş çoğu zaman uygulama geliştiricisinin üstüne kalıyor. Yukarıda söylendiği gibi, veritabanını bilmek önemli
    Tipik bir örnek, zamanla büyük miktarda biriken ve en güncel verinin en sık erişildiği veriler. Bir DBA, bölümleme ya da kısmi indekslerle erişimi hızlı tutabilir; uygulama geliştiricisi ise kayıtları arka planda ayrı bir arşiv tablosuna taşırken tüm veri kümesinde nihai arama gibi işlevleri desteklemeye devam edebilir. Bulut veritabanının özellik eksikliğiyle kısıtlanma gibi durumlarda, uygun zamanda tek bir tabloyu birden fazlaya bölmeye yönelik ilk işi araçların epey otomatikleştirebileceği hissine de kapılıyorum
    Bir başka yönetim seçeneği de büyük blob/dosyaların tamamını ayrı bir veritabanında ya da dosya sisteminde tutup farklı depolama ayarları kullanmak. Bunu da veritabanı karşılayabildiği gibi elle de yönetilebiliyor
    Uç noktada, indeksleri doğrudan kendiniz uygulamaya kadar gidilebilir gibi. Otomatik artan birincil anahtarı ve çok sayıda sütunu olan dev bir tablo tutup, o ID ile aranabilir birkaç sütunu içeren ayrı bir tablo oluşturmak gibi. Tam metin arama ya da vektörlere kadar da gidilebilir
    MSSQL 2016+’da materialized view pattern’ı elle uygularken işe yarayan bir ipucu, partition switching ile birlikte kullanmak. https://github.com/cajuncoding/SqlBulkHelpers?tab=readme-ov-... adresinde iyi açıklanmış ve uygulanmış. Tesadüfen bulduğum, ticari açıdan en faydalı ama arama sıralaması düşük ve yıldızı az olan küçük bir kütüphaneydi; .NET ile MSSQL’e toplu eklemeye odaklanıyor. Partition switching otomasyonu sayesinde satın alma/inşa etme çizgisini uygun şekilde çizen iyi bir örnek olduğunu düşünüyorum

  • Eksik kalan bir nokta: SELECT * kullanmayı bırakmalısınız. Neredeyse kesinlikle tablonun tüm genişliğine ihtiyacınız yoktur; bunu yaptığınızda filtrelenecek ve aktarılacak veri artar, ayrıca harika bir özellik olan semi join’i de engellersiniz

    • SQL kullananlar kabaca iki gruptur: analistler ve geliştiriciler
      Geliştiriciyseniz, evet. SELECT * tuzaklar içerir ve neredeyse her zaman sütunları açıkça belirtmeli ya da bunu sizin yerinize yapan bir query builder kullanmalısınız
      Ama analistseniz hayat kısa; bazen tüm sütunları tek tek yazmak istemeyebilirsiniz. SELECT * de sorun değil
  • Biraz konu dışına çıkıyor olabilir ama, bir yöneticinin pull request’i hiç yorum veya tartışma olmadan doğrudan kapatması kabul edilebilir bir yöntem mi?
    Depoya ara sıra katkı yapmış ya da yapmaya çalışmış biri olarak soruyorum
    Örnek: https://github.com/ben-n93/SQL-tips-and-tricks/pulls?q=is%3A...