GSI OVERLOADING について 自分なりにまとめてみた
みなさま Xin Chao.
ある日、お客様より DynamoDB に関するお問い合わせを受け、いろいろ調べてみたところ、あまりに情報がなかったので驚いたことがあります。 それは...
DynamoDB の GSI (グローバルセカンダリインデックス) OVERLOADING とは? です。
GSI OVERLOADING は、「GSI 多重定義」や「GSI オーバーロード」 と表記される場合もあります。
備忘録を兼ね、自分で理解した内容を事例も交え、書き残しておこうと思います。
GSI OVERLOADING とは
「AWS Black Belt Online Seminar 2018 Amazon DynamoDB Advanced Design Pattern」 を見ると、以下のように説明されています。
スライドの説明はその後も続きますが、そもそも自分は勉強不足ということもあり、1 度読んだだけでは概念が理解できませんでした...。
自分の理解
RDBMS でのテーブルの例
例えば RDBMS (リレーショナルデータベース) で、以下のようなテーブルがあるとします。 みなさんにはあまり馴染みがないかもしれませんが、自分の興味か続くよう F1 ネタを例にしてみました。
カーナンバー (プライマリキー) | ドライバー名 | 国籍 | チーム | 初優勝年 |
44 | ルイス・ハミルトン | イギリス | メルセデス | 2007 |
5 | セバスチャン・ベッテル | ドイツ | フェラーリ | 2008 |
33 | マックス・フェルスタッペン | オランダ | レッドブル | 2016 |
RDBMS では、プライマリキーとなっている「カーナンバー」はもちろんのこと、インデックスを作成することにより「ドライバー名」や「国籍」「チーム」「初優勝年」を検索キーとして、検索することが可能です。
DynamoDB に そのまま作成した場合
RDBMS のテーブルを、そのまま DynamoDB に作成すると、以下のようになります。
カーナンバー (プライマリパーティションキー) | ドライバー名 | 国籍 | チーム | 初優勝年 |
44 | ルイス・ハミルトン | イギリス | メルセデス | 2007 |
5 | セバスチャン・ベッテル | ドイツ | フェラーリ | 2008 |
33 | マックス・フェルスタッペン | オランダ | レッドブル | 2016 |
DynamoDB の場合、パーティションキー または パーティションキー+ソートキー を検索キーとした場合のみ、検索が可能です。 したがって、このテーブルでは、「カーナンバー」を検索キーとして検索することしかできません。
「ドライバー名」で検索するには、以下のような GSI を定義する必要があります。
ドライバー名 (パーティションキー) | カーナンバー (ソートキー) | 国籍 | チーム | 初優勝年 |
ルイス・ハミルトン | 44 | イギリス | メルセデス | 2007 |
セバスチャン・ベッテル | 5 | ドイツ | フェラーリ | 2008 |
マックス・フェルスタッペン | 33 | オランダ | レッドブル | 2016 |
さらに、「国籍」で検索するには、以下のような GSI も必要になります。
国籍 (パーティションキー) | カーナンバー (ソートキー) | ドライバー名 | チーム | 初優勝年 |
イギリス | 44 | ルイス・ハミルトン | メルセデス | 2007 |
ドイツ | 5 | セバスチャン・ベッテル | フェラーリ | 2008 |
オランダ | 33 | マックス・フェルスタッペン | レッドブル | 2016 |
さらに、さらに、「チーム」で検索するには、以下のような GSI も必要になります。
チーム (パーティションキー) | カーナンバー (ソートキー) | ドライバー名 | 国籍 | 初優勝年 |
メルセデス | 44 | ルイス・ハミルトン | イギリス | 2007 |
フェラーリ | 5 | セバスチャン・ベッテル | ドイツ | 2008 |
レッドブル | 33 | マックス・フェルスタッペン | オランダ | 2016 |
さらに、さらに、さらに、「初優勝年」で検索するには、以下のような GSI も必要になります。
初優勝年 (パーティションキー) | カーナンバー (ソートキー) | ドライバー名 | 国籍 | チーム |
2007 | 44 | ルイス・ハミルトン | イギリス | メルセデス |
2008 | 5 | セバスチャン・ベッテル | ドイツ | フェラーリ |
2016 | 33 | マックス・フェルスタッペン | オランダ | レッドブル |
今回の例では、以上 4 つの GSI で済みましたが、より多くのカラムを持ったテーブルの場合、GSI の制限 (1 テーブルあたり 20 GSI の初期制限, 申請により緩和可能) を意識する必要があります。
また、各 GSI にはキャパシティユニットを割り当てる必要があるため、コスト的な面も気になります。
DynamoDB で GSI OVERLOADING を意識して作成した場合
GSI OVERLOADING を意識して RDBMS のテーブルを DynamDB に作成すると、以下のようになります。
横に並んでいた各カラムの内容を、1 つの「カラムA」内に縦に並べるイメージです。
カーナンバー (プライマリパーティションキー) | カラムA (プライマリソートキー) | カラムB |
44 | ドライバー名 | ルイス・ハミルトン |
44 | 国籍 | イギリス |
44 | チーム | メルセデス |
44 | 初優勝年 | 2007 |
5 | ドライバー名 | セバスチャン・ベッテル |
5 | 国籍 | ドイツ |
5 | チーム | フェラーリ |
5 | 初優勝年 | 2008 |
33 | ドライバー名 | マックス・フェルスタッペン |
33 | 国籍 | オランダ |
33 | チーム | レッドブル |
33 | 初優勝年 | 2016 |
この時点ではカーナンバー (+カラムA の内容) を検索キーとして検索できるだけです。
そこで、以下のような GSI を定義します。
カラムA (パーティションキー) | カラムB (ソートキー) | カーナンバー |
ドライバー名 | ルイス・ハミルトン | 44 |
国籍 | イギリス | 44 |
チーム | メルセデス | 44 |
初優勝年 | 2007 | 44 |
ドライバー名 | セバスチャン・ベッテル | 5 |
国籍 | ドイツ | 5 |
チーム | フェラーリ | 5 |
初優勝年 | 2008 | 5 |
ドライバー名 | マックス・フェルスタッペン | 33 |
国籍 | オランダ | 33 |
チーム | レッドブル | 33 |
初優勝年 | 2016 | 33 |
すると、テーブルのプライマリパーティションキー+プライマリソートキー, GSI のパーティションキー+ソートキー を使って、以下のような検索を行うことができます。
検索条件 | 使用するキー | 検索キー | 結果 |
特定のドライバー名 (ルイス・ハミルトン) の カーナンバーを検索 | GSI パーティションキー + GSI ソートキー | カラムA = 'ドライバー名' カラムB = 'ルイス・ハミルトン' | カーナンバー = 44 |
特定の国籍 (ドイツ) の ドライバーのカーナンバーを検索 | GSI パーティションキー + GSI ソートキー | カラムA = '国籍' カラムB = 'ドイツ' | カーナンバー = 5 |
特定のチーム (レッドブル) の ドライバーのカーナンバーを検索 | GSI パーティションキー + GSI ソートキー | カラムA = 'チーム' カラムB = 'レッドブル' | カーナンバー = 33 |
特定の初優勝年 (2007) の ドライバーのカーナンバーを検索 | GSI パーティションキー + GSI ソートキー | カラムA = '初優勝年' カラムB = '2007' | カーナンバー = 44 |
特定のカーナンバー (44) の ドライバー名を検索 | プライマリパーティションキー +プライマリソートキー | カーナンバー = 44 カラムA = 'ドライバー名' | カラムB = 'ルイス・ハミルトン' |
GSI を 1 つ定義しただけで「ドライバー名」「国籍」「チーム」「初優勝年」を検索キーとした検索を行うことが可能になりました。
まとめ
テーブル構造を工夫することにより、1 つの GSI で複数の検索要件を満たすことができる、というのが GSI OVERLOADING であると理解したつもりです。
テーブル構成が複雑になってしまうデメリットもありますが、テーブルあたりの GSI 数制限や、検索キーに応じて GSI を増やさなければならないといったことを回避できるというメリットがあります。
なお、GSI とは何ぞや? LSI (ローカルセカンダリインデックス) というものもあったよな? という方は、以下のブログが参考になりますのでご参照ください。