SQLiteを1経路で作る

更新: 2026-09-09
SQLiteTursoIcebergデータ基盤

配信用の SQLite ファイル(dev.db)を、中継のクラウドDBを挟まずに データレイク(Iceberg)から直接作る構成の記録。 stock-app で実際に切り替えたときに踏んだ挙動を書く。 経緯は経路を1本に減らしたら、消えていた索引が出てきた

経路の形

1. マイグレーション適用db/migrations/ を全部当てる2. テーブル存在検査無ければここで異常終了3. Iceberg からエクスポート同期処理。HTTP往復なし4. Blob へ配信スナップショットが復旧元にもなる2 を入れる前は、テーブルが無いまま 3 が走って 0 件で正常終了していた。
4段のうち、1 が抜けると遅くなるだけで気づけず、2 が無いと空のファイルが配信される。

中継DBを外すと何が消えるか

消えるもの理由
HTTPクライアント一式リモートへ送らないので不要
asyncioHTTP往復を並行化するためだけに使っていた。同期化できる
ローカル/リモートの分岐送信先が1つになる
スキーマ整合の同期スクリプトマイグレーションが直接当たるので不要
手書きの MIGRATIONS 配列上と同じ。これが歯抜けの原因になる
疎通確認・スロットリング用スクリプト送信先が無くなれば宛先も無い

踏んだ挙動

1. マイグレーションの適用先が抜けて、索引が消える

生成経路を差し替えたとき、db/migrations/ を当てる段が経路から落ちた。

  • 症状: ページは正常に表示される。エラーもログも出ない。特定のクエリだけ遅い
  • 原因: 索引が1つ作られておらず、インデックスを使うはずのクエリが全走査(SCAN)へ退行していた
  • 見つけ方: EXPLAIN QUERY PLANSCAN になっていないか見る。 索引の有無は PRAGMA index_list(<テーブル>) で数える
  • 対処: 生成経路の先頭でマイグレーションを全件適用する。 「新しいファイルだから最新のはず」という前提を置かない

経路を差し替えるときは、経路上の段を1つずつ数える。 新しい経路が通ったことと、旧経路がやっていた仕事が全部移ったことは別。

2. 0件で静かに完了する

対象テーブルが存在しない状態でエクスポートを走らせると、 書き込む先が無いだけで例外にはならず、0件のまま正常終了する。 そのまま配信すると、空のファイルが本番へ出る。

対処は、エクスポート開始時に対象テーブルの存在を検査して、 無ければ異常終了させること。件数0を成功として扱わない。

起動 → 対象テーブルが全部あるか確認 → 無い → 非ゼロで終了

「何も起きなかった」と「うまくいった」を、終了コードで区別できるようにしておく。

3. 手書きの配列は必ず歯抜けになる

適用すべきマイグレーションを配列に列挙する形にしていると、 マイグレーションを足した人が配列に書き足すのを忘れた時点で黙って壊れる。 ディレクトリを読んで全部当てる形にすれば、書き忘れる場所自体が無くなる。

ゼロから作り直す

作り直せるかどうかは、テーブルごとに正本がどこにあるかで決まる。

種類正本戻し方
データレイクが正本のテーブルIcebergマイグレーション全適用 → エクスポートの2コマンド
外部取得で組み立てるテーブル外部API専用のブートストラップスクリプトで再生成
計算結果のテーブル計算処理再計算のバッチを流す

全部戻せる。ただし実運用で壊れたときの最短復旧は、配信先に置いてある スナップショットを戻すことで、再生成は最短ではない。 設計ドキュメントには「戻せるか」と「戻すのが速いか」を分けて書く。

注意点

  • 中継DBを外すと、手元と本番で同じファイルを見ることになる。 手元での生成が本番の中身そのものなので、生成の失敗は即配信の失敗になる
  • 生成時間は往復が消えた分だけ短くなるが、 効いているのはHTTPのレイテンシであってDBの速さではない
  • 配信の無料枠にはサイズ上限がある。経路を1本にしても、 出力サイズの監視は別途要る
WIKI一覧へ