Skip to main content

เนื้อหาภาษาไทย / Thai content

System guide Content reviewed

พื้นฐาน Optimization: ทำความเข้าใจ Performance Bottlenecks

บทความนี้กล่าวถึงพื้นฐานของการ Optimization ใน PHP Application โดยเน้นที่การทำความเข้าใจ Performance Bottlenecks หรือจุดคอขวดที่ทำให้ Application ทำงานช้าลง ซึ่...

พื้นฐาน Optimization: ทำความเข้าใจ Performance Bottlenecks

ในบทความก่อนหน้านี้ เราได้เรียนรู้เกี่ยวกับการใช้ Git Hooks เพื่อ Trigger Jenkins Build อัตโนมัติ ซึ่งเป็นส่วนสำคัญของ Continuous Integration (CI) ในบทความนี้ เราจะมาเจาะลึกเรื่องการ Optimization หรือการปรับปรุงประสิทธิภาพของ PHP Application ของเรา โดยจะเน้นไปที่การทำความเข้าใจ Performance Bottlenecks หรือจุดคอขวดที่ทำให้ Application ทำงานช้าลง ซึ่งเป็นขั้นตอนสำคัญก่อนที่เราจะลงมือปรับปรุงโค้ดจริง

ก่อนที่จะเริ่มลงมือ Optimization สิ่งสำคัญคือการทำความเข้าใจว่าปัญหาอยู่ที่ไหน การปรับปรุงโค้ดโดยไม่รู้ว่าอะไรคือปัญหาที่แท้จริง อาจเสียเวลาและไม่ได้ผลลัพธ์ที่ต้องการ ดังนั้น เรามาเรียนรู้เกี่ยวกับ Performance Bottlenecks ที่พบบ่อยใน PHP Application กัน

Database Queries

Database Queries มักเป็นสาเหตุหลักของ Performance Bottlenecks ใน Web Application เนื่องจาก Database เป็นที่เก็บข้อมูลที่สำคัญ และการดึงข้อมูลที่ไม่ถูกต้องหรือไม่เหมาะสม สามารถทำให้ Application ทำงานช้าลงได้อย่างมาก

ปัญหาที่พบบ่อย:

  • N+1 Query Problem: ปัญหานี้เกิดขึ้นเมื่อเราดึงข้อมูลหลักจาก Database แล้วต้องดึงข้อมูลที่เกี่ยวข้องเพิ่มเติมอีก N ครั้ง ตัวอย่างเช่น เราดึงข้อมูลรายการสินค้า แล้วต้องดึงข้อมูลผู้ขายสำหรับแต่ละสินค้า ทำให้เกิด Query จำนวนมาก
  • Slow Queries: Queries ที่ใช้เวลานานในการ Execute อาจเกิดจากการไม่มี Index หรือ Query ที่ซับซ้อนเกินไป
  • Inefficient Data Retrieval: การดึงข้อมูลที่ไม่จำเป็น (เช่น ดึงทุก Column เมื่อต้องการเพียงบาง Column) ทำให้เสีย Bandwidth และเพิ่มภาระให้กับ Database Server

ตัวอย่าง: N+1 Query Problem

สมมติว่าเรามี Table `products` และ `users` โดย `products` มี Column `user_id` ที่อ้างอิงไปยัง `users`

<?php

// ดึงข้อมูลสินค้าทั้งหมด
$products = DB::table('products')->get();

foreach ($products as $product) {
    // ดึงข้อมูลผู้ขายสำหรับแต่ละสินค้า (N+1 Query)
    $user = DB::table('users')->find($product->user_id);
    echo "Product: " . $product->name . ", Seller: " . $user->name . "<br>";
}

ใน Code นี้ เราดึงข้อมูลสินค้าทั้งหมดก่อน จากนั้นใน Loop เราจะดึงข้อมูลผู้ขายสำหรับแต่ละสินค้า ซึ่งทำให้เกิด N+1 Query (1 Query สำหรับสินค้าทั้งหมด และอีก N Query สำหรับผู้ขายแต่ละคน)

วิธีแก้ไข: Eager Loading

การใช้ Eager Loading (หรือ Join) ช่วยให้เราดึงข้อมูลที่เกี่ยวข้องมาพร้อมกับข้อมูลหลักได้ใน Query เดียว

<?php

// ดึงข้อมูลสินค้าทั้งหมด พร้อมข้อมูลผู้ขาย (Eager Loading)
$products = DB::table('products')
    ->join('users', 'products.user_id', '=', 'users.id')
    ->select('products.name as product_name', 'users.name as user_name')
    ->get();

foreach ($products as $product) {
    echo "Product: " . $product->product_name . ", Seller: " . $product->user_name . "<br>";
}

ใน Code นี้ เราใช้ Join เพื่อดึงข้อมูลสินค้าและผู้ขายพร้อมกัน ทำให้ลดจำนวน Query เหลือเพียง 1 Query

ข้อผิดพลาดที่พบบ่อย:

  • ลืมสร้าง Index บน Column ที่ใช้ในการ Query
  • ใช้ `SELECT *` แทนการระบุ Column ที่ต้องการ
  • ไม่ Optimize Query ที่ซับซ้อน

File I/O

File I/O (Input/Output) เป็นอีกหนึ่ง Performance Bottleneck ที่พบบ่อย โดยเฉพาะอย่างยิ่งเมื่อ Application ต้องอ่านหรือเขียนไฟล์จำนวนมาก หรือไฟล์ที่มีขนาดใหญ่

