แอปมีผู้ใช้หลักพันต่อวัน จะเลือก D1 หรือ Postgres ดี

สรุปสั้น ๆ
Cloudflare D1 เป็นฐานข้อมูล SQL แบบ serverless ที่สร้างบน SQLite แล้วผูกเข้ากับ Workers โดยตรง เหมาะกับแอปที่อ่านข้อมูลถี่กว่าเขียนมาก ต้องการ latency ต่ำระดับ edge และไม่ต้องการดูแล connection pool เอง แต่มีข้อจำกัดเรื่องการเขียนพร้อมกันจำนวนมากที่ต่างจาก Postgres แบบดั้งเดิม
ทีมที่เริ่มสร้างแอปบน Cloudflare Workers มักถึงจุดที่ต้องตัดสินใจว่าจะเก็บข้อมูลไว้ที่ไหน บางทีมเลือกต่อไปหา Postgres ภายนอกทันทีเพราะคุ้นเคยอยู่แล้ว บางทีมเลือกลอง D1 เพราะอยากให้ทั้งระบบอยู่ใน ecosystem เดียวกันโดยไม่ต้องจัดการ credential หรือ connection pool แยกต่างหาก
คำถามที่พบบ่อยที่สุดคือ D1 พอรับมือแอปที่มีผู้ใช้จริงระดับหลักพันคนต่อวันได้ไหม หรือควรข้ามไปใช้ Postgres ตั้งแต่แรกเลยดีกว่า คำตอบไม่ได้ขึ้นกับจำนวนผู้ใช้อย่างเดียว แต่ขึ้นกับสัดส่วนการอ่านต่อเขียน รูปแบบ query ที่ใช้บ่อย และว่าระบบต้องการ feature ขั้นสูงของ Postgres อย่าง JSON query ซับซ้อนหรือ extension เฉพาะทางหรือไม่
บทความนี้จะพาไปดูตั้งแต่ D1 ทำงานอย่างไรบน SQLite ที่เป็นเครื่องยนต์เบื้องหลัง ไปจนถึงข้อจำกัดจริงที่ต้องเข้าใจก่อนตัดสินใจผูกทั้งระบบไว้กับมัน เพื่อให้เลือกได้ถูกทางตั้งแต่ต้น ไม่ต้องมาย้ายฐานข้อมูลทีหลังตอนแอปมีผู้ใช้จริงแล้ว
D1 คืออะไร และทำไมถึงเป็น SQL ที่ผูกกับ Workers
D1 คือบริการฐานข้อมูล SQL แบบ serverless ของ Cloudflare ที่ออกแบบมาให้เรียกใช้งานได้โดยตรงจาก Workers ผ่าน binding เช่นเดียวกับ Vectorize ไม่ต้องเปิด connection string หรือจัดการ credential แยกต่างหาก ต่างจากการต่อ Postgres ภายนอกที่ต้องจัดการเรื่อง connection pooling และมักเจอปัญหา connection limit เมื่อมี Workers หลาย instance ยิง request เข้ามาพร้อมกันจำนวนมาก
จุดที่ D1 ตอบโจทย์ได้ตรงคือทีมที่ต้องการฐานข้อมูล SQL เต็มรูปแบบ (ไม่ใช่ key-value store) แต่ไม่อยากดูแล infrastructure ของฐานข้อมูลเอง และต้องการให้ query ทำงานใกล้ผู้ใช้มากที่สุดเท่าที่จะทำได้ ด้วยการอ่านข้อมูลผ่าน read replica ที่กระจายอยู่ตามภูมิภาคต่าง ๆ
สิ่งที่ควรเข้าใจตั้งแต่ต้นคือ D1 ไม่ใช่ Postgres ที่ห่อด้วยหน้าตาใหม่ แต่เป็นฐานข้อมูลที่สร้างอยู่บน SQLite ซึ่งมีปรัชญาการออกแบบต่างจาก Postgres ในหลายจุด ทั้งเรื่อง data type, การจัดการ concurrency และฟีเจอร์ขั้นสูงที่รองรับ
SQLite คือเครื่องยนต์จริงเบื้องหลัง D1 ต้องรู้อะไรบ้าง
SQLite เป็นฐานข้อมูลที่ขึ้นชื่อเรื่องความเรียบง่ายและเสถียรภาพ ถูกใช้งานอยู่ในอุปกรณ์หลายพันล้านเครื่องทั่วโลกตั้งแต่โทรศัพท์มือถือไปจนถึงเบราว์เซอร์ แต่รูปแบบการทำงานของมันต่างจากฐานข้อมูลแบบ client-server อย่าง Postgres หรือ MySQL อย่างชัดเจน โดยเฉพาะเรื่อง data type ที่ SQLite ใช้ระบบ dynamic typing ซึ่งยืดหยุ่นกว่าแต่ก็เสี่ยงต่อบั๊กที่ตรวจจับยากกว่าถ้าไม่ระวังตอนออกแบบ schema
D1 นำ SQLite มาห่อเป็นบริการ serverless แล้วเพิ่มความสามารถกระจายข้อมูลแบบ read replica เข้าไป ทำให้ query อ่านข้อมูลทำงานได้เร็วจากหลายภูมิภาค แต่การเขียนข้อมูล (write) ยังต้องผ่านจุดศูนย์กลางเดียวเสมอ เพราะ SQLite ไม่ได้ออกแบบมาให้เขียนพร้อมกันจากหลายจุดแบบ distributed write เหมือนฐานข้อมูล NewSQL บางตัว
ทีมที่มีพื้นฐาน Postgres มาก่อนควรระวัง data type บางตัวที่ SQLite ไม่มีแบบตรงตัว เช่น boolean ที่ SQLite เก็บเป็นตัวเลข 0/1 แทนที่จะเป็น type แยกต่างหาก หรือ array และ JSON ที่ต้องจัดการผ่านฟังก์ชันเฉพาะแทนที่จะเป็น native type แบบ Postgres จึงควรตรวจ schema เดิมให้ละเอียดก่อนย้ายมาใช้ D1
จุดแข็งเรื่องอ่าน กับข้อจำกัดเรื่องเขียนพร้อมกัน
ตารางด้านล่างสรุปพฤติกรรมทั่วไปที่ทีมส่วนใหญ่พบเจอเมื่อใช้งาน D1 เทียบกับ Postgres แบบดั้งเดิม เป็นกรอบวิเคราะห์ประกอบการตัดสินใจ ตัวเลขจริงและ limit ควรตรวจจากเอกสารล่าสุดของ Cloudflare ก่อนออกแบบสถาปัตยกรรมจริง
| ลักษณะงาน | D1 | Postgres ภายนอก |
|---|---|---|
| อ่านข้อมูลจากหลายภูมิภาค | เร็ว เพราะกระจาย read replica ตามโครงสร้าง edge | ขึ้นกับตำแหน่งฐานข้อมูล อาจต้องตั้ง read replica เอง |
| เขียนข้อมูลพร้อมกันจำนวนมาก | จำกัดกว่า เพราะเขียนผ่านจุดศูนย์กลางเดียว | รองรับ concurrency สูงกว่าด้วยกลไก transaction ที่สมบูรณ์ |
| Query ซับซ้อนแบบ window function/CTE ขั้นสูง | รองรับบางส่วนตาม SQLite feature set | รองรับครบตามมาตรฐาน SQL ขั้นสูง |
| การดูแล infrastructure | ไม่ต้องดูแลเอง เป็น managed service เต็มรูปแบบ | ต้องดูแล connection pool, scaling, backup เอง หรือใช้ managed provider |
จัดการ Schema Migration ใน D1 ต่างจาก Postgres ยังไง
D1 รองรับคำสั่ง migration ผ่าน Wrangler CLI ซึ่งเป็นเครื่องมือบรรทัดคำสั่งหลักของ Cloudflare Workers ทีมสามารถเขียนไฟล์ SQL migration แล้วรันผ่านคำสั่งเฉพาะเพื่ออัปเดต schema ได้ทั้ง local development และ production โดยไม่ต้องเชื่อมต่อผ่าน client SQL ทั่วไปแบบที่คุ้นเคยกับ Postgres
ข้อควรระวังคือ SQLite มีข้อจำกัดเรื่องการแก้ไข schema บางประเภทที่ Postgres ทำได้ตรงไปตรงมากว่า เช่นการเปลี่ยน data type ของคอลัมน์ที่มีข้อมูลอยู่แล้ว หรือการลบคอลัมน์ในบางเวอร์ชันเก่าของ SQLite ต้องใช้วิธีสร้างตารางใหม่แล้วย้ายข้อมูลแทนคำสั่งแก้ไขตรง ๆ ทีมที่คุ้นเคยกับ ALTER TABLE แบบยืดหยุ่นของ Postgres อาจต้องปรับวิธีคิดเรื่อง migration ใหม่
แนวทางที่ปลอดภัยกว่าคือทดสอบทุก migration บน local D1 database ก่อนเสมอ เพราะ Wrangler รองรับการรัน D1 แบบ local สำหรับ development โดยไม่กระทบข้อมูล production และช่วยจับปัญหา schema ที่เข้ากันไม่ได้ตั้งแต่ก่อนขึ้นจริง
Use Case ที่ D1 เหมาะและไม่เหมาะ
D1 เหมาะกับแอปที่มีลักษณะอ่านมากกว่าเขียนอย่างชัดเจน เช่นเว็บไซต์เนื้อหา บล็อก ระบบ CMS ขนาดเล็กถึงกลาง แอปที่เก็บ configuration หรือ feature flag ระบบสมาชิกที่ไม่ได้มีการอัปเดตข้อมูลถี่มาก หรือ API ที่ให้บริการข้อมูลอ้างอิงที่เปลี่ยนแปลงไม่บ่อย ลักษณะงานเหล่านี้ได้ประโยชน์เต็มที่จากความเร็วในการอ่านและการไม่ต้องดูแล infrastructure
ในทางกลับกัน แอปที่มีการเขียนข้อมูลพร้อมกันจำนวนมากในเวลาเดียวกัน เช่นระบบตัดสต็อกสินค้าแบบเรียลไทม์ที่มีคำสั่งซื้อเข้ามาพร้อมกันหลายร้อยรายการต่อวินาที หรือระบบที่ต้องการ transaction ซับซ้อนข้ามหลายตารางบ่อยครั้ง มักไม่เหมาะกับ D1 เพราะข้อจำกัดเรื่องการเขียนผ่านจุดศูนย์กลางเดียวจะกลายเป็นคอขวดได้ง่าย
อีกกลุ่มที่ควรพิจารณา Postgres แทนคือทีมที่ต้องใช้ feature เฉพาะทางอย่าง full-text search ขั้นสูง, geospatial query, หรือ extension เฉพาะทางอย่าง pgvector เพราะ SQLite ที่เป็นฐานของ D1 ไม่มี ecosystem extension ที่หลากหลายเท่า Postgres
ข้อจำกัดเรื่องขนาดฐานข้อมูลและการ Scale
D1 มีเพดานขนาดฐานข้อมูลต่อ instance ที่ต้องตรวจสอบจากเอกสารล่าสุดก่อนออกแบบระบบ ถ้าแอปคาดว่าจะมีข้อมูลโตเกินเพดานนี้ในอนาคต ต้องวางแผนแบ่งข้อมูลเป็นหลาย database ตั้งแต่ต้น เช่นแยก database ตาม tenant หรือแยกตามช่วงเวลา แทนที่จะยัดทุกอย่างไว้ใน database เดียวแล้วมาเจอปัญหาทีหลัง
แนวคิดการแบ่ง database หลายตัวนี้ต่างจากการ scale Postgres แบบดั้งเดิมที่มักใช้วิธีเพิ่มขนาดเครื่อง (vertical scaling) หรือทำ read replica D1 สนับสนุนแนวคิดการแบ่งตาม tenant หรือ shard ได้เป็นธรรมชาติกว่า เพราะการสร้าง database ใหม่ทำได้ง่ายและไม่มีค่าใช้จ่ายด้าน infrastructure เพิ่มเหมือนการตั้งเซิร์ฟเวอร์ Postgres ใหม่
ตัวอย่างสมมติที่ใช้แนวทางนี้คือแอป SaaS ที่มีลูกค้าองค์กรหลายราย แต่ละรายมีข้อมูลไม่เชื่อมโยงกัน ทีมสามารถสร้าง D1 database แยกต่อลูกค้าหนึ่งราย ทำให้ทั้งเรื่อง data isolation และการจัดการขนาดข้อมูลทำได้ง่ายกว่าการยัดทุกลูกค้าไว้ในฐานข้อมูลเดียวแล้วพึ่ง row-level security อย่างเดียว
เริ่มต้นใช้งาน D1 กับ Workers แบบ Step-by-step
ขั้นตอนเริ่มต้นใช้งาน D1 ไม่ซับซ้อนสำหรับทีมที่คุ้นเคยกับ Wrangler CLI อยู่แล้ว แต่ต้องทำตามลำดับให้ครบเพื่อไม่ให้ binding หายหรือ migration ไม่ตรงกันระหว่าง environment
- สร้าง D1 database ใหม่ผ่านคำสั่ง Wrangler แล้วบันทึก database id ที่ได้กลับมาไว้ในไฟล์ config ของ Workers project
- ประกาศ binding ของ D1 ใน wrangler.toml เพื่อให้ Workers เข้าถึง database ผ่านชื่อตัวแปรที่กำหนดไว้ ไม่ใช่ผ่าน connection string แบบเดิม
- เขียนไฟล์ migration แรกที่นิยาม schema เริ่มต้น แล้วรันผ่านคำสั่ง migration ทั้งบน local และ remote environment แยกกัน เพื่อให้แน่ใจว่า schema ตรงกันทั้งสองฝั่ง
- ทดสอบ query พื้นฐานผ่าน Workers ในโหมด local development ก่อน โดยใช้ D1 local binding ที่ไม่กระทบข้อมูลจริง
- ตั้งกระบวนการ backup หรือ export ข้อมูลเป็นระยะ เพราะแม้ D1 จะเป็น managed service แต่การมีสำเนาข้อมูลสำรองที่ทีมควบคุมเองยังจำเป็นสำหรับกรณีฉุกเฉิน
ทำแบบนี้แล้วพัง เพราะเข้าใจผิดว่า D1 เหมือน Postgres ทุกอย่าง
ทีมที่ย้ายจาก Postgres มา D1 โดยไม่ตรวจ schema ก่อน มักเจอปัญหาแรกคือ query ที่ใช้ syntax เฉพาะของ Postgres เช่นฟังก์ชันจัดการ array หรือ JSONB บางตัวใช้ไม่ได้ตรง ๆ ใน SQLite ต้องเขียนใหม่ด้วยฟังก์ชันที่ SQLite รองรับ ซึ่งบางกรณีอาจต้องปรับ logic ฝั่ง application ร่วมด้วย ไม่ใช่แค่แก้ query อย่างเดียว
อีกอาการที่พบบ่อยคือทีมออกแบบระบบที่ต้องเขียนข้อมูลพร้อมกันถี่มาก เช่น log event ทุกครั้งที่ผู้ใช้คลิก แล้วเจอปัญหา write contention เมื่อ traffic สูงขึ้น เพราะ D1 เขียนผ่านจุดศูนย์กลางเดียว วิธีแก้ที่เหมาะกว่าคือใช้ Queues หรือ Durable Objects เป็นตัวรับ event ก่อน แล้วค่อย batch เขียนเข้า D1 เป็นช่วง ๆ แทนการเขียนทุก event แบบ real-time
อาการที่สามคือทีมลืมว่า D1 เขียนผ่านจุดศูนย์กลางเดียวแต่ Workers อาจรันหลาย instance พร้อมกันในหลายภูมิภาค ทำให้ transaction ที่ออกแบบมาโดยคิดว่าเป็นระบบเดียวแบบ monolithic เจอ race condition ที่ไม่คาดคิด การแก้คือใช้กลไก transaction ของ D1 อย่างระมัดระวังและทดสอบกรณี concurrent write ให้ครบก่อนขึ้น production จริง
สรุป
D1 ไม่ใช่ Postgres เวอร์ชัน serverless แต่เป็นฐานข้อมูลที่สร้างอยู่บนปรัชญาของ SQLite ซึ่งเหมาะกับงานที่อ่านมากกว่าเขียนและต้องการความเรียบง่ายในการดูแล infrastructure จุดแข็งชัดเจนคือไม่ต้องจัดการ connection pool เองและอ่านข้อมูลได้เร็วจากหลายภูมิภาค
ก่อนผูกทั้งระบบไว้กับ D1 ควรประเมินสัดส่วนการอ่านต่อเขียนของแอปให้ชัดเจน ถ้าเขียนถี่มากและต้องการ concurrency สูง การอยู่กับ Postgres หรือออกแบบให้ใช้ Queues ร่วมกับ D1 เพื่อ batch การเขียน จะปลอดภัยกว่าการเขียนตรงเข้า D1 ทุกครั้งที่มี event เกิดขึ้น
- D1 สร้างบน SQLite ไม่ใช่ Postgres เวอร์ชันย่อ มีข้อจำกัดเรื่อง data type และ feature ต่างกัน
- จุดแข็งคืออ่านข้อมูลเร็วจากหลายภูมิภาคโดยไม่ต้องดูแล connection pool เอง
- การเขียนข้อมูลผ่านจุดศูนย์กลางเดียว ไม่เหมาะกับงานที่เขียนพร้อมกันหนักมาก
- แบ่งข้อมูลเป็นหลาย database ตาม tenant หรือ shard ดีกว่ายัดทุกอย่างไว้ใน database เดียว
- ทดสอบ migration และ concurrent write บน local environment ก่อนขึ้น production ทุกครั้ง
คำถามที่พบบ่อย
D1 รองรับ transaction แบบ ACID เหมือน Postgres ไหม
D1 รองรับ transaction พื้นฐานตามที่ SQLite เบื้องหลังทำได้ แต่รูปแบบการเขียนผ่านจุดศูนย์กลางเดียวทำให้พฤติกรรมภายใต้โหลดสูงต่างจาก Postgres ที่ออกแบบมาสำหรับ concurrency สูงโดยเฉพาะ ควรทดสอบ use case การเขียนพร้อมกันของทีมเองก่อนพึ่งพาเต็มรูปแบบ
ย้ายจาก Postgres มา D1 ต้องแก้ query เยอะไหม
ขึ้นกับว่า query เดิมใช้ feature เฉพาะของ Postgres มากแค่ไหน query พื้นฐานอย่าง SELECT, JOIN, WHERE ทั่วไปมักย้ายได้ตรงตัว แต่ฟังก์ชันเฉพาะทางอย่างการจัดการ array, JSONB ขั้นสูง หรือ extension พิเศษ ต้องเขียนใหม่ด้วยวิธีที่ SQLite รองรับ
D1 เหมาะกับแอปที่มี traffic เขียนสูงมากไหม
ไม่เหมาะโดยตรง เพราะการเขียนผ่านจุดศูนย์กลางเดียวจะกลายเป็นคอขวดเมื่อมีการเขียนพร้อมกันจำนวนมาก แนวทางที่เหมาะกว่าคือใช้ Queues รับ event ก่อนแล้ว batch เขียนเข้า D1 เป็นช่วง แทนการเขียนทุก event แบบทันที
มีวิธี backup ข้อมูลใน D1 เองไหม
ทีมควรตั้งกระบวนการ export ข้อมูลเป็นระยะด้วยตัวเอง แม้ D1 จะเป็น managed service ที่ดูแล infrastructure ให้อยู่แล้ว การมีสำเนาข้อมูลที่ทีมควบคุมเองยังจำเป็นสำหรับกรณีต้องกู้คืนข้อมูลฉุกเฉินหรือย้ายระบบในอนาคต
D1 รองรับ full-text search ไหม
SQLite ที่เป็นฐานของ D1 มีความสามารถ full-text search พื้นฐานผ่านกลไกของตัวเอง แต่ไม่ครบเครื่องเท่า extension เฉพาะทางบน Postgres ถ้าระบบต้องการ full-text search ที่ซับซ้อนมาก ควรประเมิน Postgres หรือบริการค้นหาเฉพาะทางแยกต่างหาก
แอปขนาดเล็กที่เพิ่งเริ่มควรใช้ D1 เลยไหม หรือรอให้ผู้ใช้เยอะก่อน
ถ้าลักษณะแอปเป็นแบบอ่านมากกว่าเขียนตั้งแต่ต้น การเริ่มด้วย D1 ตั้งแต่วันแรกช่วยลดความซับซ้อนของ infrastructure ได้จริง แต่ถ้าตั้งแต่ตอนออกแบบก็รู้อยู่แล้วว่าจะมีการเขียนพร้อมกันหนักมาก การเริ่มด้วย Postgres ตั้งแต่ต้นจะประหยัดเวลาย้ายระบบในอนาคตมากกว่า
อ่านต่อแบบเจาะลึก
วัด Conversion LINE ทุกแบรนด์ รวมศูนย์ที่เดียว
องค์กรที่มีหลายแบรนด์ หลายสาขา หลาย LINE OA — linli รวม Tracking และส่ง Conversion กลับทุกแพลตฟอร์ม พร้อม Custom Limit เริ่มฟรี 14 วัน
ติดต่อทีม Salesบทความที่เกี่ยวข้อง

ทำไม Agent ที่ตอบคำถามเก่งแค่ไหนก็ยังเปิดเว็บจริงเองไม่ได้ถ้าไม่มี Browser รองรับ

Vectorize ของ Cloudflare เก็บ Embedding ได้กี่มิติ แล้วใช้ทำ RAG ได้จริงไหม
