ในโลกของการพัฒนาซอฟต์แวร์ขนาดใหญ่ (Enterprise Applications) การจัดการกับความซับซ้อนของระบบที่ต้องรองรับทั้งการเขียนข้อมูล (Write) และการอ่านข้อมูล (Read) จำนวนมหาศาล มักนำไปสู่ปัญหาคอขวด (Bottleneck) และความยากในการขยายระบบ (Scalability) แนวคิดหนึ่งที่ถูกนำมาใช้แก้ไขปัญหานี้คือ Command Query Responsibility Segregation (CQRS) ซึ่งเป็นรูปแบบสถาปัตยกรรมที่ทรงพลัง
CQRS คือหลักการที่แยกความรับผิดชอบในการดำเนินการคำสั่ง (Command) ซึ่งเป็นการเปลี่ยนแปลงสถานะของข้อมูล ออกจากความรับผิดชอบในการสอบถามข้อมูล (Query) ซึ่งเป็นการอ่านข้อมูลเท่านั้น การแยกส่วนนี้ไม่ได้หมายความว่าต้องใช้ฐานข้อมูลสองตัวเสมอไป แต่เป็นการแยก Logic และ Model ออกจากกันอย่างชัดเจน เพื่อให้แต่ละส่วนสามารถถูกปรับปรุงและขยายได้อย่างอิสระ
หลักการทำงานของ CQRS ในบริบทของ PostgreSQL
เมื่อเราใช้ CQRS ร่วมกับ PostgreSQL เราจะแบ่งระบบออกเป็นสองส่วนหลักที่ทำงานเกือบจะเป็นอิสระต่อกัน:
1. Command Model (Write Side)
ส่วนนี้รับผิดชอบในการรับคำสั่ง (Commands) เช่น ‘สร้างผู้ใช้ใหม่’ หรือ ‘อัปเดตสินค้า’ การดำเนินการทั้งหมดจะมุ่งเน้นไปที่การรักษาความสมบูรณ์ของข้อมูล (Data Integrity) และการจัดการ Transaction ที่ซับซ้อน โดยทั่วไปแล้ว เราจะใช้ตารางหลัก (Source of Truth) ใน PostgreSQL เพื่อดำเนินการคำสั่งเหล่านี้
2. Query Model (Read Side)
ส่วนนี้รับผิดชอบในการตอบสนองต่อการสอบถาม (Queries) เช่น ‘แสดงรายการสินค้าทั้งหมด’ หรือ ‘ค้นหาผู้ใช้ตามชื่อ’ เป้าหมายหลักคือความเร็วในการอ่าน (Read Performance) เราสามารถสร้าง View, Materialized View หรือตารางที่ถูกปรับให้เหมาะสมสำหรับการอ่านโดยเฉพาะ เพื่อให้การ Query มีประสิทธิภาพสูงสุด โดยไม่ต้องผ่าน Logic การคำนวณที่ซับซ้อนจากการเขียนข้อมูล
ตัวอย่างการใช้งาน PostgreSQL เพื่อแยก Command และ Query
สมมติว่าเรามีระบบจัดการสินค้าที่ต้องรับคำสั่งอัปเดตสต็อก (Command) และต้องแสดงผลรายการสินค้าที่จัดเรียงตามหมวดหมู่ (Query) เราสามารถใช้ PostgreSQL ดังนี้:
SQL
-- 1. Command Model: ตารางหลักที่รับการเปลี่ยนแปลง (Source of Truth) --
CREATE TABLE products (
product_id SERIAL PRIMARY KEY,
name VARCHAR(100) NOT NULL,
stock_quantity INT NOT NULL,
last_updated TIMESTAMP DEFAULT NOW()
);
-- คำสั่ง (Command): อัปเดตสต็อกสินค้า (Write Operation) --
UPDATE products SET stock_quantity = stock_quantity - 10, last_updated = NOW() WHERE product_id = 1;
-- 2. Query Model: การสร้าง View สำหรับการอ่านที่เหมาะสม (Read Optimization) --
-- เราสร้าง View ที่รวมข้อมูลที่จำเป็นสำหรับการแสดงผลเท่านั้น
CREATE VIEW product_read_view AS
SELECT
product_id,
name,
(SELECT array_to_string(ARRAY['apple', 'banana', 'orange'], ',')) AS categories,
stock_quantity
FROM products;
-- การสอบถาม (Query): ดึงข้อมูลจาก View ที่ถูกปรับปรุงแล้ว (Read Operation) --
SELECT * FROM product_read_view WHERE stock_quantity > 0 ORDER BY name ASC;
ในตัวอย่างนี้ การ `UPDATE` คือ Command ที่เปลี่ยนแปลงสถานะข้อมูล ในขณะที่การ `SELECT` จาก `product_read_view` คือ Query ที่ถูกออกแบบมาเพื่อการอ่านที่รวดเร็วที่สุด โดยไม่จำเป็นต้องคำนึงถึงความซับซ้อนของการเขียนข้อมูล
บทสรุป: ประโยชน์ที่ได้รับจาก CQRS
การนำ CQRS มาใช้ในการออกแบบระบบด้วย PostgreSQL ช่วยให้สถาปนิกสามารถจัดการความซับซ้อนของระบบได้อย่างมีประสิทธิภาพอย่างยิ่ง ประโยชน์หลักคือการเพิ่มความยืดหยุ่นในการขยายระบบ (Scalability) เนื่องจากเราสามารถปรับปรุงส่วน Write และส่วน Read ได้อย่างอิสระตามภาระงานที่แตกต่างกัน นอกจากนี้ยังช่วยให้ทีมพัฒนาสามารถโฟกัสกับความรับผิดชอบเฉพาะส่วนได้เต็มที่ ทำให้โค้ดสะอาดขึ้น บำรุงรักษาง่ายขึ้น และระบบโดยรวมมีความเสถียรสูงขึ้นมาก