შემთხვევითი ჩანაწერის ამორჩევა მონაცემთა ბაზის ცხრილიდან

ალბათ ბევრგან დაგჭირვებიათ შემთხვევითი ჩანაწერის ამოღება (random წერილის გამოყვანა ბლოგზე, random ფრაზა, random წიგნი – ბიბლიოთეკის საიტზე, random პროდუქტი – მაღაზიის საიტზე, ა.შ.) და შეიძლება რაიმე კარგი მეთოდიც გაქვთ შერჩეული ამისთვის.
მე კვლევები არ მიწარმოებია :))) ამ საკითხზე. უბრალოდ შემხვდა სასარგებლო სტატია, სადაც ამ მეთოდების განხილვაა მოყვანილი და მათი სისწრაფეებია შედარებული.

მეთოდი 1:

ვიყენებთ RAND() ფუნქციას, რომელიც float ტიპის რიცხვს აბრუნებს 0-დან 1-მდე.
sql მოთხოვნას შემდეგი სახე აქვს: SELECT * FROM `table` ORDER BY RAND() LIMIT 0,1;

როგორც სტატიის ავტორი წერს, მეთოდის პრობლემა მისი შესრულების დროა. MySQL-ს ყველა ჩანაწერი დროებით ცხრილში გადააქვს, თითოეულს ანიჭებს რაღაც შემთხვევით ინდექსს სორტირებისთვის. შემდეგ შედეგებს ასორტირებს და აბრუნებს პირველ ჩანაწერს.

უკეთესი მიდგომის აზრი ის არის, რომ ჯერ შეირჩეს შემთხვევითი რიცხვი და ამ შემთხვევითი რიცხვის მიხედვით ამოირჩეს მხოლოდ ერთი ჩანაწერი.

მეთოდი 2:

იმ შემთხვევაში, თუ თითოეულ ჩანაწერს უნიკალური გასაღები (მაგალითად id) გააჩნია, მაშინ შეგვიძლია ავირჩიოთ შემთხვევითი id უმცირეს და უდიდეს id-ებს შორის და შემდეგ დავაბრუნებინოთ იმ არჩეული id-ის ჩანაწერი.

უდიდესი და უმცირესი id-ის გასაგებად MAX() და MIN() ფუნქციები გამოვიყენოთ.

$range_result = mysql_query( " SELECT MAX(`id`) AS max_id , MIN(`id`) AS min_id FROM `table` ");
$range_row = mysql_fetch_object( $range_result );
$random = mt_rand( $range_row->min_id , $range_row->max_id );
$result = mysql_query( " SELECT * FROM `table` WHERE `id` >= $random LIMIT 0,1 ");
მეთოდი საკმაოდ შეზღუდულია, რადგან შეიძლება ცხრილს უნიკალური გასაღები საერთოდ არ ჰქონდეს. ამიტომ მესამე მეთოდში MySQL-ის LIMIT-ს ვეყრდნობით.

მეთოდი 3:

LIMIT ორ არგუმენტს იღებს. მაგალითად LIMIT 5,10  დააბრუნებს ჩანაწერებს 6-დან 15-მდე. ათვლა 0-დან იწყება.  პირველი არგუმენტი offset-ია (არ ვიცი როგორ ითარგმნება), ხოლო მეორე – offset-დან ათვლილი წამოსაღები ჩანაწერების მაქსიმალური რაოდენობა.

რომ გამოვთვალოთ offset პირველ ჩანაწერამდე – დავაგენერიროთ შემთხვევითი რიცხვი MySQL-ის RAND() ფუნქციის საშუალებით. შემდეგ მიღებული რიცხვი გადავამრავლოთ ცხრილში არსებულ ჩანაწერთა რაოდენობას (ამ რაოდენობას COUNT() ფუნქციის მივიღებთ). რადგან LIMIT მხოლოდ მთელ რიცხვებს იღებს არგუმენტებად, ეს ნამრავლი უნდა დავამრგვალოთ – გამოვიყენოთ FLOOR() ფუნქცია.

FLOOR() არითმეტიკული ფუნქციაა, რომელიც გამოთვლის უდიდეს მთელ რიცხვს გადაცემულ პარამეტრამდე. საბოლოოდ, კოდს ასეთი სახე ექნება:

