PostgreSQL ve çalışan sorguları görmek…
PostgreSQL üzerinde çalışma yaparken özellikle ürünlerin geliştirme, performans ve unit testler sırasında o anda veri tabanında çalışan sorguları görmek isteriz, bu sayede yazılım hatalarını bulabilir ve daha performanslı sorgular yazabiliriz, peki bunu nasıl yaparız, bu konuda daha önceleri PostgreSQL üzerinde full query logging yapıyordum ancak başka yolları olduğunuda keşfettim (yaşasın özgür dökümanlar) Öncelikle postgresql.conf dosyamızda bulunan "stats_command_string" yapılandırma bildirimini "true" olarak değiştirmemiz gerekiyor. Ardından pg_ctl reload yada /etc/init.d/postgresql reload ile yeni yapılandırma ayarlarının postgres tarafından algılanmasını sağlamalıyız.
Şimdi artık veri tabanı sunucumuzda koşan sorguları yine veri tabanına göndereceğimiz basit bir sorgu ile öğrenebiliriz, bu sorguyu pg_stat_activity tablosunu kullanarak hazırlayacağız, bu tablo üzerinde çalışan sorguları, pid numaralarısını, hangi kullanıcının sorguyu çalıştırdığını, veri tabanı adını, ve sorgunun çalışmaya başlama zamanını öğrenebiliriz,
SELECT datname,procpid,current_query FROM pg_stat_activity;
datname | procpid | current_query
---------+---------+-------------------------------------------------------------
manager | 18432 | SELECT datname,procpid,current_query FROM pg_stat_activity;
Kimi zaman özellikle çalışan sunucularda performans çalışması yaparken hangi sorguların en sık çalıştırıldığını görmemiz gerekir bu tür durumlarda ise aşağıdaki gibi bir sorguyu çalıştırmamız yeterli olacaktır.
SELECT count(*) as cnt, usename, current_query FROM pg_stat_activity GROUP BY usename,current_query ORDER BY cnt DESC;
cnt | usename | current_query
-----+---------+------------------------------------------------------------------------------------------------------------------------
1 | root | SELECT count(*) as cnt, usename, current_query FROM pg_stat_activity GROUP BY usename,current_query ORDER BY cnt DESC;
fazlaca koşturan bir veri tabanım "henüz" olmadığından ayrıntılı örnek veremiyorum. Azla yetinmeyi öğrenin biraz canım.. Bizim zamanımızda yoktu böyle bloglar falan, deli gibi arardık her bişiyi...
Concat,PostgreSQL
Elimdeki proje ile uğraşırken bir soruna denk geldim, Aşağıdaki gibi bir sonuç döndüren sorgumun tek satırda almam gerekiyor, ancak name alanlarındaki verileri de kaybetmemem gerekiyordu. Biraz google biraz doküman okuyarak concat aggregate fonksiyonunu buldum ancak bu aggregate fonksiyonu PostgreSQL için yoktu, biraz daha bakınınca dökümanlardan birinde hazır yapılmışına rastladım. Eh burayada koymazsam olmaz sonra unutuyorum ![]()
SELECT name,phone FROM TABLENAME;
name | phone
-----------------+------------------
AAAAAAAF | 9054444333xx
AAAAAFFF | 9054444333xx
SSSSSDDDDAAAF | 9054444333xx
=> CREATE AGGREGATE concat (
(> BASETYPE = text,
(> SFUNC = textcat,
(> STYPE = text,
(> INITCOND = ''
(> );
CREATE AGGREGATE
SELECT CONCAT(name||', ') AS name, phone FROM TABLENAME GROUP BY phone ;
name | phone
------------------------------------------------------------------------------------------+------------------
AAAAAAAF,AAAAAFFF,SSSSSDDDDAAAF | 9054444333xx
Pek bir güzel oldu....
cursor, propel
Bazen veri tabanında büyük veriler ile çalışmanız gerekebilir. (şu andaki bir projemizde haftada 500 bin satır veri girilen bir tablomuz var örneğin) ve PHP5′in pek bir güzel framework’ü olan symfony ile bu büyüklükteki bir datayı işlemek isteyebilirsiniz. Karşınıza çıkacak sorunlar kısaca şunlardır. PHP’nin çalışma zamanını aşması (evet bu miktar çözülebilinir) ve PHP için ayrılan bellek miktarının yetmemesi. Bu gün symfony e-posta listesine benzer bir soru geldi ve büyük datalarla çalışan bir arkadaş (test amaçlı 100.000 satır veri ile) PHP’nin bellek sorununa takıldığını 100MB belleğin yetmediğini ve paket ürün olduğunda bu veri miktarının 10 misli artacağını ve sorunu nasıl çözeceğini soran bir e-posta atmış. (ben biraz geç fark ettim yoksa hemen üstüne atlardım. ) MySQL’de bu işler nasıl bilmiyorum ama PostgreSQL denen enfes veri tabanında CURSOR denen pek bir güzel kavram vardır. BEGIN COMMIT bloğu içerisinde bir cursor tanımlarsınız ve yapmış olduğunuz işlemin sonucu PostgreSQL tarafından bellekte tutulur ve bu bellekteki veriye belirttiğiniz CURSOR ile erişebilirsiniz. Bunun güzel tarafı sonucun postgreSQL tarafında tutulması böylece büyük resultset’ler sonucunda PHP’nin kullandığı bellek miktarını daha uygun bir şekilde kullanabilirsiniz. Elbette bu sonuç seti içerisinde ileri geri hareket edebilirsiniz.
Hemen bir e-posta ile hızlı ve tu kaka cinsinden bir yanıt verdim ve ardından verdiğim yanıtın testini yaptım (baya ukela biriyim önce test yapsana be adam alla alla) bir iki hata dışında CURSOR kullanımını Propel içerisinden nasıl yapılacağına dair bir kod ortaya çıktı. Eminim birileri bir gün büyük datalarla Propel nasıl çalışır diye arayacaktır (yada ben unutacağım ve o zaman buraya bakacağım) diye buraya yazayım dedim.
public static function getCity()
{
$con = Propel::getConnection();
try
{
$con->begin();
$stmt = $con->PrepareStatement("DECLARE mycursor CURSOR FOR SELECT * FROM ".self::TABLE_NAME);
$stmt->executeQuery();
$loop=true;
while($loop)
{
$loop = false;
$res = $con->executeQuery("FETCH FORWARD 60 FROM mycursor");
while($res->next())
{
$loop = true;
//birşeyler yapın
}
}
$con->rollback();
}catch(Exception $e)
{
// birşeyler yapın
}
// sonucu döndürebilirsiniz ama tavsiye etmem
}
İşlem yapacağınız Tablonun Peer sınıfına yukarıdaki bir method yazıyoruz yaptığımız iş kısaca,
DECLARE deyimini kullanabilmek için BEGIN ile bir transaction açıp, ardından
$stmt = $con->PrepareStatement(”DECLARE mycursor CURSOR FOR SELECT * FROM “.self::TABLE_NAME); satırı ile mycursor isimli bir CURSOR’ü “SELECT * FROM “.self::TABLE_NAME” deyimi için tanımlamak.
ardından sorgumuzu çalıştırmak, burada bize bir result set dönecektir bu result set boş olduğundan ihtiyacımız yok.
Hemen ardından loop içerisinde mycursor adındaki sonuç kümesinden 60′ar adet veri alabilmek için ” $res = $con->executeQuery(’FETCH FORWARD 60 FROM mycursor’); ” deyimini çalıştırıyoruz buradan bize 60 satırlık bir result set dönecektir. bu resultset’ide diğer bir loop içerisinde kullanarak içerisindeki verilerimizi alıp işliyoruz (ne yapacağınız size kalmış.) Yukarıdaki kod bloğunda “FETCH FORWARD 60 FROM mycursor” deyimi bir adet fazla çalışıyor. Nedenini biliyorum, peki siz düzeltebilirmisiniz? (hızlı bir PHP bilgisi testidir efendim kazananlar uzay havası ile ödüllendirileceklerdir. )
Merak işte
Günün birinde bir PostgreSQL veri tabanında ki bir tablonun disk üzerinde kapladığı alanı merak ederseniz şu SQL sorgusunu çalıştırın;
select pg_total_relation_size('tablename');
Aferim... akıllı çocuk...