Back to notes
foundations-database
Featured

Database Architecture Mastery: Normalization และกฎเหล็ก ACID

ออกแบบ Database ผิดชีวิตเปลี่ยน! เจาะลึกการจัดระเบียบข้อมูล (Normalization) และหัวใจของความปลอดภัยข้อมูล (ACID) พร้อมเคสตัวอย่างโอนเงิน

January 30, 20262 min read readNNexis by Seereen

🛑 1. The Problem First: วันที่ "ข้อมูลขัดแย้งกันเอง" (Data Inconsistency)

ลองดูการเก็บข้อมูลแบบจูเนียร์ที่ต้องการความง่าย:

HLJS SQL
-- ❌ Naive Approach: เก็บทุกอย่างไว้ในตารางเดียว (Flat Table)
-- ตาราง Orders:
-- [ID: 1, Customer: 'Joe', Address: 'Bangkok', Item: 'Keyboard']
-- [ID: 2, Customer: 'Joe', Address: 'Phuket', Item: 'Mouse'] -- 🌋 อ้าว! ตกลง Joe อยู่ไหนกันแน่?

ปัญหา: เมื่อคุณเก็บข้อมูลซ้ำซ้อน (Redundancy) ในหลายที่ วันหนึ่งเมื่อคุณต้องการอัปเดตที่อยู่ของ 'Joe' คุณอาจจะลืมอัปเดตบางแถว ทำให้ข้อมูลขัดแย้งกันเอง และเมื่อระบบใหญ่ขึ้น การแก้ไขข้อมูลแบบนี้จะกลายเป็นฝันร้ายที่ทำลายความน่าเชื่อถือของระบบครับ


💡 2. Real-Life Analogy: ตู้ยาที่จัดระเบียบ vs ลิ้นชักเอนกประสงค์

  • Normalization: เหมือนการจัด "ตู้ยาแยกประเภท". ยาแก้ปวดอยู่กล่องหนึ่ง ยาแก้แพ้อยู่อีกกล่องหนึ่ง เวลาเปลี่ยนยี่ห้อยาแก้ปวด คุณก็แค่เปลี่ยนในกล่องเดียว ไม่ต้องไล่หาในทุกลิ้นชักของบ้าน
  • JOINs: เหมือนการ "ต่อจิ๊กซอว์". คุณมีชิ้นส่วนลูกค้า และชิ้นส่วนคำสั่งซื้อ เมื่อต้องการดูว่า "ใครสั่งอะไร" คุณแค่เอาชิ้นส่วนที่มีรอยต่อ (Foreign Key) มาวางต่อกัน
  • ACID (Transaction): เหมือนการ "แลกเงินที่ธนาคาร". คุณส่งเงินให้พนักงาน (ตัดเงินเรา) และพนักงานส่งธนบัตรใบใหม่ให้คุณ (เพิ่มเงินเรา) กระบวนการนี้ต้อง "เกิดขึ้นพร้อมกันทั้งหมด หรือไม่เกิดขึ้นเลย". ถ้าพนักงานเอาเงินเราไปแล้วไฟดับพอดี เงินเราต้องถูกคืน ไม่ใช่หายไปกลางอากาศ

🚀 3. Execution Journey: มหากาพย์การโอนเงิน (Transaction)

เมื่อมีการโอนเงิน 100 บาท จาก A ไป B ระบบต้องทำสิ่งที่เรียกว่า ACID Transaction:

🛠 Step-by-step:

  1. BEGIN: กั้นอาณาเขตพิเศษ ห้ามคนอื่นมายุ่งกับเงินของ A และ B ชั่วคราว
  2. Atomic Action 1: ตัดเงิน A ออก 100 บาท
  3. Atomic Action 2: เพิ่มเงินให้ B อีก 100 บาท
  4. Validation: เช็คว่ายอดเงินติดลบไหม? (Consistency)
  5. COMMIT: บันทึกลง Harddisk ถาวร (Durability)
HLJS SQL
-- ✅ Best Practice: ใช้ Transaction สำหรับงานที่ต้องทำสำเร็จ "ยกแผง"
BEGIN;
  UPDATE accounts SET balance = balance - 100 WHERE id = 'A';
  UPDATE accounts SET balance = balance + 100 WHERE id = 'B';
COMMIT; -- 🛠 ถ้าบรรทัดใดบรรทัดหนึ่งพัง ให้สั่ง ROLLBACK ทันที!

🪤 4. The Junior Trap: โรค "JOIN กลัวตาย"

จูเนียร์มักจะกลัวการทำ JOIN เพราะมองว่ามันยาก เลยใช้วิธี Query หลายรอบ:

HLJS JAVASCRIPT
// ❌ Junior Trap: Query ใน Loop (N+1 Problem)
const orders = await db.query("SELECT * FROM orders");
for (const order of orders) {
  const user = await db.query(
    `SELECT * FROM users WHERE id = ${order.user_id}`,
  ); // 🌋 พัง! ถ้ามี 1,000 orders จะยิง SQL 1,001 ครั้ง!
}

ระวัง: การยิง SQL ถี่ๆ ใน Loop จะทำให้ Database ค้างและ Network เต็ม! ✅ การแก้ไข: ใช้ JOIN หรือ IN (...) เพื่อดึงข้อมูลทั้งหมดมาในการยิง SQL เพียงครั้งเดียว


⚖️ 5. The Why Matrix: ท่าไหนคุ้มกว่า?

หัวข้อNormalization (แยกตาราง)Denormalization (รวมตาราง)
ความถูกต้องข้อมูล⚡⚡⚡ สูงมาก (แก้ที่เดียวจบ)ต่ำ (เสี่ยงข้อมูลขัดแย้ง)
การเขียน (Write)เร็วและสะอาดช้า (ต้องกระจายเขียน)
การอ่าน (Read)ช้ากว่า (เพราะต้อง JOIN)⚡⚡⚡ เร็วมาก (ไม่ต้องต่อตาราง)
พื้นที่จัดเก็บประหยัดเปลืองพื้นที่

🎓 6. Senior Mindset Summary

การเป็น Senior คือการเลิกมอง Database เป็นแค่ "ที่เก็บไฟล์" แต่ให้มองเป็น "ระบบจัดการความถูกต้อง (Integrity)" ของธุรกิจ การออกแบบ Schema ที่ดีคือกองหลังที่แข็งแกร่งที่สุดของทีม Developer ครับ!

Share this note

© 2026 My Notes by Seereen