結局DynamoDBってなんやねん

# 前書き

DynamoDBに関してどの記事見ても、他と照らさないと結局なんやねんってなることが多かったので、
これ見れば何となく掴めるように噛み砕いた記事を書いてみました。

# 想定読者

* AWS認定-DVAの取得を目指している方
    * SAAなどデベロッパー以外の資格では使わない知識だと思う
* RDB（いわゆる一般的なDB）は知ってるけどDynamoDBはよくわからんよーな方
    * RDBと比較しての説明が主なのでRDBって何ぞって方はまずはそちらを調べてください
* 簡単にDynamoDBってモノを知りたい
    * ほんとにざっくり記事なのでプロの方は見ちゃダメです 

# そもそもDynamoDBとは

形式ばった言い方をすると以下

`Amazon DynamoDB は、高速で予測可能なパフォーマンスとシームレスなスケーラビリティを実現する、完全マネージド型の NoSQL データベースサービスです。`
（引用元（公式）：https://docs.aws.amazon.com/ja_jp/amazondynamodb/latest/developerguide/Introduction.html）

ざっくり言えば、

* AWSが管理しているDB
* NoSQL型のDB

という感じです。
ちなみにNoSQLとは、その名の通りSQLを使わないって解釈で良いと思います。
（正確な定義は割愛）


# ざっくりデータ構造

最初にざっくり構造図を示します。以下のユースケースで設計するとします。

例：
サービス内に複数提供しているソーシャルゲームの戦績情報

属性

* user_id：ユーザー毎に一意の値
* game_id：サービス内のゲームの種別
* clear_flag：クリアしたか否か

これをDynamoDBで管理すると以下。

![DynamoDB図解.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/609990/6e388e64-0be1-8ded-792a-89c04a4ac849.png)

初見の方は
なんでテーブル複数あるん？
表形式で表せばええんちゃう？
ってなられていると思うので、解説していきます。

# 各部名称

各名称と、それが指すモノを、

* RDBと紐付けられるモノ
* DynamoDB独自の概念

に分けて解説していきます。

## RDBと紐付けられるモノ

前提として、厳密に同じ意味ではないので注意してください。（あくまで例え）

### RDB:データベース→`DynamoDB：AWSアカウント(?)`

?としている理由はユースケースによって変わるかなと思ったからです。

というのも、１つのAWSアカウントに対して、複数のテーブルを作成できます。（１つのリージョンに最大256個、上限は申請で緩和可能）
通常各サービス毎にAWSアカウントは分けると思っていますが、もし１つで複数サービスを運用する場合は意味合いが変わるかなと思いました。

また、テーブル毎にIAMでアクセス制限をかけられるので、若干別物な気もしますが、イメージはこのような形かと思います。

### RDB:テーブル→`DynamoDB：テーブル`

![DynamoDB図解-Page-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/609990/7f66ee6c-910b-1326-1b8d-5633dfa7ae2f.png)


そのままですね。
なんか複数のテーブル囲っているように見えてますが、`これら１つで１テーブルです`！
この区切りについては後述する`パーティション`と呼ばれるものになります。


### RDB:レコード→`DynamoDB：項目（Item）`

![DynamoDB図解-Page-3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/609990/3ef3f748-2ac4-fc20-b352-ac620094aac0.png)


レコードに相当するものは`項目（英語表記:Item)`と呼ばれます。

### RDB:カラム→`DynamoDB：属性（Attribute）`

![DynamoDB図解-4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/609990/8da9e402-f207-b26f-7bbb-569a39e70e1e.png)


カラムに相当するものは`属性（英語表記:Attribute)`と呼ばれます。

以下はDynamoDBと言うよりNoSQLの特徴になると思いますが、
大きな違いは、１つの項目に対して自由に属性を格納できると言うことです。
何言ってるのかと言うと、例えばuser_id:1、game_id:3の情報に関しては追加の情報を入れたりとかできたりします。

![DynamoDB図解-Copy of 4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/609990/a5231785-e2a5-98a4-5824-ce6313251721.png)


## 独自の概念

以下はDynamoDB独自の概念です。

### パーティション

![DynamoDB図解-6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/609990/f1a5306c-4a46-eaf6-b6cf-dd23f7416f20.png)

DynamoDB独自の仕様となります。
内部的には１つのテーブルに対して、パーティションと呼ばれる区切りに自動で分けてデータが保存されます。

どのように区切っているかというと、後述する`パーティションキー`という値のハッシュ値で決定されます。

なんで分けているかと言われると、そういう仕様なので目を瞑りましょう。
（パッと見クリティカルな答えはなかったのであくまで仕様という認識）

### パーティションキー

![DynamoDB図解-7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/609990/9bc482a6-2882-b9b7-11f8-0f2242bd9b3f.png)

どのパーティションに格納するかを決めるための属性。
テーブル作成時に必須。
AWS推奨のベストプラクティスに則ると、多様な値が入りうる属性を指定すると良いです。
（何故なら１つのパーティションに偏っちゃうから、偏るとパフォーマンスが落ちる）

