Cassandraテーブル設計の注意点
テーブル設計の考慮点をそこはかとなくまとめていく...
機能的なこと
・( RDBがSQLで提供するような )テーブル項目間の結合機能を提供してないことを踏まえる必要
⇒複数テーブルのデータの結合が必要な場合、以下のように対応する。
・クライアント側で複数テーブルから読み取りを行って、アプリケーション側で結合を行う。
・結合結果に対応する非正規化されたテーブルを作成する
※複数テーブルを読み取ってアプリケーション側で対応するのは面倒だし、処理中に問題が起こるとよろしくないし、性能的な問題もあるので、非正規化で対応できるのならそれにこしたことはないかな...。
・where句で指定可能なcolumnはprimary keyないしsecondary indexで指定されたcolumnのみ
・クエリで使用可能なソートは、CREATE TABLEコマンドで指定したclustering keyの選択によるのみ
( SELECTステートメントはORDER BYをサポートするが、clustering keyで指定されている順序に限定
RDBのような任意のソートはできない。)
・clustering keyのcolumn内容でpartition keyのcolumn項目を「逆引き」することはできない。
⇒逆引き用のlookupテーブルを用意するとか。
・primary keyが一意であること。
Cassandraは常にupsertなので、偶然同一key値となった場合、エラーなく上書きされてしまうので気をつけないといけない。
※軽量トランザクションを使えば回避できるけど、それはオーバヘッド大。
性能的なこと
・テーブル正規化 (非正規化) について、分散DBとしての特性考慮が必要
・分散DBであり、joinもサポートしないので、読み取りについてはRDBより正規化の短所の面が強く出る。
⇒ 発行するクエリに対応するスキーマとすることで、複数回読み込みを回避
RDB: データモデル化 → クエリ作成
Cassandra: クエリパスモデル化 → モデルをサポートするテーブル設計
・データを各ノードに均等に分散できるようなpartition keyになっていることが望ましい。
・単一partitionにread/write が大量に発生すると、ノードの負荷に偏りが発生する。
・巨大なpartitionを作らない。
・clustering keyで行をrowを追加する構造だと、partitionがどんどん成長する可能性がある。
partiton内のcolumn(セル)の上限は2B(20億個)だが、100MB以下が推奨
・partitonが大きくなりすぎると、repair、ストリーミング、読み取りのパフォーマンスに問題が生じる可能性
・I/Oパターン(読み取り/書き込み) により、Compaction Strategyの使い分け考慮でテーブルを分割する。
( Compaction StrategyはSStableごと = テーブルごとの設定なので )
・secondary indexについて、cardinalityが極端に高いcolumnへの適用は効率が悪い。
secondary indexの検索は全ノードに対し実施するが、
cardinalityが高く、例えば1partitionのみ取得(ほとんどのノードでは対象検出しない)となると、効率悪い。
・secondary indexについて、cardinalityが低いと、大量の応答結果が生成される可能性があるので注意。
・secondary indexの効率悪い場合は、lookupテーブルの利用を検討
※ただし、テーブル間の参照整合性メカニズムを用意しないので、整合性の問題が出ないか考慮