KodFeed İLMİN ZEKATI…

12Nis/104

MSSQL Random Veri Seçme

Öncelikle bir veritabanında yapmış olunan count sorgulama işlemi tabloda veriler fazla ise bir hayli yavaştır. Eğer bir where şartı olmadan count alınacak ise;

SELECT COUNT(*) FROM TABLE

yerine

SELECT rows AS TABLECOUNT FROM sysindexes WHERE id = OBJECT_ID('TABLENAME') AND indid < 2

sorgusunu çalıştırmak daha avantajlıdır. Testler sonucuna bakıldığında 80.575.646 verinin bulunduğu tabloda yapmış olduğum testte 1. sql komut satırı çalıştırıldığında MSSQL Management Studio'da 28 saniyede sayımı tamamladı, 2. sql komut satırını çalıştırıldığında ise sayım işemi 00:00:00 olarak gösteriyor :) Webden timer ile çalıştırıp yaptığımda zaman sadece 0,0302734 saniye sürdüğü görülmektedir. Aslında ikinci sql'de count alınmıyor. Zaten tablolardaki kayıt sayısı sysindexes tablosunda mevcut.

Bu ipucuyu verdikten sonra şimdi asıl konumuz olan random verinin alınması olayına geri dönelim. Database'de rastgele bir verinin seçilmesi için veritabanımızda kaç verinin olduğunu bulmamız şarttır. Yukarıda yazmış olduğum sql ise tam olarak burada devreye girmekte. Normal'de yaygın olarak kullanılan 2 yol vardır rastgele verinin seçilmesi için.

1. yol MsSql'de bulunan RAND fonksiyonu

SELECT top 1 ID,FIELDNAME FROM TABLENAME ORDER BY RAND(ID), FIELDNAME 

Bu sql çalıştırıldığında random olarak bir veri bize geri dönecektir. Bu sql çalıştırıldığında Management Studio 18 saniyede cevabı döndermiştir. Görüldüğü gibi epey bir yavaştır. Böyle bir sql'i sayfanızda çalıştırdığınızı düşünsenize :)

2. yol MSSQL'de Recordset Move Olayı

Diğer yaygın kullanımlardan biriside recordset'in movenext olayını kullanmaktır. Bu yolda; öncelikle sql çalıştırılmakta, ardından random bir sayı oluşturulmakta ve bu random sayıya move diyerek ilerlemektir.

sql = "SELECT * FROM TABLENAME"
rs.Open sql, conn,1,3
Randomize Timer
intRnd = (Int(RND * rs.RecordCount))
rs.Move intRnd

Yukarıda göründüğü gibi öncelikle sql çalıştırımakta ve 1,3 ile sayı alınmakta ve recordcount'a kadar random bir sayı üretilmektedir. Bu üretilen sayıyada rs.move ile gidilip veri alınmaktadır. Bunu webde kullandığımda sonuç tam bir fiyasko :) Timeout expired. Bu arada sayfamızın timeout expired hatasına düşmemesi için aşağıdaki kodları eklememiz gerekiyor. Arada bunuda söylemiş olalım :)

  Server.ScriptTimeout = 999999
  conn.CommandTimeout = 0

Açıkcası bu kodu yazıp çalıştırdım ve gelip burada yazmaya devam ettim. Halen arka planda sayfa çalışmaya devam ediyor :) Cevap verecek gibi değil. Buraya sonra tekrar dönüp sonucu yazacağım diyorum ve devam ediyorum.

3. Yol Count Bulma Yöntemi

Count bulma yöntemi yazdım isim olarak ama ne kadar doğru oldu bilemiyorum. Arkadaşın sorusu üzerine aklıma geldi bu yöntem ve açıkcası bu count mssql ipucusunu yazacakken bu örneği bulmak iyi oldu. Bu yöntemde ise önce count bulunacak, ardından random bir sayı oluşturulacak ve bu random sayının verileri çağrılacaktır.

   sql = "SELECT rows AS TABLECOUNT FROM sysindexes WHERE id = OBJECT_ID('TABLENAME') AND indid < 2"
 rs.open sql,conn   SQLCount = rs("TABLECOUNT")
 rs.close   Randomize Timer   intRnd = (Int(RND * SQLCount))   sql = "SELECT TOP 1 * FROM TABLENAME WHERE PK ="&intRnd
 rs.open sql,conn

Bu yöntemi kullandığımızda performans fevkalede (Yemede yanında yat :) ). Bu yöntemde görüldüğü gibi 1. sql çalıştırılarak veri sayısı bulunuyor, Randomize Timer kullanarak aynı verinin çağırmamasını sağlıyoruz ve intRnd değişkenine bir random sayı alıyoruz. Bu random sayıyı ile yeni bir sql oluşturuyoruz ve bu SQL'de verimizi çağırıyoruz :) Performans testinde ise bu yöntem ile cevabın geri dönmesi 0,401 saniye sürmektedir.

