這個週末嘗試把 sqlite 的資料轉移到 postgresql 上,結果遇到許多坑。

sqlite 的 data dump 其實需要更改不少地方,才能用在其他資料庫。這部份很容易犯錯,所以我想找其他方法。

嘗試過的方法

我先是在 RailsCast 上看到 taps 這個 gem ,能夠透過另開 server 作到讀取資料再匯入的功能。可惜這個 gem 已經沒有維護了,自己嘗試修問題都是以失敗告終。

接下來我使用 pgloader ,這似乎能直接匯入資料進入 pg ,可是最近的版本似乎有 UTF8 的問題,我就算直接把 master 抓下來手動編譯,還是無法成功解決這問題,故放棄。

心灰意冷時,我突然想到,以 SQL 不行,但是既然 ActiveRecord 能夠支援各種資料庫,那麼只要把舊的資料以 yaml 格式備份出來,然後在新的資料庫給塞回去,就可以了。找了一下發現 active-dump 這款 gem ,最後作了一些調整,終於成功的轉移資料庫。

注意的地方

  • 有使用 foreign key 的話,記得依照 key 的 dependency 把匯入的順序調整,被 Key 指向的 table 移到前面。
  • 匯出前也要先把 orphan record 先刪除(就是有 foreign key 指向已經不存在的資料時)
  • 匯入前,先轉換資料庫然後跑 migration
  • 匯入後,每個 table 的 id 並不會自動設成從目前最大的 id 開始繼續遞增。必須跑類似 ALTER SEQUENCE product_id_seq RESTART WITH 1453; 來對每個 table 一一作設定,不然的話可能新增的 record 會從前面沒有的 id 開始建立。
  • 以前在 MySQL 或是 Sqlite 時似乎沒有指定 order 就會以 primary key 自動作排序。但是在 Postgresql 我發現丟回來的東西順序不是這樣(我看到的是相反的 id desc)。這代表 query 都得手動加入 order(:id) 才能確保跟以前一樣以 id desc 排序。

後記

資料轉移完以後,我才偶然發現 sequel gem 似乎也有提供類似的轉移功能,因為這款 gem 很有名,所以很有可能比以上我使用的方法更可靠好用。這就等其他人來試試看報告一下了。