จัดระเบียบซอร์สโค๊ด PHP ลดการ query ฐานข้อมูล MySQL ลดภาระเซิร์ฟเวอร์ให้น้อยลง (คิวรี่ซ้อนคิวรี่)

โดย SONGCHAI SAETERN
การเขียนโปรแกรมด้วยภาษา php เป็นภาษาที่ยืดหยุ่น และผมถนัดที่สุด เพราะเราสามารถออกแบบการทำงานได้ง่ายกว่าภาษาอื่น ที่ผมเขียนเป็น เรื่องตัวแปรก็ยืดหยุ่น เรียกใช้ง่าย

บทความนี้จะนำเสนอเทคนิคการเขียนโปรแกรม ที่ช่วยลดจำนวนครั้งในการคิวรี่ฐานข้อมูลน้อยลง เพื่อเป็นการลดภาระของฐานข้อมูล MySQL ให้ใช้ CPU ประมวลผลน้อยลง

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



กรณีที่ต้องแสดงข้อมูลหลายเรคอร์ดเรามักจะเจอ fatal error “Allowed memory size exhausted” ข้อความนี้อยู่เป็นประจำ จึงเป็นเหตุผลให้เราต้องแบ่งหน้าการแสดงผล เพื่อให้แสดงผลเร็วขึ้น และไม่ใช้หน่วยความจำเกินขีดจำกัดที่เซิร์ฟเวอร์มีให้

และขั้นตอนการเขียนโปรแกรมที่จะช่วยลดจำนวนการคิวรี่เพื่อให้ MySQL ทำงานได้เร็วขึ้นมีดังนี้


1. ตัดส่วนที่ต้องคิวรี่เพื่อดึงข้อมูลในลูปออกมาไว้นอกลูป

วิธีนี้จะสามารถใช้ได้กับ ตารางข้อมูลที่ข้อมูลตายตัว หรือมีการเพิ่มข้อมูลไม่บ่อย และจะไม่เกินหลักพัน ประมาณนี้

2. สร้างอาร์เรย์เก็บข้อมูลของตารางที่ต้องคิวรี่ในลูปนี้ เอาไว้เรียกใช้ในลูปแทนการคิวรี่จากฐานข้อมูล

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



การเขียนโค๊ด PHP แบบเดิม (เรียกข้อมูลในลูป)

<?php
$no = 0;
$sql = "SELECT * FROM booking WHERE month = '04' ";
//*** คิวรี่ครั้งที่ 1 ***
$result = mysql_query($sql);
while( $rs = mysql_fetch_assoc($result) ){

$dpId = $rs["book_department_id"];
//*** คิวรี่ครั้งที่ 2 ***
$qry = mysql_query("SELECT department_name FROM tb_department WHERE department_id = '".$dpId."' ");
$rsDp = mysql_fetch_assoc($qry);
$departMentName = $rsDp["department_name"];

echo "<br/>", $departMentName;
}
?>
คิวรี่ครั้งที่ 1 :: คือการเรียกข้อมูลการจองของเดือนเมษายน
คิวรี่ครั้งที่ 2 :: คือการการเรียกชื่อแผนกที่พนักงานคนที่รับจองสังกัดอยู่ 
ซึ่งถ้าเดือนเมษายนมีการจอง 50 รายการ ก็จะเรียกคำสั่งคิวรี่ทั้งหมด 50 ครั้ง



การเขียนโค๊ด PHP แบบใหม่ (แยกส่วนที่เรียกข้อมูลในลูป ออกมาไว้นอกลูป)

<?php
//รายชื่อแผนกทั้งหมด
$allDepart = array();
//*** คิวรี่ครั้งที่ 2 ***
$qry = mysql_query("SELECT department_id, department_name FROM tb_department");
while($rsDp = mysql_fetch_assoc($qry)){
$allDepart[$rsDp['department_id ']] = $rsDp['department_name']
}

$no = 0;
$sql = "SELECT * FROM booking WHERE month = '04' ";
//*** คิวรี่ครั้งที่ 1 ***
$result = mysql_query($sql);
while( $rs = mysql_fetch_assoc($result) ){
$dpId = $rs["book_department_id"];
$departMentName = isset($allDepart[$dpId]) ? $allDepart[$dpId] : $dpId;
 
echo "<br/>", $departMentName;
}
?>
คิวรี่ครั้งที่ 1 :: คือการเรียกข้อมูลรายชื่อแผนกทั้งหมด
คิวรี่ครั้งที่ 2 :: คือการเรียกข้อมูลการจองของเดือนเมษายน ถึงแม้เดือนนี้จะมี 50 รายการ แต่การคิวรี่จะเกิดขึ้นเพียง 2 ครั้งเท่านั้นเพราะรายชื่อแผนกทั้งหมดเก็บไว้ในอาร์เรย์ $allDepart แล้ว ซึ่งเรียกใช้ด้วยไอดีทันที