$offset_result = mysql_query( " SELECT FLOOR(RAND() * COUNT(*)) AS `offset` FROM `table` ");

$offset_row = mysql_fetch_object( $offset_result );
$offset = $offset_row->offset;

$result = mysql_query( " SELECT * FROM `table` LIMIT $offset, 1 " );
MySQL 4.1 და უფრო მაღალ ვერსიებში ეს ორი მეთოდი შეგვიძლია ასე გავაერთიანოთ:

მეთოდი 4:

SELECT * FROM `table` WHERE id >= (SELECT CEILING( MAX(id) * RAND()) FROM `table` ) ORDER BY id LIMIT 1;

ამ მეთოდს იგივე ნაკლი აქვს, რაც მეორეს. ის მხოლოდ უნიკალურ გასაღებიან ცხრილებთან მუშაობს.

სტატიის ავტორმა მეთოდების სისწრაფეები შეადარა და სოფტის და ჰარდის სპეციპიკაციებს თუ არ ჩავუღრმავდებით, მიახლოებით ასეთი შედეგი მიიღება:

ყველაზე ნელი პირველი მეთოდია. ვთქვათ, რომ მას დროის 100% დასჭირდა შესრულებისთვის.
მეორე მეთოდს 79%.
მესამეს – 13%.
მეოთხეს – 16%.
გამოდის, რომ ყველაზე სწრაფია მესამე მეთოდი.

7 thoughts on “შემთხვევითი ჩანაწერის ამორჩევა მონაცემთა ბაზის ცხრილიდან

  • 07 იანვარი, 2009 at 17:33
    Permalink

    სირბილაძის წკგ მეთოდები არ წავა? 🙂

    ძალიან მომწონს საიტის დომეინი 🙂

    და ისე მთელი პოსტები რომ გამოდის read more ქონდეს არ ჯობს?

    ეს თემა შენ დაწერე? 🙂 ასეთ ლამაზ თემას მხოლოდ ჭეშმარიტი სამურაი გაჩითავდა 🙂 😛

    blogroll-ში დაგამატებ თუ არ გეწყინბა? 😀

    Reply
  • 07 იანვარი, 2009 at 17:38
    Permalink

    :))) არ მეწყინება
    არა მე არ დამიწერია.. უფრო ვთარგმნე. პოსტშიც არის ორიგინალის ლინკი.

    რაღაც გული არ მიმდის წკგ-ებზე 😀

    Reply
  • 07 იანვარი, 2009 at 18:54
    Permalink

    მაგ სტატიაზე კი არა ვორდპრესის თემაზე ვამბობ 🙂

    ბლოგი samurai, პერსონალური girl 😀 – ფერების მიხედვით 😀

    აუფ ჩემი სურათი რა დიდის ამბით ეხატება წავედი wordpress.com -ზე …

    Reply
  • 07 იანვარი, 2009 at 19:42
    Permalink

    ხომ. სკინი ჩემი დახატულია, თუ ეს მკითხე.

    Reply
  • 19 აპრილი, 2009 at 00:13
    Permalink

    SELECT * FROM `table` WHERE id >= (SELECT FLOOR( MAX(id) * RAND()) FROM `table` ) ORDER BY id LIMIT 1;

    აქ შეცდომაა, FLOOR ფუნქციის ნაცვლად CEILING უნდა იყოს, წინააღმდეგ შემთხვევაში ბოლო ელემენტი რჩება თამაშს გარეთ 🙂

    Reply
  • 20 აპრილი, 2009 at 02:16
    Permalink

    ყველაზე მარტივი გამოსავალი ეს არის:

    SELECT * FROM `table` ORDER BY rand() LIMIT 1;

    Reply
  • 22 აპრილი, 2009 at 17:36
    Permalink

    @linguistuss
    სწორი შენიშვნაა 🙂 მეოთხე მეთოდში ბოლო ჩანაწერს ვკარგავთ დამრგვალების გამო. პოსტსაც ჩავასწორებ 🙂

    Reply

კომენტარის დატოვება

თქვენი ელფოსტის მისამართი გამოქვეყნებული არ იყო. აუცილებელი ველები მონიშნულია *