Archive

Archive for the ‘MySQL’ Category

Random Row เรื่องเล็กๆ ที่สามารถสร้างปัญหาใหญ่ๆ

February 25, 2013 Leave a comment

หลังจากที่มีข้อมูลใน Database MySQL เยอะขึ้นแล้ว สิ่งที่มองข้ามในหลาย ๆ จุดก็เริ่มแสดงผลขึ้น

เรื่องง่ายอย่างเช่นการสุ่มแสดงผลโดยใช้ RAND() ใน Mysql กลับใช้ทรัพยากรอย่างมากในการสุ่มแต่ละครั้ง

ทำให้ Server เริ่มเกิดอาการโหลดหนัก เนื่องจากมีการสุ่มข้อมูลเพื่อนำไปใช้ตลอด

(กว่าจะเจอต้นตอของความช้าก็ไล่ Benchmark Code แต่ละส่วนนานอยู่)

 

สำหรับเว็บที่มีแถวข้อมูลเป็นจำนวนมาก การใช้ RAND() นั้นไม่เหมาะแน่ ข้างล่างคือ Code เจ้าปัญหา

[Codeigniter]

$query = $this->db->limit(1)->order_by(‘unique_id’, ‘random’)->get(‘product’);

ผลลัพธ์ที่ออกมาได้หลังจาก Benchmark คือ 0.0693 วินาที อาจดูไม่มาก

แต่ด้วยจำนวน Req กับการที่ MySQL มันซด CPU ไปเยอะ แทบจะโดน VPS Provider เตะออก

 

คราวนี้มาแก้ไขกัน

ทั่วไปเค้าจะให้นำตัวเลขที่เป็น ID [auto increasement] มาหาค่า MAX แล้วสร้าง Random ตัวเลขเปล่าขึ้นมา

หลังจากนั้นก็นำตัวเลขนั้นไป Query Where ตรง ๆ แต่ในกรณีของผม ตัวตาราง DB ของสคริปนั้นไม่ได้มี AI Number

จึงเปลี่ยนมาใช้การตั้ง Limit Offset แทน ตัวอย่างโค๊ด ด้านล่าง

$count = $this->db->count_all_results(‘product’);
$query = $this->db->limit(1, rand(1, $count))->get(‘product’);

ผลลัพธ์ที่ได้คือ 0.0079 วินาที ไวกว่าเกือบ 10 เท่า และไม่ต้องกังวลเมื่อมี Product เพิ่มมากขึ้น

หลังจากที่ได้นำวิธีนี้ไปลองใช้ สามารถลดการใช้ CPU ไปได้อีกเยอะ

Trim ผ่าน MySQL โดยตรง

June 26, 2012 Leave a comment

UPDATE smf_messages set subject= TRIM(subject);

ตัวอย่าง :: trime หัวข้อเว็บบอร์ด smf

และ

UPDATE smf_messages set subject= replace(subject,’\t’,”);

สำหรับบางกรณีที่เป็น Tab Character

Categories: MySQL Tags: ,

วิธี Group การค้นหา Where แบบ OR

September 12, 2011 Leave a comment

ปกติถ้าต้องการค้นหาบางฟิลด์แบบหลายเงื่อนไข บางคนอาจใช้วิธี Loop Query ตั้งแต่ต้นแล้วมาเชื่อมด้วย OR ใหม่ เช่น

SELECT * FROM Users WHERE FirstName = ‘Mac’ AND LastName = ‘Smith’ OR FirstName = ‘John’ AND LastName = ‘Jones’);

แต่คราวนี้เราจะใช้วิธี Group Where ที่ต้องการค้นหาแบบหลายผลลัพท์ ตัวอย่างด้านล่าง

SELECT * FROM Users WHERE FirstName = ‘Mac’ AND (LastName = ‘Smith’ OR LastName = ‘Jones’);

เท่านี้ MySQL ก็จะค้นหา FirstName = Mac โดยที่ LastName จะเป็น Smith หรือ Jones ก็ได้

Categories: MySQL Tags: , ,

การ Group By วันที่ ใน Format ต่าง ๆ

May 28, 2011 Leave a comment

จะขอยกตัวอย่างใน codeigniter นะครับ ซึ่งถ้าใช้ Query String ก็ใช้แบบเดียวกัน

การ Group By เวลาของ Unix time

(Unix time จะเป็นตัวเลข 10 หลัก ซึ่งถ้าไม่ใช้ Function ของ MySQL ลำบากแน่ครับ)

$this->db->group_by(“FROM_UNIXTIME(ชื่อฟิลด์ที่ต้องการกรุ๊ป, ”%Y-%m-%d”)”);

จะเป็นการ Group ตามวันเรียง ๆ กันไป เราสามารถใช้อีกเงื่อนไข

เพื่อทำการนับได้ว่าตามวันนั้น ๆ ที่ List เรียงจาก MySQL มีจำนวนเท่าไหร่

$this->db->select(‘Count(“ชื่อฟิลด์ที่ต้องการกรุ๊ป“) as number,ชื่อฟิลด์ที่ต้องการกรุ๊ป ‘);

เช่น

2011-05-28 มี 5 แถว

2011-05-29 มี 3 แถว

ค่าฟิลด์ number ของวันที่ 2011-05-28 ตาม Unix time ก็จะเท่ากับ 5

ส่วน 2011-05-29 ก็จะเท่ากับ 3 ในเวลาที่เรา foreach ผลลัพท์ออกมาทีละแถว

คราวนี้มาดู วิธี Group Datetime ของ MySQL กันบ้าง

ถ้าเรามีฟิลด์ Datetime อยู่ แล้วอยากให้ Group กัน แค่วันที่เพื่อนับว่าวันนึงมีสถิติผู้ใช้เท่าไหร่ ให้ใช้คำสั่งนี้

$this->db->group_by(“DATE(ชื่อฟิลด์ที่ต้องการกรุ๊ป)”);

หลังจากนั้นถ้าต้องการนับผลลัพท์จำนวนแถวทั้งหมด (จำนวนแถวจริง ไม่ใช่แนวหลัง Group นะครับ) ก็ให้ใช้คำสั่งแบบเดิม

คือการ Count ชื่อฟิลด์ที่กรุ๊ปแบบเดียวกับด้านบน เท่านี้ก็เขียนวิธีนับแถวตามวันได้แบบง่าย ๆ แล้ว

 

ปล. สำหรับ Codeigniter ถ้ามีปัญหาให้ลอง ใช้คำสั่งนี้วาง บนและล่างของบรรทัดที่ใช้ MySQL Function เช่น

$this->_protect_identifiers = FALSE;

$this->db->group_by(“DATE(regis_datetime)”);

$this->db->select(‘Count(“regis_datetime”) as number,DATE(regis_datetime) as day’);

$this->_protect_identifiers = TRUE;