Green green glass of home

Posted in Photography | No Comments »

Well, this is not my home and rice is, technically, a relative of grass.

 

ใช้แอพอะไรบน WP8

Posted in Review | No Comments »

เมื่อวานไปกินข้าวกับ @markpeak และ @TonsTweetings ช่วงหนึ่งของการสนทนา ก็คุยกันถึง Windows Phone ว่าเป็นอย่างไรบ้าง

ถ้าให้ตอบสั้น ๆ ก็คือ WP ก็ยังเป็นมือถือโลกที่สาม ที่มีลำดับความสำคัญน้อยมากในหมู่นักพัฒนาแอพ แอพจำนวนหนึ่งที่มีก็มีแบบให้รู้ว่ามีนะ แต่คุณภาพก็งั้น ๆ

ก่อนที่จะไปตอบยาว ๆ ควรจะบอกก่อนว่า ผมใช้บริการของ Google หลายอัน เช่น GMail ทั้งเมลส่วนตัวและเมลของที่ทำงาน รวมถึง GCal, GTalk และ G+ ด้วย ซึ่งในสมัยที่ใช้โทรศัพท์แอนดรอยด์ ชีวิตก็มีความสุขดี แต่พอเปลี่ยนมาใช้  WP ชีวิตก็ลำบากทันที ลองมาไล่ดูนะครับ

 

  • EMail: Mail บน WP ห่วยมาก แม้แต่ว่าจะใช้กับ Hotmail เพราะว่าแทบไม่มีความสามารถอะไรเลย เช่น เรียงเมลตามผู้ส่งหรือวันที่ก็ทำไม่ได้ ยิ่งถ้าใช้ GMail ด้วยแล้ว จะลำบากมาก เพราะต้องย้อนไปใช้ IMAP หรือ POP ในการดึงเมล ทำให้ใช้ความสามารถของ GMail  ไม่ได้เต็มที่ ทางแก้ก็ ไปซื้อแอพ 3rd party มาใช้ ตัวที่ใช้อยู่คือ MetroMail ซึ่งเป็นแอพสำหรับ GMail โดยเฉพาะ สนับสนุนความสามารถของ GMail เช่น Label, Star หรือ Archive เป็นต้น แต่…… ก็ยังไม่มี Sort เหมือนเดิม แต่โดยรวม ก็ถือว่าคุ้มดีครับ
  • Calendar: Mail บน WP ว่าห่วยแล้ว Calendar บน WP ยิ่งห่วยกว่า อะไรคือ Calendar ที่ไม่มี Week View วะครับ แถม Month View ก็พยายามแสดงรายการโดยตัวหนังสือ แต่มันก็เล็กมาก จนอ่านไม่ออก แถมพอวันไหนมีงานเยอะ มันก็ไม่แสดงงานทั้งหมด ส่วน Day View ก็ใช้ยาก เพราะหนึ่งหน้าแสดงได้แค่หกชั่วโมง ซึ่งก็คือแค่ครึ่งเช้าหรือบ่าย ถ้าจะดูทั้งวัน ก็ต้องถูขึ้นถูลง และยิ่งถ้าจะเช็คว่า วันไหนว่างบ้าง เพื่อจะนัดวัน เนื่องจากไม่มี Week View ก็ต้องถูขึ้นถูลง เพื่อดูว่าวันไหนว่าง สรุปว่า ใช้งานแทบไม่ได้ ตัวที่ใช้อยู่ ก็ซื้อมาอีกแล้ว ชื่อ Cal เฉย ๆ มีครบทั้ง Month, Week, Day, Agenda View และแต่ละวิว ก็ใช้งานได้จริง เช่น Month View ก็แยกเป็นสองส่วน ส่วนบน เป็นปฏิทินทั้งเดือน ที่มีจุดสีในแต่ละวัน เพื่อแสดงว่า วันนั้นมีนัดหมายหรือไม่ ซึ่งถ้ากดที่วัน ด้านล่าง ก็จะแสดงรายการนัดหมายในวันนั้น ซึ่งใช้งานได้จริงกว่าการพยายามยัดข้อมูลทั้งหมดใส่ลงไปในปฏิทิน Week View ก็แสดงแบบ Agenda (แสดงเพราะรายการนัดหมาย) ทำให้หน้ามันไม่ยาวเกินไป สรุปว่า ใช้งานได้จริง และประทับใจครับ ข้อเสียมีอยู่แค่ว่า บางทีก็มีกระตุกบ้าง แต่เดี๋ยวคงดีขึ้น
  • Social Networks: ผมเลิกใช้ FB ไปแล้ว และลดเล่น Twitter ไปเยอะ แต่ยังใช้ G+ อยู่ ซึ่ง WP ไม่มี Native Client ของ G+ แต่โชคดีที่ IE บน WP ค่อนข้างโอเค ก็เลยเล่น G+ บน WP ได้แบบถูไถ ที่บอกว่าถูไถ เพราะมันเป็น mobile app ที่ทำอะไรไม่ค่อยได้ เช่น จะอัพรูปก็ทำไม่ได้ครับ เพราะ IE ไม่สนับสนุนการเปิดไฟล์ในเครื่อง ต้องใช้วิธีส่งรูปขึ้น OneDrive แล้วไปแชร์ลิงค์จาก OneDrive เอา ซึ่งก็พอถูไถไปได้
  • Instant Messaging: แน่นอน ไม่มี GTalk Client แต่มี 3rd party ที่พอใช้ได้คือ Gchat ก็ถูไถใช้ไป ส่วน ตัวอื่นเช่น Line หรือ WhatsApp ก็มีแอพให้ใช้ครับ แต่ก็ตามประสามือถือโลกที่สาม มีแอพ แต่มีไม่ครบฟีเจอร์ เช่นใน Line ไม่มี เกม (นับเป็นข้อดี) มีสติกเกอร์สโตร์ก็เหมือนไม่มี เพราะ สติกเกอร์ที่ขายบนสโตร์ ก็มีเฉพาะที่มีในเครื่องอยู่แล้ว (นี่มันบั๊กชัด ๆ !!!) แต่ฟีเจอร์ที่ใช้งานบ่อย เช่น Line Call ก็ทำงานได้ดีครับ ก็ถือว่าใช้งานได้ดี สรุปว่า มีใช้ในระดับถูไถ จนถึงดีครับ
  • Office: คงไม่ต้องพูดถึง เพราะมี MS Office อยู่ ใช้งานได้ดี ครบเครื่อง แฮปปี้ มีความสุข
  • Cloud Storage: ไม่มี Native Dropbox/GDrive Client ครับ จบข่าว ย้ายค่ายสถานเดียว ตอนนี้ก็เริ่มย้ายไป OneDrive บ้าง แต่บางครั้งก็ต้องแชร์งานกับคนอื่นผ่าน Dropbox/GDrive ก็ใช้ Web Client  ไป ก็พอถูไถ
  • Note: ผมใช้ Evernote อยู่ ซึ่ง Client บน WP ก็ทำงานได้ในระดับถูไถ คือฟีเจอร์จะมาช้ากว่าแพลตฟอร์มอื่นมาก แถม Sync ช้าอีกต่างหาก แต่การใช้งานโดยรวมก็นิ่งดีครับ และเนื่องจากผมใช้ Email to evernote เยอะมาก ซึ่ง OneNote ยังทำได้ไม่ดี ก็เลยยังไม่ย้ายไป OneNote
  • News Reader: ผมอ่านข่าวบน Pulse ซึ่ง เช่นกัน ไม่มี Native Client บน WP แต่อ่านบน Mobile Web ก็โอเคดี ก็อ่าน ๆ ไป
  • Twitter/Facebook/Instagram/Amazon/Ebay/LinkedIn/MoloMe/Skype/TuneIn Radio/Weather/Foursquare/ กลุ่มนี้เป็นแอพ Utility ที่ทำ Native Client มาค่อนข้างดีครับ ใช้งานได้ดีทุกตัว
  • ดูหนังฟังเพลง โปรแกรมฟังเพลงบน WP ก็ใช้งานได้พอถูไถ การ Sync ผมใช้ Windows Media Player ทำ Playlist แล้ว Sync เข้ามาก็โอเคดี จะมีปัญหาแค่ Youtube ที่ไม่มี Native Client อีกแล้ว แต่ Mobile Web ก็พอถูไถ
  • Endomondo ผมใช้ Endonmodo track การออกกำลังการอยู่ (ไม่มี Nike+ นะ) ซึ่งแอพตัวนี้เก่ามาก ขาดฟีเจอร์ที่มีบนแอพอื่นไปเยอะ สรุปว่า ก็พอถูไถอีกแล้ว
  • ผมไม่เล่นเกมบนมือถือครับ ไม่ว่าจะแพลตฟอร์มไหน

