Database & Storage Concepts - System Design, Simply Explained
บทความนี้จะอธิบาย Database & Storage Concepts พื้นฐานในมุมมองของ System Design บอกข้อดีและ Trade-off ที่ควรรู้ พร้อมยกตัวอย่างผ่าน Use Case ของระบบ Gym Application
บทความอื่นๆ ที่เกี่ยวข้องกัน
- Core Infrastructure Concepts - System Design, Simply Explained
- Distributed Systems Concepts - System Design, Simply Explained
- Communication Concepts - System Design, Simply Explained
Gym Application
สมมุติว่าบริษัทอยากทำแอปสำหรับยิม โดย Release แรกมีความสามารถประมาณนี้
- ลูกค้าสมัครสมาชิกและเลือกแพ็กเกจได้
- ลูกค้าชำระเงินค่าสมาชิกได้
- ลูกค้าจองคลาสและเทรนเนอร์ได้
- ลูกค้าสแกน QR Code เพื่อเข้ายิมได้
- Admin อัปโหลดรูปคลาส รูปเทรนเนอร์ และเอกสารสัญญาได้
- ระบบต้องดูประวัติการเปลี่ยนแปลงของสมาชิกได้

ถ้ามองแบบ High-level ของ System Design ระบบนี้จะประกอบด้วย
- Mobile/Web App สำหรับลูกค้าและ Admin
- API Server สำหรับรับ Request จากผู้ใช้งาน
- Database สำหรับเก็บข้อมูลหลักของระบบ
- Cache สำหรับข้อมูลที่ถูกอ่านบ่อย
- Object Storage สำหรับไฟล์ขนาดใหญ่ เช่น รูปและเอกสาร
- Event Store / Log สำหรับเก็บเหตุการณ์บางอย่างที่ต้องตรวจสอบย้อนหลัง
SQL Database
SQL Database หรือ Relational Database คือฐานข้อมูลที่เก็บข้อมูลเป็นตาราง มีแถวและคอลัมน์ และสามารถเชื่อมความสัมพันธ์ระหว่างตารางผ่าน Foreign Key ได้ ภาษาที่ใช้จัดการข้อมูลคือ SQL (Structured Query Language) ในการดำเนินการกับข้อมูล (เพิ่ม, ลบ, แก้ไข, ค้นหา) ระบบจัดการฐานข้อมูล SQL ที่ได้รับความนิยมในปัจจุบัน ได้แก่ MySQL, PostgreSQL, Oracle และ SQL Server

ลองดู Use Case ในระบบ Gym Application ช่วงแรกระบบยังมีผู้ใช้งานไม่เยอะ เราอาจเริ่มด้วย SQL Database เพียงตัวเดียวก่อน เพราะข้อมูลหลักของระบบมีความสัมพันธ์กันชัดเจน เช่น
- สมาชิกคนหนึ่งมีสัญญาสมาชิก
- สัญญาผูกกับแพ็กเกจ
- การจองคลาสผูกกับสมาชิกและคลาส
- การชำระเงินผูกกับสัญญา

ข้อมูลแบบนี้เหมาะกับ Relational Database เพราะเราสามารถออกแบบเป็นตาราง เช่น members, contracts, plans, payments, classes, bookings แล้วเชื่อมความสัมพันธ์ผ่าน Foreign Key
ข้อดี
- SQL Database ช่วยควบคุมความถูกต้องของข้อมูลผ่าน ACID และ Constraints เช่น Primary Key และ Foreign Key ทำให้ลดโอกาสเกิดข้อมูลซ้ำหรือข้อมูลที่ไม่สอดคล้องกัน
- รองรับ Query ได้ยืดหยุ่น ทั้งการ Join หลายตาราง การทำ Aggregation และการสร้าง Index จึงเหมาะกับข้อมูลที่มีความสัมพันธ์กันชัดเจน
Trade-off
- เมื่อข้อมูลมีจำนวนมาก Query ที่ซับซ้อนหรือ Join หลายตารางอาจใช้ CPU, Memory และ Disk I/O มากขึ้น ทำให้ Latency สูงขึ้น
- การทำ Horizontal Scaling จะเริ่มซับซ้อนขึ้น โดยเฉพาะเมื่อระบบมี Transaction, Join หรือข้อมูลถูกกระจายไปหลาย Shard
ACID
ACID คือชุดคุณสมบัติที่ช่วยให้ Database Transaction มีความน่าเชื่อถือ โดยเฉพาะเวลามีหลายคำสั่งที่ต้องสำเร็จหรือผิดพลาดพร้อมกัน
ACID ย่อมาจาก Atomicity, Consistency, Isolation และ Durability
- Atomicity ถ้าขั้นตอนไหนพลาด ต้อง Rollback ทั้งหมด
- Consistency ก่อนและหลัง Transaction ข้อมูลต้องถูกต้องตาม Rule
- Isolation คือการควบคุมผลกระทบระหว่าง Transaction ที่ทำงานพร้อมกัน เพื่อให้ได้ระดับความถูกต้องตาม Isolation Level ที่กำหนด
- Durability Commit แล้วข้อมูลต้องไม่หาย แม้ Server จะล่ม

