ยินดีต้อนรับคุณ, บุคคลทั่วไป กรุณา เข้าสู่ระบบ หรือ ลงทะเบียน

เข้าสู่ระบบด้วยชื่อผู้ใช้ รหัสผ่าน และระยะเวลาในเซสชั่น

ThaiSEOBoard.comพัฒนาเว็บไซต์Programming[PHP,SQL] จะ random เรคคอร์ดอย่างไรให้รวดเร็ว ???
หน้า: [1]   ลงล่าง
พิมพ์
ผู้เขียน หัวข้อ: [PHP,SQL] จะ random เรคคอร์ดอย่างไรให้รวดเร็ว ???  (อ่าน 3957 ครั้ง)
0 สมาชิก และ 1 บุคคลทั่วไป กำลังดูหัวข้อนี้
xmen256k
หัวหน้าแก๊งเสียว
*

พลังน้ำใจ: 98
ออฟไลน์ ออฟไลน์

กระทู้: 1,999



ดูรายละเอียด
« เมื่อ: 11 กรกฎาคม 2013, 21:51:24 »

มีเรคคอร์ดอยู่ประมาณ 10,000 อัน และมีสถานะกำกับอยู่

ผมอยากจะสุ่มข้อมูลมาโชว์ 1 อันครับ

ไม่ทราบว่า เขียน SQL ยังไงให้คิวรี่ได้เร็วและไม่หนักโฮสบ้าง

ปล.
ผมลอง
โค๊ด:
SELECT * FROM table WHERE status ='correct' ORDER BY RAND() LIMIT 1 

มันช้าอ่าครับ

ขนาดรันใน localhost ใช้เวลาไป 993ms

รบกวนหน่อยนะครับ

ขอบคุณครับ
บันทึกการเข้า
mikeyx
Verified Seller
เจ้าพ่อบอร์ดเสียว
*

พลังน้ำใจ: 271
ออฟไลน์ ออฟไลน์

กระทู้: 4,046



ดูรายละเอียด เว็บไซต์
« ตอบ #1 เมื่อ: 11 กรกฎาคม 2013, 21:56:51 »

โค๊ด:
SELECT filed1,filed2,.... FROM table WHERE status ='correct' ORDER BY RAND() LIMIT 1

ทำ index
เวลา query ให้ query ตรง ๆไปเลย เช่น
$query_tb = mysql_query("SELECT filed1,filed2,.... FROM table WHERE status ='correct' ORDER BY RAND() LIMIT 1");
$show_data = mysql_fetch_array($query_tb);
บันทึกการเข้า
Bigguide
คนรักเสียว
*

พลังน้ำใจ: 7
ออฟไลน์ ออฟไลน์

กระทู้: 138



ดูรายละเอียด เว็บไซต์
« ตอบ #2 เมื่อ: 11 กรกฎาคม 2013, 22:01:52 »

1.ทำ index ให้ field "status" ดูครับ
2. ถ้า Query เราช้า ให้ลองใช้ explain ดูนะครับ จากตัวอย่าง query คุณ ใช้เป็น
explain SELECT * FROM table WHERE status ='correct' ORDER BY RAND() LIMIT 1

บันทึกการเข้า

I'm a dreamer
goldxp
สมุนแก๊งเสียว
*

พลังน้ำใจ: 73
ออฟไลน์ ออฟไลน์

กระทู้: 557



ดูรายละเอียด เว็บไซต์
« ตอบ #3 เมื่อ: 11 กรกฎาคม 2013, 22:41:19 »

SELECT * FROM table WHERE status ='correct' ORDER BY RAND() LIMIT 1
ผมใช้เครื่องpc รุ่นซื้อมา 7 ปีแล้ว run ยังแค่ 16-50 ms ครับ
ถ้าต้องการให้เร็วขึ้นลอง

set @number = (select max(id) from `table`)*rand();
select * from `table` where status='correct' and id > @number limit 1;