จากตัวอย่างการเขียนโค๊ดสองกรณีนี้ คงพอจะเห็นถึงความแตกต่างแล้วนะครับ กรณีเรียกข้อมูลทั้งหมดมาเก็บในตัวแปล $allDepart ถามว่าจะทำงานช้าไปรึเปล่า บอกได้เลยว่าไม่ช้าครับ แต่จะเปลือง RAM เยอะหน่อยถ้าเก็บข้อมูลเยอะมากๆ ^^;

ผมเคยทดสอบกับข้อมูลตารางที่มีฟิลด์มากกว่า 50 ฟิลด์ เก็บข้อมูลมากกว่า 50,000 เรคอร์ด
และเรียกโดยการ SELECT * FROM table มาเก็บในตัวแปรอาร์เรย์ใช้เวลาเพียงไม่กี่วิครับ
แต่ทดสอบกับเซิร์ฟเวอร์ภายในนะครับ ไม่ได้ทดสอบผ่านอินเตอร์เน็ต แต่ถึงอย่างไรก็เร็วกว่ากรณีแรกอยู่ดีครับ


ปัญหาที่พบคือการใช้กับตารางที่มีข้อมูลเยอะเกินไป จะทำให้เกิดการใช้หน่วยความจำเกินที่กำหนดไว้ครับ ซึ่งผมก็ไม่แนะนำให้ทำ ก็ลองเอาไปปรับใช้กันดูนะครับ แล้วท่านจะเห็นว่าความเร็วต่างกันอย่างไร



ตัวอย่างเพิ่มเติมของการใช้ Array เก็บข้อมูลเพื่อใช้อ้างอิงแทนการ Query หรือ JOIN โดยตรง
- การทำ Index ให้ MySQL Database เพื่อเพิ่มความเร็ว 







PHP CI MANIA - PHP Code Generator 

โปรแกรมช่วยสร้างโค้ด "ลดเวลาการเขียนโปรแกรม"
http://fastcoding.phpcodemania.com/index.php/#purchase-order
ราคาสุดคุ้ม  
http://fastcoding.phpcodemania.com



Fatal error: Uncaught Error: undefined function CodeIgniter\locale_set_default()

โดย SONGCHAI SAETERN
หลังจากที่ได้ติดตั้ง PHP 8.0 และลองนำ CodeIgniter Framework 4.0.4 มาทดสอบดู ก็ปรากฏ Error ดังนี้




ปัญหาเกิดจากขาด Extension บางตัว ให้แก้ไขที่ไฟล์ php.ini

1. ค้นหา ;extension=intl   จะเห็นว่ามี ; อยู่ด้านหน้า
    ให้เอาคอมเมนต์ออกเหลือเพียง 
    extension=intl

2. ค้นหา extension_dir จากนั้นให้ใส่เป็น PATH เต็มเข้าไปแทน
    เช่น extension_dir = "C:\Apache24\php8\ext"


ให้ทำการ ปิด-เปิด Service ของ Apache ใหม่ (เปิด Command promt แบบ Run as administrator)

C:\> cd C:\Apache24\bin
C:\Apache24\bin> httpd.exe -k restart

ถ้ายังไม่ได้ให้ทำการคัดลอกไฟล์เหล่านี้ไปวางที่ System32


icu*.dll    <-- จะมีหลายตัวด้วยกันที่ขึ้นต้นด้วย icu.......

เอาไปวางที่ C:\Windows\System32 

ถ้ายังรันไม่ได้ให้เอาไปวางที่ C:\Windows\SysWOW64 อีกที่ด้วย




อ้างอิง
https://codeinsane.wordpress.com/2018/05/16/install-apache-and-php/
https://forum.codeigniter.com/thread-77086.html
https://www.php.net/manual/en/install.pecl.windows.php
http://forum.wampserver.com/read.php?2,80704,printview,page=1


PHP CI MANIA - PHP Code Generator 

โปรแกรมช่วยสร้างโค้ด "ลดเวลาการเขียนโปรแกรม"
http://fastcoding.phpcodemania.com/index.php/#purchase-order
ราคาสุดคุ้ม  
http://fastcoding.phpcodemania.com

