QofQ: Query of Queries ile verileri uygulama seviyesinde işlenmesi


Query of Queries uygulama seviyesinde sorgu sonuçlarını tekrar işlemeye yarayan önemli bir yöntemdir. 

QofQ Eğer geliştirme sürecinde verilerin miktarı ve/veya sorgu sayılarınızın çokluğu ile başınız belada ise kullanmanız gereken yöntemdir. 

Yoğun veriler üzerinde çalışıyorsunuz, aynı veri kümesi üzerinde farklı farklı işlemler yapıyorsunuz. Nihai olarak aslında aynı salt tabloya/tablolara sorgular göndererek sonuçlar üretmeye çalışıyorsanız query of queries konusuna hakim değilsiniz demektir. Çünkü aynı veri kümesini uygulama seviyesine çektikten sonra uygulama belleğinde yine mevcut sorgudan sorgular üretmeniz mümkün. Böylece defalarca veritabanını meşgul etmemiş ve trafik yüzünden işinizi yavaşlatmamış olursunuz.


Başlamadan önce

Eğer query of queries metodunu kullanacaksanız ana sorguda diğer sorgularda kullanacağınız salt verileri aldığınızdan emin olun. Çünkü query of queries inner veya outer join desteklemez! Diğer tüm kavramları desteklesede birden fazla sorguyu birlikte kullanmanız mümkün olmayacaktır. Sadece union kavramıyla aynı kümeye ait birden fazla sorguyu alt alta eklemek kaidesi ile birleştirmeye izin verir.

B planı

Hemen işe koyulduk ve sorgumuzu yazdık, o da ne bir yerde gruplama yaparak toplamlar oluşturmak filan istiyoruz. Mesela kdv oranlarına göre alt toplamlar. En iyi şartta yeni bir query oluşturup veritabanına işletmemiz mümkün. Ancak zaten bu veri elimizde değil miydi? O zaman elimizde ki veriyi nasıl hesaplarız diye düşünüp loop işleminin ortasına diziler değişkenler oluşturup veritabanı işlemlerini azaltayım derken kodu çoğaltmış bulabilirsiniz. Tabi "DevLog - Filter, Map ve Reduce İşlemleri" başlıklı yazıda ki durumları yapmışsanız kabul ama diğer türlü asla diyebilirim. Elimizde en iyi ihtimalle bir kayıt kümesi yani sorgu sonucu var ve bu sorguyu aslında yeniden çalıştırsak işimizi görebiliriz diye düşünüyorsak doğru yerdeyiz. B planımız hazır!


Select * From tbl_fatura_satirlar Where fatura_tarihi >= {d '2010-10-10'}

Sorgumuz basit olarak veritabanından tbl_fatura_satirlar tablosunda ki 10.10.2010 tarihinden sonraki kayıtları alıyor. Böyle sorgu olmaz demeyin farz edelim ki var. Bunu da loop işlemi ile bir tabloya output ettiriyoruz. Buraya kadar herşey çok güzel ya toplam işlemleri? Genel toplamlar daha basitçe. Şöyle bir sorgu işimizi görür gibi


Select Sum(tutar) as toplam_tutar, Sum(net) as toplam_net From query_fatura_satirlar

Çok mu basit geldi? Tabiki çok basit, dbtype değerini query olarak eşitlediğimizde request içerisinde oluşturulan bir queryi direk tablo gibi kullanabiliyoruz. Bu sorgudan toplam tutarı okumak için query_toplamlar.toplam_tutar demek yeterli olacaktır. Tekrar veritabanına gitmemize gerek kalmadı. Tabi işlem basitti biraz daha zor bir konuya değinelim. Kdv oranlarına göre kdv tutarlarının toplamı gibi


Select kdv, sum(kdv_tutar) as kdv_toplam From query_fatura_satirlar Group By kdv

Yine standart bir sorguda ki gibi group by kısmını kullanarak yapıyoruz. Bu şekilde bize fatura satırlarında ki kdv oranlarının miktarı kadar satır dönmüş oluyor ve bu işlem için veritabanını rahatsız etmemiş oluyoruz. Buraya kadar query of queries konusunu aslında tamamlamış olduk. Klasik where bölümü de kullanabiliyoruz. Hatta daha önce belirttiğim gibi union ile alt alta tabloları yine birleştirmek mümkün. Bu konu sorgu yapabilen herkes için aslında çok basit bir kavram.

Daha fazlası gerekiyor ise

Bazen daha fazlasına ihtiyaç duyabiliriz. Bu işlemler için Pipe denilen No-Sql kavramının temelini oluşturan işlemleri yapmamız gerekir. Bir query of queries sorgusu kullanılarak pipe işlemine girebilir ve bu aşamada işlemlere tabi tutulara gerek join gerek ise subsetler oluşturulabilir. Bu işlemlerden hangisi hoşunuza gider bilemiyorum. Daha önce belirttiğim gibi "DevLog - Filter, Map ve Reduce İşlemleri" ile belirttiğim yazıyı okursanız daha iyi anlayabilirsiniz. Bu yazıda ki kavramlarla pipe oluşturup verileriniz için subsetler veya structlar yaratarak sonucunuzu kullanmanız gerekecektir.