ตัวอย่างในระบบ Gym คือคลาสโยคะเหลือที่นั่งสุดท้าย 1 ที่ แต่มีลูกค้า 2 คนกดจองพร้อมกัน ถ้าไม่มี Isolation ที่ดี ระบบอาจขายที่นั่งเดียวให้ 2 คนได้
ข้อดี
- ACID ช่วยให้ Transaction มีความน่าเชื่อถือ เช่น ถ้าบางขั้นตอนทำงานไม่สำเร็จสามารถ Rollback ได้ หากมี Transaction ที่ทำงานพร้อมกันจะไม่ส่งผลกระทบต่อกัน และข้อมูลที่ Commit แล้วไม่ควรสูญหายแม้ระบบล่ม
Trade-off
- Transaction อาจใช้เวลามากขึ้น เพราะ Database ต้องตรวจสอบ Constraint จัดการ Lock และรอให้ Commit เสร็จก่อนตอบกลับ
- เมื่อมี Request เข้ามาพร้อมกันจำนวนมาก Transaction บางส่วนอาจต้องรอกัน ทำให้จำนวน Transaction ที่ระบบรองรับต่อวินาทีลดลง
NoSQL Database
NoSQL Database คือฐานข้อมูลที่ไม่ได้ยึดรูปแบบตารางแบบ Relational เป็นหลัก อาจเป็น Key-Value Store, Document Store, Wide-column Store หรือ Graph Database จุดเด่นคือยืดหยุ่นกว่า และมักออกแบบมาเพื่อรองรับการอ่านเขียนจำนวนมาก

ลองดู Use Case ในระบบ Gym Application บางข้อมูลไม่จำเป็นต้องอยู่ใน SQL Databases เสมอไป ตัวอย่างเช่น เราอาจเก็บ Session ของสมาชิกโดยใช้ member_id เป็น Key เมื่อระบบต้องการตรวจสอบ Session ก็สามารถเรียก get(member_id) เพื่อดึงข้อมูลออกมาได้ทันที โดยไม่ต้อง join กับตารางไหน
ข้อดี
- NoSQL รองรับข้อมูลที่มีโครงสร้างยืดหยุ่น เช่น JSON Document หรือ Key-Value ทำให้เพิ่มหรือเปลี่ยน Field ได้ง่าย
- NoSQL แต่ละประเภทเหมาะกับ Access Pattern ที่แตกต่างกัน เช่น Graph Database เหมาะกับข้อมูลความสัมพันธ์ และ Key-Value Store เหมาะกับการเข้าถึงข้อมูลผ่าน Key โดยตรง
Trade-off
- NoSQL หลายประเภทไม่มี Foreign Key หรือ Referential Integrity แบบ SQL และมักมีการเก็บข้อมูลซ้ำเพื่อให้อ่านได้เร็วขึ้น จึงต้องระวังข้อมูลในแต่ละจุดไม่ตรงกัน
- การ Join หรือ Query ด้วยเงื่อนไขที่ซับซ้อนอาจไม่ยืดหยุ่นเท่า SQL และบางกรณีต้องนำข้อมูลมาประมวลผลต่อใน Application
Index
Index คือโครงสร้างข้อมูลที่ช่วยให้ Database ค้นหาข้อมูลได้เร็วขึ้น โดยไม่ต้องไล่อ่านทุกแถวในตาราง คล้ายสารบัญของหนังสือที่ช่วยให้เราเปิดไปยังหน้าที่ต้องการได้เร็วกว่าอ่านตั้งแต่หน้าแรก

