DynamoDB超入門 0章

最終更新日

現在開発中のプロジェクトでDynamoDBを使うことになり、数日調査をするも、理解するまでに結構時間がかかったので、これから始めてみようかという人に向け、超単純化した解説を載せていきます。

※最新情報やより詳細な解説についてはAWSのドキュメントをご覧ください
※DynamoDB特有の呼称や難しい単語、横文字は極力避けるため、あくまで対象は超初心者向けです

開発環境

  • PHP8
  • Laravel8
  • baopham/laravel-dynamodbを使用

まずDynamoDBの大きな特徴

・無限にレコードを追加でき、検索が早い
・リレーションが無い
・設計が独特

検索方法に「SCAN」と「QUERY」がある

DynamoDBからデータを取り出すとき(SELECTするとき)「SCAN」と「QUERY」という2つのパターンのいずれかで行われる。
ザックリいうと「SCAN」は全件走査、「QUERY」はインデックスを使って検索する。
よって、よほどのことが無い限り、「QUERY」を使う。
「QUERY」を使うためには、きちんとインデックスが使われる検索をしないといけない。
※SCAN検索をすると、検索効率がめちゃくちゃ悪い上に、予想外に費用がかかる

DynamoDBのインデックス

DynamoDBには大きく分けて3つのインデックスがある

1.プライマリーキー

テーブルを作るときに必ず作るインデックス。
後で詳しく書くが、パーティションキーのみ、あるいはパーティションキーとソートキーの組み合わせで一意になるようなカラムで構成される

2.ローカルセカンダリーインデックス(通称LSI)

プライマリーキーと似ているが、テーブルのパーティションキーと、プライマリーキーのソートキー以外のカラムをセットにして作る。
プライマリーキーのソートキー以外で検索する必要があるときなどに使う。
※テーブル作成時にしか追加できない。(後から追加できない)
※最大5個まで作れる。

3.グローバルセカンダリーインデックス(通称GSI)

プライマリーキーとは違う組み合わせで、パーティションキー、ソートキーを使ったインデックス。
※テーブル作成後も追加できる(updateTableで追加)
※最大20個まで作れる。
※作る分だけ費用が上がるので、なるべく抑えるように設計が必要

パーティションキーとソートキー

パーティションキー(通称:PK)

検索するためのカラム。SQLでいうところの、where=’:pk’として使われるキー
検索するときに、PKや後述のソートキー以外のカラムを条件に入れると、「SCAN」検索になってしまう。
※プライマリーキーにパーティションキーのみしか使用しない(ソートキー無し)場合は、パーティションキーの値は一意である必要がある。同じ値を持つレコード(DynamoDB的にはアイテム)が合ってはならない。RDBのPrimary keyと同じイメージでOK。

ソートキー(通称:SK)

超簡単に言うと、結果をソートするためのキー。一部の検索機能(begin_with関数など)はソートキーにのみしか使えないなどの制限がある。

サンプル1:ユーザーテーブル

user_id
ユーザーID
name
氏名
email
メールアドレス
created_at
作成日
deleted_at
削除日
000000001山田 太郎yamada@hoge.com2022-02-01 00:00:00NULL
000000002伊藤 亜沙子ito@hoge.com2022-02-02 13:00:00NULL
000000003佐藤 隆sato@hoge.com2022-02-05 12:00:002022-02-10
usersテーブル

RDBとしてはこのようなテーブルはよく見かける。

例えば、メールアドレスで検索する場合、
select * from users where email=’yamada@gmail.com’ limit 1;
このようなSQLが一般的であるが、上記SQLを「QUERY」で検索しようとした場合、DynamoDBでは
プライマリーキーのパーティションキーはemailとなる(emailは一意でないといけない)
※上記SQLでは「削除済みユーザー」も検索できるという前提

次に、削除されていないユーザーを登録が新しい順番で検索する場合、
select * from users where deleted_at is null order by created_at desc;
SQL的にはこんな感じになる。deleted_atが条件となり、created_atが並び替えになるので、
DynamoDBとしては、パーティションキー:deleted_at、ソートキー:created_atとなる。

更に、user_idで特定のユーザーも検索したい場合は
select * from users where user_id = ‘000000001’ limit 1;
となり、この場合、パーティションキー:user_idとなる。

上記3つのパターンでアプリケーションが検索を行えることが必要な場合、
ひとまず最も単純な設計としては、

プライマリーキー

パーティションキー:user_id

GSI1

パーティションキー:email

GSI2

パーティションキー:deleted_at、ソートキー:created_at

このように3つのインデックスを用意したテーブルを作る必要がある。

ただし、DynamoDB的には、GSIをなるべく圧縮する方向で設計するのが定石となります。
ひとまず上の3つの検索ができてGSIを少なくし、DynamoDB的な作り方をすると以下のようなテーブルになります。(いくつか方法があるうちの一つです)

user_iddata_typedata_valuenamecreated_at
000000001profileyamada@hoge.com山田 太郎
000000001deletedNULL2022-02-01 00:00:00
000000002profileito@hoge.com伊藤 亜沙子
000000002deletedNULL2022-02-02 13:00:00
000000003profilesato@hoge.com佐藤 隆
000000003deleted2022-02-102022-02-05 12:00:00

プライマリーキー

パーティションキー:user_id、ソートキー:data_type
user_idに同じ値が複数入るため、user_id+data_typeで一意になるようdata_typeをソートキーに設定

GSI1

パーティションキー:data_value、ソートキー:created_at

こうすることで、GSIは1つで3つの検索が実現できる設計になります。

メールアドレスでの検索
select * from users data_value=’yamada@hoge.com’; (GSI1使用)

退会してないユーザーを入会日順で検索
select * from users data_value=’NULL’ order by created_at desc; (GSI1使用)

ユーザーIDで検索
select * from users user_id = ‘000000001’; (プライマリーキー使用)

そして、DynamoDBでは、テーブルは少ないほど優秀だそうです。
衝撃的なのはDynamoDBの最も優れた設計という点では、アプリケーション一つで、テーブルは1つなのだそうです。
いやはや、RDBに慣れている人ほど、とっつきにくいですよね。

今回はDynamoDBを学ぶ上で最も大切なインデックスと簡単な設計例について書きました。
実際にLaravel8を使って開発を行う方法など記事を追加していこうと思っています。

masa