ปัญหาที่พบบ่อย:

  • Reading Large Files: การอ่านไฟล์ขนาดใหญ่ทั้งหมดเข้า Memory อาจทำให้ Memory Exhaustion และ Application ทำงานช้าลง
  • Frequent File Access: การเข้าถึงไฟล์บ่อยๆ (เช่น การอ่าน Config File ทุกครั้งที่ Request เข้ามา) ทำให้เสียเวลาในการค้นหาและอ่านไฟล์
  • Unnecessary File Operations: การทำ File Operations ที่ไม่จำเป็น (เช่น การเขียน Log ทุกครั้งที่เกิด Error) อาจทำให้ Application ทำงานช้าลง

ตัวอย่าง: Reading Large Files

<?php

// อ่านไฟล์ทั้งหมดเข้า Memory (อาจทำให้เกิดปัญหา)
$content = file_get_contents('large_file.txt');
echo $content;

ใน Code นี้ เราอ่านไฟล์ `large_file.txt` ทั้งหมดเข้า Memory ซึ่งอาจทำให้เกิด Memory Exhaustion หากไฟล์มีขนาดใหญ่มาก

วิธีแก้ไข: Streaming

การใช้ Streaming ช่วยให้เราอ่านไฟล์ทีละส่วน แทนที่จะอ่านทั้งหมดเข้า Memory

<?php

// อ่านไฟล์ทีละส่วน (Streaming)
$handle = fopen('large_file.txt', 'r');
if ($handle) {
    while (($line = fgets($handle)) !== false) {
        echo $line;
    }
    fclose($handle);
}

ใน Code นี้ เราเปิดไฟล์ด้วย `fopen()` และอ่านทีละบรรทัดด้วย `fgets()` ทำให้ลด Memory Usage อย่างมาก

ข้อผิดพลาดที่พบบ่อย:

  • ลืมปิด File Handle หลังจากใช้งาน
  • ไม่ตรวจสอบ Error ใน File Operations
  • ใช้ Function ที่ไม่เหมาะสมกับขนาดไฟล์

CPU Intensive Tasks

CPU Intensive Tasks คือ Tasks ที่ใช้ CPU เป็นจำนวนมาก เช่น การเข้ารหัสข้อมูล การประมวลผลภาพ หรือการคำนวณทางคณิตศาสตร์ที่ซับซ้อน Tasks เหล่านี้อาจทำให้ CPU Overload และ Application ทำงานช้าลง

ปัญหาที่พบบ่อย:

  • Complex Algorithms: การใช้อัลกอริทึมที่ซับซ้อนและไม่มีประสิทธิภาพ
  • Unoptimized Loops: Loops ที่มีการทำงานซ้ำๆ โดยไม่จำเป็น
  • Blocking Operations: Operations ที่ Block Process อื่นๆ (เช่น การรอ Response จาก External API)

ตัวอย่าง: Complex Algorithms

<?php

// คำนวณ Fibonacci Sequence (Inefficient)
function fibonacci($n) {
    if ($n <= 1) {
        return $n;
    }
    return fibonacci($n - 1) + fibonacci($n - 2);
}

echo fibonacci(40); // ใช้เวลานานมาก

ใน Code นี้ เราคำนวณ Fibonacci Sequence โดยใช้ Recursive Function ซึ่งเป็นวิธีที่ไม่ Efficient และใช้เวลานานมากสำหรับค่า `n` ที่มีขนาดใหญ่

วิธีแก้ไข: Memoization

การใช้ Memoization ช่วยให้เรา Cache ผลลัพธ์ของการคำนวณที่เคยทำไปแล้ว เพื่อนำกลับมาใช้ใหม่โดยไม่ต้องคำนวณซ้ำ

<?php

// คำนวณ Fibonacci Sequence (Memoization)
$memo = [];
function fibonacci($n) {
    global $memo;
    if (isset($memo[$n])) {
        return $memo[$n];
    }
    if ($n <= 1) {
        return $n;
    }
    $memo[$n] = fibonacci($n - 1) + fibonacci($n - 2);
    return $memo[$n];
}

echo fibonacci(40); // เร็วกว่าเดิมมาก

ใน Code นี้ เราใช้ Array `$memo` เพื่อเก็บผลลัพธ์ของการคำนวณ Fibonacci Sequence ทำให้ลดเวลาในการคำนวณอย่างมาก

ข้อผิดพลาดที่พบบ่อย:

  • ไม่ใช้ Profiler เพื่อระบุ CPU Intensive Tasks
  • ไม่ Optimize Loops และ Algorithms
  • ไม่ใช้ Caching เพื่อลดภาระให้กับ CPU

สรุป

ในบทความนี้ เราได้เรียนรู้เกี่ยวกับ Performance Bottlenecks ที่พบบ่อยใน PHP Application ได้แก่ Database Queries, File I/O และ CPU Intensive Tasks การทำความเข้าใจปัญหาเหล่านี้เป็นขั้นตอนสำคัญในการ Optimization Application ของเรา ในบทความถัดไป เราจะมาเรียนรู้เกี่ยวกับการใช้ OPcache และ Redis เพื่อเพิ่มความเร็วให้กับ Application ของเรา

Office.in.th Custom Service

Want to build or adapt a system from this structure?

Office.in.th designs and develops enterprise web applications, API integrations, and public- and private-sector management systems, with long-term support.

See our software development service