For the complete documentation index, see llms.txt. This page is also available as Markdown.

Migrate your databases to PostgreSQL Database as a Service

วิธีการย้าย Database เดิมของคุณ มาใช้งาน PostgreSQL Database as a Service บน NCS

เนื่องจากการย้าย Database จากระบบภายนอก (On-premises หรือ Provider อื่น) มายัง PostgreSQL Database ของ NCS จำเป็นต้องมีการโอนถ่ายข้อมูลผ่าน Logical Dump เพื่อความเข้ากันได้ของระบบสูงสุด จึงแนะนำให้ใช้วิธีมาตรฐานในการดำเนินการ

Prerequisite

  • มี PostgreSQL Database ต้นทาง ที่พร้อมสำหรับการ Export ข้อมูล

  • มี PostgreSQL Database Instance ใน Project บน NCS

    • ควรกำหนดขนาดพื้นที่จัดเก็บข้อมูลและทรัพยากรของระบบให้เหมาะสมกับปริมาณข้อมูลและการใช้งานของฐานข้อมูลเดิม

  • เครื่องที่ใช้ดำเนินการ (Migration Workstation) ต้องติดตั้ง postgresql-client ซึ่งมี pg_dump, pg_restore, psql

    • ควรใช้ Version เดียวกับ PostgreSQL ปลายทาง และไม่เก่ากว่า Server ต้นทาง

  • ตั้งค่า Port ของ Database บน NCS เป็น 5432 ให้รองรับการเชื่อมต่อจาก IP ของเครื่องที่ใช้ดำเนินการ ซึ่งเป็นค่าเริ่มต้นของ NCS อยู่แล้ว

Instruction

1

เตรียมความพร้อมของข้อมูล

เปิด Read-only บนต้นทางเพื่อ Freeze ข้อมูล:

psql -h [source_host] -U [username] -d postgres -c "ALTER SYSTEM SET default_transaction_read_only = on;"

psql -h [source_host] -U [username] -d postgres -c "SELECT pg_reload_conf();"

ตรวจสอบว่าเปิดสำเร็จ:

psql -h [source_host] -U [username] -d postgres -c "SHOW default_transaction_read_only;"

ตัวอย่าง Output:

 default_transaction_read_only
--------------------------------
 on
2

สั่งสร้างไฟล์ Backup จาก Database ต้นทาง (Export)

ก่อนเริ่ม Dump ข้อมูล ควรตรวจสอบชื่อ Database บนเครื่องต้นทางก่อนเสมอ เพื่อป้องกันการ Dump ผิด Database

ใช้คำสั่งนี้เพื่อแสดงรายการ Database ทั้งหมดบน PostgreSQL ต้นทาง:

psql -h [source_host] -U [username] -d postgres -c "\l"

คำสั่งนี้จะเชื่อมต่อไปยัง Database เริ่มต้นชื่อ postgres แล้วแสดงรายการ Database ทั้งหมดที่ User มีสิทธิ์มองเห็น จากนั้นให้ตรวจสอบชื่อ Database ที่ต้องการ Migrate ให้ถูกต้องก่อนนำไปใช้ในคำสั่ง pg_dump

ใช้คำสั่ง pg_dump เพื่อ Export ข้อมูลและ Schema ออกมาเป็นไฟล์ Backup ในรูปแบบ Custom Format โดยกำหนดตัวเลือก -Fc

pg_dump -h [source_host] -U [username] -Fc -d [db_name] -f nipa_migration.dump

รายละเอียด Parameter:

  • source_host: Hostname หรือ IP Address ของ PostgreSQL ต้นทาง

  • username: Database User ของ Database เดิม

  • db_name: ชื่อ Database ที่ต้องการดึงข้อมูลมา

  • -Fc: กำหนดรูปแบบไฟล์ Dump เป็น Custom Format

  • -f nipa_migration.dump: กำหนดชื่อไฟล์ Backup ที่ต้องการสร้าง

หลังจากรัน pg_dump เสร็จ ให้ตรวจสอบว่าไฟล์ Dump ถูกสร้างขึ้นเรียบร้อย และมีขนาดไฟล์ที่เหมาะสม

ls -lh nipa_migration.dump

ตัวอย่าง Output:

-rw-rw-r-- 1 nc-user nc-user 2.8M Jul  9 14:37 nipa_migration.dump

