MyISAM vs InnoDB: เลือก Storage Engine ให้ถูกใจ MySQL

myisam-convert-innodb-storage-engine-wordpress

เคยไหม? รัน Query เดิม ข้อมูลเท่าเดิม แต่พอเปลี่ยน Storage Engine ปุ๊บ เร็วขึ้นเป็นเท่าตัว!

เรื่องนี้เกิดขึ้นจริงกับผม เมื่อสัปดาห์ที่แล้ว ตาราง sendrefer ขนาด 130,793 แถว ที่ใช้ MyISAM อยู่ ๆ JOIN ทีช้าจนได้ เปลี่ยนเป็น InnoDB เท่านั้นแหละครับ Query ที่เคยใช้เวลาเป็น 10 วินาที เหลือหลักเสี้ยววินาทีทันที!

บทความนี้จะพาทุกคนไปรู้จักกับ 2 Storage Engine ยอดฮิตของ MySQL ว่ามันต่างกันยังไง? เมื่อไหร่ควรใช้อะไร? และทำไม InnoDB ถึงเป็น Default ในปัจจุบัน


🧠 Storage Engine คืออะไร?

Storage Engine เปรียบเสมือน เครื่องยนต์ของรถ MySQL เป็นตัวถัง แต่เครื่องยนต์คือสิ่งที่กำหนดว่า:

  • จะเก็บข้อมูลยังไง?
  • จะค้นหาข้อมูลยังไง?
  • จะจัดการความปลอดภัยของข้อมูลยังไง?
  • รองรับการทำงานพร้อมกันกี่คน?

MySQL รองรับหลาย Storage Engine แต่ที่นิยมสุดคือ MyISAM และ InnoDB


🆚 ตารางเปรียบเทียบ MyISAM vs InnoDB

คุณสมบัติMyISAMInnoDB
การ LockTable-level Lock (ล็อคทั้งตาราง)Row-level Lock (ล็อคเฉพาะแถว)
Transaction (ACID)❌ ไม่รองรับ✅ รองรับ (COMMIT, ROLLBACK)
Foreign Key❌ ไม่รองรับ✅ รองรับ
Clustered Index❌ ไม่มี (Heap-organized)✅ มี (Index-organized)
Full-text Search✅ มี (แต่รุ่นเก่า)✅ มี (ตั้งแต่ MySQL 5.6)
Data CachingCache เฉพาะ IndexCache ทั้ง Data และ Index
Compression✅ รองรับ✅ รองรับ (แต่ซับซ้อนกว่า)
ความเร็วในการอ่าน⚡ เร็วมาก🚀 เร็ว (ถ้าใช้ Index ถูก)
ความเร็วในการเขียน🐢 ช้า (ล็อคทั้งตาราง)⚡ เร็ว (ล็อคเฉพาะแถว)
พื้นที่จัดเก็บ💾 น้อยกว่า💿 มากกว่า (มี overhead)

🔬 เจาะลึกความแตกต่าง

1. การ Lock ข้อมูล 🔒

-- MyISAM: เวลาอัพเดท จะล็อค TABLE ทั้ง table
UPDATE myisam_table SET status = 1 WHERE id = 5;
-- ตอนนี้ TABLE myisam_table โดนล็อคทั้งหมด!
-- คนอื่นจะ SELECT หรือ UPDATE ไม่ได้ จนกว่าจะเสร็จ

-- InnoDB: ล็อคเฉพาะ ROW
UPDATE innodb_table SET status = 1 WHERE id = 5;
-- ล็อคเฉพาะแถว id=5
-- คนอื่น UPDATE แถว id=6 ได้ปกติ!

2. Clustered Index vs Heap-organized 📚

MyISAM (Heap-organized):

Primary Key Index     Data File
[id: 5] ------> [Address: 0x7F8A] ------> [5 | Somchai | 50000]
[id: 8] ------> [Address: 0x7F9B] ------> [8 | Somsak  | 60000]
  • ต้องค้นหา 2 รอบ: Index → Address → Data

InnoDB (Clustered Index):

Primary Key Index + Data
[id: 5 | Somchai | 50000]  [id: 8 | Somsak | 60000]
  • ข้อมูลอยู่กับ index! ค้นหาเจอปุ๊บ ได้ข้อมูลปั๊บ

3. Buffer Pool vs Key Cache 🗃️

-- InnoDB: มี Buffer Pool ใหญ่ๆ ไว้ cache ทุกอย่าง
SHOW VARIABLES LIKE 'innodb_buffer_pool_size';
-- ผล: 134217728 (128MB) - cache ทั้ง data และ index