ลองดู Use Case ในระบบ Gym Application เมื่อระบบเริ่มมีสมาชิกหลักแสน Admin อาจค้นหาสมาชิกจากเบอร์โทร อีเมล หรือเลขสมาชิก ถ้าไม่มี Index เวลา Query เช่น SELECT * FROM members WHERE email = 'boon@example.com'; Database อาจต้องไล่อ่านทุกแถวในตาราง members เพื่อหาแถวที่ต้องการ วิธีนี้เรียกว่า Full Table Scan เราควรสร้าง Index ที่ email, phone_number หรือ member_code เพื่อช่วยให้ Query แบบนี้เร็วขึ้น
ข้อดี
- Index ช่วยให้ Database ค้นหาข้อมูลได้เร็วขึ้น โดยไม่ต้อง Full Table Scan ทุกครั้ง เหมาะกับคอลัมน์ที่ถูกใช้ใน
WHERE,JOINหรือORDER BYบ่อย ๆ - เมื่อ Database อ่านข้อมูลน้อยลง ก็ช่วยลด Disk I/O และทรัพยากรที่ใช้ในการ Query ได้ด้วย
Trade-off
- ทุกครั้งที่มี
INSERT,UPDATEหรือDELETEDatabase อาจต้องอัปเดต Index ที่เกี่ยวข้องตามไปด้วย ทำให้การเขียนข้อมูลช้าลง - Index ใช้พื้นที่จัดเก็บเพิ่มเติม ดังนั้นการสร้าง Index มากเกินไปอาจเพิ่มภาระให้ Database โดยไม่จำเป็น
Data Partitioning
Data Partitioning คือการแบ่งข้อมูลขนาดใหญ่ออกเป็นส่วนย่อยๆ เพื่อให้จัดเก็บ ค้นหา หรือดูแลได้ง่ายขึ้น ข้อมูลอาจถูกแบ่งเป็น Partition ตามเงื่อนไขบางอย่าง เช่น เวลา พื้นที่ หรือประเภทข้อมูล

ลองดู Use Case ในระบบ Gym Application ผ่านไป 2 ปี ตาราง check_in_logs ใหญ่มาก เพราะทุกครั้งที่สมาชิกสแกน QR Code เข้ายิม ระบบจะบันทึกข้อมูล ถ้า Query รายงานประจำเดือนต้องไปอ่านข้อมูลทั้งหมดตั้งแต่วันแรกที่เปิดระบบ มันจะช้าโดยไม่จำเป็น
เราสามารถใช้ Data Partitioning แบ่งข้อมูลออกเป็นส่วนย่อย เช่น แบ่ง check_in_logs ตามเดือนได้ดังนี้
- check_in_logs_2026_01
- check_in_logs_2026_02
- check_in_logs_2026_03
เมื่อ Admin ดูรายงานเดือนมีนาคม Database ก็อ่านเฉพาะ Partition ของเดือนมีนาคม ไม่ต้องอ่านข้อมูลทั้งหมด
ข้อดี
- ถ้า Query มีเงื่อนไขตรงกับ Partition Key Database สามารถอ่านเฉพาะ Partition ที่เกี่ยวข้องได้ ไม่ต้องสแกนข้อมูลทั้งหมด
- การจัดการข้อมูลเก่าทำได้ง่ายขึ้น เช่น Archive หรือลบข้อมูลทั้งหมดของ Partition แทนการลบทีละแถว
Trade-off
- ถ้าเลือก Partition Key ไม่ดี ข้อมูลหรือ Traffic อาจกระจุกอยู่ใน Partition เดียว ทำให้เกิด Hot Partition
- ถ้า Query ต้องค้นหาข้อมูลจากหลาย Partition Database ต้องอ่านและรวมข้อมูลจากหลายส่วน ทำให้ใช้ทรัพยากรมากขึ้นและอาจช้าลง
Sharding
Sharding คือการแบ่งข้อมูลออกไปเก็บใน Database หลายเครื่อง โดยแต่ละเครื่องเรียกว่า Shard และรับผิดชอบข้อมูลเพียงบางส่วน เป้าหมายคือกระจายทั้งปริมาณข้อมูลและ Traffic ออกจากเครื่องเดียว