Basitçe bir senaryo düşünürsek fatura listesi oluştururken satırları da almamız gerekti. Ancak satırları farklı bir query de fatura query içinde ki idlerle toplu olarak çektiğimizi varsayarak şöyle basitçe subset olarak alabiliriz.



Select * From query_fatura_satirlar Where fatura_id = #fatura_id#

Bu şekilde loop işlemi sürecinde query_fatura_satirlar sorgusundan ilgili faturaya ait olan satırları filtreleyerek join kurmadan subset olarak almış oluruz. Bu klasik veritabanı sorgusundan daha performanslı çalışacaktır. Bir pipe operasyonu yapmak istiyorsak


Bu örnekte de fatura başlık satırı subset satırı ile birleştirilerek bir diziye dolduruldu. Dizide bulunan fatura değişkeni fatura satırının struct halini subset ise bu faturaya ait sorguyu içerecektir. Dönen değeri de loop işlemi içerisinde işlem yürütmeden yapmayı mümkün kılmakta. Burada valueArray kullanarak fatura id lerinin bir dizisini alarak map işlemi ile fatura id değerini element üzerinden sorguya, index değerini de fatura satırını almak için queryGetRow fonksiyonuna vermiş olduk. Tam olarak no-sql mantığı ile işlemi yürütmüş olmasak da kısmen no-sql kısmen sql formatında işlem yaptık. Aynı işlemi no-sql formatıyla yapmak için "DevLog - Filter, Map ve Reduce İşlemleri" isimli yazıda ki yöntemleri kullanarak yapmanız mümkün.

Bu işlemi birden fazla subset üzerinde ve/veya birden fazla derinlikte subsetler olarak kullanmanız da mümkün olacaktır. Ancak bu işlemler için şu fonksiyonları da bilmenizde fayda var.

valueArray(query, column_name) array

Bir sorguda ki belirtilen kolonda bulunan değerleri dizi olarak döndürür. Sorgu adı (değişken olarak) ve kolon adı (string olarak) belirtilmelidir.

queryGetRow(query, row_index) struct

Bir sorguda ki belirtilen satırı key-value olarak struct içerisinde döndürür. Key sütun adı olup value da sütunun değerini içerir.

Yukarıda ki iki fonksiyon sql tabanından no-sql tabanına geçiş için gereklidir. Ancak sql katmanında kalarak queryMap, queryFilter, queryReduce işlemlerini de kullanabilirsiniz. Yalnız unutmamanız gereken en önemli nokta sql katmanında kalmanız (yani query üzerinde direk işlem yapmanız, qoq dahil) sizin esnekliğinizi kısıtlayacak yada esneklik elde etmek için çok fazla efor sarf etmenize neden olacaktır. Çünkü sorguların içerisinde ki veriler hem primitive dir hem de yeni sütunlar eklemeniz kolay bir konu değildir. Ancak no-sql yaklaşımı sizin için structlar ve arrayları kullandıracağı için her bir işlem de dahi farklı sütun ve veri tiplerini kullanabilmenize imkan sağlar.

Doğru yaklaşım

Query of queries işlemleri genellikle salt bir veri kümesini okumak ve bunun üzerinde işlemleri uygulama katmanında yapmayı hedefler. Query manuplation işlemleri genellikle subset oluşturmak için kullanılır. Tabi ki queryMap gibi bir fonksiyonla var olan sütunlarda değişiklik yapmak (örneğin TL değerleri USD ye dönüştürmek sorgu da ki tutar gibi kolonların değerlerini değiştirmek olacaktır) gibi işlemlerde olabilir. Ancak bu manuplasyonlar query of queries in konusu değildir.

Öncelikle bir dökümanda hangi verileri sunulacağına karar verilmeli, verileri salt bir şekilde okunup okunmayacağına bakılmalı, subsetlerin ortak kümelenmesi mümkünmü ayrı kümelerde ise veri miktarı çokmu gibi konulara odaklanmalıdır. Eğer bir yada birden fazla durum query of queries için uygun ise çekinmeden bu işlem yapılabilir. Ancak qoq kullanmak her zaman için mantıklı değildir, tek bir veri kümesinde işlem veritabanına yaptırılıp sonuç işlenmeden dökümana yansıyacak şekilde ise bu durumu qoq kapsamında değerlendirmemek daha iyi olabilir. Clean code yaklaşımına uygun davranacak isek model ve view kodlarını ayırmak adına ana sorgudan sonra alt sorguları da hemen ilişkilendirmek, gerekli query hesaplamalarını yaparak view kodlarına yansıtmak doğru olan seçenek olacaktır. Eğer tablo kolonlarınız çok fazla değil ise (structlar çok fazla değer aldıklarında memory daha fazla doldurabiliyorlar) no-sql mantığıyla verileri array ve structlara dönüştürmeli ve pipe ile ilerlenmelidir. Böylece siz veya sizden sonra geliştirime devam edecek developerlar model üzerinde ki işlemleri rahatlıkla okuyabilir ve gerekiyor ise yeni veri alanları açarak istenilen özellikleri yansıtabilirler. Unutmayın spagetti kodlar içerisinde gözden kaçabilecek hesaplamalar ve değişkenler ile yazılımcının hata yapma/gözden kaçırma riskini artırırsınız. 


Yazan: Halit Yurttaş - Workcube Software Architecture


Geri Bildirim

Bu içeriği faydalı buldunuz mu?
İlişkili İçerikler