จากตัวอย่าง Output แปลว่าไฟล์ nipa_migration.dump ถูกสร้างสำเร็จ โดยมีขนาด 2.8M และถูกแก้ไขล่าสุดวันที่ Jul 9 14:37

หากไฟล์มีขนาดเล็กผิดปกติ เช่น ไม่กี่ KB หรือเป็น 0 byte ควรตรวจสอบ Error ระหว่างการ Dump หรือเช็คว่าเลือก Database ถูกต้องหรือไม่

กรณีมีหลาย Database ที่ต้องการ Migrate พร้อมกัน

หากมีหลาย Database ที่ต้องการ Migrate ให้ใช้ pg_dump แยกทีละ Database เนื่องจากไม่สามารถใช้ pg_dumpall ได้

สามารถใช้ Loop เพื่อ Dump หลาย Database ได้ดังนี้:

for db in customer_db order_db payment_db; do
  pg_dump -h [source_host] -p [source_port] -U [username] -d "$db" -Fc -f "${db}.dump"
done

คำสั่งนี้จะวน Dump Database ตามรายชื่อที่กำหนดไว้ในตัวแปร db ได้แก่ customer_db, order_db และ payment_db

หลังจากรันสำเร็จ จะได้ไฟล์ Dump แยกตามชื่อ Database เช่น:

customer_db.dump
order_db.dump
payment_db.dump

ไฟล์ Dump แต่ละไฟล์ต้องนำไป Restore แยกกันตามขั้นตอน Restore โดยต้องสร้าง Database, Schema และ Database User บน NCS ให้ครบทุกชื่อก่อนเริ่ม Restore

2.1 ตรวจสอบไฟล์ Dump ก่อน Restore (Pre-restore Validation)

ก่อนนำไฟล์ Dump ไป Restore จริง ควรตรวจสอบเนื้อหาภายในไฟล์ก่อนว่า Object สำคัญถูก Dump มาครบ เช่น Schema, Extension, Table, View, Function และ Trigger

ใช้คำสั่ง pg_restore -l เพื่ออ่านรายการ Object ทั้งหมดภายในไฟล์ Dump โดยคำสั่งนี้จะไม่เขียนข้อมูลใด ๆ ลง Database ปลายทาง จึงปลอดภัยสำหรับการตรวจสอบก่อน Restore จริง

pg_restore -l nipa_migration.dump > dump_contents.txt
cat dump_contents.txt

คำสั่งนี้จะอ่าน Table of Contents จากไฟล์ nipa_migration.dump แล้วบันทึกผลลัพธ์ลงไฟล์ dump_contents.txt จากนั้นใช้ cat เพื่อเปิดดูรายการ Object ทั้งหมด

ตัวอย่าง Output

8; 2615 16510 SCHEMA - analytics sourceuser
2; 3079 16390 EXTENSION - pgcrypto
3; 3079 16427 EXTENSION - uuid-ossp
225; 1259 16511 TABLE analytics daily_revenue sourceuser
221; 1259 16462 TABLE public bookings sourceuser
217; 1259 16438 TABLE public customers sourceuser
223; 1259 16485 TABLE public payments sourceuser
219; 1259 16451 TABLE public rooms sourceuser
224; 1259 16504 VIEW public booking_summary sourceuser
272; 1255 16502 FUNCTION public set_updated_at() sourceuser
3366; 2620 16503 TRIGGER public customers trg_customers_updated_at sourceuser

จากตัวอย่าง Output แปลว่าไฟล์ Dump มี Object สำคัญหลายประเภท เช่น:

  • Schema ชื่อ analytics

  • Extension ชื่อ pgcrypto

  • Extension ชื่อ uuid-ossp

  • Table ใน Schema analytics เช่น analytics.daily_revenue

  • Table ใน Schema public เช่น bookings, customers, payments, rooms

  • View ชื่อ public.booking_summary

  • Function ชื่อ public.set_updated_at()

  • Trigger ชื่อ trg_customers_updated_at บน Table public.customers

นับจำนวน TABLE DATA ที่พบในไฟล์ Dump เพื่อดูว่ามีข้อมูลของกี่ตารางถูก Dump เข้ามา

grep -c "TABLE DATA" dump_contents.txt

ผลลัพธ์ที่ได้ควรนำไปเทียบกับจำนวนตารางจริงที่ต้นทาง โดยต้องนับรวมทุก Schema ไม่ใช่เฉพาะ Schema public