การเปิด Error Reporting บน Localhost และ Production Server

โดย SONGCHAI SAETERN
สำหรับการพัฒนาเว็บฯสิ่งที่หลีกเลี่ยงไม่ได้คือ Error ดังนั้นการจะ Debug ได้นั้น ก็ต้องทำความเข้าใจกับ Error ให้ได้เสียก่อน (ซึ่ง StackOverflow นั้นช่วยได้เยอะทีเดียว)

วิธีการเปิดข้อความแจ้ง Error บน Localhost นั้นง่ายๆครับ แค่เข้าไปแก้ไขที่ไฟล์ php.ini




แต่ถ้าข้อผิดพลาดเกิดขึ้นบน Production Server เราอาจจะไม่สามารถแก้ไขที่ php.ini ได้โดยตรง เราสามารถเพิ่มคำสั่งในไฟล์หน้านั้นๆ เพื่อแสดง Error ได้ดังนี้

Production Server :
(ส่วนนี้ให้เอาไว้ที่ไฟล์ Controller ที่ต้องการตรวจสอบเป็นไฟล์ๆไปนะครับ ทดสอบเสร็จก็ลบออกด้วย)

<?php
    ini_set('display_errors', 1);
    ini_set('display_startup_errors', 1);
    error_reporting(E_ALL);


นำคำสั่งสีน้ำเงินไปวางไว้บนสุด หลังเปิดแท็ก PHP
เพียงเท่านี้เราก็จะเห็น Error ที่เกิดขึ้นเมื่อนำไฟล์ไปรันบน Web hosting หรือ Production Server ได้ทันที


PHP CI MANIA - PHP Code Generator 

โปรแกรมช่วยสร้างโค้ด "ลดเวลาการเขียนโปรแกรม"
 http://fastcoding.phpcodemania.com/index.php/#purchase-order
ราคาสุดคุ้ม  4,500  บาท
http://fastcoding.phpcodemania.com

วิธีตั้งเวลา Backup MySQL อัตโนมัติ เพื่อสำรองข้อมูลไว้ใช้เมื่อต้องการเรียกคืนภายหลัง

โดย SONGCHAI SAETERN

ทดสอบแล้วใช้ได้ แต่ใช้จริงต้องปรับตำแหน่งเรียก mysqldump ที่ต่างกัน

OS : Windows Server


เช่นถ้าใช้ wamp เป็นตัวติดตั้งก็จะอยู่ที่
C:\wamp\bin\mysql\mysql5.5.24\bin\mysqldump


ถ้าติดตั้ง MySQL เพียวๆ ก็คงต้องหาตำแหน่งที่ถูกต้องของเซิร์ฟเวอร์แต่ละเวอร์ชั่น

เช่น C:\Program Files\MySQL\MySQL Server 5.1\bin\mysqldump

การจะกำหนดเวลาแบ็กอัพนั้น Schedule ของ Windows Server ให้เรียกไฟล์ xxxxx.bat เพื่อทำงานตามเวลาที่กำหนด  (หากใช้ลีนุกซ์ก็คงจะใช้ cronjob และจะสะดวกกว่าหากจัดการด้วย webmin)

@echo off
echo Running dump...
set MYDATABASE=xxxxxxx
set MYSQLUSER=root
set MYSQLPASS=xxxxxxx
set BACKUPFILE="F:\Backup\MySQL\%MYDATABASE%_%date:~10,4%-%date:~4,2%-%date:~7,2%_TIME.%time:~0,2%.%time:~3,2%.sql"
C:\wamp\bin\mysql\mysql5.5.24\bin\mysqldump -u%MYSQLUSER% -p%MYSQLPASS% --result-file=%BACKUPFILE% %MYDATABASE%
echo Done! %BACKUPFILE%
หลังจากทดสอบแบ็กอัพฐานข้อมูลขนาด 1GB ใช้เวลาประมาณแค่ 1 นาทีเท่านั้น
ส่วนผลข้างเคียงหรือปัญหาอื่นๆยังไม่ทราบ เพราะเป็นการทำงนผ่าน mysqldump ก็ไม่น่าจะมีปัญหาอะไร เพราะลอง Import ทดสอบดูก็ผ่านฉลุย

แต่ที่แน่ๆ เขาบอกว่าดีกว่า Batch Script ตัวเดิมที่ผมใช้อยู่
(แบบเดิมคัดลอกไดเรกทอรี่ฐานข้อมูลทั้งดุ้น)


