Cloudflare D1 の無料プランでの制限事項をいまいちど調べ直す
Cloudflare Workers に D1 (SQLite) データベースを組み合わせたウェブアプリをいくつか作っているので、「無料枠の中で制限事項って何かないのか?」と気になって調べた。以降、「Paid」と表記しているのが「有料プラン」の場合の情報。
- 1レコードの最大サイズ : 2MB
- 1レコードの最大カラム数 : 100
- 1テーブルの最大行数 : 行数制限はなし
- 1データベースの最大容量 : 500MB (Paid は 10GB)
- 1アカウントで作れるデータベース数 : 10個 (Paid は5万個)
- 1アカウント全体のストレージ : 5GB (Paid は 1TB)
- 1DB あたり 500MB × 1アカウント 10DB まで = 5GB
- Free 日次 Read : 500万行/日 (Paid は 250億行/月)
- 1アカウント内での総量
- SELECT 時は、インデックスがあれば
WHERE id = 1は Read 1件に抑えられるが、インデックスがない場合は全件スキャンして計上される - UPDATE と DELETE 時のスキャンでも計上される (もしインデックスのないテーブルへの UPDATE・DELETE なら全件 Read スキャンすることになる)
- Free 日次 Write : 10万行/日 (Paid は 5千万行/月)
- コチラも1アカウント内での総量
- INSERT・UPDATE・DELETE の操作した行数 + 紐付いて書き換えられるインデックスも計上される
$ wrangler d1 executeコマンドで SQL を流した場合もカウント対象になる
- SQL 1つの長さ : 最長 100KB
db.prepare('INSERT INTO ... VALUES (?, ?)').bind(id, data);というコードの、prepare()内に書かれる SQL が 100KB を超えたらダメ.bind()で Bind したパラメータの値は 100KB 制限内には含まれず、「1レコード 2MB 上限」の方が引っ掛かることになる$ wrangler d1 executeの場合、INSERT INTO ... VALUES ....;とリテラル展開されているので、Bind は関係なく、書き込む文字列の長さによって1つの SQL が 100KB を超える可能性がある
- Workers 呼び出し1回の中でのクエリ数 (= サブリクエスト数) : Free は50回、Paid は1000回
- 1回のリクエスト内で
db.prepare().run();を50個以上書いた場合、51個目の実行時にエラーが出る。50個目までは処理されるためコミットされた状態となり、トランザクション不正が起こりうる db.batch()は1サブリクエスト扱いなので、複数クエリを実行する必要がある場合は積極的に使用したい。ただ、Batch 内の一つひとつのクエリに関しては、「SQL 1文で 100KB 上限」など上述の条件がかかる- 極端な話、1回のリクエスト内で
db.batch()を50個書くことは可能
- 1回のリクエスト内で
- Workers 呼び出し1回の中での同時接続数 : 最大6接続
Promise.all([db.prepare('...').all(), db.prepare('...').all(), ...]);というように、並列でクエリを7つ以上投げた時に待たされる
- 1クエリ (バッチ内の各文含む) の最大実行時間 : 30秒
db.batch()内で500件の INSERT を流したとして、500件の処理が終わるまでに30秒以上かかったらその Batch ごと失敗する。実際のところ、大抵は数秒以内に終わるが、大容量データを取り扱う際は留意
- Paid プランへの移行は「Workers Paid」プラン (月額5ドル) に明示的に変更することで有効になり、アカウント内のすべての D1・Workers が一律で Paid 上限適用に変わる
- 1DB だけ有料プランにしたい、などは不可能
以下感想。
- 無料プランの場合、Workers は最大100個作れるので、それに対して D1 データベースが10個までしか作れないのは、複数アプリを作りたい人にとっては厳しいところかも
- 1レコードあたりの最大サイズ 2MB というのは、1カラムに JSON 文字列なんかをゴッソリ登録するようなアプリだと厳しくなってくるかもしれない
- 日次で Read・Write 件数の上限があるのだが、CRUD の全てでインデックスが影響してくるところに留意
- 複数テーブルを結合した SELECT が多いアプリであれば、「全件スキャンを回避するために、インデックスをしっかり張る」方が Read 数を節約できそう
- 書き込みが多く、読み出しが少ないようなアプリであれば、「Write 数を節約するために、インデックスをむやみに張らない」もアリかも
- この制限は1アカウント内での総量になるので、「アプリ A」で大量の Read をして上限に達すると、「アプリ B」「アプリ C」の Read もその日は出来なくなる、という風によそを巻き込むので注意
- SQL 1つの長さ 100KB というのは、大体5~10万文字くらいに相当する。複雑なサブクエリとかがあっても10万文字も使うようなことは稀かとは思う
自分専用のアプリをいくつか作る場合なら無料枠でも困ることはないと思うが、一般公開して色んな利用者が読み書きをするようなウェブサービスを作る場合は、うっかり人気サービスになってしまうと無料枠では厳しくなる場面が出てくるかもしれない。