อันนี้ใช้เวลาใกล้เคียงกันครับ น่าจะแล้วแต่ว่าเครื่องกำลังทำงานอย่างอื่นด้วยหรือเปล่าซึ่งจะทำให้ช้าลงด้วยครับ  Tongue
« แก้ไขครั้งสุดท้าย: 11 กรกฎาคม 2013, 22:50:15 โดย goldxp » บันทึกการเข้า

MapTwoZa
ก๊วนเสียว
*

พลังน้ำใจ: 75
ออฟไลน์ ออฟไลน์

กระทู้: 366



ดูรายละเอียด
« ตอบ #4 เมื่อ: 12 กรกฎาคม 2013, 01:39:42 »

ถ้า data เยอะๆ order by rand() ไม่ดีแน่ๆครับ ห้ามใช้เด็ดขาดไอ order by rand() อ่ะ


ให้ใช้วิธี random ใน php แล้วไป query เอาครับ เช่นให้ใช้วิธี random ใน php แล้วไป query เอาครับ เช่น
$minId = rand(0,10000);
$result = mysql_query("SELECT * FROM `table` where id>$minId LIMIT 1");
** ใช้ > เพื่อกัน missing row ในกรณีเป็น auto increase
**** วิธีนี้ต้องรู้ range ของ data ที่แน่นอนครับ


แต่ถ้าข้อมูลไม่นิ่ง มีเพิ่มเรื่อยๆ ก็ให้ใช้วิธีนี้ครับ
สร้างตารางเป็น memory engine เอาไว้เก็บผลการ random ครับ วิธีนี้จะช้าตอนที่ query ครั้งแรก กับตอน data ในอีก table หมดครับ
เช่น ตาราง table กับ tablerand
โค๊ด:
function queryRandom(){
   $result = mysql_query("select tr.*, (select min(tr2.trid) as mini from tablerand tr2) from tablerand tr where tr.trid = mini");
   if(mysql_num_rows($result)==0){
      prepareData();
      return queryRandom();
   }
   else{
      // delete from tablerand where id = mini
      return ...; // return result of the query
   }
}
function prepareData(){
   // insert into tablerand select null as trid, t.* from table t order by rand() limit 100-1000
}
ตรงไหนเป็น comment ก็ไปเพิ่ม code เอาเองนะครับ


** ตาราง table rand ให้มี trid เป็น pk auto increase นะครับ

ปล. วิธีที่ 2 อาจจะช้าก็ได้นะ แค่ลองคิดแปลกๆ 55+ แต่คิดว่าน่าจะไวเพราะเอา memory engine มาใช้กับอีกตาราง
« แก้ไขครั้งสุดท้าย: 12 กรกฎาคม 2013, 02:22:27 โดย MapTwoZa » บันทึกการเข้า

Good code quality Developer Cheesy
Nomkhonwaan
คนรักเสียว
*

พลังน้ำใจ: 31
ออฟไลน์ ออฟไลน์

กระทู้: 198



ดูรายละเอียด
« ตอบ #5 เมื่อ: 12 กรกฎาคม 2013, 08:32:08 »

เป็นผมน่ะ

query รอบแรกดึงจำนวน record ทั้งหมดออกมาดูว่ามีกี่ record

จากนั้นใช้ php rand() ตัวเลขจากจำนวน record ทั้งหมด แล้ว query รอบสองก็ใช้ limit, offset เอา

เช่นสมมติดึงได้ 10k records ก็สั่ง rand()&10000 มันก็จะ random ตัวเลขระหว่าง 0 - 10000 ออกมา

ก็เอาไป query แบบนี้

โค๊ด:
$offset = rand()&(10000 - 1)
SELECT * FROM `table` WHERE `condition` .... LIMIT $offset, 1

 wanwan020
บันทึกการเข้า
teerdear1
Newbie
*

พลังน้ำใจ: 11
ออฟไลน์ ออฟไลน์

กระทู้: 85



ดูรายละเอียด
« ตอบ #6 เมื่อ: 12 กรกฎาคม 2013, 08:42:53 »