อยากรู้ว่า MySQL ที่ติดตั้งนั้นอยู่ที่ตำแหน่งใดในระบบปฏิบัติการที่ท่านใช้ลองอ่านดู
http://dev.mysql.com/doc/refman/5.0/en/option-files.html




PHP CI MANIA PHP Code Generator 
โปรแกรมช่วยสร้างโค้ด ลดเวลาการเขียนโปรแกรม เขียนโปรแกรมง่ายและสะดวกขึ้น
สนใจสั่งซื้อราคาสุดคุ้ม >> http://fastcoding.phpcodemania.com/

Server Error 500 - Internal server error จัดการอย่างไรดี?

โดย CyberMAN

สำหรับปัญหานี้จะพบได้เมื่อรันบน Production Server!!

เมื่อเจอปัญหา Server Error 500 - Internal server error เราจะจัดการอย่างไรดี?
Server Error 500 - Internal server error
ปัญหาที่พบในครั้งนี้ก็คือ การสั่งบันทึกข้อมูล ซึ่ง data type ควรจะเป็น String แต่ตอนเขียนคำสั่ง Query ดันส่งค่าเป็น Integer ดังนั้นก็เจอ error ตามระเบียบ





และเราจะรู้ได้อย่างไรว่าแต่ละครั้งที่เจอปัญหา Server Error 500 - Internal server error นั้นเกิดจากอะไร???

ถ้าอยากรู้ก็ต้องเปิดดู error เพื่อดูการแจ้งเตือนจากข้อความที่แสดงออกมาบนหน้าเว็บครับ

สำหรับขั้นตอนก็มีดังนี้

1. เปิด Internet Information Services (IIS) Manager ขึ้นมา
2. เปิด Error pages



3. คลิกขวาที่รหัส 500 แล้วเลือก Edit Feature Setting..



4. เปลี่ยนตัวเลือกไปที่ Detailed errors



จากนั้นก็ไปยังหน้าเพจที่ Server Error 500 - Internal server error แล้วลองรันอีกครั้ง คราวนี้จะพบกับข้อความแสดงข้อผิดพลาดขึ้นมา ซึ่งในที่นี้ก็คือการกำหนด Data Type ไม่ตรงกับฐานข้อมูลนั่นเอง



ทั้งนี้ทั้งนั้น ข้อความที่แสดง error ของแต่ละครั้งอาจจะไม่เหมือนกัน ขึ้นอยู่กับว่าเกิดข้อผิดพลาดขึ้นที่ส่วนใดนั่นเอง

และหลังจากที่เปิดแสดงข้อผิดพลาดแล้ว ก็อย่าลืมปิดให้เรียบร้อยเหมือนเดิมด้วยนะครับ


PHP CI MANIA PHP Code Generator 
โปรแกรมช่วยสร้างโค้ด ลดเวลาการเขียนโปรแกรม เขียนโปรแกรมง่ายและสะดวกขึ้น
สนใจสั่งซื้อราคาสุดคุ้ม >> http://fastcoding.phpcodemania.com/


ติดตั้ง PHP 7.0.x สำหรับ IIS 7.5 บน Windows Server 2008 R2 64bit

โดย SONGCHAI SAETERN

สรุปขั้นตอนการอัพเกรด PHP เป็นเวอร์ชั่น 7 แบบคร่าวๆ นะครับ
สำหรับท่านใดที่ใช้ IIS เป็นเว็บเซิร์ฟเวอร์บนระบบปฏิบัติการ Windows Server 2008 R2  64bit ก็สามารถใช้ขั้นตอนต่อไปนี้ได้เลย ซึ่ง IIS สำหรับระบบปฏิบัติการ Windows Server 2008 R2 จะได้เป็นเวอร์ชั่น 7.5 และเมื่อติดตั้ง PHP จะได้เวอร์ชั่น PHP 5.3 

ติดตั้ง PHP เพื่อใช้งาน PHP บน IIS Web Server (Windows Server 2008)

หลังจากที่ปลายปีที่แล้ว PHP ได้ปล่อยเวอร์ชั่น 7 ออกมา ซึ่งเท่าที่เก็บข้อมูลมาแล้วเห็นว่าประสิทธิภาพดีกว่าทุกรุ่น จึงสนใจที่จะอัพเกรดเป็น PHP 7.0.13 ที่เป็นเวอร์ชั่นล่าสุด แต่เมื่อดาวน์โหลดมาใช้กลับไม่สามารถสั่งให้เว็บเซิร์ฟเวอร์รันได้ ก็เลยเปลี่ยนเป็นใช้วิธีติดตั้งเวอร์ชั่นที่มีใน Web Platform Installer แทน ซึ่งก็ได้เป็น PHP 7.0.9 มาแทน