หากจำนวน TABLE DATA น้อยกว่าที่คาดไว้ อาจเกิดจากบาง Table ไม่มีข้อมูล, User ที่ใช้ Dump ไม่มีสิทธิ์เข้าถึงบาง Schema/Table หรือ Dump มาไม่ครบ

หากไฟล์ Dump มีการใช้ Extension เช่น pgcrypto หรือ uuid-ossp ตามตัวอย่างข้างต้น ต้องตรวจสอบว่า PostgreSQL ปลายทางบน NCS รองรับ Extension เหล่านี้หรือไม่ก่อน Restore จริง

หาก Extension ไม่พร้อมใช้งาน อาจทำให้ Restore Fail ในขั้นตอน CREATE EXTENSION

psql -h [nipa_db_endpoint] -U [nipa_db_user] -d [db_name] -c \
  "SELECT * FROM pg_available_extensions WHERE name IN ('pgcrypto', 'uuid-ossp');"

คำสั่งนี้ใช้เชื่อมต่อไปยัง Database ปลายทาง แล้วตรวจสอบว่า Extension ที่ไฟล์ Dump ต้องใช้มีอยู่ในรายการ Extension ที่ PostgreSQL ปลายทางรองรับหรือไม่

ตัวอย่าง Output:

   name    | default_version | installed_version |                     comment
-----------+-----------------+--------------------+---------------------------------------------------
 uuid-ossp | 1.1             | 1.1                | generate universally unique identifiers (UUIDs)
 pgcrypto  | 1.3             | 1.3                | cryptographic functions

จากตัวอย่าง Output แปลว่า PostgreSQL ปลายทางรองรับ Extension ทั้ง uuid-ossp และ pgcrypto

2.1.1 เก็บ Row Count จาก Source ไว้เป็น Baseline

หลังจากตรวจสอบ Object ในไฟล์ Dump แล้ว ควรเก็บจำนวนแถวของ Table สำคัญจาก Database ต้นทางไว้เป็น Baseline เพื่อใช้เปรียบเทียบกับ Database ปลายทางหลัง Restore เสร็จ

ต้องระบุทุกตารางที่ต้องการตรวจสอบ ที่พบจาก TOC ในไฟล์ Dump

psql -h [source_host] -U [username] -d [db_name] -c \
  "SELECT 'public.bookings' AS table_name, COUNT(*) FROM public.bookings
   UNION ALL SELECT 'public.customers', COUNT(*) FROM public.customers
   UNION ALL SELECT 'analytics.daily_revenue', COUNT(*) FROM analytics.daily_revenue;"

คำสั่งนี้ใช้เชื่อมต่อไปยัง Database ต้นทาง แล้วนับจำนวนแถวของแต่ละ Table ที่ต้องการตรวจสอบ โดยผลลัพธ์จะแสดงชื่อ Table และจำนวน Record ของแต่ละ Table

ตัวอย่าง Output:

       table_name        | count
--------------------------+-------
 public.customers         | 10000
 public.bookings          | 50000
 analytics.daily_revenue  |    31
(3 rows)

ให้บันทึกค่า Row Count เหล่านี้ไว้ เพื่อนำไปเปรียบเทียบกับ Database ปลายทางหลัง Restore เสร็จ หากจำนวนแถวไม่ตรงกัน อาจแปลว่าข้อมูลถูก Restore มาไม่ครบ หรือมีข้อมูลเปลี่ยนแปลงระหว่างช่วงเวลาที่ทำ Dump

2.1.2 เก็บ Checksum จาก Source ไว้เป็น Baseline

นอกจาก Row Count แล้ว ควรเก็บค่า Checksum ของข้อมูลจาก Table สำคัญไว้ด้วย เพื่อใช้ตรวจสอบว่าข้อมูลภายใน Table ตรงกันระหว่าง Source และ Target หรือไม่

PostgreSQL ไม่มีคำสั่ง CHECKSUM TABLE แบบ MySQL จึงใช้ md5(string_agg(...)) แทน โดยแนวคิดคือแปลงข้อมูลใน Table เป็นข้อความ เรียงลำดับข้อมูลให้แน่นอน แล้วคำนวณค่า MD5 ออกมาเป็นค่า Checksum

ควรรันแยกทีละตาราง โดยเฉพาะ Table สำคัญหรือ Table ที่ใช้ยืนยันความถูกต้องของข้อมูล