สรุปว่าแอพบางส่วนก็ใช้งานได้ดีครับ อันที่ไม่ดีก็พอถูไถ หรือถ้าไม่มี Native Client ก็ใช้ Mobile Web ก็พอถูไถเช่นกัน โดยรวม ๆ ถือว่าผ่านครับ ไม่รู้สึกว่าขาดอะไร

 

 

 

 

Ant

Posted in Photography | 1 Comment »

OLYMPUS DIGITAL CAMERA

5ส เป็นเรื่องง่ายไปในทันที

Posted in Photography | No Comments »



ดอกมะนาว

Posted in Photography | No Comments »

ปลูกมาสองปี จะได้ลูกแล้ว



นกธรรมดา

Posted in Photography | No Comments »



ยุบ รวม เลิก

Posted in Photography | No Comments »

พบว่าการแตกเป็น 3 บลอคมันอาจจะเยอะเกินไป สรุปว่า ยุบ Confession of a late night programmer กับ between the line มารวมกับบลอคนี้เลยนะครับ :3

โมบายของแมงมุม

Posted in Photography | No Comments »



Top 20+ MySQL Best Practices

Posted in CS, Web | No Comments »

ถอดความจาก http://net.tutsplus.com/tutorials/other/top-20-mysql-best-practices/ เอาคร่าว ๆ นะ รูปประกอบ ไปดูได้จากเว็บต้นทาง ขี้เกียจทำรูปใหม่ และไม่อยาก repost/hot link รูปเขา

 

