> For the complete documentation index, see [llms.txt](https://docs-epc.gitbook.io/ncs-documents/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs-epc.gitbook.io/ncs-documents/migration/migrate-your-databases-to-mysql-database-as-a-service.md).

# Migrate your databases to MySQL Database as a Service

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

## Prerequisite

* มี MySQL Database ต้นทาง ที่พร้อมสำหรับการ Export ข้อมูล
* มี MySQL Database Instance ใน Project บน NCS
  * ควรกำหนดขนาดพื้นที่จัดเก็บข้อมูลและทรัพยากรของระบบให้เหมาะสมกับปริมาณข้อมูลและการใช้งานของฐานข้อมูลเดิม
* เครื่องที่ใช้ดำเนินการ (Migration Workstation) ต้องติดตั้ง `mysql-client` และ `mysqldump`
* ตั้งค่า Port ของ Database บน NCS เป็น 3306 ให้รองรับการเชื่อมต่อจาก IP ของเครื่องที่ใช้ดำเนินการ ซึ่งเป็นค่าเริ่มต้นของ NCS อยู่แล้ว

{% hint style="info" %}
ช่วงเวลาที่ทำตาม Document นี้ ควรอยู่ในช่วงการปรับปรุงระบบ (Maintenance Phase)
{% endhint %}

{% stepper %}
{% step %}

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

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

```sql
SET GLOBAL read_only = 1;
SET GLOBAL super_read_only = 1;
```

{% hint style="warning" %}
คำสั่งนี้จะกำหนดให้ Database Server อยู่ในโหมด **Read-only** ส่งผลให้ไม่สามารถเพิ่ม แก้ไข หรือลบข้อมูลได้ จนกว่าจะมีการเปลี่ยนค่ากลับ จึงควรดำเนินการในช่วง Maintenance และตรวจสอบให้แน่ใจว่าไม่มี Application หรือผู้ใช้งานกำลังเขียนข้อมูลอยู่
{% endhint %}

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

```sql
SHOW VARIABLES LIKE 'read_only';
SHOW VARIABLES LIKE 'super_read_only';
```

ทั้งสองค่าต้องเป็น `ON`

**ตัวอย่าง Output:**

```
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| read_only     | ON    |
+---------------+-------+
+-----------------+-------+
| Variable_name   | Value |
+-----------------+-------+
| super_read_only | ON    |
+-----------------+-------+
```

{% endstep %}

{% step %}

## Export ข้อมูลจากต้นทาง (Dump)

**กรณี Migrate 1 Database:**

```bash
mysqldump -h [source_host] -u [username] -p \
  --single-transaction \
  --routines \
  --triggers \
  --databases [db_name] \
  > nipa_migration.sql
```

**กรณี Migrate หลาย Database พร้อมกัน:**

```bash
mysqldump -h [source_host] -u [username] -p \
  --single-transaction \
  --routines \
  --triggers \
  --databases db1 db2 db3 \
  > nipa_migration.sql
```

{% hint style="warning" %}
ห้ามใช้ `--all-databases` เด็ดขาด เสี่ยงเขียนทับ User ที่ NCS ใช้จัดการ Instance
{% endhint %}

{% hint style="info" %}
ชื่อ Database ที่ระบุหลัง `--databases` ต้องตรงกับชื่อ Database Schema บน NCS หากชื่อไม่ตรงกับ Schema ปลายทาง จะ Import ไม่ผ่านทันที [(วิธีการสร้าง Database Schema)](https://docs-epc.gitbook.io/ncs-documents/database-as-a-service/sql-database/manage-sql-database-schema/create-database-schema#id-3.-database-schema#id-3.-database-schema)
{% endhint %}

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

```bash
ls -lh nipa_migration.sql
```

**ตัวอย่าง Output:**

```
-rw-rw-r-- 1 nc-user nc-user 5.3K Jul  9 12:35 nipa_migration.sql
```

จากตัวอย่าง Output แปลว่าไฟล์ `nipa_migration.sql`ถูกสร้างสำเร็จ โดยมีขนาด 5.3K

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

{% step %}

## ตรวจสอบความถูกต้องของไฟล์ Dump ก่อน Import (Pre-restore Validation)

ก่อนนำไฟล์ Dump ไป Import เข้าฐานข้อมูลปลายทาง ควรตรวจสอบไฟล์เบื้องต้นก่อนว่าไฟล์มี Object สำคัญครบตามที่คาดไว้ เช่น Table, Trigger, Procedure และ Function

นอกจากนี้ควรเก็บค่า Baseline จาก Database ต้นทางไว้ล่วงหน้า เช่น Row Count และ Checksum เพื่อใช้เปรียบเทียบกับ Database ปลายทางหลัง Import เสร็จในขั้นตอนตรวจสอบผลลัพธ์หลัง Migrate

การตรวจสอบในขั้นตอนนี้มี 2 ดังนี้:

1. ตรวจสอบเนื้อหาไฟล์ Dump ว่ามี Object ครบตามที่คาดไว้
2. เก็บค่า Baseline (Row Count + Checksum) จาก Source ไว้ล่วงหน้า เพื่อนำไปเทียบกับปลายทางหลัง Import ใน Step 5.1

### 2.1.1 ตรวจสอบ Object ที่อยู่ในไฟล์ Dump

ให้ใช้คำสั่ง `grep` เพื่อตรวจสอบว่าไฟล์ Dump มีคำสั่งสร้าง Object สำคัญ เช่น `CREATE TABLE`, `CREATE PROCEDURE`, `CREATE FUNCTION` และ `CREATE TRIGGER`

```bash
grep -E "CREATE TABLE|CREATE DEFINER.*PROCEDURE|CREATE DEFINER.*FUNCTION" nipa_migration.sql
```

**ตัวอย่าง Output :**

```
CREATE TABLE `bookings` (
CREATE TABLE `customers` (
CREATE DEFINER=`sourceuser`@`%` PROCEDURE `get_customer_count`()
```

จากนั้นใช้คำสั่งต่อไปนี้เพื่อตรวจสอบ Trigger:

```bash
grep -A 2 -i "TRIGGER \`" nipa_migration.sql
```

**ตัวอย่าง Output :**

```
/*!50003 CREATE*/ /*!50017 DEFINER=`sourceuser`@`%`*/ /*!50003 TRIGGER `trg_log_customer` BEFORE UPDATE ON `customers` FOR EACH ROW BEGIN
    SET NEW.updated_at = CURRENT_TIMESTAMP;
END */;;
```

จากตัวอย่างด้านบน Trigger นี้มี `DEFINER` เป็น `sourceuser`@`%` เช่นเดียวกัน ดังนั้นหลัง Import ไปยัง Database ปลายทาง ต้องตรวจสอบว่า User ดังกล่าวมีอยู่จริงหรือไม่ หากไม่มี อาจทำให้ Trigger หรือ Procedure เกิด error ตอนเรียกใช้งานจริง แม้ขั้นตอน Import จะสำเร็จก็ตาม

### 2.1.2 เก็บ Row Count ของแต่ละตารางจาก Source (Baseline)

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

ให้ใช้คำสั่ง `COUNT(*)` เพื่อนับจำนวน Record ของตารางสำคัญ โดยรันแยกทีละตาราง เช่น `bookings` และ `customers`

```bash
mysql -h [source_host] -u [username] -p -D [db_name] -e \
"SELECT COUNT(*) FROM bookings;"

mysql -h [source_host] -u [username] -p -D [db_name] -e \
"SELECT COUNT(*) FROM customers;"
```

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

**ตัวอย่าง Output :**

```
+----------+
| COUNT(*) |
+----------+
|        2 |
+----------+
```

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

### 2.1.3 เก็บ Checksum ระดับตารางจาก Source (Baseline)

นอกจากการตรวจสอบจำนวน Record แล้ว ควรเก็บค่า Checksum ของตารางสำคัญจาก Database ต้นทางไว้ด้วย เพื่อใช้ตรวจสอบว่าข้อมูลภายในตารางตรงกันกับ Database ปลายทางหลัง Import หรือไม่

ให้ใช้คำสั่ง CHECKSUM TABLE ซึ่งเป็นคำสั่ง Built-in ของ MySQL สำหรับคำนวณค่า Checksum ของข้อมูลในตาราง

```bash
mysql -h [source_host] -u [username] -p -D [db_name] -e \
  "CHECKSUM TABLE bookings, customers;"
```

คำสั่งนี้ใช้คำนวณค่า Checksum ของตาราง bookings และ customers จาก Database ต้นทาง โดยค่าที่ได้จะถูกนำไปเปรียบเทียบกับค่า Checksum ของ Database ปลายทางหลัง Import เสร็จ

**ตัวอย่าง Output :**

```
+----------------------+-----------+
| Table                | Checksum  |
+----------------------+-----------+
| DB-Default.bookings  | 950851913 |
| DB-Default.customers | 974903714 |
+----------------------+-----------+
```

{% hint style="info" %}
เก็บค่าจาก 2.1.2 และ 2.1.3 ไว้เทียบกับปลายทางใน Step 5.1 หลัง Import เสร็จ
{% endhint %}

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

หาก Database ปลายทางมีอยู่แล้วและมีข้อมูลที่ไม่ต้องการให้ถูกแก้ไขหรือลบ ต้องการเพียงเพิ่มแถวใหม่ที่ยังไม่มีในปลายทาง ให้ใช้ Flag ชุดนี้แทนการ Dump แบบเต็ม (Step 2):

```bash
mysqldump -h [source_host] -u [username] -p \
  --single-transaction \
  --no-create-info \
  --skip-triggers \
  --insert-ignore \
  --databases [db_name] \
  --tables [table1] [table2] \
  > nipa_data_update.sql
```

* `--no-create-info`: ไม่รวมคำสั่ง `DROP TABLE`/`CREATE TABLE` เพื่อไม่ให้กระทบ Schema เดิมที่ปลายทาง
* `--skip-triggers`: ไม่รวม Trigger มาด้วย ป้องกัน Error `Trigger already exists` หากปลายทางมี Trigger ชื่อเดียวกันอยู่แล้ว
* `--insert-ignore`: เปลี่ยนเป็น `INSERT IGNORE INTO` หากแถวที่ Insert ชนกับ Primary/Unique Key เดิมที่ปลายทาง จะข้ามแถวนั้นไปโดยไม่ Error และไม่ทับข้อมูลเดิม
* `--tables`: ระบุเฉพาะตารางที่ต้องการ Sync ข้อมูล (ใช้คู่กับ `--databases` ได้)

{% hint style="warning" %}
วิธีนี้ตรวจสอบความซ้ำของข้อมูลจาก Primary Key/Unique Key เท่านั้น หากตารางปลายทางไม่มี Unique Key ที่มีความหมาย (เช่นมีเพียง Auto Increment ID ที่ไม่ตรงกับต้นทาง) ข้อมูลอาจถูกมองว่าเป็นแถวใหม่ทั้งหมดและถูก Insert ซ้ำได้ ควรตรวจสอบ Schema ของตารางก่อนใช้งานเสมอ
{% endhint %}
{% endstep %}

{% step %}

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

1. เข้า NCS Console → Database Instance → **Database Schema → CREATE** ตั้งชื่อให้ตรงกับต้นทาง [(วิธีการสร้าง Database Schema)](https://docs-epc.gitbook.io/ncs-documents/database-as-a-service/sql-database/manage-sql-database-schema/create-database-schema#id-3.-database-schema#id-3.-database-schema)
2. ไปที่ **Access Management → CREATE** (หรือ Edit Access ของ User เดิม) เพื่อผูก Database User เข้ากับ Schema ที่เพิ่งสร้าง [(วิธีการสร้าง User ใหม่)](https://docs-epc.gitbook.io/ncs-documents/database-as-a-service/sql-database/manage-sql-database-user/create-database-user)
   * หากไฟล์ Dump มี Trigger, Procedure หรือ Function ที่ระบุ `DEFINER=` เป็น User จาก Server ต้นทาง (เช่น `sourceuser@%` ตามตัวอย่าง Step 2.1.1) **ต้อง Create User นั้นให้มีอยู่จริงบน NCS ก่อน Import** เพื่อป้องกันการเกิด Error `definer does not exist`

{% hint style="warning" %}
Schema ใหม่ที่สร้างผ่านปุ่ม CREATE จะไม่มี Database User ผูกอยู่โดยอัตโนมัติ [วิธีการแก้ไขสิทธิ์การเข้าถึง Database Schema](https://docs-epc.gitbook.io/ncs-documents/database-as-a-service/sql-database/manage-sql-database-user/edit-access#id-3.-edit-access)
{% endhint %}
{% endstep %}

{% step %}

## นำข้อมูลเข้าสู่ Database บน NCS (Import)

```bash
mysql -h [nipa_db_endpoint] -u [nipa_db_user_or_root] -p [db_name] < nipa_migration.sql
```

* `nipa_db_endpoint`: External IP / Hostname ของ MySQL Database บน NCS
* `nipa_db_user_or_root`: User ที่ใช้ Import
* `db_name`: ชื่อ Database

{% hint style="warning" %}
หากต้นทางมี Trigger หรือ Stored Procedure/Function ต้อง Import ด้วย Root User เท่านั้น เนื่องจาก Database User ปกติที่ NCS มอบให้ไม่มีสิทธิ์ `SUPER` ซึ่งจำเป็นสำหรับการสร้าง Trigger/Procedure [(วิธีเปิด Root User)](https://docs-epc.gitbook.io/ncs-documents/database-as-a-service/sql-database/manage-sql-database-root-user/enable-root-user)
{% endhint %}
{% endstep %}

{% step %}

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

### 5.1 เทียบ Row Count และ Checksum กับ Baseline จาก Source

**เทียบ Row Count:**

```bash
mysql -h [nipa_db_endpoint] -u [nipa_db_user] -p -D [db_name] -e \
  "SELECT COUNT(*) FROM bookings;"
mysql -h [nipa_db_endpoint] -u [nipa_db_user] -p -D [db_name] -e \
  "SELECT COUNT(*) FROM customers;"
```

รันแยกทีละตารางเช่นเดียวกับ Step 2.1.2 แล้วนำผลลัพธ์ของแต่ละตารางไปเทียบกับค่าที่บันทึกไว้จาก Baseline ทีละตาราง

**เทียบ Checksum:**

```bash
mysql -h [nipa_db_endpoint] -u [nipa_db_user] -p -D [db_name] -e \
  "CHECKSUM TABLE bookings, customers;"
```

คำสั่งนี้ใช้คำนวณค่า Checksum ของตาราง `bookings` และ `customers` จาก Database ปลายทาง เพื่อนำไปเทียบกับค่า Checksum ที่เก็บไว้จาก Source ใน Step 2.1.3

**ตัวอย่าง Output (ต้องตรงกับ Baseline ทุกค่า):**

```
+----------------------+-----------+
| Table                | Checksum  |
+----------------------+-----------+
| DB-Default.bookings  | 950851913 |
| DB-Default.customers | 974903714 |
+----------------------+-----------+
```

{% hint style="info" %}
หาก Checksum และ Row Count ตรงกับ Baseline ทั้งหมด ยืนยันได้ว่าข้อมูลถูกโอนย้ายมาครบถ้วน ไม่มีความเสียหายระหว่างกระบวนการ Export/Import
{% endhint %}

### 5.2 ทดสอบเรียกใช้งาน Trigger/Procedure จริงด้วย Database User ปกติ (ไม่ใช่ Root)

เพราะ Root มีสิทธิ์ Superuser เต็ม การทดสอบด้วย Root อาจไม่พบปัญหาสิทธิ์ที่จะเกิดขึ้นจริงกับ Application จึงควรทดสอบด้วย User ที่ Application จะใช้งานจริงเสมอ

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

* เข้าใช้งาน Database บน NCS ผ่าน CLI หรือ MySQL Workbench เพื่อตรวจสอบจำนวนตารางและข้อมูล เทียบ Row Count กับต้นทางให้ตรงกัน
* ตรวจสอบฟีเจอร์ใหม่ (หาก Database Instance สร้างหลัง 01/04/2025) เช่น การสร้าง Replica หรือการจัดการ Monitoring User
  {% endstep %}

{% step %}

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

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

1. ปิด Read-only บนต้นทาง (ถ้ายังต้องใช้งานต่อ) โดยตรวจสอบว่า `read_only`/`super_read_only` บน Database ใหม่เป็น `0` (OFF) แล้ว
2. อัปเดต Connection String ใน Application (Host, Database User, Password) ให้มาชี้ที่ Database ใหม่บน NCS
3. ตรวจสอบการทำงานของระบบว่าสามารถ อ่าน-เขียน (Read-Write) ข้อมูลได้ตามปกติ รวมถึงฟีเจอร์ที่พึ่งพา Trigger/Procedure ด้วย
   {% endstep %}
   {% endstepper %}
