DynamoDBのテーブル設計どうやってるのか雰囲気掴みたい
概要
これまでほぼRDBMSしか触ってなかったので
転職の合間で少し時間あるこの時期にDynamoDBの公式ドキュメント触って
スケーラブルでマネジドなNoSQLちょっと語れる男になりたい
大事なこと
- RDBMSはそこまで使い方見えてなくてもテーブル設計できる
- DynamoDBではどのキーで検索してどういう情報取得するか見えてないと設計できない
- 検索の柔軟性がないので事前に使われ方がわかってないといけないのだ
- DynamoDBではどのキーで検索してどういう情報取得するか見えてないと設計できない
- テーブルも正規化してたくさん作るんじゃなくてなるべく少なく
- もはや1個がベスプラの世界線
- インデックスっていう概念を利用して検索性を高くできる
- ただインデックスはなるべく少なくしないと高コストになる
テーブル設計してみる
これ読んだ自分の理解をメモっとくだけ
「お客様が従業員に注文する」みたいなよくあるケース
アクセスパターンの洗い出し
例えばこんな感じのデータ取得がしたいとする
- 従業員IDを元に従業員詳細を取得
- 従業員名を元に従業員詳細を取得
- 特定のお客様の注文一覧をお客様IDと日付から取得
- お客様全体の注文情報を日付から取得
エンティティを定義
アクセスパターンを踏まえて
大元テーブルを作成するためにエンティティを定義
- Employee - PK: EmployeeID, SK: EmployeeName
- Customer - PK: CustomerID, SK: AccountRepID
- Order - PK OrderID, SK: CustomerID
ここで定義したPK(Partition Key)の単位でデータが保存されるらしい
このPKを均等に分散してデータアクセスするとコスト効率とレイテンシーが低いみたい
同じPKの箇所に大量にデータアクセスがくるとコストも高くレイテンシーも高くなるみたい
(とりあえずは従業員やお客様のID指定が無難かなぁ)
SK(Sort Key)にはPKに加えて検索したい条件を指定する
この項目で前方一致とか範囲指定もできる
大元になるテーブル作成
エンティティで定義したPK, SKを元にitem(レコード)作成して
各項目で必要なデータもAttributesとして考えてく
Partition Key | Sort Key | Attributes | ||
---|---|---|---|---|
(EmployeeID) EMPLOYEE1 |
(EmployeeName) John Smith |
(Email) xxx@example.com |
(Country) Japan |
|
(SalesPeriod) Quota-2017-Q1 |
(OrderTotals) 50000 |
|||
(CustomerID) CUSTOMER1 |
(CustomerName) Taro Tanaka |
(Country) Japan |
||
(OrderID) ORDER1 |
(CustomerID) CUSTOMER1 |
(StatusDate) OPEN#2018_08_11 |
(OrderTotal) 1200 |
(SalesRepID) EMPLOYEE1 |
RDBMSとは正反対な設計の流れ
スキーマを定義して正規化してくんじゃなくて
一つのテーブルでよろしくデータ突っ込めるように頑張ってく感じ
集約
2行目にあるように特定期間の合計値を格納するのは集約
と呼ばれるテクニックらしい
4行目にあるようにOrderが入ってItemが追加されたことを契機に
Amazon DynamoDB Stream発動してLambdaが計算して2行目の合計値を更新する
こういうテクニック系は知らないとわからんわな・・
アクセスパターンを実現するためにインデックス作成
Global Secondary Index
作成した元テーブルのPKでは検索できないような条件がある場合
Global Secondary Indexを指定して検索できるようになるのだ
イメージとしては別のテーブルが作成されるような感じっぽい
例えば従業員の名前から従業員詳細取りたいとか
お客様の特定期間における購入情報を知りたいとか
Partition Key | Sort Key | Attributes |
---|---|---|
(EmployeeName) John Smith |
(StatusDate) OPEN#2018_08_11 |
(Email) xxx@example.com |
(CustomerID) CUSTOMER1 |
(StatusDate) OPEN#2018_08_11 |
(OrderTotal) 1200 |
ちなみに作成できるGSIには上限があるので
ひとつのGSIで複数の検索条件を実現できるようにするのを
GSI Over Loading
というらしい
GSIシャーディング
ある特定期間の全体売り上げみたい
とかいう時に使えるテクニックらしい
Partition Key | Sort Key | Attributes | |
---|---|---|---|
(Coefficient) [0..N] |
(StatusDate) OPEN#2018_08_11 |
(CustomerID) CUSTOMER1 |
(OrderTotals) 50000 |
(Coefficient) [0..N] |
(StatusDate) OPEN#2018_08_11 |
(ProductID) PRODUCT1 |
(OrderQuantity) 50 |
こうするとよしなにpartition分散したデータ格納になって
ほっとパーティションを生み出さず効率よくデータが取れる!
ちなみにNの算出は以下のような計算式があって
それに準じて算出するのが良いらしい
ItemsPerRCU = 4KB / AvgItemSize
PartitionMaxReadRate = 3K * ItemsPerRCU
N = MaxRequiredIO / PartitionMaxReadRate
その他特質すべきパターン
時系列データ
基本テーブル数を少なく、1つにするぐらいがいいらしいけど
時系列データに関してはテーブル分割するとうまいことできる
ちょっと描くのめんどくさくなってきたのでリンクだけ貼りますが
古いテーブルを別出しすることで
トラフィックボリュームの多い最近のデータに必要なリソースを割り当て
古いデータにはコストをかけないというテクニックがあるらしい
まとめ
まだまだ奥は深そうだけど
なんとなくドキュメント読んで雰囲気を掴んだ
結構癖が強めだが
なんといっても使用しないとお金かからない
サーバーレス構成の利点はでかいので
今Privateで作ってるシステムのストレージとして検討してみる!!
Discussion