แชทสดหรือแดชบอร์ดที่อัปเดตเองต้องใช้ Supabase Realtime เมื่อไหร่ ไม่ใช่ทุกโปรเจกต์

สรุปสั้น ๆ
Supabase Realtime คือฟีเจอร์ที่ส่งข้อมูลอัปเดตจากฐานข้อมูลไปหา client ผ่าน websocket แบบทันที เหมาะกับงานที่ต้องเห็นการเปลี่ยนแปลงแบบสด เช่นแชทหรือแดชบอร์ดที่มีคนใช้พร้อมกันหลายคน แต่ไม่ใช่ทุกโปรเจกต์ที่ต้องการความเร็วระดับนั้น งานที่ข้อมูลเปลี่ยนไม่บ่อยหรือผู้ใช้เปิดหน้าจอทิ้งไว้นาน ๆ ใช้ polling ธรรมดาราคาถูกกว่าและดูแลง่ายกว่า
ฟีเจอร์หนึ่งที่ทำให้หลายทีมตื่นเต้นตอนเจอ Supabase ครั้งแรกคือ Realtime เพราะดูเหมือนแค่เปิดสวิตช์แล้วได้แอปแบบแชทสดหรือแดชบอร์ดที่อัปเดตเองโดยไม่ต้องเขียนโค้ด websocket เองสักบรรทัด แต่พอเริ่มใช้งานจริงในโปรเจกต์ที่มีผู้ใช้พร้อมกันจำนวนมาก หลายทีมกลับพบว่าเปิดใช้แบบไม่คิดหน้าคิดหลังแล้วเจอปัญหาเรื่อง connection และต้นทุนที่ไม่ได้คาดไว้
คำถามที่ควรถามก่อนเปิดใช้ Realtime ไม่ใช่แค่ 'ใช้ยังไง' แต่ควรเป็น 'โปรเจกต์นี้ต้องการความเร็วระดับวินาทีจริงไหม' เพราะมีงานจำนวนมากที่ผู้ใช้พอใจกับการรีเฟรชทุกสิบวินาทีหรือกดปุ่มรีเฟรชเองได้ โดยไม่ต้องแลกกับความซับซ้อนของการดูแล connection ที่เปิดค้างตลอดเวลา
บทความนี้จะอธิบายว่า Realtime ของ Supabase มีกลไกอะไรบ้าง เหมาะกับงานแบบไหนจริง ๆ และมีเงื่อนไขไหนที่ควรถอยไปใช้วิธีธรรมดากว่าแทน ถ้าต้องการอ่านเรื่องการควบคุมสิทธิ์อื่น ๆ ในระบบเพิ่มเติม ดู Supabase Storage และ Supabase Auth คืออะไร ประกอบได้เช่นกัน
Supabase Realtime คืออะไร ทำงานผ่านกลไกไหน
Supabase Realtime คือ service ที่เปิดช่องทาง websocket ระหว่าง client กับเซิร์ฟเวอร์ ทำให้ client รับข้อมูลอัปเดตได้ทันทีที่มีเหตุการณ์เกิดขึ้น โดยไม่ต้องเรียก query ซ้ำ ๆ เองแบบ polling ซึ่งเบื้องหลังอาศัยกลไกของ Postgres ที่เรียกว่า logical replication คอยฟังการเปลี่ยนแปลงของแถวข้อมูลในตาราง แล้วส่งต่อมาเป็น event ให้ client ที่ subscribe อยู่
จุดที่ทำให้ Realtime ต่างจากการเขียน websocket เองตั้งแต่ต้นคือ ทีมพัฒนาไม่ต้องจัดการเรื่อง connection pool, reconnect logic, หรือ authorization ของแต่ละ channel เอง เพราะ Supabase เตรียมโครงสร้างพื้นฐานพวกนี้ไว้ให้แล้ว สิ่งที่ทีมต้องทำคือ subscribe channel ที่ต้องการฟัง แล้วเขียน callback รับข้อมูลเมื่อมี event เข้ามา
อีกจุดที่ควรรู้คือ Realtime ไม่ได้ผูกกับ Postgres เพียงอย่างเดียว ยังมีชั้น Broadcast และ Presence ที่ทำงานแยกจาก database โดยตรง ซึ่งจะอธิบายรายละเอียดในหัวข้อถัดไป
Postgres Changes, Broadcast, Presence ต่างกันตรงไหน ใช้เมื่อไหร่
Realtime ของ Supabase แบ่งออกเป็นสามรูปแบบหลักที่ทำงานต่างกัน และเลือกใช้ตามลักษณะงาน ไม่ใช่ทุกงานที่ต้องใช้แบบเดียวกันหมด:
- Postgres Changes ฟังการเปลี่ยนแปลงของแถวข้อมูลในตารางโดยตรง เหมาะกับงานที่ต้องการให้ UI sync กับข้อมูลจริงในฐานข้อมูลเสมอ เช่นแดชบอร์ดสถานะออเดอร์
- Broadcast ส่งข้อความระหว่าง client ต่อ client ผ่าน channel โดยไม่ต้องผ่านฐานข้อมูลเลย เหมาะกับงานที่ต้องการความเร็วสูงและไม่ต้องเก็บ log ทุกข้อความ เช่นตำแหน่ง cursor ในเครื่องมือทำงานร่วมกัน
- Presence ใช้บอกว่าใครกำลังออนไลน์อยู่ใน channel นั้นบ้าง เหมาะกับฟีเจอร์แบบ 'กำลังพิมพ์...' หรือแสดงจำนวนคนที่กำลังดูหน้าเดียวกันอยู่
- โปรเจกต์หนึ่งสามารถใช้ทั้งสามแบบผสมกันได้ เช่นแอปแชทอาจใช้ Postgres Changes เก็บประวัติข้อความจริง ใช้ Broadcast ส่งสถานะกำลังพิมพ์แบบเรียลไทม์ที่ไม่ต้องเก็บถาวร และใช้ Presence แสดงว่าใครออนไลน์อยู่
โปรเจกต์แบบไหนที่ Realtime คุ้มค่าจะลงทุนเวลาไปทำ
งานที่ Realtime สร้างมูลค่าได้ชัดเจนที่สุดคืองานที่ผู้ใช้หลายคนต้องเห็นข้อมูลชุดเดียวกันเปลี่ยนแปลงพร้อมกันโดยไม่มีการรีเฟรชหน้าเอง เช่นระบบแชทที่ต้องเห็นข้อความใหม่ทันที แดชบอร์ดปฏิบัติการที่ทีมหลายคนเฝ้าดูสถานะออเดอร์หรือ ticket พร้อมกัน หรือเครื่องมือทำงานร่วมกันแบบเห็น cursor ของเพื่อนร่วมทีมสด ๆ
อีกกลุ่มที่คุ้มค่าคือระบบแจ้งเตือนที่ต้องการความเร็ว เช่นแจ้งเตือนเมื่อมีคำสั่งซื้อใหม่เข้ามาในระบบร้านค้า หรือแจ้งเตือนเมื่อมีคนตอบกลับในเธรดสนทนา เพราะความล่าช้าแม้เพียงไม่กี่วินาทีก็ส่งผลต่อประสบการณ์การใช้งานจริง
จุดร่วมของงานกลุ่มนี้คือมีผู้ใช้พร้อมกันหลายคนบนข้อมูลชุดเดียวกัน และความเร็วของการอัปเดตมีผลต่อคุณค่าของฟีเจอร์นั้นโดยตรง ถ้าขาดสองเงื่อนไขนี้ไป ความคุ้มค่าของ Realtime จะลดลงมาก
เมื่อไหร่ที่ยังไม่ควรใช้ Realtime และใช้ polling ธรรมดาแทนดีกว่า
ไม่ใช่ทุกฟีเจอร์ที่ต้องการความเร็วระดับวินาที หลายหน้าจอในระบบ admin หรือรายงานสรุปที่คนเปิดดูนาน ๆ ครั้ง ไม่จำเป็นต้อง sync แบบเรียลไทม์เลย การกด refresh เองหรือ polling ทุกสิบถึงสามสิบวินาทีก็เพียงพอ และเขียนโค้ดง่ายกว่ามาก ไม่ต้องดูแล connection ที่เปิดค้างตลอดเวลา
อีกกรณีที่ควรคิดให้รอบคอบคือแอปที่มีผู้ใช้จำนวนมากแต่แต่ละคนเปิดหน้าจอทิ้งไว้เฉย ๆ นาน ๆ โดยไม่ได้โต้ตอบอะไร เพราะ connection ที่เปิดค้างไว้จำนวนมากโดยไม่มีการใช้งานจริง กินทรัพยากรฝั่งเซิร์ฟเวอร์และอาจดันต้นทุนขึ้นโดยไม่ได้สร้างคุณค่าคืนมาเท่าที่ควร
ทีมขนาดเล็กที่กำลังสร้าง MVP ก็ควรคิดสองรอบก่อนใช้ Realtime ตั้งแต่วันแรก เพราะเพิ่มความซับซ้อนในการ debug และทดสอบ ถ้าฟีเจอร์หลักยังไม่นิ่ง การเริ่มจาก polling ธรรมดาก่อนแล้วค่อยเปลี่ยนมาใช้ Realtime ทีหลังเมื่อพิสูจน์แล้วว่าผู้ใช้ต้องการความเร็วนั้นจริง มักเป็นทางเลือกที่ประหยัดเวลากว่า
| ลักษณะงาน | แนะนำใช้ |
|---|---|
| แชทสด/collaboration หลายคนพร้อมกัน | Realtime |
| แดชบอร์ดที่คนเปิดดูเป็นระยะ ไม่ได้เฝ้าตลอด | Polling ทุก 10-30 วินาที |
| รายงานสรุป/หน้า admin ที่เปิดดูนาน ๆ ครั้ง | โหลดข้อมูลตอนเปิดหน้า + ปุ่ม refresh |
| แจ้งเตือนที่ต้องเห็นทันทีเมื่อมีเหตุการณ์สำคัญ | Realtime |
Realtime เชื่อมกับ RLS ยังไง ข้อมูลที่ส่งผ่าน subscription ปลอดภัยแค่ไหน
คำถามที่พบบ่อยคือ ถ้า subscribe ตารางที่มี Row Level Security เปิดอยู่ ข้อมูลที่ส่งผ่าน Realtime จะถูกกรองตาม policy เหมือนกับตอน query ปกติไหม คำตอบคือ Postgres Changes ของ Realtime เคารพ RLS เช่นกัน ผู้ใช้จะได้รับ event เฉพาะแถวที่ policy อนุญาตให้เห็นเท่านั้น ไม่ใช่ได้รับทุก event ที่เกิดขึ้นในตารางแบบไม่กรอง อ่านรายละเอียดเรื่องการเขียน policy เพิ่มเติมได้ใน Supabase RLS คืออะไร
แต่จุดที่ต้องระวังคือ Broadcast และ Presence ไม่ได้ผูกกับ RLS ของตารางโดยอัตโนมัติ เพราะสองแบบนี้ไม่ได้อ่านข้อมูลจากตารางโดยตรง การควบคุมสิทธิ์เข้าถึง channel ต้องตั้งค่า authorization ของ channel เองแยกต่างหาก ถ้าปล่อยให้ channel เปิดกว้างโดยไม่ตรวจสอบ ใครก็สามารถ subscribe ฟังข้อมูลที่ส่งผ่าน Broadcast ได้
หลักที่ควรยึดไว้คือตรวจสอบทุกครั้งว่า channel ที่เปิดใช้งานจริงมีการควบคุมสิทธิ์ที่เหมาะสม ไม่ใช่คิดว่าแค่เปิด RLS บนตารางแล้วทุกอย่างจะปลอดภัยอัตโนมัติทั้งระบบ
connection ที่เปิดค้างจำนวนมากกระทบต้นทุนและ performance ยังไง
แต่ละ client ที่ subscribe Realtime จะเปิด connection websocket ค้างไว้กับเซิร์ฟเวอร์ตลอดเวลาที่หน้าจอนั้นเปิดอยู่ ถ้าแอปมีผู้ใช้พร้อมกันหลักพันหรือหลักหมื่นคน จำนวน connection ที่เปิดค้างพร้อมกันก็จะสูงตามไปด้วย ซึ่งมีผลโดยตรงต่อทรัพยากรฝั่งเซิร์ฟเวอร์และค่าใช้จ่ายตาม plan ที่ใช้งานอยู่
ปัญหาที่พบบ่อยในทีมที่ไม่ได้วางแผนล่วงหน้าคือ subscribe channel ไว้ในหน้าจอที่ไม่จำเป็นต้องใช้ Realtime เลย เช่นหน้า landing page หรือหน้าที่ผู้ใช้เปิดทิ้งไว้เป็นชั่วโมงโดยไม่ได้โต้ตอบ ทำให้จำนวน connection ที่เปิดค้างโตเร็วกว่าจำนวนผู้ใช้ที่ใช้งานจริง
แนวทางที่ช่วยควบคุมต้นทุนได้คือ unsubscribe channel ทันทีที่ผู้ใช้ออกจากหน้าจอนั้น ไม่ปล่อยให้ connection ค้างไว้เกินความจำเป็น และจำกัดจำนวน channel ที่ subscribe พร้อมกันต่อผู้ใช้หนึ่งคนให้อยู่ในระดับที่จำเป็นจริง ๆ เท่านั้น หากต้องประมวลผลข้อมูลก่อนเขียนกลับเข้าตารางที่ Realtime subscribe อยู่ ทำได้ผ่าน Supabase Edge Functions เช่นกัน
เขียนโค้ด subscribe จริงต้องระบุอะไรบ้าง แล้ว limit ของ plan อยู่ตรงไหน
การ subscribe Realtime ในโค้ดจริงเริ่มจากสร้าง channel ด้วย supabase.channel('ชื่อ channel ที่ตั้งเอง') แล้วผูก listener ด้วย .on('postgres_changes', { event: 'INSERT', schema: 'public', table: 'messages', filter: 'room_id=eq.42' }, callback) ก่อนปิดท้ายด้วย .subscribe() เพื่อเปิด connection จริงกับเซิร์ฟเวอร์ ค่า event กำหนดได้ว่าจะฟังเฉพาะ INSERT, UPDATE, DELETE หรือใช้ '*' ฟังทุกเหตุการณ์ ส่วน filter เป็นเงื่อนไข optional ที่ช่วยลดปริมาณ event ที่ส่งมาถึง client ให้เหลือเฉพาะแถวที่เกี่ยวข้องจริง แทนที่จะรับทุก event ของทั้งตารางแล้วมากรองเองฝั่ง client
จุดที่มักถูกมองข้ามคือต้องเก็บ reference ของ channel ที่สร้างไว้ในตัวแปร แล้วเรียก supabase.removeChannel(channel) ตอน component ถูก unmount หรือผู้ใช้ออกจากหน้านั้น ไม่ใช่แค่ปล่อยให้ browser ปิด tab ไปเอง เพราะถ้าไม่เรียก removeChannel ทุกครั้ง connection อาจยังค้างฝั่งเซิร์ฟเวอร์อยู่ระยะหนึ่งก่อนจะถูกตัดด้วย timeout ของระบบเอง ซึ่งระหว่างนั้นก็นับรวมเป็น connection ที่ใช้ทรัพยากรอยู่จริง
ตัวอย่างสมมติ (ข้อมูลสมมติ ไม่ใช่ตัวเลขจริงจาก Supabase): แอปแดชบอร์ดที่มีผู้ใช้เปิดหน้าจอพร้อมกัน 3,000 คน แต่ละคน subscribe 2 channel คือ order-status กับ notification รวมเป็น 6,000 connection พร้อมกัน ถ้า plan ที่ใช้อยู่มี concurrent connection จำกัดต่ำกว่านั้น ทีมจะเจอ error การเชื่อมต่อล้มเหลวในช่วงเวลาที่มีคนใช้งานพร้อมกันมาก การประเมินจำนวน channel ต่อผู้ใช้หนึ่งคนคูณกับจำนวนผู้ใช้พร้อมกันสูงสุดที่คาดไว้ ก่อนเลือก plan จึงสำคัญกว่าการดูแค่จำนวนผู้ใช้ทั้งหมดในระบบ
ทำแบบนี้แล้วพัง เพราะ...: บางทีมเขียน useEffect ที่สร้าง channel ใหม่ทุกครั้งที่ component re-render โดยไม่ผูก dependency array ให้ถูกต้อง ผลคือแต่ละครั้งที่หน้าจอ re-render จะเปิด channel ซ้อนทับกันเพิ่มขึ้นเรื่อย ๆ โดยไม่ unsubscribe อันเก่าก่อน ทำให้จำนวน connection จริงสูงกว่าจำนวนผู้ใช้มาก และ event บางตัวมาถึง callback ซ้ำหลายรอบเพราะมี listener ซ้อนกันอยู่หลายตัวโดยไม่รู้ตัว
ข้อผิดพลาดที่พบบ่อยตอนเริ่มใช้ Realtime
สรุปข้อผิดพลาดที่พบได้บ่อยเมื่อทีมเริ่มใช้ Realtime ในโปรเจกต์จริง:
- เปิด Realtime ทุกตารางตั้งแต่วันแรกโดยไม่คิดว่าจำเป็นไหม — ทำให้มี connection และ event จำนวนมากที่ไม่มีใครใช้ประโยชน์จริง
- ลืม unsubscribe เมื่อ component ถูก unmount — connection ค้างสะสมจนกระทบ performance โดยไม่รู้สาเหตุ
- ปล่อย Broadcast channel เปิดกว้างไม่ตรวจสอบสิทธิ์ — ข้อมูลที่ควรเป็นส่วนตัวหลุดไปให้คนที่ไม่เกี่ยวข้อง subscribe ฟังได้
- ใช้ Realtime แทนการออกแบบ state management ที่ดีในฝั่ง frontend — ทำให้โค้ดพึ่งพา event จากเซิร์ฟเวอร์มากเกินไปจนจัดการ state ยากขึ้นแทนที่จะง่ายขึ้น
สรุป
Supabase Realtime แก้ปัญหาการอัปเดตข้อมูลแบบสดได้ดีมากสำหรับงานที่ผู้ใช้หลายคนต้องเห็นการเปลี่ยนแปลงพร้อมกัน แต่ไม่ใช่เครื่องมือที่ต้องเปิดใช้ทุกโปรเจกต์ตั้งแต่วันแรก การประเมินว่าฟีเจอร์ไหนต้องการความเร็วระดับวินาทีจริง ๆ ช่วยประหยัดทั้งความซับซ้อนของโค้ดและต้นทุนของ connection ที่เปิดค้างไว้
ถ้าตัดสินใจใช้ Realtime แล้ว ควรเลือกรูปแบบให้ตรงกับงาน ไม่ว่าจะเป็น Postgres Changes, Broadcast, หรือ Presence และดูแลเรื่อง unsubscribe กับ authorization ของ channel ให้รัดกุม เพื่อไม่ให้ connection ค้างเกินจำเป็นหรือข้อมูลหลุดไปให้คนที่ไม่เกี่ยวข้อง
- Realtime เหมาะกับงานที่ผู้ใช้หลายคนต้องเห็นข้อมูลเปลี่ยนแปลงพร้อมกันแบบทันที ไม่ใช่ทุกฟีเจอร์
- Postgres Changes เคารพ RLS แต่ Broadcast และ Presence ต้องตั้งค่า authorization ของ channel เอง
- connection ที่เปิดค้างไว้จำนวนมากกระทบต้นทุนและ performance โดยตรง
- งานที่ไม่ต้องการความเร็วระดับวินาที ใช้ polling หรือโหลดข้อมูลตอนเปิดหน้าธรรมดาก็เพียงพอ
คำถามที่พบบ่อย
Supabase Realtime ใช้กับ mobile app ได้ไหม
ได้ Supabase มี client library สำหรับหลายแพลตฟอร์มรวมถึง mobile ที่เชื่อมต่อ websocket ได้เหมือนฝั่งเว็บ แต่ควรพิจารณาเรื่องแบตเตอรี่และการจัดการ reconnect เมื่อแอปสลับไปทำงานเบื้องหลัง เพราะ mobile OS มักตัด connection ที่ไม่ได้ใช้งานอยู่เบื้องหน้า
Realtime รองรับผู้ใช้พร้อมกันได้กี่คน
ขึ้นกับ plan และการตั้งค่าโปรเจกต์ ควรตรวจสอบขีดจำกัด connection พร้อมกันจากเอกสารของ Supabase ตาม plan ที่ใช้งานจริง แล้ววางแผนขยายล่วงหน้าถ้าคาดว่าผู้ใช้จะเติบโตเร็ว
ถ้าไม่ใช้ Realtime เลย โปรเจกต์เสียโอกาสอะไรไหม
ไม่เสมอไป โปรเจกต์จำนวนมากทำงานได้ดีด้วย polling หรือโหลดข้อมูลตอนเปิดหน้าธรรมดา การไม่ใช้ Realtime ไม่ได้แปลว่าด้อยกว่า ถ้าลักษณะงานไม่ต้องการความเร็วระดับนั้นจริง
Broadcast เหมาะกับงานแบบไหนมากที่สุด
เหมาะกับข้อมูลที่ไม่ต้องเก็บถาวรและต้องการความเร็วสูง เช่นตำแหน่ง cursor ในเครื่องมือทำงานร่วมกัน หรือสถานะกำลังพิมพ์ในแชท เพราะไม่ต้องผ่านฐานข้อมูลโดยตรง
เปลี่ยนจาก polling มาใช้ Realtime ทีหลังยากไหม
ไม่ยากถ้าโครงสร้าง state ฝั่ง frontend ออกแบบไว้ดีตั้งแต่ต้น เพราะแค่เปลี่ยนแหล่งที่มาของการอัปเดต state จาก interval เป็น event จาก subscription เท่านั้น ส่วนที่ซับซ้อนกว่าคือการจัดการ authorization ของ channel ให้ถูกต้อง
Realtime ทำงานร่วมกับ Edge Functions ได้ไหม
ได้ Edge Functions สามารถเป็นตัวประมวลผลข้อมูลก่อนแล้วเขียนกลับเข้าตารางที่มี Realtime subscribe อยู่ หรือส่ง Broadcast ต่อไปยัง client ได้เช่นกัน
อ่านต่อแบบเจาะลึก
วัด Conversion LINE ทุกแบรนด์ รวมศูนย์ที่เดียว
องค์กรที่มีหลายแบรนด์ หลายสาขา หลาย LINE OA — linli รวม Tracking และส่ง Conversion กลับทุกแพลตฟอร์ม พร้อม Custom Limit เริ่มฟรี 14 วัน
ติดต่อทีม Salesบทความที่เกี่ยวข้อง

ทดสอบ schema ใหม่บน production ตรง ๆ ได้ไหมหรือต้องแยก branch ก่อนเสมอ

ทีมเล็กที่ยังไม่มี DevOps ควรลงมือกับ Cloudflare Workers ตอนไหนถึงจะคุ้ม