ลองดู Use Case ในระบบ Gym Application ถ้าวันหนึ่งระบบขยายไปหลายประเทศ ข้อมูลสมาชิกและ Booking เยอะจนเครื่องเดียวไม่พอ เราอาจต้องทำ Sharding โดยใช้ member_id % 4 เพื่อเลือก Shard ในระบบ Gym จะได้ดังนี้
- ผลลัพธ์ 0 เก็บที่ Shard 0
- ผลลัพธ์ 1 เก็บที่ Shard 1
- ผลลัพธ์ 2 เก็บที่ Shard 2
- ผลลัพธ์ 3 เก็บที่ Shard 3
ข้อดี
- Sharding ช่วยกระจายข้อมูลและ Traffic ไปยัง Database หลายเครื่อง ทำให้ลดภาระของเครื่องเดียว
- เมื่อข้อมูลหรือ Request เพิ่มขึ้น เราสามารถเพิ่ม Shard เพื่อช่วยรองรับ Load และพื้นที่จัดเก็บที่มากขึ้นได้
Trade-off
- ถ้า Query ต้องค้นหาข้อมูลจากหลาย Shard ระบบต้องส่งคำสั่งไปหลายเครื่องแล้วนำผลลัพธ์กลับมารวมกัน ทำให้ Latency และ Network Overhead สูงขึ้น
- Transaction ข้าม Shard รวมถึงการเพิ่มหรือลดจำนวน Shard มีความซับซ้อนกว่า Database เครื่องเดียว และอาจต้องมีการย้ายข้อมูลเพื่อ Rebalance ระบบ
Replication
Replication คือการทำสำเนาข้อมูลไว้ในหลาย Server เพื่อช่วยเพิ่มความสามารถในการอ่านข้อมูล และทำให้ระบบยังทำงานต่อได้หาก Server บางเครื่องล่ม

รูปแบบที่พบบ่อยคือ Leader-Follower
- Primary รับผิดชอบการเขียน
- Replica เก็บสำเนาข้อมูลและช่วยรองรับการอ่าน
ใน Gym Application การเขียนข้อมูล เช่น สร้าง Booking หรืออัปเดต Payment จะเข้า Primary ส่วนการอ่านข้อมูล เช่น ดูรายละเอียดคลาส หรือดูประวัติสมาชิก สามารถกระจายไปอ่านจาก Replica แทน เพื่อลดภาระของ Primary
ข้อดี
- สามารถกระจายการอ่านข้อมูลไปยัง Replica หลายเครื่อง ช่วยลดภาระของ Primary และรองรับ Read Request ได้มากขึ้น
- หาก Primary ล่ม สามารถเลือก Replica ขึ้นมาทำหน้าที่แทนได้ ช่วยลด Downtime ของระบบ
Trade-off
- ข้อมูลที่เขียนลง Primary อาจยังไปไม่ถึง Replica ทันที ทำให้การอ่านจาก Replica อาจได้ข้อมูลที่ไม่ใช่ข้อมูลล่าสุด หรือ Stale Data
- ถ้า Primary ล่ม การสลับ Replica ขึ้นมาแทนต้องจัดการอย่างระมัดระวัง เพราะ Replica อาจยังได้รับข้อมูลมาไม่ครบ และอาจเกิด Data Loss ได้ในบางกรณี
Cache
Cache คือชั้นจัดเก็บข้อมูลที่เร็วกว่า Database ใช้เก็บสำเนาของข้อมูลที่ถูกเรียกใช้บ่อย เพื่อให้ Request ถัดไปตอบได้เร็วขึ้นและลดภาระ Database
ลองดู Use Case ในระบบ Gym Application มีข้อมูลบางอย่างที่สมาชิกเปิดดูซ้ำ ๆ เช่น ตารางคลาสวันนี้ รายละเอียดเทรนเนอร์ หรือแพ็กเกจสมาชิกยอดนิยม
ถ้าทุก Request วิ่งไป Database หมด Database จะรับ Load โดยไม่จำเป็น เพราะข้อมูลเหล่านั้นไม่มีการเปลี่ยนแปลงบ่อย
ข้อดี
- Cache เก็บข้อมูลไว้ใน Memory ทำให้สามารถอ่านข้อมูลได้เร็วกว่า Database และช่วยลด Response Time
- ข้อมูลที่ถูกอ่านซ้ำบ่อยสามารถตอบจาก Cache ได้โดยตรง ช่วยลดจำนวน Request และภาระที่ Database ต้องรับ
Trade-off
- ข้อมูลใน Cache อาจไม่ตรงกับ Database หากข้อมูลต้นทางมีการเปลี่ยนแปลง จึงต้องจัดการเรื่อง TTL และ Invalidation ให้ดี
- Cache ไม่ควรเป็นแหล่งข้อมูลหลักของระบบ เพราะข้อมูลอาจหายได้เมื่อ Cache ล่มหรือ Restart นอกจากนี้ ถ้าข้อมูลจำนวนมากหมดอายุพร้อมกัน อาจเกิด Cache Stampede และทำให้ Request จำนวนมากวิ่งไปที่ Database พร้อมกัน
Cache-Aside
Cache-Aside คือ รูปแบบการทำ Cache ที่ Application เป็นคนจัดการเองว่าจะอ่านข้อมูลจาก Cache หรือ Database โดยที่ถ้าเจอข้อมูลใน Cache ก็ส่งกลับได้ทันที แต่ถ้าไม่เจอ Application จะไปอ่านจาก Database แล้วนำข้อมูลมาเก็บไว้ใน Cache สำหรับครั้งถัดไป

