SQL Server’ ın en büyük problemi zannedilen sorun performansıdır. Sürekli duyduğumuz SQL’de bir sorun mu var? SQL Server yavaşladı gibi terimleri sık sık duymaktasınız. Aslında bu performans sorunlarına sebep olan nedenleri bu makalede inceleyeceğiz. Makalede olabildiğinde Türkçe terimler kullanmaya dikkat ettim, bazı terimlerin Türkçe karşılığındaki anlam yetersizliğinden dolayı İngilizce olarak kullanıldı.
SQL Server performansı denildiğinde ilk akla gelen şey, CPU ve Memory yükseltmesidir. Genelde yazılım ve ERP bölümleri, SQL Server’ a daha fazla CPU ve daha fazla memory verilmesini sistem ekiplerinden isterler. CPU ve memory ilave yapılan SQL Serverlar ilk başta biraz daha iyi gibi çalıştığı görülse de aslında arka planda değişen hiçbir şey olmamıştır.
Bir SQL efsanesi olan CPU ve memory arttırmak yerine, gerçekte SQL Server’ ın performansını etkileyen unsurları incelemekte fayda var. İlk olarak SQL Server’ a fazlasıyla donanım kaynağı verdiniz, işletim sistemdeki performans ayalarını optimize ettiniz ve son olarak SQL Server’ daki temel ayarları yaptığınız diyelim, bundan sonra performans için nelere bakacağız, sırasıyla aşağıdaki konuları inceleyeceğiz;
- Yetersiz ve hatalı indeksleme
- Hatalı İstatistikler (Statistics)
- Uygun olmayan sorgu tasarımı
- Kötü yapılandırılmış execution planlar
- Blocking ve deadlock’ların çok fazla oluşması
- Doğru set edilmemiş SQL operatörleri
- Uygun olmayan veri tabanı tasarımı
- Index bozulmalarının sürekli yaşanması
Yetersiz ve hatalı indeksleme
SQL Server’ ın en büyük performance killer’ ın dan biri, yetersiz ve hatalı indekslemedir desek yanlış olmaz. Bir sorgudaki indeksleme doğru yapılmadığında, SQL Server bu sorguyu çalıştırmak için, daha fazla data işlemek zorunda kalacak ve bu gereksiz yapılan işlemler, SQL Server’ ın kurulu olduğu sunucu üzerinde, gereksiz şekilde donanım kaynaklarını tüketecektir. Bu donanım kaynaklarının en başında CPU, sonrasında disk ve memory gelmektedir.
Donanım kaynaklarının gereksiz yere kullanılması ile birlikte, sorguların çalışma süreleri de paralel bir şekilde olumsuz etkilenecek, süreleri uzayan sorgular da blockinglere ve deadlock’lara sebebiyet verecektir.
Peki bu başa bela olan indekslemeyi kimler yapar, SQL Server’ ın en büyük performance killer’ arından bir olan indeksleme kimin kontrolünde olmalıdır. Genellikle indekslerin sorumluluğu veri tabanı yöneticisindedir (DBA). İndekslerin oluşturulmasından ve bakımından veri tabanı yöneticileri sorumludur. Veri tabanı yöneticileri de yazmadıkları T-SQL koduna ait indeksler için inisiyatifi ele alıp, bu sorguların indeksleri üzerinde çalışma yapmak durumda bırakılırlar.
Aslında uygun olan, TSQL kodlarını yazan yazılımcılar ile veri tabanı yöneticilerinin birlikte çalışıp, TSQL kodlarında nasıl bir indeksleme yapılmasına kadar vermeleri gerekmektedir. Genellikle yazılım tarafında change management denilen, değişikliklerin yönetilmediği firmalar çoktur. Change management olmadığından, hangi kod ne zaman eklenmiş ne zaman değiştirilmiş gibi bir kayıt tutulmaz. SQL Server’ daki sorguların performansı düştükten sonra, veri tabanı yöneticisinden bu sorguların performansına bakılması istenir. Değişikliğin tespitini yapamayan veri tabanı yöneticisi de mevcutta gördüğü TSQL kodunda indeksleme yapar.
Birçok hatalı açılan indeks ve yanlış indekslemeden dolayı da birçok performans sorunu ortaya çıkmaktadır. Bir tabloda gereksiz yere fazla indeksleme yapılması, data manipulation dediğimiz, INSERT, UPDATE ve DELETE operasyonlarının yavaşlamasına da sebebiyet verecektir. Yavaş performans da blockinglerin oluşmasına öncülük edecek ve blockingler de deadlocklar ile sonlanacaktır.
Yanlış oluşturulan indeksler, optimizer tarafından kullanılmaktadırlar, CPU, memory ve disk IO larının kullanımı olumsuz yönde etkileyen bu hatalı indekslerin mutlaka düzeltilmesi SQL Server’ ın performansının iyileştirilmesi açısından çok önemlidir.
İndeksleme konusunda, mutlaka yazılım ve veri tabanı ekiplerinin birlikte çalışması. Bunun sonucunda da change management mimarisine geçilmesi önem kazanmaktadır.
Hatalı İstatistikler (Statistics)
SQL Server’ ın performans hesaplama temelleri, maliyet bazlı optimizasyona dayanır. Verinin kullanımda en çok ihtiyaç duyulan indekslerdir. İndekslerin de etkili bir şekilde kullanılmasında da statisticslerin doğru yapılandırılması çok önemlidir.
Doğru statisticsler olmadığında, SQL Server sorgulardaki satır sayısı tahminlemesin de yanlış yapacaktır. Satır sayısını tahminlemenin sorgu performansına etkisi ise, örnek olarak 10bin satır gelecek olan bir sorgunun, estimated row number değeri 1milyon olarak tahminlendiğin de gereksiz yere IO kullanımı ortaya çıkacak ve sorgu sonucu uzun süren bir işleme girecektir.
Statistics bakımları zamanında doğru bir şekilde yapılmadığı takdirde, query optimizer doğru düzgün çalışmayacak ve sorgularda performans sorunları yaşanacaktır. Sürekli veri kayıt olunan kolonlarda özellikle statisticslerin out-of-date diye tabir edilen, tarihi geçmiş olmaması önemlidir.
![clip_image002 clip_image002]()
Uygun Olmayan Sorgu Tasarımı
İndekslerin etkin bir biçimde kullanılması, SQL sorgularının yazım biçimiyle ilişkili bir yapısı vardır. Bir tabloda çok sayıda satırın döndüğü bir sonuç kümesini olması veya bir tablodan daha büyük bir sonuç döndüren bir filtre kriterini belirtilmesi durumlarında kullanılan indekslerde etkisiz kalabilmektedir.
Bu gibi durumlarda, performansı arttırmak için, sorgunun mutlaka yeni veya mevcut indeksleri kullandığından emin olunması gerekmektedir. Maliyet yani cost değerlerine dikkat edilmeden yazılan SQL sorguları, optimizer’ın uygun indeksleri seçmesini engellemektedir, bunun sonucunda da sorgu çalışma zamanlarının uzaması ve blockinglerin artmasına sebep olmaktadır.
Sorgu tasarımı, sadece tek başına kullanılan sorgulardan ibaret değildir. Bir bütün olarak düşünülmeli, birbiri ile bağlantı ilişkisel sorguların da tasarımında bütün olarak düşünülmeli ve tasarım buna göre yapılmalıdır.
Sadece tek bir sorgunun veya sorun olan sorguların performansını iyileştirmek, genel olarak SQL Server’ daki sorgu performansını iyi bir duruma getirmemektedir. Sorguların yazımında bir standart oluşturulması ve developerlar tarafından yazılan SQL kodlarının, veri tabanı yöneticileri tarafından bu kodların incelemesi ve denetlenmesi gerekmektedir.
Kötü Yapılandırılmış Execution Planlar
SQL Server’ da execution planların verimli olarak çalışmasını sağlamanın en temel yöntemi, tekrar tekrar yeniden recompile edilmeden, aynı execution planın kullanmasını sağlanmaktan geçer. Sürekli yeniden oluşturulan execution planlar, tam anlamıyla bir performance killer olduklarını söyleyebiliriz.
Yanlış ve kötü oluşturulmuş planlar, sürekli olarak parameter sniffing yapılmasına sebep olacaktır. Parameter sniffing de en iyi execution plan hangisi ise bunu seçmek için oluşturulmuş bir mekanizmadır. En iyi execution Plan’ı da statisticslerdeki bilgileri analiz ederek yapmaktadır.
Buradaki önemli nokta, statisticslerin ve parametrelerin, execution planlar oluştururken nasıl bir araya gelip, nasıl davrandıklarına hâkim olmaktır.
Bir sorguyu verimli bir şekilde çalıştırmak için, SQL Server query optimizer’ ı, execution plandaki maliyeti ilk olarak hesaplar ve ne kadar CPU kullanılması gerektiğinin maliyetini çıkartır. Execution planlar da memory üzerinde tutulur, memory üzerinde tutulmasının sebebi de disk den daha hızlı olmaları ve geri dönüşleri daha hızlıdır. Her sorgu için memory üzerinde planlar tutulmaktadır. Aynı sorgudaki parametreler değiştiğinde, bu execution planlar memory üzerinde yeniden oluşturuluyor ve bu yeniden oluşturma süreci de SQL Server’ a ek bir maliyet getirmektedir.
Execution planların memory üzerinde yeniden oluşturulmasını önlemek amacıyla, maliyeti düşük olan planın ilgili sorgu için set edilmesi önemlidir. Ayrıca stored procedure kullanımı ve stored procedurelerin de dynamic sql ile derlenmesi, memory üzerinde gereksiz plan oluşmasının önüne geçecektir.
![clip_image004 clip_image004]()
Blocking ve Deadlock’ların Çok Fazla Oluşması
SQL Server’ın mimarisinde, diğer ilişkisel veri tabanı sistemlerinde olduğu gibi ACID kavramı vardır. ACID’in açılımı şu şekildedir;
- Atomiticy – bölünmezlik
- Consistency – tutarlılık
- Isolation – izole yapı
- Durability – dayanıklılık
SQL Server bu dört kavrama uygun bir şekilde mimarisini oluşturmuş bir veri tabanı sistemidir. SQL Server’ın database engine’i, eşzamanlı transactionların birbirleriyle çakışmayacak ve izole bir şekilde çalışmasını sağlamaktadır. Bir transaction’da, data manipülasyonu tamamlanmadan, diğer bir data manipülasyon işlemi çalışmayacaktır.
Isolation yapısında, eş zamanlı olarak başlatılan birden çok transaction, ortak bir kaynağa uygun olmayan şekilde, yani aynı anda erişmeye çalıştığında veri tabanında blockingler oluşmaktadır. Birden fazla aynı anda çalışan prosesler, aynı veri kaynağın da değişiklik yapamazlar.
Bir satırdaki veriyi, aynı anda güncellemek istediğiniz de SQL Server buna izin vermez. Veri bütünlüğünü sağlamak için blocking mekanizmasını devreye sokar. Bu mekanizma veri sağlığı için gayet başarılı bir kurgudur. Fakat blockinglerin sürekli ve sık sık yaşanması, SQL Server’ da yavaşlıklara neden olmaktadır. Sürekli yaşanan blockingler, bir sorun olduğunun göstergesidir.
Blockingler ile ilişkili fakat farklı bir sorun olan konu ise deadlock’lardır. Deadlock’lar, ortak bir kaynağa erişmeye çalışan iki prosesin birbirini kilitlemesi ile başlayan, ardından query engine’nin en az maliyetli olan prosesi kill etmesiyle son bulan bir operasyondur. Bu kill edilen prosese deadlock victim denir.
Deadlockların genel olarak bir SQL Server temel sorunu olarak görülmektedir. Veri bütünlüğü ve ACID kurallarına uygunluk açısında, deadlocklar ilişkisel veri tabanı sistemlerinin olmazsa olmazlarıdır. Haliyle bir sorgunun çalışma zamanı, blocking ve deadlocklardan olumsuz bir şekilde etkilenir.
Blocking ve deadlock’ların sürekli ve sık sık oluşmasını engellemek için, isolation seviyelerini, transactionların kurgularını değiştirmek ve sorguların tasarımına dikkat etmek gerekmektedir.
![clip_image006 clip_image006]()
Doğru Set Edilmemiş SQL Operatörleri
Transact-SQL dili veri kümeleri üzerinde çalışan bir sorgulama dilidir. Aslında bunun anlamı, satır olarak düşündüğünüz bir yazılım dilinin, kolonlar bazında yani veri alanları açısından düşünmeniz gerektiğidir. T-SQL kodlarını yazarken de düz yazı gibi yazmak yerine kümelenmiş verilerin kolonlar bazında sorgulanmasını düşünerek olur.
Cursor kullanımları ve gereksiz döngüler kullanıldığında, subquerylerde ve joinlerdeki döngüyü gözden kaçırmanıza neden olabilir. Özellikle cursor kullanımı için performans killer tabirini kullanmak yerinde olur. Cursor yerine while operatörünü kullanmak ve sorgularınızı while döngüsü ile optimize edilmesi daha iyi olacaktır.
Sıkça yapılan SELECT * kullanımları da gereksiz IO tüketimlerine sebep olacaktır, * yerine ne kadar alan sorgulanmak isteniyor ise bu alanların isimleri üşenmeden yazılmalıdır.
Diğer bir performance killer ise ORDER BY’dır. SQL Server üzerinde sorting yani sıralama yapmak yerine bu işlemi yazılım tarafında yapmak, hem SQL Server performansına fayda sağlayacaktır, hem de dataların yazılıma daha hızlı gelmesi demektir. Yeni nesil yazılım teknolojilerinde interaktif sıralama modülleri oldukça gelişmiş seviyededir.
Uygun Olmayan Veri tabanı Tasarımı
Veri tabanı tasarımları genellikle yazılımı yazanlar tarafından veya yazılım yazımında kullanılan hazır frameworkler tarafından otomatik olarak yapılıyor. Özellikle hızlı ve pratik kod yazmak için, son zamanlarda bu tarz yapıların kullanımı artmaktadır.
Veri tabanı tasarlarken ilk dikkat edilmesi gereken nokta, veri işleme-manipülasyon ve blockinglerin olmaması için, tablo tasarımlarının optimize şekilde olması gerekmektedir.
Optimize bir veri tabanı nasıl tasarlanmalı konusu için, bir örnek üzerinden gidelim. Müşteri adresi ve müşteri siparişleriniz bizim verilerimiz olsun. İşin kolayına kaçarak, müşteri adresi ve müşteri siparişlerini tek tablo üzerinde tutarsanız eğer, verileriniz büyüdükçe, bir müşteri adresini ararken aynı zamanda gereksiz olarak müşteri siparişleri içinde kaynak harcayacaksınız. Her veriyi tek tablo üzerinde tuttuğunuz da ise, zamanla blockingler çoğalacak ve veri tabanınız içinden çıkılmayacak bir hale dönüşecektir.
Yukardaki örnek aslında normal bir şekilde, müşteri adresleri ve müşteri siparişleri olarak ayrı ayrı tablolarda tutulmalı. Bu tablolara ID’ler verilerek, aralarında foreing key dediğimiz yapıda bağlar kurulmalıdır.
Primary key’in her tabloda olması, veri tabanı tasarımı açısından önerilen bir durumdur, genelde ID alanlarında olması da daha performanslı çalışmasını sağlar. Primary key, unique constraints ve foreign key kullanımları tek başlarına veri tutarlığı ve doğruluğuna yetmese bile, optimizer tarafından bilinen ve sorgulama yapıldığında optimizer’a karar verme aşamasında yardımcı olan etkenlerdendir.
Veri tabanı tasarımı, veri tabanı performansının temellerini oluşturmaktadır. Veri tiplerinin de optimum şekilde seçilmesi, gereksiz olan alanlarda fazladan veya yanlış veri tipleri verildiğinde hem sorgu performansın hem de gereksiz olarak veri tabanın da büyümelere yol açacaktır.
![clip_image008 clip_image008]()
Index Bozulmalarının Sürekli Yaşanması
Bir arabanın horse power dedikleri, beygir gücü ne ise, SQL Server’ın horse power’ı indekslerdir. SQL Server performansının büyük çoğunluğunu indekslerden sağlar. İlişkisel veri tabanlarında, in-memory olarak çalışan veri tabanı sistemleri dahil, indeks yapılarına sahiplerdir.
İndeks konusu size karmaşık gelebilir, temel olarak eski telefon kulübelerindeki telefon rehberlerini düşünelim. Bu telefon rehberleri, A dan Z harfine doğru kayıtları tutmaktadır. Çilingir aramak istediğimizde, beynimiz bizi Ç harfine doğru yönlendirir. Ç harfinin, C den sonra D’den önce olduğunu, bize okulda öğrettiklerinden, bizim hemen Ç harfindeki kayıtlara gidebiliriz.
SQL dilinde, temelde bilgisayarların dili olan ASCI kod tablosuna göre yapılandırılmıştır. İlk olarak sayılar ardından harfler son olarak da özel karakterlerin olduğu uluslararası kabul görmüş bir standart bir kod tablosudur. ASCI kod tablosundaki sıra; rakam, harf ve özel karakterler, indeks performansı içinde geçerlidir. Hem harf hem de özel karakter olan bir alanı indekslemek ile, sadece rakam olan bir alanın indekslenmesi arasında, rakam olan indeks daha performanslı çalışacaktır.
Telefon rehberimize dönecek olursak, sürekli S harfinde arama yapıldığında, S harfine ait sayfalar yıpranacak, belki zamanla bu sayfalar okunamaz hale gelecek, yerine bu sayfaların yeniden yapılanması için yeni sayfalar ilave etmeniz gerekecektir. SQL Server’ da da çok sık okuma gören tablolardaki indeksler de telefon rehberindeki gibi sık sık bozulmalara maruz kalabilir.
Sürekli indeks analizi yapıp, indekslerininiz rebuild ve reorganize ederek, indeks fragmantasyonlarını düşürmeniz de fayda vardır. Veri işleme yoğunluğunuza göre, indeks bakım programlarınızın zamanlamasını kendi veri tabanlarınızın durumuna göre değiştirilmelisiniz. Indeks analizlerinde, indeksleri rebuild etmenize rağmen düzelmeyen indeksler gördüğünüz de bu indeksler page’lerini inceleyerek, page değerlerindeki yoğunluğu analiz etmeniz de fayda vardır. Düşük sayılara sahip pageler olabilir ve bunların indeks bakımlarına da ihtiyacı olmayabilir.
Özetle…
SQL Server performance tuning’i tekrarlanan bir süreç olarak adlandırabilir. SQL Server veri tabanlarınız da canlı mekanizmalardır, sadece verilerin ham olarak tutulduğu bir yer değil, sürekli veri işlenen, sürekli bakım yapılması gereken bir yapıdır.
SQL Server performansındaki değişiklikleri izlemek için, kendi baseline’larınızı oluşturup, performans iyileştirilmelerinden sonra, bu baseline değerlerine göre durumu incelemelisiniz. Genelde söylenen CPU yüzde 80’ler de idi, yüzde 30 lara indi ile başlanan cümleleri, daha somut hale getirebilmek için perfmon ile, SQL Server ve OS counterlarını toplayabilirsiniz.
Bu makalede sizlere, SQL Server’ın performansına olumsuz şekilde etkileyen unsurlar hakkında bilgiler vermeye çalıştım. Makale biraz daha SQL Server ile ilgilenen orta ve üst seviye teknik arkadaşların anlayacağı bir dille yazıldı diyebilirim. Giriş seviyesinde SQL Server bilenler için bazı kavramları detaylı olarak anlatmadım. Dediğim gibi SQL Server performance tuning konusu bitmeyen ve sürekli ihtiyaç bir konu olduğundan, sürekli SQL Server ile alakalı olanların ilgileneceği bir performans sürecidir.