ถ้าผมจำไม่ผิด ถ้ามีข้อมูลเป็นแสน แล้วใช้คำสั่ง limit 1
เปลี่ยนเป็น fetch ข้อมูลมาครั้งเดียวจะไวกว่านะครับ ถ้าจำไม่ผิดอ่านะ
บันทึกการเข้า
phurich
คนรักเสียว
*

พลังน้ำใจ: 12
ออฟไลน์ ออฟไลน์

กระทู้: 194



ดูรายละเอียด เว็บไซต์
« ตอบ #7 เมื่อ: 12 กรกฎาคม 2013, 13:25:25 »

จำเป็นต้องใช้ SQL เท่านั้นเหรอครับ? หาก function Rand() ของ SQL มันช้า ก็ไปหา Algorithm อื่น ของภาษาอื่นมาก็ได้ครับ

ลองหา Algorithm การสุ่มค่าที่เร็วที่สุดในโลกดู พอได้แล้ว ก็ให้มันสุ่มเลขขึ้นมา แล้วคุณก็เอาเลขนั้น ไป select ข้อมูลเลย
บันทึกการเข้า

ส่งของจากอเมริกากลับไทย นำเข้าจากอเมริกา Pre-order USA จำหน่ายกล้องส่องทางไกล กล้องดูดาว
จำหน่ายเมล็ดผัก ปุ๋ย ยาฆ่าแมลง ยาฆ่าหญ้า เลื่อยโซ่ยนต์ เครื่องตัดหญ้า

eMicroMart.com บริการซื้อสินค้าและจัดส่งสินค้าจากอเมริกา
ThaiOptics.com จำหน่ายกล้องส่องทางไกล กล้องดูดาว
ThaiSeedOnline.lnwshop.com จำหน่ายเมล็ดผักและเครื่องจักรการ
xmen256k
หัวหน้าแก๊งเสียว
*

พลังน้ำใจ: 98
ออฟไลน์ ออฟไลน์

กระทู้: 1,999



ดูรายละเอียด
« ตอบ #8 เมื่อ: 12 กรกฎาคม 2013, 20:36:37 »

เป็นผมน่ะ

query รอบแรกดึงจำนวน record ทั้งหมดออกมาดูว่ามีกี่ record

จากนั้นใช้ php rand() ตัวเลขจากจำนวน record ทั้งหมด แล้ว query รอบสองก็ใช้ limit, offset เอา

เช่นสมมติดึงได้ 10k records ก็สั่ง rand()&10000 มันก็จะ random ตัวเลขระหว่าง 0 - 10000 ออกมา

ก็เอาไป query แบบนี้

โค๊ด:
$offset = rand()&(10000 - 1)
SELECT * FROM `table` WHERE `condition` .... LIMIT $offset, 1

 wanwan020

คือผมก็คิดไว้แบบนี้อ่าครับ แต่มันจะมีปัญหาหรือเปล่า

สมมติว่าถ้าช่วงฟิวของ auto increasment มันขาดตอนเช่น 1 2 3 5 6 7

แล้วแรนดอมออกมาเป้น 4 มันจะไปอ้างอิง ฟิว นั้นได้ยังไงอ่าครับ ??
บันทึกการเข้า
sskzclub
ก๊วนเสียว
*

พลังน้ำใจ: 118
ออฟไลน์ ออฟไลน์

กระทู้: 482



ดูรายละเอียด เว็บไซต์
« ตอบ #9 เมื่อ: 12 กรกฎาคม 2013, 21:54:49 »

เข้ามาติดตาม ครับ ^^
บันทึกการเข้า

xmen256k
หัวหน้าแก๊งเสียว
*

พลังน้ำใจ: 98
ออฟไลน์ ออฟไลน์

กระทู้: 1,999



ดูรายละเอียด
« ตอบ #10 เมื่อ: 13 กรกฎาคม 2013, 02:47:50 »

เป็นผมน่ะ

query รอบแรกดึงจำนวน record ทั้งหมดออกมาดูว่ามีกี่ record

จากนั้นใช้ php rand() ตัวเลขจากจำนวน record ทั้งหมด แล้ว query รอบสองก็ใช้ limit, offset เอา

