---
title: "把 Zeabur 上的 PostgreSQL 搬到 Zenavo：還原備份並核對資料"
description: "將 Zeabur 匯出的 PostgreSQL 備份直接上傳還原到 Zenavo，了解版本、角色權限與 pg_dumpall 叢集備份的處理規則，並完成資料核對與切換。"
date: 2026-11-10
language: zh-TW
url: https://zenavo.app/zh-TW/blog/migrate-zeabur-postgresql
---

# 把 Zeabur 上的 PostgreSQL 搬到 Zenavo：還原備份並核對資料

從 Zeabur 搬家時，應用程式服務可以透過匯入範本一鍵建好，而資料庫裡的資料則需要透過備份搬過來。

好消息是：Zenavo 原生支援 Zeabur 下載的 PostgreSQL 備份包，不用在本機解壓縮、也不用自己改寫 SQL。本文專門說明怎麼把 Zeabur 的 PostgreSQL 備份還原到 Zenavo、核對資料並切換應用程式。整個專案的搬遷流程可以搭配[Zeabur 遷移完整指南](https://zenavo.app/zh-TW/blog/migrate-from-zeabur)一起閱讀。

## 1. 從 Zeabur 下載備份

在 Zeabur 的 PostgreSQL 服務裡下載備份，同時記下兩件事：

- **PostgreSQL 的主版本號**（例如 15、16 或 17）；
- **應用程式實際使用的資料庫名稱**。

Zeabur 下載下來的檔案通常是一個 `.zip` 壓縮包（有時檔名帶著 `.sql.gz`，但外層其實是 ZIP），裡面是一份 `pg_dumpall` 匯出的叢集 SQL。**保持下載下來的原始檔案不動即可**，Zenavo 支援直接上傳 Zeabur 的 `.zip` 備份包，也支援一般的 `.sql` 和 `.sql.gz`。

## 2. 在 Zenavo 建立同版本的空資料庫

在 Zenavo 的目標專案裡點擊 **新增服務 → 資料庫 → PostgreSQL**，選擇**與 Zeabur 上相同的主版本**並部署。

注意三點：

- **主版本一致最穩妥**：Zenavo 會阻止把高版本（如 PG 18）的叢集備份還原到低版本（如 PG 17）；先按同版本搬過來，日後有需要再單獨升級。
- **保持目標資料庫為空**：不要先啟動會自動建表的應用程式服務，再去還原備份。如果應用程式已經建了資料表，叢集備份還原會因為目標資料庫非空而報錯。
- **檢查擴充功能**：如果你的資料庫用了 PostGIS、`pgvector` 等擴充功能，請確認目標映像檔包含對應的擴充功能。

## 3. 上傳備份並還原

開啟新建的 PostgreSQL 服務的 **備份與還原（Backup & Restore）** 分頁，點擊上傳，選取第 1 步從 Zeabur 下載的備份檔，然後執行還原。

因為 Zeabur 的備份是 `pg_dumpall` 叢集匯出，Zenavo 在還原時會自動做以下轉換（詳見[備份與還原文件](https://docs.zenavo.app/zh-TW/operations/backups#uploading-a-backup)）：

- 將裡面的應用程式資料庫內容還原到目前服務的資料庫；
- 自動建立備份裡用到的業務角色，並保留其角色密碼與資料列層級安全性原則（RLS）；
- 出於安全考量，把 Zeabur 原有的 `root` 超級使用者降權為**無超級權限、禁止直接登入**的角色，同時保留它的資料表與物件擁有權；
- 自動跳過系統資料庫 `template1` 和 `postgres`。

> 如果一份叢集備份裡包含多個非系統的業務資料庫，還原會報錯提示先拆分；絕大多數 Zeabur 專案只有一個業務資料庫，直接上傳即可。

如果還原中途因為擴充功能缺失等原因報錯，修好原因後建議刪掉這個半成品資料庫服務、重新建一個乾淨的 PostgreSQL 再還原，不要在只還原了一半的資料庫上反覆重試。

## 4. 核對資料表結構與筆數

還原完成後，點開 PostgreSQL 服務的 **[資料庫檢視（Database View）](https://docs.zenavo.app/zh-TW/deploy/databases#database-view)**，可以直接在網頁上執行唯讀 SQL 核對資料。

先看所有的業務資料表是不是都在：

```sql
SELECT table_schema, table_name
FROM information_schema.tables
WHERE table_type = 'BASE TABLE'
  AND table_schema NOT IN ('pg_catalog', 'information_schema')
ORDER BY table_schema, table_name;
```

再挑幾張核心業務資料表（例如使用者表、訂單表），跟 Zeabur 上的資料對比準確筆數與最新一筆紀錄的時間：

```sql
SELECT count(*) AS row_count, max(created_at) AS latest_created_at
FROM public.orders;
```

（注意不要只看系統統計檢視裡的估算筆數 `reltuples`，用 `count(*)` 核對才準確。）

## 5. 連接應用程式並完成切換

在同專案的應用程式服務裡，把資料庫連線變數指向新的 PostgreSQL 服務（資料庫服務名稱為 `postgresql` 時）：

```dotenv
DATABASE_URL=${POSTGRESQL_CONNECTION_STRING}
```

注意：不要繼續寫死 Zeabur 舊的 `root` 帳號去連線，直接用 Zenavo 新資料庫暴露出來的連線變數（考量到 Zeabur 先前的安全事件，換用新資料庫自動產生的新密碼也更安全）。

如果你希望切換期間**零資料遺失**，正式切換流量時按這個順序操作：

1. 先用一份目前備份在 Zenavo 上演練一遍還原，確認應用程式連上後登入、查詢、新增紀錄都正常；
2. 挑選離峰時段，先把 Zeabur 上的應用程式暫停（或停掉排程任務、佇列消費者，避免再有新資料寫入舊資料庫）；
3. 在 Zeabur 上建立最後一份最新備份，上傳到 Zenavo 還原到一個乾淨的 PostgreSQL 服務中；
4. 啟動 Zenavo 上的應用程式並切換網域 DNS。

## 常見問題

**還原時報錯提示目標資料庫不為空（database is not empty）？**
這代表你的應用程式服務在還原前已經連上資料庫並自動執行了建表（如 Prisma / TypeORM 自動遷移）。先把應用程式停掉，刪掉並重建一個新的 PostgreSQL 服務，**先還原備份、再啟動應用程式**。

**還原成功後，應用程式報錯 `permission denied` 或登入失敗？**
Zeabur 備份裡的舊 `root` 超級使用者會被設為禁止登入。把應用程式的 `DATABASE_URL` 改成引用 Zenavo 資料庫服務的 `${POSTGRESQL_CONNECTION_STRING}`（使用預設的 `postgres` 帳號與新密碼）即可。

**Zeabur 下載下來的檔案副檔名是 `.sql.gz`，打不開也解壓縮不了？**
這是 Zeabur 匯出時的命名問題——它實際上是一個 `.zip` 壓縮包。不用改名也不用自己解壓縮，直接原樣上傳到 Zenavo 的 **備份與還原** 就能識別。

資料庫還原核對無誤後，記得在 Zenavo 的 **備份與還原** 裡順手開啟定期自動備份。完整搬家步驟見[Zeabur 遷移指南](https://zenavo.app/zh-TW/blog/migrate-from-zeabur)。