ลองดู Use Case ในระบบ Gym Application การดึงข้อมูลรายละเอียดคลาสเป็นแบบนี้
- API Server ขอข้อมูล
class_id = 123จาก Cache - ถ้าเจอข้อมูล เรียกว่า Cache hit แล้วส่งกลับทันที
- ถ้าไม่เจอ เรียกว่า Cache miss
- API Server ไปอ่านจาก Database
- เอาข้อมูลที่ได้มาใส่ Cache
- ส่งข้อมูลกลับให้ผู้ใช้
ข้อดี
- รูปแบบการทำงานเรียบง่าย และ Cache จะเก็บเฉพาะข้อมูลที่มีการเรียกใช้จริง
- หาก Cache ล่ม Application ยังสามารถ Fallback ไปอ่านข้อมูลจาก Database ได้
Trade-off
- Application ต้องมี Logic สำหรับจัดการ Cache เอง ทั้งการอ่าน การเติมข้อมูล และการลบหรืออัปเดต Cache เมื่อข้อมูลต้นทางเปลี่ยน
- ถ้าข้อมูลยอดนิยมหมดอายุจาก Cache พร้อมกัน อาจเกิด Cache Stampede ทำให้ Request จำนวนมากวิ่งไปยัง Database ในเวลาเดียวกัน
Write-Through
Write-through คือทุกครั้งที่มีการเขียนข้อมูล ระบบจะอัปเดตทั้ง Cache และ Database เสร็จก่อนจึงจะถือว่าการเขียนเสร็จสมบูรณ์

ลองดู Use Case ในระบบ Gym Application คือข้อมูล member_profile_summary ที่ถูกอ่านบ่อยมากหลังจากผู้ใช้แก้ไขข้อมูลส่วนตัว เมื่อสมาชิกเปลี่ยนชื่อหรือเบอร์โทร ระบบอัปเดต Database และ Cache พร้อมกัน ทำให้หลังจากเขียนเสร็จ การอ่านครั้งต่อไปได้ข้อมูลใหม่ทันที
ข้อดี
- ทุกครั้งที่เขียนข้อมูล ระบบจะอัปเดตทั้ง Cache และ Database ทำให้ข้อมูลใน Cache สอดคล้องกับ Database มากขึ้น
- เมื่อนำมาใช้ร่วมกับ Read-Through ทั้งการอ่านและเขียนสามารถจัดการผ่าน Cache Layer เดียวกัน ทำให้ Application จัดการ Cache ได้ง่ายขึ้น
Trade-off
- การเขียนข้อมูลจะช้าลง เพราะต้องเขียนทั้ง Cache และ Database ก่อนจึงจะถือว่าการทำงานเสร็จ
- หากต้องการให้ข้อมูลใน Cache ตรงกับ Database การเขียนข้อมูลทั้งหมดควรผ่าน Write-Through ถ้ามีบางส่วนเขียนตรงไปที่ Database ข้อมูลใน Cache อาจไม่ตรงกับข้อมูลจริง
Write-Back or Write-Behind
Write-Behind คือการเขียนข้อมูลลง Cache หรือชั้น Buffering ก่อน แล้วค่อยส่งข้อมูลไปยัง Database ภายหลังแบบ Asynchronous