สำหรับขั้นตอนการติดตั้ง PHP เวอร์ชั่นอื่นเพิ่มเติมก็มีดังนี้ครับ

1. ติดตั้ง PHP เวอร์ชั่น 7 สำหรับ IIS ผ่านทาง Web Platform Installer
https://sysadmin.psu.ac.th/…/%E0%B8%81%E0%B8%B2%E0%B8%A3-u…/


แต่หลังจากตั้งค่าผ่าน PHP Manager ใน IIS จะพบว่ายังไม่สามารถใช้งานได้ เพราะการจะรัน PHP 7.0.x ได้นั้นต้องมี VC14 ด้วย (Visual C++ Redistributable for Visual Studio 2015)
http://comerror.com/runtime-l1-1-0-dll-is-missing.html

แต่การจะติดตั้ง VC14 ได้นั้นระบบปฏิบัติการจะต้องอัพเกรดเป็น Service Pack 1 ก่อน

2. อัพเกรด Windows Server เป็น SP1 (ค้นหาด้วยคำว่า Windows Server 2008 R2 SP1)

เลือก windows6.1-KB976932-X64
>>> https://thaiwinadmin.blogspot.com/2011/02/install-windows-server-2008-r2-sp1.html

3. ติดตั้ง VC14 จะเป็นเวอร์ชั่น Visual C++ Redistributable for Visual Studio 2015
Visual C++ Redistributable for Visual Studio 2015
https://www.microsoft.com/en-us/download/details.aspx?id=48145


หลังจากนั้นก็รันเปลี่ยนเวอร์ชั่นไปมาระหว่าง 5.3 กับ 7.0 ด้วย PHP Manager ใน IIS ได้ตามสะดวก ^^" ซึ่งตอนนี้ได้ลองทดสอบใน VMWare แล้วผ่านฉลุย ต่อไปก็จะเป็นขั้นตอนการเปลี่ยนโค้ดจาก PHP 5.3 ไปเป็น PHP 7.0 โดยการไล่แก้คำสั่งหรือฟังก์ชั่นที่ถูกยกเลิกไปแล้ว

ซึ่งงานตรงนี้คงจะใช้เวลาค่อนข้างนานทีเดียว แต่ก็ลดเวลาในส่วนของการจัดการฐานข้อมูลได้หน่อยเพราะผมใช้คลาสที่เขียนแยกเอาไว้ ก็ไม่ต้องไปไล่แก้คำสั่งที่เกี่ยวกับฐานข้อมูลทุกหน้า แค่แก้ที่คลาสที่เดียวก็จบเลย (ตรงนี้แหละครับเป็นจุดที่ผมอยากเปลี่ยนไปใช้ CodeIgntier เพราะเราไม่ต้องแก้อะไรเลย ^^ เวลาเปลี่ยนเวอร์ชั่น PHP หรือเปลี่ยนฐานข้อมูล ถ้าใช้ Class ที่มีอยู่แล้วของ Framework)


ท่านใดที่ใช้ Windows Server ก็ลองสร้าง VM สักตัวแล้วลองทำตามขั้นตอนนี้กันดูนะครับ ^^

-------------
เพิ่มกรณีแก้ไข my.ini เพื่อเปลี่ยน datadir ของ MySQL แล้วไม่สามารถ Start MySQL Service ได้



กรณีในโฟลเดอร์ data ของ MySQL ตัวที่ติดตั้งใหม่ไม่มี 3 ไฟล์นี้ ให้ย้าย 3 ไฟล์นี้ออกไปที่อื่น (เก็บเป็น BACKUP เอาไว้ป้องกันมีปัญหาต้องการนำกลับมาใหม่)

เมื่อย้าย 3 ไฟล์นี้ออกไปแล้วลอง Start Service อีกครั้ง จะสามารถรันได้ปกติ



PHP CI MANIA PHP Code Generator 
โปรแกรมช่วยสร้างโค้ด ลดเวลาการเขียนโปรแกรม เขียนโปรแกรมง่ายและสะดวกขึ้น
สนใจสั่งซื้อราคาสุดคุ้ม >> http://fastcoding.phpcodemania.com/