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?

DynamoDBの設計と料金見積もり

Last updated at Posted at 2025-03-09

業務でDynamoDBを利用したDBを作成することになり、最適な設計と料金試算を行う方法について調べたので、まとめました。

具体的なユースケースとしては社内AIチャット履歴を保存するための設計と見積もりになります。

DynamoDBのデータ構造の設計、コストの試算、トランザクションの要否について解説します。

今回始めてDynamoを設計し、今までRDBしか触ってきておりませんので、ご指摘があればご意見いただけると幸いです🙇‍♀️

参考文献


1. なぜDynamoDBなのか?

DynamoDBは、データの増減に応じて柔軟に対応できるキーバリュー型のデータベースです。

リレーショナルデータベース(RDB)とは異なり、データの関連性を考慮せずに保存するため、設計の考え方が大きく変わります。

AWSのRDS(リレーショナルデータベース)との違い

比較項目 DynamoDB RDS(MySQL, PostgreSQL など)
データ構造 キーと値のシンプルなデータ構造 テーブル間の関係を持つ
スケーラビリティ 自動で拡張・縮小 サーバーのスケールアップが必要
データ取得 単一テーブルからの取得が基本 SQLのJOINで複数テーブルを結合可能
運用管理 フルマネージド サーバーの管理・設定・最適化が必要
コスト 従量課金制 インスタンス単位の固定費がかかる
用途 高速なキー検索、スケールが必要なデータ データの整合性が重要なシステム(金融、ECなど)

DynamoDBを選んだ理由(RDSではなくDynamoDBを採用した理由)

今回のユースケース(AIチャット履歴の保存)では、以下の点でDynamoDBが適していました。

  • アクセス頻度が比較的低く、コストを最小限に抑えられる
  • リレーショナルなデータ結合が不要(セッション単位でデータを管理するため)
  • データの自動削除(TTL機能)を活用できる

DynamoDBは管理コストがかからず、料金も使った分だけなので、チャット履歴のような大量のデータを効率的に保存・取得するのに適しています。

これがRDSだと月2000円はかかってきます。
(ストレージ料金最低20G、インスタンス料金で、最低スペック)

これがDynamoDBだと月1〜数百円程度です。

このような理由から、DynamoDBを採用しました。

設計と料金見積もりの考え方

どこにお金がかかりやすいのか?

DynamoDBの課金は以下の3つが主な要因となります。

1. ストレージ料金(保存データ量)

  • 1GBあたり 約$0.25/月(データ量に比例)
  • 不要なデータをTTLで削除しないと、どんどんコストが増える

2. 書き込みリクエスト

  • 100万回あたり $1.25
  • 頻繁にデータを更新・追加する設計にするとコストが増える

3. 読み取りリクエスト

  • 100万回あたり $0.25
  • 不要なクエリを減らすために、取得しやすい形で保存するのが重要

お金を安くするには...?

基本的にDynamoDBは従量課金制なので、クエリをできるだけ減らして、ストレージを極力減らすという考え方でコストを抑えていきます。

  • アクセスパターンを事前に考える:データの取得時に余計な読み取りを発生させない設計にする
  • データを事前にまとめて保存:RDBのようにテーブルを分割しすぎず、1回の取得で必要な情報をすべて取得できるようにする
  • TTL(Time-To-Live)を活用:不要なデータを自動削除し、ストレージコストを抑える

RDBとの設計の違いを具体例を用いて

DynamoDBでは、RDBのようにデータの正規化(テーブルを分けること)を意識しすぎるとパフォーマンスやコストが悪化します。

なぜなら、DynamoDBでは複数のテーブルを結合するようなクエリができないため、データを取得するたびに複数回のリクエストが必要になるからです。

またRDB(リレーショナルデータベース)では、どの列でもWHERE句を使って検索できますが、DynamoDBではPK(パーティションキー)を指定しないと効率的に検索できないという制約があります。

そのため、アクセス時のデータ取得を考え、あらかじめ必要なカラム一緒に保存しておくことが重要になります。

そのため、DynamoDBではアクセスパターンを考え、必要なデータを1つのテーブルにまとめて保存するのが基本的な設計の考え方です。

以下、チャット履歴と「いいね」の管理を例に、RDBとDynamoDBの設計の違いを説明します。


RDB(正規化する設計)

RDBでは、データの一貫性を保つためにテーブルを分け、JOIN を使って結合します。

テーブル: chats(チャット履歴)

PK (チャットID) セッションID ユーザーID メッセージ
chat_001 session_001 user_123 こんにちは
chat_002 session_001 user_123 今日の天気は?
chat_003 session_001 AI 今日の東京の天気は1日曇りです

テーブル: likes(いいね一覧)

PK (いいねID) チャットID ユーザーID 評価
like_001 chat_003 user_123 👍

ここで問題なのですが、DynamoDBでは JOIN ができません。

なので同じ設計をすると非効率になってしまいます。

例えば、「チャット履歴」と「いいね一覧」を取得するために、リクエストを2回発行する必要があります。
そうなると、結果として、読み取り回数が増え、コストが高くなってしまいます。

DynamoDB(非正規化する設計)

DynamoDBでは、チャット履歴といいね情報を1つのテーブルにまとめることで、1回のリクエストで取得可能にします

テーブル: chat_sessions(チャット履歴 + いいね情報)

PK (セッションID) SK (メッセージindex) ユーザーID メッセージ いいね 期限 (TTL)
session_001 1 user_123 こんにちは null 1715370000
session_001 2 user_123 今日の天気は? null 1715370500
session_001 3 AI 今日の東京の天気は1日曇りです 1715371000

テーブル: chat_feedback(セッション全体の評価)