ลองดู Use Case ในระบบ Gym Application เราอาจใช้กับข้อมูลที่เขียนเยอะมากและไม่ใช่ข้อมูลสำคัญระดับห้ามหาย เช่น Event สำหรับ Analytics
ตัวอย่างเช่น
- สมาชิกเปิดหน้าคลาส
- สมาชิกกดดูโปรไฟล์เทรนเนอร์
- สมาชิกกดดูแพ็กเกจแต่ยังไม่ซื้อ
ข้อมูลเหล่านี้มีจำนวนมาก ถ้าเขียนลง Database ทุกครั้งทันที อาจทำให้ระบบหลักช้าลง เราอาจเขียนลง Buffer ก่อน แล้วค่อย Flush ไป Database ทีหลัง
ข้อดี
- การเขียนทำได้เร็ว เพราะ Application เขียนข้อมูลลง Cache หรือ Buffer ก่อน โดยไม่ต้องรอ Database
- สามารถรวมข้อมูลหลายรายการแล้วค่อยเขียนลง Database เป็น Batch ช่วยลดจำนวน Write Request และภาระของ Database
- หาก Database ไม่พร้อมใช้งานชั่วคราว ระบบยังสามารถรับข้อมูลไว้ก่อน แล้วค่อยส่งไป Database ภายหลังได้
Trade-off
- หาก Cache หรือ Buffer ล่มก่อนที่ข้อมูลจะถูกเขียนลง Database ข้อมูลที่ยังค้างอยู่อาจสูญหาย
- ระบบต้องจัดการเรื่อง Retry, Failure และการส่งข้อมูลจาก Cache ไปยัง Database เพิ่มเติม ทำให้มีความซับซ้อนมากขึ้น
Read-Through
Read-Through คือ รูปแบบการทำ Cache ที่ Cache Layer เป็นคนจัดการเองว่าจะอ่านข้อมูลจาก Cache หรือไปดึงจาก Database ถ้ามีข้อมูลใน Cache ก็ส่งกลับทันที แต่ถ้าไม่มี Cache Layer จะไปอ่านจาก Database แล้วนำข้อมูลมาเก็บไว้ใน Cache ก่อนส่งกลับให้ Application

ลองดู Use Case ในระบบ Gym Application สมมุติ API Server ขอข้อมูลคลาสจาก Cache
- ถ้า Cache มีข้อมูล ก็คืนค่าทันที
- ถ้า Cache ไม่มีข้อมูล Cache Layer ไปโหลดจาก Database เอง
- จากนั้น Cache Layer เก็บข้อมูลไว้ และคืนค่าให้ API Server
ข้อดี
- เหมาะกับข้อมูลที่ถูกอ่านซ้ำบ่อย เพราะเมื่อข้อมูลอยู่ใน Cache แล้ว Request ถัดไปสามารถอ่านจาก Cache ได้ทันที
- Application ไม่ต้องเขียน Logic สำหรับ Cache Miss เอง เพราะ Cache Layer หรือ Library จะเป็นคนโหลดข้อมูลจาก Database และนำมาเก็บไว้ให้
Trade-off
- การอ่านข้อมูลครั้งแรกจะเกิด Cache Miss ทำให้ต้องรอโหลดข้อมูลจาก Database ก่อน จึงช้ากว่า Request ถัดไป
- ข้อมูลใน Cache ยังมีโอกาสไม่ตรงกับ Database หากข้อมูลต้นทางเปลี่ยน จึงต้องออกแบบ Write Strategy ให้เหมาะสม
- รูปแบบข้อมูลใน Cache มักผูกกับข้อมูลจาก Database มากกว่า Cache-Aside ทำให้มีความยืดหยุ่นในการจัดรูปข้อมูลน้อยกว่า
Object Storage
Object Storage คือระบบสำหรับเก็บไฟล์ขนาดใหญ่ โดยแต่ละไฟล์ถูกเก็บเป็น Object และมี Key สำหรับอ้างอิง เหมาะกับข้อมูลประเภทไฟล์ เช่น รูปภาพ วิดีโอ เอกสาร หรือ Backup