เช่นสมมติดึงได้ 10k records ก็สั่ง rand()&10000 มันก็จะ random ตัวเลขระหว่าง 0 - 10000 ออกมา

ก็เอาไป query แบบนี้

โค๊ด:
$offset = rand()&(10000 - 1)
SELECT * FROM `table` WHERE `condition` .... LIMIT $offset, 1

 wanwan020

คือผมก็คิดไว้แบบนี้อ่าครับ แต่มันจะมีปัญหาหรือเปล่า

สมมติว่าถ้าช่วงฟิวของ auto increasment มันขาดตอนเช่น 1 2 3 5 6 7

แล้วแรนดอมออกมาเป้น 4 มันจะไปอ้างอิง ฟิว นั้นได้ยังไงอ่าครับ ??

ผมพอเข้าใจหละครับ

ตอนนี้ก็ลองทำดูแล้ว ลดลงเหลือ อยู่ราวๆ 50 ms

ปัญหาต่อมาคือผมจะสุ่มมากกว่า 1 อันอ่าครับ

ซึ่งลองเปลี่ยน LIMIT xxx,1 จาก 1 เป็น 5 ดู

มันกลับให้เป็นข้อมูลที่เรียงลงมากัน

ถ้าเป็นไอดีก็จะได้  4 5 6 7 8 อะไรแบบนี้

ถ้าอยากทำแบบสุ่ม 5 ตัว พอจะมีแนวทางบ้างไหมครับ
บันทึกการเข้า
cloudsphere
เจ้าพ่อบอร์ดเสียว
*

พลังน้ำใจ: 229
ออฟไลน์ ออฟไลน์

กระทู้: 6,197



ดูรายละเอียด เว็บไซต์
« ตอบ #11 เมื่อ: 13 กรกฎาคม 2013, 09:49:23 »

เข้ามาเก็บข้อมูล  wanwan003 wanwan017
บันทึกการเข้า

คนธรรมดา
หัวหน้าแก๊งเสียว
*

พลังน้ำใจ: 138
ออฟไลน์ ออฟไลน์

กระทู้: 1,046



ดูรายละเอียด เว็บไซต์
« ตอบ #12 เมื่อ: 13 กรกฎาคม 2013, 10:55:57 »

เป็นผมน่ะ

query รอบแรกดึงจำนวน record ทั้งหมดออกมาดูว่ามีกี่ record

จากนั้นใช้ php rand() ตัวเลขจากจำนวน record ทั้งหมด แล้ว query รอบสองก็ใช้ limit, offset เอา

เช่นสมมติดึงได้ 10k records ก็สั่ง rand()&10000 มันก็จะ random ตัวเลขระหว่าง 0 - 10000 ออกมา

ก็เอาไป query แบบนี้

โค๊ด:
$offset = rand()&(10000 - 1)
SELECT * FROM `table` WHERE `condition` .... LIMIT $offset, 1

 wanwan020

คือผมก็คิดไว้แบบนี้อ่าครับ แต่มันจะมีปัญหาหรือเปล่า

สมมติว่าถ้าช่วงฟิวของ auto increasment มันขาดตอนเช่น 1 2 3 5 6 7

แล้วแรนดอมออกมาเป้น 4 มันจะไปอ้างอิง ฟิว นั้นได้ยังไงอ่าครับ ??

ผมพอเข้าใจหละครับ

ตอนนี้ก็ลองทำดูแล้ว ลดลงเหลือ อยู่ราวๆ 50 ms

ปัญหาต่อมาคือผมจะสุ่มมากกว่า 1 อันอ่าครับ

ซึ่งลองเปลี่ยน LIMIT xxx,1 จาก 1 เป็น 5 ดู

มันกลับให้เป็นข้อมูลที่เรียงลงมากัน

ถ้าเป็นไอดีก็จะได้  4 5 6 7 8 อะไรแบบนี้

ถ้าอยากทำแบบสุ่ม 5 ตัว พอจะมีแนวทางบ้างไหมครับ

ทำได้แล้วก็ใช้วิธี Loop
บันทึกการเข้า

หน้า: [1]   ขึ้นบน
พิมพ์