3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Supabase】.select("*")はなぜダメ?ページネーションの選び方まで考えた

3
Posted at

はじめに

個人開発で水泳の練習記録アプリ「Suimote」を作りました。
公開後にレビューをもらい、練習記録一覧で全レコードを全カラム一括取得している
ことを指摘されました。


問題

const { data } = await supabase
  .from("practice_records")
  .select("*")
  .order("date", { ascending: false });

2つの無駄がありました。

  1. 全件取得: 画面には最新の数十件しか表示しないのに、毎回全件ダウンロード
  2. 全カラム取得: 一覧画面で使うのは id, date, distance, time, stroke, facility の6つだけなのに、memocreated_at も毎回取得

Supabaseの無料枠は帯域5GB/月。レコードが増えるほど無駄に帯域を消費します。


解決方法

ページネーション: .range() で20件ずつ取得

const PAGE_SIZE = 20;

const { data } = await supabase
  .from("practice_records")
  .select(LIST_COLUMNS)
  .order("date", { ascending: false })
  .range(0, PAGE_SIZE - 1);

取得件数が PAGE_SIZE 未満になったら最後のページと判定し、「もっと見る」ボタンを非表示にします。

カラム絞り込み: .select("*") をやめる

// 修正前: 全カラム取得
.select("*")

// 修正後: 一覧に必要な6カラムだけ取得
const LIST_COLUMNS = "id, date, distance, time, stroke, facility";
.select(LIST_COLUMNS)

なぜこの方法を選んだか

他にも選択肢はありました。

選択肢 採用 理由
オフセットベース(.range() シンプル。練習記録は自分しか追加しないので、データの重複・欠落が起きない
カーソルベース(.lt("date", lastDate) 同時書き込みでデータがズレる問題を防げるが、今のSuimoteではその問題が起きない
無限スクロール UXは良いが、「もっと見る」ボタンで十分機能している
カラム絞り込み 1行変えるだけでリスクなく効果がある

「その問題は今の自分のアプリで実際に起きるのか?」 を基準に判断しました。

効果

項目 修正前 修正後
取得件数 全件 20件ずつ
取得カラム 全カラム(8つ) 必要な6カラムのみ
500件ユーザーの帯域 約100KB/回 約3KB/回

学んだこと

  • .select("*") は思考停止のサイン。一覧画面で本当に必要なカラムだけ取得する
  • ページネーションの方式は複数あるが、今の状況で起きない問題のために実装を複雑にする必要はない
  • 「なぜその実装なのか」「他の選択肢は何か」を常に問うことで、レビューで指摘される前に自分で気づけるようになる
3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?