Firestore の費用を円で出したら、読み取りの 91% が 1 か所だった:キャッシュを入れても効かなかった理由

English version

トレカダッシュ 開発の記録 / 2026年9月

iOS アプリ「トレカダッシュ」の裏側は、Firebase の Firestore(データベース)と、定期的に動く処理でできています。費用は、Gemini(AI)と取得サービスの分は、毎日、円で出して見ていました。ところが、Firestore の費用は、レポートに載せていませんでした。

9 月 4 日の深夜に、はじめて円で出してみました。結果は、Gemini とほぼ同額でした。この記事は、そこから読み取りの 91% が 1 か所に集中していると分かり、キャッシュを入れても効かず、直し直した記録です。

数字は、2026 年 9 月 4 日の作業の記録から書いています。価格は、東京リージョンの実際の単価です。

円で出したら、誰も見ていなかった費用が出てきた

Firestore の読み取りを、日ごとに円にしました。

日読み取り書き込み1 日の費用
8 月 28 日218 万件12 万件226 円(月 6,777 円)
9 月 1 日366 万件13.4 万件368 円(月 11,028 円)
9 月 3 日421 万件16.2 万件427 円(月 12,810 円)

無料の枠は、1 日 5 万件の読み取りまでです。その84 倍を読んでいました。しかも、1 週間で 89% 増えていて、記事が増えるほど増える形でした。

円で出していない費用は、ないのと同じでした。月に約 1 万 3 千円かかっていたのに、レポートに載っていないというだけで、誰も気にしていませんでした。

計器を入れたら、3 分で分かった

どこで読んでいるのかを知るために、「どの処理が、どのコレクション(データの置き場)を、どれだけ読んだか」を数える計器を入れました。入れたその場で、答えが出ました。

8,725 件  X 監視 | products(商品)    ← 測定した 9,593 件の 91%
  197 件  X 監視 | news_items(記事)

X の監視は、記事を 1 件処理するたびに、AI に「どの商品の話か」を聞きます。その候補を作るために、ジャンルの商品を、毎回、全部読み直していました。ポケモンのジャンルは商品が 693 件あります。記事 1 件の照合が、693 件の読み取りです。

コードを読んで探していたら、もっと時間がかかったはずです。探す前に、数える。計器を 1 つ足しただけで、読み取りの 91% が 1 か所だと分かりました。

最初のキャッシュは、ほとんど効かなかった

直し方は単純です。商品の一覧を、一度読んだら覚えておく(キャッシュ)。最初は 60 秒覚えさせました。ところが、ほとんど効きませんでした。

理由は、X の監視が、最大 32 アカウントを同時に処理していることでした(Promise.all)。コードは、こう動いていました。

  1. 1 件目が、「キャッシュに無い」と判断して、読みに行く。
  2. 読み終わる前に、残りの 31 件も、同じ「キャッシュに無い」を見る。
  3. 全員が、同じ 693 件を、同時に読みに行く。

実測では、23 秒に 1 回、読み直していました。キャッシュは「読み終わった結果」を覚えるもので、読んでいる最中の人は、まだ何も覚えていないのです。

直し方は、結果ではなく、「読み込み中」という約束(Promise)そのものを覚えることでした。1 件目が読み始めたら、その約束を置いておく。残りの 31 件は、新しく読みに行かず、同じ約束を待つ。同時に呼ばれても、読み込みは 1 本になります。

// 考え方を書いた例です。結果ではなく、読み込み中の約束を覚える
cache.set(genre, { at: Date.now(), promise: loadProducts(genre) });
// 呼び出しは、いつも cache.get(genre).promise を待つ

これに合わせて、3 つのことも決めました。

静かな時間帯で測ると、1 日に換算して、507 万件が 27.7 万件になりました。

もう 1 つ:5 分おきに 3,085 件読んで、使うのは 146 件だった

商品のキャッシュを入れたあと、計器の一番上に出てきたのが、別の処理でした。楽天ブックスの在庫を確かめ直す処理が、5 分おきに、こういう問い合わせをしていました。

news_items where saleType in ["reservation", "guerrilla"]

返ってきた 3,085 件を、プログラムの側で「楽天ブックスのものだけ」に絞っていました。実際の対象は 146 件で、95% が無駄です。1 日 288 回なので、約 88.8 万件、月に約 2,400 円でした。

直し方は、2 つです。

読み取りは、1 日 88.8 万件から約 7.9 万件へ、91% 減りました。

分かったこと

円で出していない費用は、存在しないのと同じ。

この話に出てくるもの

ほかの記録

コメント

感想や、記事の間違いの指摘は、ここへ。書くには、GitHub のアカウントが要ります。

押すと、giscus(giscus.app)と GitHub に接続します。押さなければ、接続しません。詳しくはあつかいに書いています。