PK (セッションID) SK (データ種別) ユーザーID 評価 期限 (TTL)
session_001 feedback user_123 👍 1715370000

DynamoDBの設計のポイントで、「いいね」をチャット履歴に直接持たせています** 。
liked(いいね)の情報を各メッセージに保存することで、追加のクエリが不要

DynamoDBのメリット

  • クエリ1回で、チャット履歴と「いいね」の情報をまとめて取得可能
  • リクエスト回数が減り、コストが最適化される
  • データの自動削除(TTL)を活用し、不要なデータを削減

なぜDynamoDBは結合が苦手なのか?

DynamoDBは キーと値の組み合わせでデータを保存する シンプルな構造のため、RDBのような JOIN 操作ができません。

DynamoDBが結合を苦手とする理由

  • リレーショナルデータの結合ができない → SQLの JOIN のような機能がない
  • 複数のテーブルをまたいでデータ取得するとコストが増加(複数回のクエリが必要)
  • 一貫性のある結合データを取得するにはアプリ側でマージする必要がある

そのため、事前に必要なデータを1つのテーブルにまとめておく 設計が重要になります。


トランザクション書き込み・読み込みとは? なぜ不要なのか?

DynamoDBでは 複数のデータ操作を1つのまとまった処理として実行し、すべて成功するか、すべて失敗するかを保証 する仕組みがあります。
DynamoDBのトランザクション書込読込は、整合性を担保するため、2回分のクエリを実行します。

具体例と不要な理由

❌ 不要なケース:チャット履歴の保存
  • 各メッセージは独立しており、順番に書き込めば良い
  • 部分的に失敗しても影響が小さい
✅ 必要なケース:銀行口座の振込処理
  • 送金元の口座の残高を減らし、受取口座の残高を増やす処理
  • どちらかが失敗するとデータの整合性が崩れる
  • 必ず「すべて成功 or すべて失敗」にする必要がある

今回はチャット履歴のようなケースで厳格なトランザクションではないため、不要としました!

実際のコスト試算

DynamoDBの料金は、以下の要素で決まります。

コスト項目 単位 東京リージョンの料金
ストレージ 1GBあたり/月 $0.25/GB
書き込みリクエスト 100万リクエストあたり $1.25/百万リクエスト
読み取りリクエスト 100万リクエストあたり $0.25/百万リクエスト

1:データサイズの試算

メッセージ1件あたりのサイズ

  • ユーザーのメッセージ = 50文字 × 2B = 100バイト
  • AIのメッセージ = 300文字 × 2B = 600バイト
  • 平均サイズ = (100 + 600) ÷ 2 = 350バイト

1ヶ月のメッセージデータ量

  • ユーザー1人あたり
    • 1回6メッセージ × 4週間 = 24メッセージ
    • 24メッセージ × 350バイト = **8.4KB**
  • 200人の場合
    • 8.4KB × 200人 = **1.68MB**

セッションの「いいね or 悪い」データ量

  • **1件 100バイト × 800件/月 = 80KB

いいねしたAIの回答

  • **1件 600バイト × 160件 = 96KB

2:3ヶ月分のストレージコスト

項目 1ヶ月のデータ量 3ヶ月分
メッセージ履歴 1.68MB 5.04MB
いいね or 悪い 80KB 240KB
いいねしたAIの回答 96KB 288KB
合計 1.85MB 5.57MB

ストレージ料金:

  • 5.57MB ≒ 0.006GB
  • 料金 = 0.006GB × $0.25 ≒ $0.0015 (ほぼ無料)

3:書き込み・読み取りコスト

書き込みリクエスト

  • 書き込み回数
    • メッセージ履歴: 4,800回
    • いいね or 悪い: 800回
    • いいねしたAIの回答: 160回
    • 合計: 5,760回

書き込み料金

  • 5,760 ÷ 1,000,000 × $1.25 = **$0.007**

読み取りリクエスト

  • 読み取り回数
    • 履歴取得: 1000回
    • 合計 = 1000リクエスト

読み取り料金

  • 1,000 ÷ 1,000,000 × $0.25 = **$0.00025**

総コスト

項目 1ヶ月の費用
ストレージ $0.0015
書き込みリクエスト $0.007
読み取りリクエスト $0.00025
合計 $0.00875 (約1円/月)

感想

RDBと比べて、安すぎてびっくりしました!

はじめは要件をGPTにいれこんで試算しましたが安すぎて焦ったので、公式サイトと非公式サイトで計算し直しましたがほぼ同じくらいでした。

非公式

公式

ただRDBと比べてリレーションが弱いということは拡張性が低いということを感じました。

例えば今回の例で説明したチャットいいね機能は後付しようと思うと、チャットに対するいいねを保存する別テーブルを用意する形になります。
それは、DynamoDBのクエリをできるだけ別テーブルへ発行しない考え方に反することになります。

そして料金が高くなります。

なので、PoCや小規模プロダクト・短期プロダクトなどや、ログやユーザー情報などキーが明確で構造が単純なものにはすごく力を発揮すると思いました。

逆に前職のような、売上などの複数テーブルをジョインして演算する大規模システムや基幹システムの場合は向いてないと思いました。

まとめ

✅ DynamoDBはスケーラブルかつ低コストで運用できるため、チャット履歴の保存に適している
✅ JOINが苦手なので、アクセスパターンを考慮した設計が重要
✅ トランザクションは不要と判断し、通常の書き込みを採用することでコストを最適化
✅ 200人規模では、ストレージ・リクエストコストともに約1円/月で運用可能。20,000人にスケールしても月$1未満

参考になれば幸いです🙇‍♀️

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?