psql -h [source_host] -U [username] -d [db_name] -c \
  "SELECT md5(string_agg(t::text, '' ORDER BY t::text)) FROM (SELECT * FROM public.customers) t;"

คำสั่งนี้ใช้คำนวณค่า Checksum ของข้อมูลทั้งหมดใน Table public.customers จาก Database ต้นทาง โดยใช้ ORDER BY t::text เพื่อให้ลำดับข้อมูลคงที่ก่อนนำไปคำนวณค่า MD5

ตัวอย่าง Output:

               md5
----------------------------------
 5e2c037955c70c88118f65c3a0b3370b
(1 row)

ให้บันทึกค่า Checksum นี้ไว้ แล้วหลัง Restore เสร็จให้รันคำสั่งเดียวกันบน Database ปลายทาง เพื่อนำค่า MD5 มาเปรียบเทียบกัน

บันทึกค่า Checksum ของทุกตารางไว้ จะใช้เทียบกับปลายทางใน Step 5

3

เตรียม Database ปลายทางบน NCS ก่อน Restore

ก่อนนำเข้า ต้องเตรียม Database ปลายทางบน NCS ให้พร้อม 2 อย่าง:

  1. สร้าง Database Schema เปล่า บนหน้า NCS (section Database Schema → CREATE) ให้ชื่อตรงกับต้นทาง (วิธีการสร้าง Database Schema)

  2. สร้างหรือผูก Database User เข้ากับ Database Schema นั้น (tab Access Management → CREATE) (วิธีการสร้าง User ใหม่) และ วิธีการแก้ไขสิทธิ์การเข้าถึง Database Schema

3.1 กรณีต้องการอัปเดตเฉพาะข้อมูลใหม่ โดยไม่แตะข้อมูลเดิม (Insert-Only Sync)

หาก Database ปลายทางมีข้อมูลอยู่แล้วและไม่ต้องการให้ถูกแก้ไขหรือลบ ต้องการเพียงเพิ่มแถวใหม่ที่ยังไม่มีในปลายทาง ให้ Dump แบบระบุเฉพาะข้อมูล (--data-only) พร้อมสั่งให้สร้างเป็นคำสั่ง INSERT ที่ข้ามแถวซ้ำอัตโนมัติ แทนการ Dump แบบเต็มใน Step 2:

pg_dump -h [source_host] -U [username] -d [db_name] \
  --data-only \
  --inserts \
  --on-conflict-do-nothing \
  --table=public.customers \
  --table=public.bookings \
  -f nipa_data_update.sql
  • --data-only: ไม่รวมคำสั่ง CREATE TABLE/DROP TABLE เพื่อไม่ให้กระทบ Schema เดิมที่ปลายทาง

  • --inserts: สร้างเป็นคำสั่ง INSERT INTO ทีละแถว แทนการใช้ COPY (จำเป็นสำหรับให้ --on-conflict-do-nothing ทำงานได้)

  • --on-conflict-do-nothing: เติม ON CONFLICT DO NOTHING ต่อท้ายทุกคำสั่ง INSERT หากแถวชนกับ Primary/Unique Key เดิมที่ปลายทาง จะข้ามแถวนั้นไปโดยไม่ Error และไม่ทับข้อมูลเดิม

  • --table: ระบุเฉพาะตารางที่ต้องการ Sync ข้อมูล (ใส่ได้หลายตัว)

ตรวจสอบไฟล์ก่อน Import ว่ามีแต่ INSERT ... ON CONFLICT DO NOTHING ไม่มี DDL หลุดมา:

grep -E "DROP TABLE|CREATE TABLE|INSERT INTO" nipa_data_update.sql | head -5

Import เข้าปลายทางด้วย Database User ปกติได้เลย (ไม่จำเป็นต้องมีสิทธิ์พิเศษ เพราะไม่มี DDL):

psql -h [nipa_db_endpoint] -U [nipa_db_user] -d [db_name] -f nipa_data_update.sql
4

นำข้อมูลเข้าสู่ Database บน NCS

pg_restore -h [nipa_db_endpoint] -U [nipa_db_user] -d [db_name] --clean --if-exists --no-owner --no-privileges -j 4 nipa_migration.dump
  • --no-owner --no-privileges: ข้าม Owner/Privilege เดิมของต้นทาง เพราะ User บน NCS อาจไม่ตรงกับต้นทาง

  • --clean --if-exists: ให้ Restore ทับ Database เดิมที่มีข้อมูล/Schema อยู่แล้วได้โดยไม่ต้อง Drop Database เอง