1. เขียน query ที่ทำให้ query cache ทำงานได้ดี

query cache คือระบบหนึ่งของ MySQL ที่จะช่วยลดโหลดของการ query โดยถ้าเรา query ข้อมูลหนึ่งครั้ง MySQL จะเก็บผลการ query ไว้ ดังนั้นถ้าเรา query ซ้ำเดิม (เช่นจากผู้ใช้คนอื่น แต่ใช้ query เดียวกัน) MySQL ก็สามารถเอาผลการ query ส่งไปให้ได้เลย โดยไม่ต้องไปค้นข้อมูลใหม่ ซึ่งทำให้การ query ทำงานได้ไว และลดโหลดของ server ได้เยอะ

ทีนี้ การเขียน query ก็มีผลต่อการ cache เหมือนกัน ลองดูตัวอย่าง

// query cache does NOT work

$r = mysql_query(“SELECT username FROM user WHERE signup_date >= CURDATE()”);

// query cache works!

$today = date(“Y-m-d”); $r = mysql_query(“SELECT username FROM user WHERE signup_date >= ‘$today'”);

อันบน cache ไม่ทำงาน เพราะเราใช้ CURDATE() ซึ่งเป็น function ที่ทำงานในระบบฐานข้อมูล ซึ่งทำให้ MySQL ต้อง execute query นี้เสมอ ซึ่ง function ในลักษณะนี้ก็เช่น NOW(), RAND() เป็นต้น ดังนั้น ถ้าเป็นไปได้ ควรหลีกเลี่ยงการทำงานในลักษณะนี้ เช่นในบรรทัดล่าง เราสร้าง string ของวันที่ปัจจุบันขึ้นมาก่อน แล้วค่อยส่งไป query เป็นต้น ทำให้ฐานข้อมูลเอา query นี้ไปเทียบได้เลย ต้องไม่ต้องไปทำงานภายในก่อน

2. ใช้คำสั่ง EXPLAIN เพื่อวิเคราะห์ SELECT query

พอเขียน query เสร็จ ควรใช้คำสั่ง EXPLAIN เพื่อวิเคราะห์ดูว่า query นั้นทำงานดีไหม และมีปัญหาที่เกิดจากโครงสร้งาของตารางหรือไม่ โดยเฉพาะถ้าเป็น query ที่มีการ join เยอะ ๆ ลองดูตัวอย่างในรูปของเว็บต้นทาง จะเห็นว่า การใช้คำสั่ง EXPLAIN จะแสดงให้เห็นถึงการ query ที่ไม่บน table ที่ไม่ได้สร้าง index key ที่เหมาะสม จึงทำให้จำนวน rows ที่เกี่ยวข้องมีสูง (7883  rows) ซึ่งพอใส่ index เข้าไป จำนวน rows ที่เกี่ยวข้องก็ลดลงอย่างมาก ซึ่งแน่นอนว่า การ query ก็จะไวขึ้น

3. ใช้ LIMIT 1 เมื่อต้องการ query แค่ record เดียว

อันนี้คงไม่ต้องการอะไรมาก คือถ้าเราต้องการข้อมูลแค่ record เดียว เช่นจะดูว่า มี account นี้ในระบบไหม หรือว่า มีรหัสนักศึกษานี้ในระบบไหม ให้ใส่ LIMIT 1 เสมอ เพราะในการ query ที่มี LIMIT 1 ถ้า MySQL พบข้อมูลตัวแรกแล้ว(ซึ่งก็คงมีแค่ตัวเดียว) มันก็จะหยุดการ query แล้วให้ผลคืนทันที ซึ่งต่างจากการไม่ใส่ LIMIT 1 ที่ MySQL จะต้องเช็คไปจนสุดตาราง ถึงจะหยุดการทำงานได้

4. ใส่ index สำหรับทุก field ที่ต้องการค้นหา

หลักการง่าย ๆ คือ ถ้ามี field ไหนไปโผล่ใน WHERE clause ของ SELECT จงใส่ index ให้มันเสีย เพื่อให้มัน search ได้ไวขึ้น

แน่นอน วิธีการนี้ใช้ได้กับกรณี exact match เช่น WHERE lastname like ‘pruet’ หรือว่า partial match เช่น WHERE lastname like ‘pr%’ เท่านั้น ถ้าต้องการทำ full text match เช่น WHERE lastname like ‘%pr%’ การทำ index จะไม่ช่วยอะไร ต้องไปใช้ MySQL fulltext search แทน ดังนั้น พยายามหลีกเลี่ยงการทำ full text match ด้วย

5. ใช้ข้อมูลประเภทเดียวกันใน column ที่เอามา join กัน และให้ทำ index ทั้งสองฝั่งด้วย

การ join เป็นการทำงานที่มี cost สูงมาก เพราะจะต้องมีการเอาข้อมูลจากสอง table มาเทียบกัน ในฐานข้อมูลที่ออกแบบไม่ดี การ join สอง table หมายถึงการจำนวน query ที่เท่ากับ จำนวน record ของทั้งสอง table มาคูณกัน ซึ่งเป็นการทำงานที่ช้ามากแน่นอน

สิ่งที่ต้องทำเพื่อหลีกเลี่ยงกรณีนั้นคือ ใน column ที่จะเอามา join กัน ให้ทำ index เสมอ และทั้งสอง column จะต้องเป็น data type เดียวกันเท่านั้น เพราะถ้าเป็นคนละ data type (เช่น DECIMAL กับ INT) แล้ว MySQL จะใช้ index ในการ join ไม่ได้

6. อย่าใช้ ORDER BY RAND()

ถ้าเขียนโค้ดแบบนี้

$r = mysql_query(“SELECT username FROM user ORDER BY RAND() LIMIT 1″);

MySQL จะต้องเรียกคำสั่ง RAND() ในทุก record ก่อน แล้วจึงเอา record มาเรียงกัน แล้วจึงดึงออกมาแค่หนึ่ง record ซึ่งแน่นอนว่าทำงานช้ามาก

ควรทำแบบนี้ดีกว่า

$r = mysql_query(“SELECT count(*) FROM user”);

$d = mysql_fetch_row($r);

$rand = mt_rand(0,$d[0] – 1);

$r = mysql_query(“SELECT username FROM user LIMIT $rand, 1″);

โค้ดยาวขึ้น แต่ทำงานเร็วกว่าเยอะ เพราะทำงาน rand แค่ครั้งเดียว (แถมทำนอก MySQL ด้วย) แล้วจึงไป query ออกมาแค่ record เดียว

7. หลีกเลี่ยง SELECT *

ถ้าต้องการข้อมูลเพียงไม่กี่ field ให้ระบุไปเลยว่าต้องการอะไร อย่าใช้ SELECT * เพราะยิ่งข้อมูลที่เราสั่งให้ดึงมาน้อย ก็จะลดโหลดทั้งในส่วนของการเรียกข้อมูลจาก harddisk และการส่งข้อมูลผ่าน network โดยเฉพาะถ้าต้องการข้อมูลเยอะ ๆ

8. ทุก table ต้องมี field id

ทุก table ควรจะมี field ที่เป็น PRIMARY KEY, AUTO_INCREEMENT, UNSIGNED ที่กำหนดให้เป็น id ซึ่งควรจะใช้ในการเชื่อม table เข้าด้วยกัน เพราะว่า การ query table ด้วย field id ในลักษณะดังกล่าว จะทำได้เร็วกว่าการ query โดยใช้ field ที่เป็น VARCHAR มาก (ต่อให้ทำ primary key/index แล้วก็ตาม)

9. ถ้าเป็นไปได้ พยายามใช้ ENUM แทนที่ VARCHAR

column แบบ ENUM ทำงานได้ไว และใช้พื้นที่น้อย ดังนั้นถ้ามีข้อมูลที่รู้อยู่แล้วว่ามีอะไรบ้าง และจำกัด เช่น พวก status ต่าง ๆ ก็ควรจะใช้เป็น ENUM แล้วระบุไปเลยว่ามีอะไรบ้าง

ข้อดีอีกอย่างคือ ลดการพิมพ์ผิดในกรณีของ VARCHAR ได้ เพราะถ้าพิมพ์ผมาผิด ENUM จะโวยวายทันทีว่าไม่มีข้อมูลแบบนี้

10. ใช้คำสั่ง PROCEDURE ANALYSE() เพื่อวิเคราะห์โครงสร้างตาราง

คำสั่ง PROCEDURE ANALYSE() มีประโยชน์มากในการวิเคราะห์โครงสร้างตาราง “และข้อมูลที่อยู่ด้านใน” ว่าเหมาะสมไหม เช่น ถ้าเราระบุให้ primary key เป็น INT แต่จริง ๆ แล้ว มีข้อมูลไม่กี่ตัว มันก็จะแนะนำให้ใช้ MEDIUMINT แทน ตัวอย่างเช่น ตารางที่เก็บรายชื่อของคณะต่าง ๆ ในมหาวิทยาลัยเป็นต้น

ถ้าใช้ phpmyadmin อยู่ จะมีคำสั่ง Propose table restructure อยู่ ซึ่งมันก็เรียก PROCEDURE ANALYSE() นี่แหละมาทำงาน

11. ใช้ NOT NULL เสมอ

ถ้าในตารางไม่ได้ใช้ค่า NULL ทำอะไร ซึ่งส่วนใหญ่ก็จะเป็นอย่างนั้น ก็ให้ระบุในค่า column ว่าเป็น NOT NULL แล้วใช้ค่า default จริง ๆ ไปเลย เช่น 0 สำหรับ INT และ string ว่าง สำหรับพวกข้อความต่าง ๆ  อย่างแรกคือ NULL column กินพื้นที่เยอะกว่าข้อมูลอื่น ๆ และเวลาเขียนโค้ดก็ต้องมานั่งเช็คอีกว่า มันจะ NULL ไหม

12. พยายามใช้ prepare ในการสร้าง query

โดยทั่วไป เราเขียน query ได้สองวิธี คือผ่าน prepare หรือว่า query เข้าไปตรง ๆ การใช้ prepare ข้อดีอย่างแรกคือ ช่วยป้องการ SQL injection ได้ เพราะมันจะทำการ filter ข้อมูลให้ก่อนหนึ่งชั้น ส่วนในแง่ของ performance นั้น ถ้าเกิดว่า query นั้นมีการใช้ซ้ำ ๆ หลาย ๆ ครั้ง เช่น การดึงข้อมูลมาสร้างเป็นตาราง การใช้ prepare จะช่วยลดโหลดของ MySQL ลงได้ เพราะ MySQL จะทำการวิเคราะห์ query นั้นแค่ครั้งเดียว

ข้อจำกัดของ prepare มีแค่อย่างเดียว คือ ใน MySQL version 5.0 ลงมา query ที่ใช้ผ่าน prepare จะไม่ถูก cache

13. ใช้ unbeffered query ในการ query ข้อมูลใหญ่ ๆ

ปกติ เวลาเรา query ข้อมูลจากฐานข้อมูล MySQL จะสร้าง buffer อันหนึ่งไว้เก็บ query result ทั้งหมด และเมื่อได้ result ทั้งหมดแล้ว ก็จะส่งข้อมูลใน buffer กลับมาให้ ซึ่งถ้าเรา query ข้อมูลขนาดใหญ่ จะส่งผลสองประการคือ 1. กินพื้นที่ memory ของ server 2. กว่าจะได้ข้อมูลกลับมา ก็ต้องรอให้ได้ข้อมูลครบก่อน ซึ่ง php ก็มีคำสั่ง mysql_unbuffered_query ให้ใช้ โดยจะไม่มีการรอให้ MySQL ค้นข้อมูลให้หมดก่อน แต่จะทยอยส่งมาให้เลย ด้วยวิธีการนี้ จะช่วยลดขนาด memory ที่ใช้ และเพิ่มความเร็วในการได้ข้อมูลแรก ๆ ด้วย

ข้อจำกัดคือ เราจะต้องอ่านข้อมูลทั้งหมด หรือสั่ง mysql_free_result ก่อนที่จะส่ง query ถัดไป และกลุ่มคำสั่งที่จัดการข้อมูลแบบทั้งก้อน เช่น mysql_num_rows และ mysql_data_seek จะใช้งานไม่ได้

14. เก็บ IP address เป็น UNSIGNED INT

ปกติ เรามักจะเก็บ IP address เป็น VARCHAR(15) ด้วยว่ามันมีจุดหลายจุด แต่จริง ๆ แล้ว เราสามารถเก็บมันเป็นตัวเลขแบบ UNSIGNED INT ด้วย ซึ่งกินพื้นที่น้อยกว่า index ได้ไวกว่า และเปรียบเทียบกันได้ไวกว่าด้วย วิธ๊การก็คือ สร้าง column ให้เป็น UNSIGNED INT แล้วใช้ function INET_ATON() และ INET_NTOA() ของ MySQL แปลงไป/แปลงกลับระหว่าง IP ADDRESS และ ตัวเลข เช่น ตัวอย่าง

$r = “UPDATE users SET ip = INET_ATON(‘{$_SERVER['REMOTE_ADDR']}’) WHERE user_id = $user_id”;

ถ้าไม่อยากไปทำที่ระดับ MySQL ใน PHP ก็มีคำสั่ง ip2long() กับ long2ip() ให้ใช้

15. table แบบ Fixed-length  ทำงานเร็วกว่า

table ที่ทุก column มีขนาดจำกัด (fixed-length) จะเรียกว่า static หรือ fixed-length table ซึ่งชนิด column ที่”ไม่ใช่” fixed-length คือ VARCHAR, TEXT และ BLOB. ดังนั้น ถ้าสามารถหลีกเลี่ยง column ทั้งสามชนิดนี้ได้ จะทำให้ MySQL ทำงานกับ table นั้นได้ไวกว่ามาก เพราะว่าเวลา MySQL จะไปอ่านข้อมูลใน record หนึ่ง ๆ มันจะสามารถคำนวณตำแหน่งได้ง่าย (เช่น ตำแหน่งที่ต้องการ x ความยาว record) ซึ่งถ้า table มันไม่ fixed MySQL ก็ต้องวิ่ง seek หาตำแหน่งเอา หรือว่าไปดูจาก primary key

ถ้าจำเป็นต้องมี column ที่ไม่ใช่ fixed-length อาจจะใช้เทคนิค Vertical Partitioning ในการแยก column ที่ fixed กับ ไม่ fixed ออกจากกัน ลองดูข้อถัดไป

16. Vertical Partitioning

เป็นเทคนิคการแบ่ง table ออกเป็นหลายส่วน โดยการกระจาย column ออกไปเพื่อผลทางประสิทธิภาพ สมมติว่าเรามี table หนึ่งที่มี column ดังต่อไปนี้ table1(id, login, fname, lname, address, last_login)

ตัวอย่างที่ 1: เช่นถ้าเรารู้ว่า บาง column ไม่ได้ถูกใช้บ่อย ๆ (เช่น ที่อยู่) ก็สามารถแย่งออกไปเป็นอีก table หนึ่ง เช่นแยกเป็น  table1(id, login, fname, lname, last_login) และ table2(id, address) ซึ่งจะทำให้ table1 มีขนาดเล็กลงมาก และทำงานได้ไวขึ้น

ตัวอย่างที่ 2: ถ้าเรารู้ว่า บาง column มีการ update ถี่ ๆ ในขณะที่ column อื่นไม่มีการเปลี่ยนแปลง ก็อาจจะแยก column นั้นออกมา เพื่อให้ข้อมูลใน column อื่น ๆ คงอยู่ใน cache ได้ เช่นในตัวอย่าง last_login จะมีการ update ทุกครั้งที่ผู้ใช้ติดต่อ server ซึ่งการ update แต่ละครั้ง ก็จะทำให้ทั้ง record ถูก flush ออกไป เราจึงควรแบ่ง table ออกเป็น table1(id, login, fname, lname, address) และ t2(id, last_login) เพื่อให้การ update เกิดใน t2 เท่านั้น

ข้อควรระวังคือ พอแบ่งเป็น 2 table แล้ว ก็ไม่ควรให้มัน join กันบ่อย ๆ เพราะมันมีค่าใช้จ่ายสูง ถ้า column ที่ถูกแยกออกมา ต้องถูกใช้ร่วมกันบ่อย ๆ ก็ไม่ควรแยกตั้งแต่แรก

17. กระจาย DELETE กับ INSERT query ใหญ่ ๆ ออกมา

ถ้าเราจำเป็นต้องทำการ DELETE หรือ INSERT ข้อมูลจำนวนมาก ๆ บนเว็บที่กำลังทำงานอยู่ ก็ไม่ควรทำทีเดียวทั้งหมด เพราะมันจะไป lock table ของเรา แล้วทำให้ MySQL ไม่สามารถทำงานอื่น ๆ ได้ วิธีการคือ ค่อย ๆ กระจายทำทีละน้อย ๆ เช่น ลบทีละ 10,000 record แล้วหยุดไปสักพัก เพื่อให้ MySQL สามารถไปทำอย่างอื่น เช่น จัดการ SELECT query ที่คั่งค้าง ก่อนจะกลับมาลบต่อ ลองดูตัวอย่าง

while (1) {
mysql_query(“DELETE FROM logs WHERE log_date <= ‘2009-10-01′ LIMIT 10000″);
if (mysql_affected_rows() == 0) {
// done deleting
break;
}
// you can even pause a bit
usleep(50000);
}

จากตัวอย่าง เราลบไป 10,000 record แล้วก็หยุดพักไปครู่ใหญ่ โดยใช้คำสั่ง usleep ก่อนที่จะสั่งลบต่อ

18. column เล็ก ๆ ทำงานไวกว่า

สิ่งที่ทำให้ database ทำงานช้าสุดคือ harddisk ดังนั้น ถ้าเราสามารถลดปริมาณข้อมูลที่ต้องอ่านเขียนจาก harddisk ได้ ระบบเราก็จะทำงานเร็วขึ้น และประหยัดพื้นที่ harddisk มากขึ้น วิธีการหนึ่งก็คือ การใช้ชนิด column ให้เหมาะสม เช่น ถ้าเราคิดว่าจะมี record แค่ไม่กี่อัน ก็อย่าใช้ INT เป็น primary key แต่เปลี่ยนเป็น MEDIUMINT, SMALLINT หรือแม้แต่ TINYINT แทน เป็นต้น หรือว่าถ้าต้องการเก็บแค่วันที่ ก็ใช้ DATE แทนที่จะเป็น DATETIME เป็นต้น

19. ใช้ storage engine ให้ถูก

ใน MySQL มี storage engine หลักอยู่สองตัวคือ MyISAM กับ InnoDB ถ้าเอาง่าย ๆ ก็คือ MyISAM เหมาะกับโปรแกรมที่เน้นการ read เพราะว่ามันเป็น table-level locking เวลามีคนพยายาม insert/update/delete มันจะล๊อคทั้ง table ซึ่งทำให้ทำงานช้า ส่วน InnoDB สนับสนุน row-based locking ซึ่งทำให้การ insert/update/delete จะทำได้ไวกว่า MyISAM แต่ด้วยความซับซ้อนของมัน โดยทั่วไปสำหรับโปรแกรมเล็ก ๆ ที่เน้น SELECT (โดยเฉพาะ SELECT COUNT(*))  มันเลยจะทำงานกว่า MyISAM

20. พยายามใช้ ORM

ORM หรือ Object Relational Mapper นอกจากจะทำให้เขียนโปรแกรมง่าย เพราะว่าไม่ต้องไปยุ่งกับ SQL มากแล้ว ยังสามารถเพิ่มประสิทธิภาพของโปรแกรมได้ด้วย เพราะว่า ORM library โดยทั่วไป จะถูกเขียนให้มีประสิทธิภาพสูงอยู่แล้ว และมันยังทำ lazy loading ได้ด้วย นั่นคือ ถ้าเราสั่งเรียกข้อมูลมา แต่ไม่ได้ใช้ทันที ORM ก็จะไม่เรียกมากให้ทันทีเช่นกัน โดยจะเรียกมาเพื่อจะใช้

21. ระวังการใช้ Persistent Connection

โดยทั่วไป Persistent Connection จะช่วยลด overhead ในการเชื่อมต่อได้ เพราะว่าเราไม่ต้องทำการสร้างการเชื่อมต่อทุกครั้งที่ต้อง query ข้อมูล แต่เนื่องจาก connection มันไม่ถูกปิด ดังนั้นมีโอกาสที่ connection ของ MySQL จะเต็มเพราะว่า Apache มัน reuse connection ของ child process จนทำให้ connection ปิดไม่ได้นั่นเอง ตัวอย่างเช่น ถ้า MySQL ใช้ table-locking แล้ว php script ก่อนหน้านี้ ไม่ได้ปลดล๊อคก่อนที่จะปิดตัว script ตัวถัดมา จะถูก lock ทันที เพราะว่า ตราบใดที่ connection ยังไม่ถูกปิด MySQL ก็ต้องคง lock อันนั้นไว้อยู่

คำแนะนำคือ อย่าใช้

 

 

 

 

ใช้ GMail ให้สนุก ต้องเข้าใจ Label

Posted in Life, Web | No Comments »

เนื่องมาจากมีน้องสาวท่านหนึ่งทวีตว่า

Screenshot (30)

ทำให้รู้ว่าหลาย ๆ คนยังไม่เข้าใจหลักการของ label ใน GMail ถึงแม้ว่าจะเปิดบริการมาแล้วเกือบสิบปี

ถ้าให้อธิบายสั้น ๆ สำหรับคำถามของน้องเขาก็คือ ทุกอย่างใน GMail เป็น label และทั้ง inbox/folder ทั้งหลาย ก็เป็น label ทั้งนั้น

หรืออีกในหนึ่ง ใน GMail ไม่มี inbox/folder นั่นเอง

 

 

ก็ขอย้อนอดีตนิดหนึ่ง อีเมลแต่ดั้งเดิมนั้น ได้แนวคิดมาจากการส่งจดหมายจริง ๆ (หรือที่มักจะเรียกกันว่า Snail Mail) ที่ว่าพอจดหมายมาถึง เราก็จะเอาจดหมายมาจัดแยก เช่นถามผู้รับ หรือตามหัวข้อ ซึ่งช่องหรือสิ่งที่ใช้เก็บจดหมายนั้น ภาษาอังกฤษก็จะเรียกว่า Folder ดังนั้น ในโปรแกรมอีเมลดังเดิม ก็จะมี folder ไว้ให้ เพื่อให้ผู้ใช้ระบุว่า จะเก็บอีเมลของตัวเองที่ไหน เช่น จดหมายเจ้าจะอยู่ใน Inbox ซึ่งถ้าอ่านแล้ว คิดว่าเป็นเรื่องเกี่ยวกับงาน เราก็จะย้ายจาก Inbox ไปใส่ Business เป็นต้น แล้ววันหลัง พอเราอยากจะหาจดหมายฉบับดังกล่าว ก็จะเขาไปดูใน Business แล้วอาจจะสั่งให้มันเรียงตามวันส่ง เรียงตามผู้ส่ง หรือตามหัวข้อ ซึ่งไม่ว่าจะด้วยวิธีการใด ขบวนการทั้งหมด ก็เลียนแบบมาจากการส่งจดหมายจริง ๆ

 

แต่จดหมายต่างจากอีเมลตรงที่ว่า มันอยู่ได้เพียงที่เดียว แต่อีเมลเป็นข้อมูลอีเล็คทรอนิกส์ มันไม่จำเป็นต้องอยู่ที่เดียวก็ได้ นั่นคือที่มาของระบบ label ใน GMail

 

label ใน GMail นั้น สามารถถูกำหนดให้กับอีเมลไหนก็ได้ และอีเมลหนึ่ง ๆ จะมีหลาย label ก็ได้ ซึ่งจะทำให้การจัดการอีเมลมีความยืดหยุ่นมากขึ้น ลองดูรูปด้านล่าง

Screenshot (23)

ด้านซ้ายมือที่เขียนไว้ว่า A ในโปรแกรมอีเมลดั้งเดิมจะเป็นรายการของ folder แต่ใน GMail รายการดังกล่าวคือรายการของ label ที่เราเลือกให้มาแสดง ดังนั้น ถ้าเรากดเลือกตรง Starred แล้ว GMail ก็จะแสดงอีเมลทั้งหมดที่มี label Starred กำหนดอยู่ หรือถ้าเรากดเลือก Important เขาก็จะแสดงรายการอีเมลที่มี label Important กำหนดอยู่ ดังนั้นถ้าอีเมลใด มี label มากกว่าหนึ่งอัน มันก็จะไปโผล่ในหลาย ๆ ที่ได้

Screenshot (24)

ซึ่งรายการ label ด้านซ้ายนี้ เราสามารถระบุได้ว่า จะให้แสดงอะไรบ้าง โดยระบุใน Settings ซึ่งพอเข้าไป จะเห็นได้ชัด จากรูปที่เขียนไว้ว่า B ว่า นี่ไม่ใช่ folder list แต่เป็น label list โดยเราสามรถที่จะเลือก show hide หรือ show if unread ได้ โดย show if unread หมายความว่า ถ้ามีอีเมลที่ยังไม่ได้อ่าน และมี label ดังกล่าวอยู่ ชื่อ label ดังกล่าวก็จะแสดงใน label list

Screenshot (25)

นอกจากนั้น เรายังทำ label แบบ nested ได้ด้วย เช่น ในรูป ตรงที่เขียนไว้ว่า C/D จะเห็นว่า 261102 จะอยู่ภายใต้ CPE ดังนั้น อีเมลได้ที่ถูกกำหนด label 261102 ก็จะได้รับ label CPE ไปโดยอัตโนมัติ ซึ่งเราสามารถทำ nested แบบหลายชั้นได้

Screenshot (26)

ปัญหาหนึ่งของการทำ label หรือ tag คือการที่เราขี้เกียจใส่ label/tag ซึ่ง GMail ก็ใช้วิธีการให้เราสร้าง filter ได้ โดยถ้าอีเมลใดตรงกับ filterก็จะสามารถกำหนด Action ต่าง ๆ ที่รวมถึงการใส่ label ได้ เช่นในรูปด้านบน ตรงที่เขียนไว้ว่า E ผมสร้าง filter ที่บอกว่า ถ้ามีอีเมลใดที่มาจาก mailing list ที่จัดการโดย tccc.list.cs.columbia.edu ก็จะไม่ต้องเอาใส่ใน Inbox และให้ใส่ label Conf เข้าไปเลย

หมายเหตุ: ใน GMail จะมี label ของ system อยู่สองสามตัวที่จะทำงานโดยอัตโนมัติ เช่น All Mail จะเป็น label ที่กำหนดให้กับอีเมลทุกอัน และไม่สามารถลบได้ Inbox จะเป็น label ที่ถูกกำหนดให้กับอีเมลที่เพิ่งได้รับโดยอัตโนมัติเป็นต้น

Screenshot (27)

การสร้าง filter ก็ทำไม่อยาก เพราะมันเป็น rule base แบบ match/action ธรรมดา โดยขั้นแรกเราจะกำหนดเงื่อนไขก่อนว่า อีเมลได้จะถูกกรองโดย filter นี้ ซึ่งอาจจะมาจากชื่อผู้ส่ง หัวข้อ หรือว่าเนื้อความก็ได้ (ซึ่งก็เป็นเหตุให้ Google ถูกบ่นว่าแอบอ่านอีเมลของผู้ใช้อยู่) ตามรูปด้านบน ตรงช่อง F

Screenshot (28)

เมื่อกำหนด match condition แล้ว ก็จะมากำหนด action ซึ่ง มีมากมาย ตามรูปด้านบน ช่อง G ซึ่งถ้านั่งดูดี ๆ เกือบทั้งหมด เป็นการกระทำที่เกี่ยวข้องกับ label ทั้งนั้น

ฟหกดฟหกด

หรือว่าถ้าอยากกำหนด label เอง ก็ทำได้ โดยที่ toolbar ด้านบน จะมีรูป label/tag อยู่ ก็กดเลือกตรงนั้น แล้วมันจะแสดงตามพื้นที่ H ก็กดเลือก label ที่ต้องการได้เลย ใช้ได้ทั้งในหน้าอ่านจดหมาย และหน้าแสดงรายการจดหมาย

ซึ่งถ้าเราใช้ label จนคล่องแล้ว ก็อาจจะพลิกแพลงได้ เช่น ใช้ทำ GTD เป็นต้น

GMail ได้เปลี่ยนวิธีการจัดการอีเมลให้เข้ากับโลกสมัยใหม่มากขึ้น ในเมื่อไม่มีความจำเป็นต้องใส่อีเมลเข้าไว้กับ folder ใด folder หนึ่งอีกต่อไปแล้ว ดังนั้น ก็ขอให้ลืมไปเลยว่า ต้องแยกจดหมายโดยใช้ folder แต่เปลี่ยนไปใช้การกำหนด label ให้กับจดหมายแทน แล้วแยกจดหมายตาม label เอา ซึ่งไม่ใช่เฉพาะเรื่อง label เท่านั้น ที่ GMail เปลี่ยนวิธีการจัดการอีเมล แม้แต่การจัดการรายการอีเมล GMail ก็เปลี่ยนจากการ sort เป็นการ search แทน นั่นคือแทนที่เราจะต้องเรียงจดหมายตามผู้ส่ง ตามวันที่ส่ง หรือตามหัวข้อ เพื่อหาอีเมลที่ต้องการ GMail ก็บอกเราว่า ฉันจะเรียกตามวันที่ได้รับเท่านั้น ส่วนถ้าต้องการหาอีเมลอะไร ก็ search เอาสิ ซึ่งการใช้ label ก็เพื่อให้การ search ทำได้อย่างมีพลังอีกด้วย

ทั้ง label และการจัดการรายการอีเมลโดยการ search ก็มาจากธรรมชาติของบริษัท Google ที่เป็น search engine company นั่นเอง