単純に、主キーと捉えてユーザーIDとかを入れるイメージで良いかと。

例では、user_idをパーティションキーとしています。

### ソートキー

![DynamoDB図解-7 (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/609990/56dfea14-0605-da0b-fa57-06519e56a570.png)

同じパーティションキーを持つデータ位置を近づけるために使われる属性。
設定するかは任意。
また、データ取得時に条件を絞るためにも使われる。

### プライマリーキー

RDBでいうところの`主キー`や`複合キー`という解釈で良いと思います。
テーブル作成時に設定するモノで、以下の２種類から構成可能です。

* パーティションキーのみ
* パーティションキー ＋ ソートキー

簡単にいうと、何を元に一意の項目とするかを決めるための設定です。

### （捕捉）パーティションキーとソートキーの意義

仕様的な説明だけだと、なんでこんなの設定するん？となると思うので捕捉します。

大前提、`DynamoDBはパーティションキー及びソートキー以外に沿った個別検索ができない`です。
もっと言うと、以下の条件に沿ったデータのみ取得可能です。

* パーティションキーの一致
* パーティションキーで絞ったデータに対しての、ソートキーの範囲検索
* テーブル全部（←キャパオーバーになりうるので基本NG）

例で例えると、

* １人のユーザーの情報のみ
* １人のユーザの、特定のゲームの情報
* 全ユーザの全情報

のみしか一度に取得出来ないのです。

他の条件に沿ったデータ取得に対応するための仕様(※)は存在しますが、
まずは、`上記を考慮した設計となる`ことは認識した方が良いです。

(※)`ローカルセカンダリインデックス`と`グローバルセカンダリインデックス`と言うモノ

# DynamoDBの機能（一部）

より開発者向けかもしれませんが、独自に備わっている機能を一部紹介します。

### 操作のためのAPIが用意されている

RDBだと接続したりとか面倒な操作があるイメージですが、DynamoDBはAPI叩くだけで操作が可能です。
もちろんSDKなども用意されています。
セキュリティ類はIAMなどで管理する感じです。

### 変更をトリガーに別AWSサービスを実行する（DynamoDBストリーム）

これを使うと、余計なコーディングをせずGUI上の設定のみで、DynamoDBで起きた変更をトリガーに別のAWSサービスを実行することが可能です。
例えば、ある項目が更新された際に、それをトリガーにLambdaを走らせたい、など。

### LSIとGSI

それぞれ`ローカルセカンダリインデックス`と`グローバルセカンダリインデックス`と呼ばれるモノです。
チラッと書きましたが、パーティションキーやソートキー以外で検索させたいときに使用するモノです。
詳細な仕様はこの記事の趣旨とブレるので、需要あったら別記事で書こうかなと。

ここでは、`パーティションキーやソートキー以外で検索させることもある程度は可能にできる`、と言うことを認識いただければと。

# メリットとデメリット

結局気になるのはここだと思うので、RDBと比較したときの利点や欠点で思いついたものを記してみます。

## メリット

* AWS管理のサービスなので、サーバやバージョンなどの管理が不要（いわゆるサーバレス）
    * ただし、書き込みや読み込み時のキャパシティは自分で検討、設計する必要がある
* 容量無制限
* スケーリングの設定が簡単
* バックアップや障害対策の設定が簡単
* 独自の設計を豊かにしてくれる機能が備わっている
* NoSQLのメリットを継承（こちらは別途NoSQLで調べると良いかもです）

など

`クラウドならではのメリット`をふんだんに盛り込んでいる印象です。

## デメリット

* 学習コスト
    * 多分一番のネックがここ、RDBと整合性がほぼないので基本０からの学習が必要 
* 検索の制限
    * つまり集計などには向かないです
    * 解決策にLSIとGSIを記しましたが、乱用出来る代物ではないので補佐的な位置づけで見た方が良い
* AWSのサービスであること
    * AWSを使用できない、したくない場合は厳しい
    * AWS外で動いているサービスと連携できる（と思うが）、例えばGCPなど別クラウドを使っていてピンポイントでDynamoDBのみ使用するのはアーキテクト的に微妙な気もします

など

# 後書き

さらに踏み込んだ仕様に関しては、他の有識者の方の記事を見るととても参考になります。
当記事をDynamoDBの理解への踏み台にしていただけたら幸いです。

分かりにくい箇所などあればご意見いただけると。

# 参考記事

* https://qiita.com/blackcat5016/items/c2af7d3d55093134bac3
* https://qiita.com/leomaro7/items/383c1aa287c7daf49518
* https://qiita.com/shibataka000/items/e3f3792201d6fcc397fd#%E3%83%91%E3%83%BC%E3%83%86%E3%82%A3%E3%82%B7%E3%83%A7%E3%83%B3

以下、Udemyのハンズオン講座
とても参考になるが、全て英語での説明、表記となる。（一応字幕は付けられます）

* https://www.udemy.com/share/101WgCAEIceV5bRHkH/