Sonuç olarak yapılan test 80.575.646 data üzerinden yapılmıştır. Bu datalara göre istatistikler şu şekildedir.

Management Studio için test sonuçları:

1. Yöntem : 18 saniye
2. Yöntem : Management Studio'da test edilmedi.
3. Yöntem: Management Studio'da test edilmedi

Web Sayfası için test sonuçları:

1. Yöntem : 19,26611
2. Yöntem: Timeout Expired ( Zaman aşımına uğradı) ve zaman aşımına uğramaması için kodlara ekledim ama yazımın sonuna gelmeme rağmen halen cevap dönmedi. Belki birgün verir :)
3. Yöntem: 0,401 saniye

Her 3 testide test etmeniz için ASP kodu aşağıdadır.

<%
  Dim StartTime
  StartTime = Timer
  dim SQLCount
  '1. Yöntem
  StartTime = Timer
  sql="SELECT top 1 PK,FIELDNAME FROM TABLENAME ORDER BY RAND(PK), FIELDNAME"
  rs.open sql,conn
  Response.Write("1. Yöntem" & Timer-StartTime &" saniye sürmüştür. Random ID" & rs("FIELDNAME") & "")
  rs.close

  '2. Yötenm
  StartTime = Timer
  sql = "SELECT * FROM TABLENAME"
  rs.Open sql, conn,1,3
  Randomize Timer
  intRnd = (Int(RND * rs.RecordCount))
  rs.Move intRnd
  Response.Write("2. Yöntem" & Timer-StartTime &" saniye sürmüştür. Random ID" & rs("FIELDNAME") & "")
  rs.close

  '3. Yöntem
  sql = "SELECT rows AS TABLECOUNT FROM sysindexes WHERE id = OBJECT_ID('TABLENAME') AND indid < 2"
  rs.open sql,conn
  SQLCount = rs("TABLECOUNT")
  Response.Write ("Toplam Kayıt : " & SQLCount &"")
  rs.close
  Randomize Timer
  intRnd = (Int(RND * SQLCount))
  sql = "SELECT * FROM TABLENAME WHERE PK ="&intRnd
  rs.open sql,conn
  Response.Write("1. Yöntem" & Timer-StartTime &" saniye sürmüştür. Random ID" & rs("FIELDNAME") & "")
  rs.close
%>

Bol perfomanslı günler :)

VN:F [1.9.13_1145]
Rating: 8.0/10 (1 vote cast)
VN:F [1.9.13_1145]
Rating: 0 (from 0 votes)
MSSQL Random Veri Seçme , 8.0 out of 10 based on 1 rating
Yorumlar (4) Geri izlemeler (1)
  1. Bence yukardaki ifadeleri karşılaştırmak yersiz. Örneğin neden 3. örnekte yapılan işlemi direk 1. SQL de yapmadınız? 80 küsür milyon satırı sıralattınız sql e, sonra gidip en tepedekini seçtiniz. 80 milyon satırı sıralamak sürdü o kadar yani.

    Dikkat edilmesi gereken diğer bir önemli husus da, 3. yöntemin işlemesi için tablo’da PK nın identity ve aralıksız ardışık olması gerekiyor. (yani tablonun şimdiye kadar herhangi bir satırı hiç delete edilmemiş ve/veya hatalı insert denenmemiş olması gerekiyor.)

    En azından bu iki sebeple bile yukardaki karşılaştırma kısıtlı kalıyor bence ne yazık ki :(

    VA:F [1.9.13_1145]
    Rating: 0.0/5 (0 votes cast)
    VA:F [1.9.13_1145]
    Rating: 0 (from 0 votes)
  2. Merhabalar,

    3. örnekte 80 küsür milyon satırı sıralamıyorum. 3 örnekte yapılan işlem şu; işlem yaptığımız tabloda kaç kayıt olduğunu alıyoruz ve o aralıkta random bir sayı tutup o datayı çekiyoruz.

    Satır delete edilmemiş ve aralıksız ardışık olması gerekiyor evet. Fakat bu sadece 3. yol değil 2. yolda da aynısı geçerlidir. Kod sadece test için geliştirilmiş olduğundan dolayı geliştirilmemiştir. Sql query null bir değer gelirse tekrar sorgu yapılabilir. Amaç performans karşılaştırması.

    VN:F [1.9.13_1145]
    Rating: 0.0/5 (0 votes cast)
    VN:F [1.9.13_1145]
    Rating: 0 (from 0 votes)
  3. eyvallah

    VA:F [1.9.13_1145]
    Rating: 0.0/5 (0 votes cast)
    VA:F [1.9.13_1145]
    Rating: 0 (from 0 votes)
  4. Merhaba, merak ettiğim bir şey var eğer bir tane değil de birden çok veri sıralamak istiyorsak random olarak ne yapmamız gerekiyor?

    VA:F [1.9.13_1145]
    Rating: 0.0/5 (0 votes cast)
    VA:F [1.9.13_1145]
    Rating: 0 (from 0 votes)

Leave a comment

(required)