วันพฤหัสบดีที่ 16 มกราคม พ.ศ. 2557

เทคนิคการเขียนโค้ด PHP และ MySQL เพื่อเพิ่ม Performance

เทคนิคการเขียนโค้ด PHP และ MySQL เพื่อเพิ่ม Performance
[PHP]
  • คำสั่ง echo จะทำงานเร็วกว่าคำสั่ง print
  • การสั่ง echo ถ้าใส่ ‘string’ จะทำงานเร็วกว่าใส่ “string” เนื่องจากว่าตัว php จะตรวจสอบว่ามี variable อยู่ใน “” หรือเปล่า แต่จะไม่ตรวจสอบใน ‘’
  • ในการเขียน for loop ควรกำหนดจำนวนครั้งสูงสุดของการวนรอบไว้ก่อนที่จะเข้ามาใน loop ไม่ควรมากำหนดค่าหรือเปลี่ยนค่าภายใน loop
  • อย่าเรียกใช้ function ข้างใน for loop เช่น ($x=0; $x < count($array); $x) เพราะมันต้องเสียเวลาเรียก count() ทุกครั้งที่วน loop
    • ตัวแปรไหนที่ไม่ใช้แล้ว ก็ควรจะ unset ทิ้งไปซะ เก็บไว้ก็เปลืองหน่วยความจำ โดยเฉพาะพวก array ใหญ่ๆ
    • คำสั่ง str_replace จะทำงานเร็วกว่าคำสั่ง preg_replace แต่คำสั่ง strtr ทำงานเร็วกว่าคำสั่ง str_replace ถึง เท่า
    • การใส่เครื่องหมาย นำหน้าคำสั่งเพื่อไม่ให้แสดงข้อความ erroยิ่งจะทำให้ระบบช้าลง
    • สั่งปิดการเชื่อมต่อกับ database ถ้าใช้งานเสร็จแล้ว
    • การระบุ index ของ array โดยใส่เครื่องหมาย single quote ‘’ ครอบไว้ เช่น $row[‘id’] จะทำงานเร็วกว่าไม่ใส่เครื่องหมาย เช่น $row[id] ถึง เท่า
    • ถ้าจะใช้ if … elseif … elseif … elseif … else … หลายๆอันแบบนี้ เปลี่ยนมาใช้ switch case ดีกว่า
    • การเพิ่มค่าของ local variable จะทำงานเร็วสุด และการเรียกใช้ local variable ใน function ก็ใช้เวลาใกล้เคียงกัน
    • การเพิ่มค่าของ global variable จะช้ากว่าการเพิ่มค่า local variable 2 เท่า
    • การเพิ่มค่าของ property ของ object เช่น $this->prop++ จะช้ากว่าการเพิ่มค่าของ local variable 3 เท่า
    • การเพิ่มค่าของ local variable ที่ไม่ได้ถูกประกาศไว้ จะช้าเป็น 9-10 เท่าของการเพิ่มค่าใน local variable ที่ถูกประกาศไว้ก่อนแล้ว เพราะว่า php ต้องเสียเวลาประกาศตัวแปรใหม่ก่อนแล้วค่อยเพิ่มค่า
    • การประกาศ global variable ทิ้งไว้แล้วไม่ใช้ จะทำให้การทำงานช้าลง
    • ในภาษา php การใช้ ++$i จะเร็วกว่า $i++ เพราะคำสั่ง ++$i ใช้ 3 opcode แต่ $i++ ใช้ 4 opcode
    • ในการหาความยาวของ string ปกติแล้วเราจะใช้คำสั่ง strlen() ซึ่งเป็น function แต่เราสามารถประยุกต์ใช้คำสั่ง isset() มาใช้เพื่อให้ทำงานเร็วกว่าได้ เพราะคำสั่ง isset() ไม่ได้เป็น function ดังนั้นจะลดการเสียเวลาในการเรียกใช้function ไปได้เยอะ ตัวอย่างการใช้งาน
    • if(strlen($foo) < 5) { echo “Foo is too short”; } เทียบกับ
    • if (!isset($foo{5})) { echo “Foo is too short”; }
    • ถ้าไม่จำเป็นต้องเขียน OOP ก็ไม่ต้องเขียน เพราะการเขียน OOP จะใช้ memory มากกว่า
    • การประมวลผลคำสั่ง php จะช้ากว่าการแสดงผลหน้า HTML ธรรมดาอยู่ 2-10 เท่า หน้าไหนที่ไม่จำเป็นต้องเขียนด้วย php ถ้าเป็นไปได้ก็ควรเขียนเป็น HTML ธรรมดาจะดีกว่า
    [MySQL]
    • ถ้าจะ SELECT ค่ามาแค่ 1 row ไม่ควรใช้ SELECT * ใช้ SELECT 1 แล้วใส่ Limit เป็น จะดีกว่า
    -         SELECT 1 FROM user WHERE state = ‘Alabama’ LIMIT 1″;
    • ถ้าจะเก็บค่าใน field เป็น VARCHAR ซึ่งมีค่าซ้ำๆกับ เช่น มี column ชื่อ status สำหรับเก็บค่า “active”, “inactive”, “pending” แนะนำให้เก็บเป็นแบบ ENUM จะเร็วกว่า VARCHAR
    • ไม่ควรเก็บค่าเป็น NULL ถ้าไม่จำเป็นจริงๆ เพราะถึงยังไงค่า NULL ก็ยังต้องใช้พื้นที่ในการเก็บข้อมูลอยู่ดี และอาจมีปัญหาในกรณีที่ต้องการ JOIN หรือเรียกใช้งานภายหลังได้ ทางที่ดีถ้าเราสามารถกำหนดค่า Default ไปเลยได้จะดีกว่าเช่น height ถ้าไม่ใส่อะไรเลยจะมีค่าเป็น แทนที่จะเป็น NULL
    • การเก็บค่า IP Address สามารถเก็บเป็น UNSIGNED INT ได้ เพราะจะใช้พื้นที่ในการเก็บแค่ 4 Byte เวลาจะเก็บก็แปลงจาก IP เป็น Int ก่อนก่อนโดยใช้คำสั่ง SQL ชื่อ INET_ATON() และถ้าจะแปลงกลับก็ใช้ INET_NTOA() หรือถ้าจะใช้PHP แปลงก็ใช้คำสั่ง ip2long() และแปลงกลับโดยใช้ long2ip()
    • การกำหนดความยาวของข้อมูลใน field ไว้ จะดีกว่าไม่กำหนด เช่น กำหนด VARCHAR(20) ดีกว่าเป็น VARCHAR เฉยๆ เพราะ MySQL จะใช้เวลาในการค้นหาข้อมูลน้อยกว่า
    • เลือกใช้ Database Engine ให้เหมาะสม โดยปกติใน MySQL จะนิยมใช้ Engine อยู่ ตัวคือ MyISAM กับ InnoDB ซึ่งทั้ง แบบก็มีข้อดีข้อเสียแตกต่างกัน MyISAM เหมาะกับงานที่เน้นการอ่านข้อมูลปริมาณมากๆ แต่ถ้ามีการเขียนเยอะๆ จะทำได้ไม่ดีนัก เช่นถ้าเราสั่ง UPDATE 1 roแล้วทั้ง table จะถูกล็อกไว้ process อื่นจะเข้ามาอ่านไม่ได้จนกว่า process แรกจะทำ Query เสร็จ แต่ใน InnoDB จะสามารถเลือกล็อกแค่ row เดียวได้
    • ระวังเรื่องการใช้ Persistance Connection เพราะบางทีเราเขียนโปรแกรมไม่ดี ทำให้ Apache เปิด child process ขึ้นมาใหม่ แล้วสร้าง connection ขึ้นมาอีกรอบ ทำให้เกิดปัญหา connection limit หรือ memory leak ได้

    50 เทคนิคการเขียน PHP ให้เร็วขั้นสุด และ ถูกต้อง

    การเขียน php ที่ทำให้ประมวลผลเว็บได้เร็วขึ้น หลักการและเทคนิคการเขียน php ที่ควรเป็น เพื่อให้เว็บทำงานได้เร็วสุดๆ
    คืออ่านมาจาก http://www.hm2k.com/posts/50-php-optimisation-tips-revisited แล้วเอามาแปล + ความรู้ที่ตัวเองมีนะครับ ซึ่งอาจจะไม่ถูกทั้งหมด อะไรที่เป็นความเห็นของผม ไม่ต้องอ่านก็ได้ เอาที่หลักๆของแต่ละหัวข้อเอาแล้วกันครับ อันนี้เขียนตามความเข้าใจ ซึ่งอาจจะไม่ถูกหรืออนาคตอาจจะเปลี่ยนแปลงไปได้เช่นกัน และผมจะไม่แปลแบบ automatic นะครับ เพราะว่าจะแปลให้คนอ่านเข้าใจครับ เหอๆๆๆ โดยการแปลมา ผมจะแปลตามความเข้าใจก่อน แล้วบรรทัดต่อมาที่ขึ้นด้วย * ก็คือคำอธิบายครับ ข้ามไปก็ได้
    1. echo เร็วกว่า print
    *ก็แน่นอนครับ เพราะว่า echo เป็น function ที่เรียบง่ายมากกว่า แต่ว่ากลับกัน print มันทำอะไรได้มากกว่า ก็เลยช้ากว่านั่นเอง
    2.เวลาใส่ตัวหนังสือ หรือข้อความให้ใส่ใน ' ' จะเร็วกว่า ใส่ใน " " เพราะว่าเครื่องหมาย "..." มันจะทำการค้นหาตัวแปรที่อยู่ภายในก่อน
    3.ใช้คำสั่ง sprintf แทนที่จะยัดตัวแปรลงไปตรงๆ จะทำให้เร็วขึ้น 10 เท่า!!
    ลองดูวิธีใช้ htttp://th.php.net/sprintf ไม่ยากครับ
    4.เรียกใช้ echo หลายครั้ง จะเร็วกว่าการเสียเวลาเพื่อเชื่อมตัวหนังสือก่อนเรียก echo ครั้งเดียว
    เช่นเชื่อมด้วย $tmp .= 'xxx'; เป็นต้นครับช้า อย่าทำ
    5.ในกระบวนการ loop ควรคำนวค่าต่างๆเอาไว้ก่อนเท่าที่ทำได้ เช่น
    1
                                  for($x=0;$x < count($array);$x)
    เราควรเปลี่ยนมาใช้
    1
                $max = count($array);
    ก่อน ค่อยเอาค่า$max ไปใช้ เพราะว่ามันจะเสียเวลาคำนวรอบเดียวเท่านั้น
    6.พยายามตรวจสอบตัวแปร array ถ้ามีค่าไหนไม่ได้ใช้ก็ unset ทิ้งไปบ้าง
    *อันนี้หลายคน ตัวแปรเกลื่อนระบบ เปลืองแรมครับ ตรวจสอบได้จาก print_r($array); นะครับ
    7.พยายามอย่าเรียกใช้ function พิเศษ เช่น __get, __set, __autoload
    8.เรียกใช้ require() แทนที่จะใช้ require_once() เท่าที่จะเป็นไปได้
    *ก็เพราะว่า require_once มันจะเสียเวลาตรวจสอบก่อน ว่าไฟล์นี้เคยโหลดเข้ามาหรือยัง ถ้าโหลดแล้วจะไม่โหลดซ้ำ
    9.ใช้ Full path ในการ include หรือ require เพื่อลดเวลาการค้นหา path ของ OS ที่รัน
    * full path ของไฟล์ที่กำลังทำงานเรียกได้จาก dirname(__FILE__);
    10. require() และ include() มันทำงานได้เหมือนกันเลือกใช้ให้ตรงตามความต้องการ มันต่างตรงที่ว่า require() ถ้าไม่พบไฟล์ มันก็หยุดทำงานเลย ความเร็วที่ได้แทบไม่ต่าง*
    11. ตั้งแต่ PHP5 เวลาจุดเริ่มต้นของการ ประมวลผล จะเรียกได้จาก $_SERVER[?REQUEST_TIME?] ไม่ต้องเรียกใช้ time() หรือ microtime()
    ตอนนี้ น่าจะ php5 กันแทบทุกที่แล้วมั้งครับ ไม่มั่นใจลองใช้ phpinfo();
    12. PCRE regex ทำงานได้เร็วกว่า EREG แต่จะเห็นผลเมื่อใช้ในแบบ native function
    13.เมื่อจะประมวลผล XML ใน php ใช้ xml2array จะเป็นการเรียกใช้ PHP XML function และสำหรับ HTML  สามารถเรียกใช้ PHP's DOM document หรือ DOM XML ใน PHP4
    14.str_replace ทำงานได้เร็วกว่า preg_replace แต่บางครั้ง strtr ก็ทำงานได้เร็วกว่าถ้าต้องใช้กันตัวหนังสือเยอะๆ และเราจะใช้ array() ในการทำงานของ str_replace จะทำให้ทำงานได้เร็วกว่าการเรียก str_replace หลายรอบ
    15. statement else if ทำงานได้เร็วกว่า select statement หรือว่า case/switch
    เพราะว่า else if เป็นคำสั่งเงื่อนไขที่ simple ที่สุดแล้วครับ
    16.การปิด error ด้วย ทำให้ทำงานได้ช้ามาก
    เจอบ่อยมาก @mysql_connect แต่ว่า บางครั้ง ก็ปิดเพื่อความปลอดภัยครับ
    17.การจะลด bandwidth ให้เรียกใช้ mod_deflate ใน apache 2 และ mod_gzip ใน apache1
    *อันนี้ก็ต้องดูว่า server ที่ใช้งานรองรับหรือไม่
    18.ปิดการเชื่อมต่อกับ database เมื่อทำงานเสร็จทุกอย่าง
    เพื่อให้เหลือ connection ว่างสำหรับรองรับการทำงานต่อไป และเป็นการคืน ทรัพยากรกลับเข้ามาด้วย
    19.$row['id'] เร็วกว่า $row[id] 7เท่า เพราะว่าถ้าเราไม่ใส่เครื่องหมาย มันจะเสียเวลาทำความเข้าใจ index ว่าหมายความว่าอะไร
    ใน php5 มันจะ error แบบเห็นชัดเลย ถึงแม้ว่าเป็นตัวเลขก็ใส่ไว้ครับ เพื่อความเคยชิน
    20.ใช้ <?php ... ?> tag เมื่อเราจะใช้ PHP แทนการเรียกใช้แบบอื่นๆ รวมทั้งการใช้ short tag ด้วย
    *<? ... ?> อย่างนี้พยายามเลี่ยงครับ
    21.เขียนโค้ดให้ถูกต้องตามไวยากรณ์ เพื่อลด error ที่จะเกิดขึ้น ซึ่งหลายครั้งมันเป็นเพียง notice หรือ warning เท่านั้น จะทำให้ลด over head ไปได้ หรือว่าลองเปิด error_reporting(E_ALL) เพื่อให้เห็น error แบบเต็มๆ
    *เปิดไว้เถอะครับ เขียนให้ถูกต้องเสมอ อย่าซ่อนขยะใต้พรม
    22.การแสดงผลแบบ PHP ทำให้หน้าเว็บช้ากว่า static page 2-10 เท่า (ใน apache httpd) ดังนั้น ใช้ php เท่าที่จำเป็น
    ถ้าหน้าไหนเป็น static ก็ใช้ .html ไปเลย
    23.PHP script จะต้องถูกประมวลผลทุกๆครั้งที่มีการเรียกใช้หน้าเว็บ ถ้าไม่มี cache ดังนั้นควรหาระบบ cache มาใช้(เช่น memcached, eAccelerator , Turck MMCache) เพื่อเพิ่มประสิทธิภาพการทำงานได้ 25-100% เพราะว่าจะลดเวลาการประมวลผลลงได้
    *นอกจากนี้ยังมีพวกที่ทำ file cache ด้วยนะครับ คือประมวลผลเสร็จ เก็บผลที่ได้เป็นไฟล์เลย
    24.ใช้เทคนิคการทำ cache แบบอื่นๆสำหรับหน้าเว็บที่ไม่ได้มีการเปลี่ยนแปลงมากนัก การทำ cache มันจะเหมือนการแสดงผล HTML ออกหน้าเว็บธรรมดา ลองใช้พวก Smarty หรือ Cache Lite ดู
    การทำ cache จะได้ผลดีสำหรับเว็บที่มี traffic มาก เปิดเว็บเยอะ หรือการเปิดแต่ละครั้งต้องใช้การประมวลผลอย่างหนัก
    25.พยายามใช้ isset แทนการใช้ strlen เช่น
    1
        if (strlen($foo) < 5) { echo ?Foo is too short?;}
    ก็ควรเปลี่ยนมาเป็น
    1
        if (!isset($foo{5})) { echo ?Foo is too short?; }
    *อย่างน้อยก็ลดการใช้ strlen ได้เลยล่ะ
    26.++$i เร็วกว่า $i++ หรือว่า การเพิ่มค่าก่อนนำไปใช้นั่นเอง
    27.พยายามใช้ function ต่างๆที่ php มีให้เรา อย่าเขียน function มาใช้งานเอง แต่ถ้าว่างมาก ก็ไปเขียน C extension หรือ module ให้รู้แล้วรู้รอดไปเลย
    อันนี้ออกแนวเหน็บๆ แต่ก็จริง เพราะว่าถ้าเป็น C extension หรือ php module มันก็ทำงานได้เร็วกว่า php function ที่เราเขียนมาแน่นอน
    28.พยายามตรวจสอบการทำงานของโค้ดของคุณ เพื่อจะได้รู้ว่า ทำงานหนักมากน้อยขนาดไหน หรือใช้พวก Xdebug debugger ช่วยตรวจสอบภาพรวมก็ได้
    *ถ้าเจอตัวแปรเหลือๆก็ unset ทิ้งตามระเบียบ
    29.เขียน document ให้โค้ดที่ตัวเองเขียนด้วย
    หลายครั้งกลับมาดูของตัวเอง แล้วมึนก็บ่อยไป โดยเฉพาะคนที่ไม่ได้ใช้ frame work ซึ่งมีอิสระในการเขียนโค้ด มักจะเจอประจำ
    30.หมั่นศึกษาการเขียนโค้ดในแบบที่ดี และแบบที่ผิดๆเอาไว้
    ที่ต้องศึกษาแบบที่ผิด เราจะได้รู้ว่าแบบนี้ผิด และไม่ควรทำนั่นเอง
    31.พยายามเขียนโค้ดให้ตรงตามมาตรฐานให้มากที่สุด มันจะช่วยให้คนอื่นอ่านแล้วเข้าใจ รวมทั้งตัวเองด้วย
    *เคยเจอเขียนแบบสับขาหลอกตัวเองมาแล้ว
    32.พยายามแยกส่วนโค้ดออกมา ให้ php แยกจาก HTML มากเท่าที่จะเป็นไปได้
    เพราะว่าการเอาไปปนกันหมดนั้นมันจะทำให้งงมาก
    33.อย่าใช้ระบบ template ที่ซ้ำซ้อนเช่นพวก smarty โดยไม่จำเป็น php เองก็มี function ที่ทำงานคล้ายกัน ลองดู ob_get_content และ exact
    34.อย่าวางใจ ข้อมูลที่ได้มาจากการป้อนของ user เช่น form $_POST ให้ใช้ mysql_real_escape_string เมื่อใช้ mysql และ htmlspecialchars เมื่อแสดงผล HTML
    35.ด้วยเหตุผลด้านความปลอดภัย ไม่ควรแสดง path , extension และ configuration สู่สาธารณะ เช่นการ แสดง error หรือ phpinfo() ใน webroot
    36.ปิดการทำงานของ register_globals ไม่มีสคริปไหนในงานจริงที่เปิดใช้กันหรอก มีแต่สคริปแย่ๆและเก่าๆเท่านั้น อีกทั้ง register_globals ก็จะไม่มีอีกแล้วให้ php6
    แต่ก็แปลก หนังสือสอน php ภาษาไทยส่วนใหญ่ชอบสอนให้ใช้ เซ็งจริงๆ
    37.ควรเก็บรหัสผ่าน มากกว่าเป็นตัวหนังสือดิบๆ อย่างน้อยควรเอารหัสผ่านไปเข้ารหัสเช่น MD5
    หรือ sha1 ก็ได้นะ
    38.ใช้ ip2long() และ long2ip() เพื่อแปลงค่า ip v4 ให้เป็นเลขชนิด long แทนที่จะเก็บเป็น text ใน database
    ขนาด database ต่างกันชัดเจน
    39.ควรศึกษารายละเอียดที่เกี่ยวกับ PEAR ให้ดี เพราะว่าจะทำให้โค้ดมีมาตรฐานที่ดีมากขึ้น
    40.เมื่อใช้ header('Location:'.$url); จำไว้เสมอว่าต้องตามด้วยคำสั่ง die(); เพื่อป้องกันการหลุดของคำสั่ง
    เพราะหลายกรณีโดน hack แล้วก็โดนควบคุมให้ทำงานในแบบที่คิดไม่ถึงเลย (ถ้าไม่ die(); php จะทำงานเลยไปด้วยนะครับ)
    41.ใน OOP ถ้า method ใดเป็นชนิด static method ก็ให้ประกาศเป็นชนิด static ไปเลย จะทำให้เร็วขึ้นอีก เท่า
    42.การเพิ่มค่าตัวแปรใน local OOP method นั้นเร็วที่สุด ใกล้เคียงกับการเรียก ตัวแปร local ของ function และการเพิ่มค่าตัวแปรแบบ globla ช้าเป็นเท่าตัวเมื่อเทียบกับ local
    43.การเพิ่มค่าของ object property (เช่น $this->prop++) ช้าเป็น เท่าเมื่อเทียบกับ local variable
    44.การเพิ่มค่าให้กับตัวแปร local ที่ไม่ได้ประกาศไว้ก่อน ทำให้ช้ากว่าปกติ 9-10 เท่าเมื่อเทียบกับการประกาศไว้ก่อน
    45.การสร้างตัวแปร global แม้ว่าจะไม่ได้เอาไปใช้ใน function ก็ทำให้ช้าลง เพราะว่า php จะออกไปเช็คตัวแปร global ที่มีอยู่เสมอ
    46.จำนวน method ที่เพิ่มขึ้น ไม่ส่งผลต่อ performance (ถ้าใช้งานเท่าเดิม)
    47.method ใน derived classes ทำงานได้เร็วกว่า base class
    48.function ที่รับ 1 parameter แต่ใน function ว่างเปล่ามีลักษณะเหมือน การทำงาน $localvar++ 7-8 ครั้ง และถ้าเป็น method ลักษณะนี้ ก็เปรียบกับ $localvar++ 15 ครั้ง
    49.ไม่จำเป็นต้องทำทุกอย่างเป็น OOP มันจะทำให้เกิด overhead และ method, object จะทำให้เปลือง memory
    50.อย่าวางใจ ข้อมูลที่ได้มาจากการป้อนของ user เช่น form $_POST ให้ใช้ mysql_real_escape_string แทนการใช้ mysql_escape_string หรือ addslashs แต่ถ้า เปิด magic_quotes_gpc ไว้ ก็ให้ใช้ stripslashes ไว้ก่อน
    51.ระวังโดน header injection กับ function mail()
    * form mail ที่หลายคน copy ตามเว็บมาใช้ มักจะโดนเอาไว้ใช้เป็นช่องทางส่ง email spam โดยที่เจ้าของเว็บไม่รู้ตัวเสมอๆ
    52.unset ตัวแปรของ database (อย่างน้อยที่สุดก็ password) ไม่จำเป็นตั้งใช้ หลังจากการเชื่อมต่อ เรียบร้อยแล้ว
    53.RTFM! ซะ แปลว่า Read The Fucking Manual หรือ อ่านไอ้คู่มือหน่อยเถอะ อ่านได้ที่ http://th.php.net มีคำบรรยาย พร้อมตัวอย่างมากมาย ภาษาก็ไม่ยากเกินไปหรอกนะ

ไม่มีความคิดเห็น:

แสดงความคิดเห็น