ลองดู Use Case ในระบบ Gym Application ข้อมูลบางอย่างไม่ควรเก็บใน Database โดยตรง เช่น
- รูปโปรไฟล์สมาชิก
- รูปเทรนเนอร์
- รูปคลาส
- เอกสารสัญญาสมาชิก
- วิดีโอแนะนำการออกกำลังกาย
ไฟล์เหล่านี้มีขนาดใหญ่ Pattern ที่พบบ่อยคือเก็บไฟล์จริงใน Object Storage แล้วเก็บ Metadata ไว้ใน Database เช่น file_id, owner_id, object_key, size, content_type และ created_at
ข้อดี
- Object Storage เหมาะกับการเก็บไฟล์ขนาดใหญ่ เช่น รูปภาพ วิดีโอ เอกสาร หรือ Backup และสามารถรองรับข้อมูลจำนวนมากได้
- ต้นทุนต่อพื้นที่จัดเก็บมักต่ำกว่าการนำไฟล์ขนาดใหญ่ไปเก็บไว้ใน Database โดยตรง
Trade-off
- Object Storage ไม่ได้ถูกออกแบบมาสำหรับ Transaction หรือ Query ที่ซับซ้อนเหมือน Database
- ถ้าเก็บไฟล์ไว้ใน Object Storage แต่เก็บ Metadata ไว้ใน Database ต้องดูแลให้ข้อมูลทั้งสองส่วนตรงกัน เช่น เมื่อลบไฟล์ Metadata ที่เกี่ยวข้องก็ควรถูกจัดการตามไปด้วย
Event Sourcing
Event Sourcing คือการเก็บ Event ที่เกิดขึ้นตามลำดับเป็น Source of Truth แล้วใช้ Events เหล่านั้นในการสร้างสถานะปัจจุบันของระบบ

ลองดู Use Case ในระบบ Gym Application มีข้อมูลบางอย่างที่เราไม่ได้อยากรู้แค่สถานะล่าสุด แต่อยากรู้ว่าเกิดอะไรขึ้นมาก่อนหน้า เช่น Contract ของสมาชิกคนหนึ่ง
- สมัครสมาชิกแพ็กเกจ Basic
- อัปเกรดเป็น Premium
- หยุดสมาชิกชั่วคราว
- กลับมา Active
- ยกเลิกสมาชิก
ถ้าเราเก็บเฉพาะสถานะล่าสุดว่า cancelled เราจะไม่รู้ History ก่อนหน้าว่าเกิดอะไรขึ้นบ้าง
ข้อดี
- Event Sourcing เก็บประวัติการเปลี่ยนแปลงของข้อมูลไว้ครบ ทำให้สามารถตรวจสอบย้อนหลังและเข้าใจ Timeline ของข้อมูลได้
- เราสามารถ Replay Events เพื่อดูว่าสถานะของระบบ ณ ช่วงเวลาหนึ่งในอดีตเป็นอย่างไร จึงเหมาะกับข้อมูลที่ต้องการ Audit Trail
Trade-off
- ถ้ามี Events จำนวนมาก การคำนวณสถานะปัจจุบันอาจช้า เพราะต้อง Replay Events หลายรายการ จึงมักใช้ Snapshot เข้ามาช่วยลดจำนวน Events ที่ต้องประมวลผล
- การออกแบบ Events, Snapshot และการรองรับ Event ที่เปลี่ยนแปลงไปตามเวลา ทำให้ระบบซับซ้อนกว่าการเก็บเฉพาะสถานะล่าสุด
สรุป
เนื้อหาในบทความนี้เป็นการอธิบาย Concepts พื้นฐานของ Database & Storage ในมุมมองของ System Design เพื่อให้เห็นว่าแต่ละแนวคิดเหมาะกับปัญหาแบบไหน และมี Trade-off อะไรที่ต้องพิจารณา
ในการนำไปใช้กับระบบจริง ยังมีรายละเอียดอีกมากที่ต้องศึกษาเพิ่มเติม สิ่งสำคัญคือไม่มีคำตอบที่ดีที่สุดสำหรับทุกระบบ การเลือกใช้ SQL, NoSQL, Cache, Sharding, Replication หรือ Storage แบบต่างๆ ต้องดูจากลักษณะข้อมูล, Access Pattern, Scale และความต้องการของระบบในตอนนั้น
สุดท้าย ผมอยากให้เข้าใจว่าทุกอย่างคือ Trade-off ไม่มีคำตอบที่ดีที่สุดตลอดเวลา มีแต่คำตอบที่เหมาะกับบริบทของระบบ ณ ตอนนั้น
Refs