กรณี Database ต้นทางมีหลาย Schema คำสั่งนี้ใช้ได้เหมือนเดิมโดยไม่ต้องแก้ไข เพราะ pg_dump ดึงทุก Schema มาให้อัตโนมัติเป็นค่าเริ่มต้น

ตรวจสอบทันทีหลัง Restore ว่า Object ถูกสร้างครบ:

psql -h [nipa_db_endpoint] -U [nipa_db_user] -d [db_name] -c "\dt public.*"
psql -h [nipa_db_endpoint] -U [nipa_db_user] -d [db_name] -c "\dt analytics.*"
psql -h [nipa_db_endpoint] -U [nipa_db_user] -d [db_name] -c "\dv"

ตัวอย่าง Output จริง:

            List of tables
 Schema |   Name    | Type  |  Owner
--------+-----------+-------+---------
 public | bookings  | table | db-user
 public | customers | table | db-user
 public | payments  | table | db-user
 public | rooms     | table | db-user
(4 rows)

               List of tables
  Schema   |     Name      | Type  |  Owner
-----------+---------------+-------+---------
 analytics | daily_revenue | table | db-user
(1 row)
5

ตรวจสอบความถูกต้องและตั้งค่าเพิ่มเติม

เทียบ Row Count กับ Baseline ที่เก็บไว้ใน Step 2.1 — ต้องตรงกันทุกตาราง:

psql -h [nipa_db_endpoint] -U [nipa_db_user] -d [db_name] -c \
  "SELECT 'public.customers' AS table_name, COUNT(*) FROM public.customers
   UNION ALL SELECT 'analytics.daily_revenue', COUNT(*) FROM analytics.daily_revenue;"
psql -h [nipa_db_endpoint] -U [nipa_db_user] -d [db_name] -c \
  "SET timezone = 'UTC'; SELECT md5(string_agg(t::text, '' ORDER BY t::text)) FROM (SELECT * FROM public.customers) t;"

ต้องรัน SET และ SELECT ในคำสั่งเดียวกันเสมอ เพราะการตั้งค่าด้วย SET มีผลแค่ Session/Connection นั้นๆ

ตัวอย่างผลการทดสอบจริง:

ก่อนตั้ง timezone = 'UTC':  customers checksum = c0fd14ebc79c23704fbb8c2b8addbd2a   (ไม่ตรงกับ Baseline)
หลังตั้ง timezone = 'UTC':  customers checksum = 5e2c037955c70c88118f65c3a0b3370b   (ตรงกับ Baseline)

ตรวจสอบเพิ่มเติมอื่นๆ:

  • เข้าใช้งาน Database บน NCS ผ่าน CLI (psql) เพื่อตรวจสอบจำนวนตารางและข้อมูล เทียบ Row Count กับต้นทางให้ตรงกัน

  • ตรวจสอบว่า Extension ที่ต้นทางใช้งาน มีการติดตั้งและ Enable บน Database ใหม่ครบถ้วน

  • ตรวจสอบฟีเจอร์ใหม่ (หาก Database Instance สร้างหลัง 01/04/2025) เช่น การสร้าง Replica หรือการจัดการ Monitoring User

6

เชื่อมต่อระบบเดิมกับ Database ใหม่บน NCS

เมื่อตรวจสอบความถูกต้องแล้ว ให้ดำเนินการเปลี่ยนถ่ายระบบดังนี้:

  • ปิดโหมด Read-Only บน Database ต้นทาง (หากยังต้องใช้งานต่อ) หรือปิดในกรณีที่ทำ Rollback:

psql -h [source_host] -U [username] -d postgres -c "ALTER SYSTEM SET default_transaction_read_only = off;"
psql -h [source_host] -U [username] -d postgres -c "SELECT pg_reload_conf();"
  • อัปเดต Connection String ใน Application (Host, Database User, Password) ให้มาชี้ที่ Database ใหม่บน NCS

  • ตรวจสอบการทำงานของระบบว่าสามารถ อ่าน-เขียน (Read-Write) ข้อมูลได้ตามปกติ รวมถึงฟีเจอร์ที่พึ่งพา Trigger/Function/View ด้วย

Last updated