-- MyISAM: มี Key Cache เฉพาะ index
SHOW VARIABLES LIKE 'key_buffer_size';
-- ผล: 8388608 (8MB) - cache เฉพาะ index
-- data ต้องอ่านจาก disk ตลอด

📊 ทดสอบ Performance จริง

สมมติ我们有 2 ตาราง:

-- MyISAM
CREATE TABLE users_myisam (
    id INT PRIMARY KEY,
    name VARCHAR(100),
    salary DECIMAL(10,2)
) ENGINE=MyISAM;

-- InnoDB
CREATE TABLE users_innodb (
    id INT PRIMARY KEY,
    name VARCHAR(100),
    salary DECIMAL(10,2)
) ENGINE=InnoDB;

-- ใส่ข้อมูล 1 ล้านแถวเหมือนกัน

ทดสอบที่ 1: SELECT with JOIN

-- MyISAM
EXPLAIN SELECT * FROM users_myisam u
JOIN orders_myisam o ON u.id = o.user_id;
-- type: ALL, rows: 1,000,000
-- Extra: Using join buffer (Block Nested Loop)

-- InnoDB
EXPLAIN SELECT * FROM users_innodb u
JOIN orders_innodb o ON u.id = o.user_id;
-- type: eq_ref, rows: 1
-- Extra: Using index

ทดสอบที่ 2: UPDATE พร้อมกันหลายๆ คน

-- Connection 1: MyISAM
UPDATE users_myisam SET salary = 100000 WHERE id = 5;
-- ❌ Connection 2 ต้องรอจนกว่า Connection 1 จะ COMMIT

-- Connection 1: InnoDB
UPDATE users_innodb SET salary = 100000 WHERE id = 5;
-- ✅ Connection 2 UPDATE id=6 ได้ทันที ไม่ต้องรอ!

🎯 เลือกใช้แบบไหนดี?

MyISAM เหมาะกับ:

  1. Data Warehouse / Read-only – อ่านอย่างเดียว ไม่มีเขียน
  2. ระบบ Log – INSERT อย่างเดียว ไม่มี UPDATE
  3. ตารางเล็กๆ – ไม่เกิน 100,000 แถว
  4. Full-text Search (ใน MySQL รุ่นเก่าๆ)
-- ตัวอย่าง Data Warehouse ที่เหมาะกับ MyISAM
CREATE TABLE sales_summary_2019 (
    month INT,
    total_sales DECIMAL(15,2),
    total_customers INT
) ENGINE=MyISAM;
-- INSERT เดือนละครั้ง, SELECT ตลอดทั้งปี

InnoDB เหมาะกับ:

  1. ระบบ Transaction – การเงิน, E-commerce, ERP
  2. ระบบที่มี User เ� تطبیق 많음 – Web application, Mobile backend
  3. ตารางที่มี UPDATE/DELETE บ่อย
  4. ระบบที่ต้องมี Foreign Key – ต้องการ Data Integrity
  5. ทุกอย่าง! (เพราะเป็น default แล้ว)
-- ตัวอย่างระบบ E-commerce ที่เหมาะกับ InnoDB
CREATE TABLE orders (
    id INT PRIMARY KEY AUTO_INCREMENT,
    user_id INT,
    total DECIMAL(15,2),
    status VARCHAR(20),
    created_at DATETIME,
    FOREIGN KEY (user_id) REFERENCES users(id)
) ENGINE=InnoDB;
-- มี INSERT, UPDATE, DELETE ตลอดเวลา
-- ต้อง保住 data integrity

🚨 เรื่องต้องรู้ก่อนเปลี่ยน Engine

1. Full-text Search

  • MyISAM มี Full-text มานาน
  • InnoDB มี Full-text ตั้งแต่ MySQL 5.6
  • ถ้าใช้ Full-text อยู่ ตรวจสอบ version ก่อนเปลี่ยน

2. ** AUTO_INCREMENT behavior**

-- MyISAM: AUTO_INCREMENT เร็วมาก
-- InnoDB: AUTO_INCREMENT ช้ากว่า (ต้อง lock special table)

-- แต่ InnoDB มีข้อดี: INSERT พร้อมกันหลายๆ แถวได้!

3. Space Usage

-- InnoDB ใช้พื้นที่มากกว่า ~20-30%
SELECT 
    table_name,
    ROUND(((data_length + index_length) / 1024 / 1024), 2) AS 'Size (MB)'
FROM information_schema.tables
WHERE table_schema = 'your_db';
-- MyISAM table ขนาด 100MB
-- InnoDB table เดียวกัน ขนาด 120-130MB

4. COUNT(*) Performance

-- MyISAM: COUNT(*) เร็วมาก (cache ค่าไว้)
SELECT COUNT(*) FROM big_table_myisam; -- 0.001 วินาที

-- InnoDB: COUNT(*) ต้องนับจริง (เพราะ MVCC)
SELECT COUNT(*) FROM big_table_innodb; -- 2.5 วินาที

-- แต่ InnoDB แก้ได้ด้วย:
SELECT COUNT(*) FROM big_table_innodb WHERE id > 1000; -- เร็ว

🛠️ วิธีเปลี่ยน Engine (step-by-step)

1. หาให้เจอว่ามีตารางไหนใช้ MyISAM บ้าง

SELECT 
    table_schema AS database_name,
    table_name,
    engine
FROM information_schema.tables
WHERE engine = 'MyISAM'
AND table_schema NOT IN ('information_schema', 'mysql', 
                         'performance_schema', 'sys');

2. สำรองข้อมูล

# Backup ก่อนเปลี่ยนเสมอ!
mysqldump -u root -p your_database > backup_before_change.sql

3. เริ่มเปลี่ยนทีละตาราง

-- เปลี่ยนทีละตาราง (แนะนำ)
ALTER TABLE your_table ENGINE = InnoDB;

-- หรือสร้างคำสั่งอัตโนมัติ
SELECT CONCAT('ALTER TABLE ', table_schema, '.', table_name, 
              ' ENGINE = InnoDB;') AS alter_command
FROM information_schema.tables
WHERE engine = 'MyISAM';

4. อัพเดทสถิติ

ANALYZE TABLE your_table;

5. ตรวจสอบผลลัพธ์

EXPLAIN SELECT your_query;
-- ดูว่า type ดีขึ้น, rows ลดลงมั้ย

💡 เคล็ดลับเพิ่มประสิทธิภาพ InnoDB

1. ปรับ Buffer Pool

# my.cnf

[mysqld]

# ตั้งให้ประมาณ 70-80% ของ RAM innodb_buffer_pool_size = 4G # ถ้า RAM > 16GB ให้แยก instance innodb_buffer_pool_instances = 4

2. ใช้ Index ให้ถูก

-- สร้าง composite index ให้ตรงกับ WHERE
ALTER TABLE your_table 
ADD INDEX idx_composite (col1, col2, col3);
-- ไม่ใช่ index ทีละ col แยกกัน

3. เลือก Data Type ให้เหมาะสม

-- ใช้ INT แทน VARCHAR ถ้าเก็บตัวเลข
-- ใช้ DATE/DATETIME แทน VARCHAR สำหรับวันที่

-- ไม่ดี
CREATE TABLE bad (
    user_id VARCHAR(20),
    reg_date VARCHAR(20)
);

-- ดี
CREATE TABLE good (
    user_id INT,
    reg_date DATE
);

🏁 สรุป

ยุคStorage Engine ที่นิยม
MySQL 3.x – 5.0MyISAM คิง
MySQL 5.1 – 5.5MyISAM + InnoDB
MySQL 5.6+InnoDB default
MySQL 8.0InnoDB เท่านั้น!

InnoDB ชนะขาดในทุกด้าน สำหรับยุคสมัยนี้:

  • ✅ Row-level locking
  • ✅ Transaction support
  • ✅ Foreign key
  • ✅ Crash recovery
  • ✅ ACID compliance

MyISAM ยังมีที่ทางแค่กรณีเฉพาะ เช่น:

  • ตารางที่เป็น read-only
  • ระบบ data warehouse ที่ bulk insert แล้วอ่านอย่างเดียว
  • MySQL รุ่นเก่าที่ต้องการ full-text search

📝 ทิ้งท้าย

จากประสบการณ์จริงที่ผมเจอมา การเปลี่ยนจาก MyISAM → InnoDB ให้ผลลัพธ์ที่น่าทึ่งมาก Query ที่เคยช้าติดลม กลายเป็นไวปรื๋อ

แต่… ก็ไม่เสมอไปนะครับ! บางครั้ง MyISAM ก็ยังเหนือกว่า โดยเฉพาะการ COUNT(*) ทั้งตาราง หรือการทำ full-text search ใน MySQL รุ่นเก่า

ดังนั้น: ใช้ InnoDB เป็น default แต่เข้าใจ MyISAM ไว้เผื่อกรณีพิเศษ


🔗 อ้างอิง