【ふくだ学習録】データベースエンジニア養成読本を読んで part4【4日目】

# ふくだ学習録とは？
ふくだが学習したことの備忘録。
目に見える形で残すことによってやる気を出す個人的な作戦です。
他人に見せるように書いているわけではないので、すごく読みにくいです。

# データベースエンジニア養成読本を読んで

### インピーダンスミスマッチとは？
データモデルの違いからくる、プログラミング工数の増加や効率性の悪化などの際に使われる言葉。
文脈的には、オブジェクト指向言語とリレーショナルデータベースとのギャップを示すことが多い。

詳しくは[インピーダンスミスマッチについて本気出して考えてみた - 酔いどれ設計ナイト2019](https://qiita.com/a-suenami/items/de7e3dc0ee91910c8b3d)を見たら分かりやすい。

### 集合論とは？
数学用語。
データベース界隈では、RDBの「データ構造」と「データ操作」の両方に深く関わってくる考え方。

↓これ超分かりやすかった！
[ITエンジニアの数学](http://itmath.blog60.fc2.com/blog-entry-3.html)

ざっくりは理解してたけど、この本読んでしっかりと復習しよ。
[https://www.amazon.co.jp/dp/4774171972](https://www.amazon.co.jp/dp/4774171972)

### 述語とは？述語論理とは？
SQLにおける述語とは、関数のこと。
さらに関数の中でも、入力項に対し、命題の真理値(true、false、unknown)を出力する特殊な関数のカテゴリのこと。
述語論理に関しては、端的に説明するのは難しいが、下記サイトがすごい分かりやすかった。神。

[SQLの中の述語論理](http://mickindex.sakura.ne.jp/database/db_sql_predicate.html)

### 階層型モデル、ネットワーク型モデルとは？
データモデルの種類。
リレーショナル型、階層型、ネットワーク型が、データモデル型の中でも主要な３種類。（現在はリレーショナル型が多くなっている。）

- 階層型 
木構造でデータを管理する。そのため「多対一」や「多対多」な関係性を示すとき、冗長になってしまう。
- ネットワーク型
それぞれのデータが網目のようにつながりあうような形でデータを管理する。そのためデータ構造を理解していないとデータにアクセスできないという、データ構造への強い依存性が発生してしまう。


[データベースと言ってもいろいろ、全部いえますか？](https://builder.japan.zdnet.com/db-sql/sp_07database/20356199/)

### NoSQLが普及してきている理由
RDBMSでは対応できないことが増えてきたから。
具体的には、インターネットの普及やCPUなどのハードウェアの進化、システムの複雑化などによって、データの管理/処理に必要な性能が高騰化し、RDBMSのみではまかないきれなくなった。

### ３Vとは？

- **Volume（データの量）**
- **Variety（データの種類）**
- **Velocity（データ発生/処理の頻度/速度）**

を意味する用語。
近年これらが高くなってきたので、それに対応するようにNoSQLが流行ってきた。

### RDBMSは必要なくなるのか？ 
答えは「NO」　理由は下記3点。

- そもそもの話、依然としてほとんどの領域の問題はRDBMSで対応可能な場合の方が多い。そのため現在使われているNoSQLは特定の問題に特化している場合が多く、汎用的に使えるものはまだあまりない
- NoSQLでは、RDBMSで対応できない問題を解決するために、RDBMSでは使える機能を犠牲にしている場合が多い
- まだ技術的に枯れていない場合が多いので、学習コストおよび管理コストが高い。

なので、「RDBMS vs NoSQL」といった考え方ではなく「RDBMS & NoSQL」といった考え方で進めていくことが重要。
※ただしいずれも2013年時点での考察のため、現時点では見解が違うかもしれない。

### NoSQLの分類
一口にNoSQLといっても様々なデータベースがある。
様々あるNoSQLだが、ある程度分類分けできる。

#### データ配置による分類
「格納されたデータが物理的にどのように配置されるか」といった視点での分類

- **スタンドアロン型**  

全てのデータがまとめて1つのノードに格納される方式。レプリケーションする場合は、全てのノードが同一データが入る。（データの分割は行われない）

- **分散マスタ型**  

複数のノードにデータが分割されて配置される。どこのノードにどういったデータが配置されたかを管理する特別なノードが存在する。

- **分散P2P型**  

複数のノードにデータが分割されて配置される。どこのノードにどういったデータが配置されたかは、各ノード自体が管理している。 

基本的には分散型が多いイメージ。理由は、V3のVolume問題に対して、単純にノードの追加をするだけで対応できるようになるから。

#### データの表現による分類
ユーザー側から見て、どういう形でデータを格納してどう取り出すのか、という点に着目した分類方法。

- **KVS（キーバリュー型）**
- **ドキュメント型**
- **カラムファミリー型**
- **グラフ型**

の主に4つがある。

#### KVS型
KVS型は、「キー」と「値」という形でデータを格納するもの。検索する場合は、キーに対して検索を行なって値を取り出す。
シンプルな作りなので、データを問い合わせてから取得できるまで（そういう待ち時間のことをレイテンシというらしい）が速いことが多い。

代表的なデータベースとしては、

- **memecached**

歴史のあるKVS。
メモリに全てのデータを乗せて、ハッシュテーブルで検索を行うため、単純なキーでのアクセスしかできず、データ保存できないが、その分非常に高速。
主な使用方法として、他のデータベースをバックエンドとして、キャッシュ層として用いることが多い。

- **TokyoTyrant/KyotoTycoon**

平林さんが開発したKVS。
memecachedと同様に、単純なキーバリュー型のモデル。
最大の特徴として、データを全てメモリ上に置いておく必要がなく、ディスクベースでの動作が可能。その分速さなどはmemecachedよりも劣るが、データの永続化が可能。

- **Redis**

オンメモリで動作するKVS。
単純な値だけでなく、リスト、ハッシュ、セットなどの構造化データをサポートしていて、それらを操作するAPIも提供されている。
memecachedでは実現できないような利用方法が可能。

- **Riak**

Basho Technologies社が開発しているKVS。
上気しているKVSとは異なり、データの分散配置をサポートしている。
分散のアーキテクチャとしては、Amazonが開発したDynameで使用されている「コンシステントハッシング」という手法を用いている。
この手法を用いることで、ノードが追加/削除されると、データの再配置をRiak側で行なってくれるので、容易にスケールアウトすることが可能になる。
分散もP2P型で行うので、単一障害点がなくて可用性が高い。（マスターノードが管理するわけではないので、障害に強い）

#### ドキュメント型データベース
ドキュメントという単位でデータを管理するデータベースのこと。
ドキュメントとはRDBMSでいうレコードに相当するもので、構造化された一連のデータのまとまり。
ドキュメントとRDBMSとのレコードとの違いは、ドキュメント構造を事前に定義しておく必要がないという点。

代表的なデータベースとしては、

- **MongoDB**

データの配置は分散マスタ型。

- **CouchDB**

データの配置はスタンドアロン型で、分散用ミドルウェアが別に存在している。

- **ArangoDB**

データの配置はスタンドアロン型で、分散昨日の実装はロードマップに含まれる。

各々の比較は
[CouchDBとMongoDBを比較してみた](http://blog.madoro.org/mn/35)
[ArangoDB ってのが面白いと思うんだ](http://pg-kura.hatenablog.com/entry/2018/04/22/203951)
を見れば分かりやすいが、細かいことは気にしたくないときは「とりあえずMongoDB！」って感じでも良さそう。（メジャーだから）

#### カラムファミリー型データベース（カラムナデータベース）
Googleが発表したBigTableをベースに作られたデータベース。
非常に多くのサーバに分類することを前提として設計されていることが特徴。

データモデルとしては、テーブルをベースにした構造で管理するが、複数の列をまとめたカラムファミリーという単位を取り入れている。
実際のデータは、行/カラムファミリー/列をキーとして、それらが辞書順にソートされたKVSのような形で保持されている。列に関しては事前に定義しなくてもいい。

上記の特性から、カラムファミリー型は下記の特徴をもつ。
**①非常に多くの列を扱うことができる**
**②多くの列について空になるような非定型的なデータを効率よく扱うことができる。**

列指向のRDBMSと混同されることが多いが、
カラムファミリー型は、行単位での入力検索を高速に行うこと（OLTP）が得意領域で、
RDBMSは、格納されたデータの集計や複雑な計算（OLAP）処理が得意。

代表的なデータベースとしては、

- **HBase**

分散マスタ型。

- **Cassandra**

分散P2P型。

それぞれの違いや使い方のプラクティスは[Cassandraとh baseの比較して入門するno sql](https://www.slideshare.net/yutuki/cassandrah-baseno-sql)を見るべし。分かりやすさが鬼でした。神。

#### グラフ型データベース
グラフ構造を備えたデータベースのことである。データの構造が従来のリレーショナルではなくネットワーク状になっている場合に、格納・検索の面で威力を発揮する。

[グラフデータベースとは何か　～ネットワーク状のデータ構造から瞬時に情報を検索するDBを解説](https://www.imagazine.co.jp/12805-2/)

ちなみにBlueprintsというライブラリがあり、これを用いると、実際に動作しているグラフ型データベースが何であるかにかかわらず共通のコードで操作できるようになる。

### その他のデータベース

#### アナリティカルデータベース

データの操作は、レコード単位の入力/検索を中心に行う**OLTP**と、格納されたデータの全体または大部分について複雑な問い合わせを行う**OLAP**に大きく分けられる。

この操作自体はMySQLとかPostgreSQlでも実行できるが、あまり高速には行えない。
なので、それにOLAP操作に特化したRDBMSが開発されていて、それらをアナリティカルデータベースと呼んでいる。

#### NewSQL
アナリティカルデータベースとは逆に、OLTPに特化したRDBMSも作られている。
それらのことをNewSQLと読んだりする。

#### Hadoop
SQLの実行エンジンをHadoop場で動かす流れが活発になっている。
ここ難しい…　誰か噛み砕いて教えて（泣）

下記記事が面白かった。理解度５０％ぐらいやけども…
[SQL on HadoopだったらDWHでよくね？](http://fj.hatenablog.jp/entry/2016/03/14/000527)

### MySQLのストレージエンジン
通常はInnoDBを用いる。場合によって（テーブルによって）MyISAMなどの別エンジンを使用することもできる。
ストレージエンジンの種類は下記。

- **InnoDB**

標準のストレージエンジン。
トランザクションセーフ、行単位のロック、外部キーのサポートなどといった特徴を持っている。

- **MyISAM**

古いバージョンのMySQLで標準だったストレージエンジン。

- **Memory(HEAP)**

メモリ上にデータを格納する。

- **Archive**

大量のデータをインデックスなしで格納する際に適している。

- **NDB**

MySQL Clusterで利用するストレージエンジン。
MySQL Clusterってインメモリデータベースでトランザクション処理もできるから最強やん！って初見感じたけど、使い方次第なんやね。勉強なる。
[MySQL Cluster Casual Talksメモ](https://b.l0g.jp/mysql/mysql-cluster-casual-talks-memo/)

### ミューテックスっとは？
排他処理をするための仕組み。
対象が「未使用（使用可能）」か「使用中（使用不可）」かを表すもの。
似たものでセマフォといったものもあるが、違いは下記サイトが分かりやすい。

[ミューテックス、セマフォ、条件変数、違いを整理してみよう](http://hiroakiuno.hatenablog.com/entry/20070321/p1)

### オプティマイザとは？
SQLを自動チューニングしてくれる機能のこと。

### Nested Loop Joinとは？
一方の表から1行ずつ行を取り出し，もう一方の表のそれぞれの行に突き合わせて，結合条件を満たす行を取り出す入れ子型のループ処理の結合方法。

[効率の悪いNESTED LOOPS JOINの対策](http://itdoc.hitachi.co.jp/manuals/3020/3020647000/W4700022.HTM)

### MySQL Cluster CGEとは？
MySQLの商用エディション。（非商用のMySQL Clusterもある）
マスタとスレーブにデータベースを分ける際などに使用することがある。

### MySQL Workbenchとは？
データベースエンジニアが使用するいくつかの機能を提供してくれている。
例えばビジュアルデータモニタリングや、ユーザーの作成機能など。

### TCOとは？
Total Cost of Ownershipの略。
コンピューターシステム構築の際にかかるハード・ソフトの導入費用から、運用後の維持費・管理費・人件費など全てを含む、システムの総所有コストを意味する。

### マルチコアCPUとは？
CPU効率を上げるためのもの。
CPU効率はクロック数を上げることでも向上するが、クロック数の向上には限界がある。
そのため、擬似的、または物理的にコア数を増やすことによる分散処理で、処理能力を向上させようという考え方が主流になった。
つまりマルチコアCPUは、コア数が複数個あるCPUのこと。

### pg_stantsinfoとは？
PostgreSQLの拡張ツールの１つ。データベースの監視のために使用される。
PostgreSQLサーバに関して、定期的に統計情報を収集するツール。

### ストアドプロシージャとは？
DB上での一連処理に, 名前をつけて関数のように, 呼び出して使用できるもの。
戻り値などは存在しないもの。

### hstoreとは？
PostgreSQLで、KVS形式でデータを扱うための拡張。

### MADlibとは？
PostgreSQLの内部で、統計やデータマイニングの処理を行うための拡張。

### RDBMSの強み
**「トランザクション処理」**と**「SQL」**
データの整合性やSQLによる操作の容易性が最大の強み。

### MongoDBのシャーディング
MongoDBでシャーディングを行う際は、フィールドを1つ選択する必要がある。
この選択したフィールドのことを「シャードキー」と呼ぶ。このシャードキーになっているフィールドの値の数だけ分割できるようになるため、値の数が少ないフィールドはシャードキーに適さない。
（例えば「性別」のフィールドをシャードキーにすると、男か女の2つしか値がないため、最大でシャーディングするとしても2つまでしか分けれなくなってしまう）

最適なシャードキーの条件は

- **値が単調に増加しないこと**
- **値のバリエーションが多いこと**
- **ほぼ全てのクエリに利用でき、それらのクエリが適当に分散すること**

### 複合インデックスとは？
複数の並び替え条件でインデックスを作ること。
下記サイトがすごい分かりやすかった！

[DBのインデックスと複合インデックス](https://qiita.com/towtow/items/4089dad004b7c25985e3)

### キャップトコレクションとは？
最初にデータサイズとドキュメント数を決めてしまい、それを超過した場合は古いデータから削除されていくコレクションのこと。

### Oplogとは？
レプリカセットに対する更新内容を保存するキャップトコレクションのこと。
セカンダリノードがプライマリノードとすぐに同期するために、セカンダリノードはごく短い間隔でプライマリノードのOplogを参照している。

### MongoDBを活用するためのポイント

#### Oplogに十分なサイズを確保する
障害などで、セカンダリノードを一時的にシャットダウンし、長期間同期が行われなかった場合、Oplogを元に復旧作業を行うことになるが、Oplog内容が不十分だった場合、更新データだけの差分同期ができなくなってしまい、データ全体の同期が必要になってしまう。そうすると非常に大きな負荷がかかってしまうので、Oplogは十分な容量確保しておかなくてはならない。

#### ドキュメントの再配置を起こさない
MongoDBを運用する際の、最大の留意点。これ次第でデータベース全体の性能が4〜8倍変わるとのこと。
MongoDBでは、ドキュメントを更新（拡大）する際、削除処理と新規追加処理が行われる。
（元データ領域は空白になり、最後尾に更新された情報が追加されるイメージ）

paddingFactorという、ドキュメントを追加する際にあらかじめ余分の保存領域を確保するために用いられる係数があるが、これを常に１にするように運用しなくてはならない。
(paddingFactorが2になってしまっていたら、格納するデータの２倍分データベースを使用することになってしまう)

#### ヒューマンエラー対策

MongoDBでは、レプリカセットの冗長性は堅牢になっている。
しかしもちろんヒューマンエラーでデータが全消去されることなども、起こり得てしまう。
そういった際には、レプリカセットに下記のような設定を対策として行なっておく、

- **隠しメンバー**

レプリカセットの構成時に「hidden:true」と指定すると、そのノードはクライアントから見れなくなる。
そのため重いバックアップ処理なども行えるようになるため、サービスに影響を与えずにバックアップ処理できる。

- **遅延メンバー**

頻繁にバックアップを行うようにしても、一日２〜3回程度が限界になりがち。
そのバックアップの間にヒューマンエラーが起こってしまうと、数時間分のデータを失ってしまうことになる。
その対策として、MongoDBはあえてセカンダリノードの同期を遅らせる設定ができるようになっている。
例えば5分後に同期するように設定しておけば、プライマリサーバで何か障害が発生しても、5分後までそのセカンダリサーバは同期されない（データを保持し続ける）ので、最悪5分までのデータ欠損で済む。

#### ドキュメントの存在チェック
ドキュメントの存在チェックする場合は、findOne()関数ではなく、find()関数を使用するようにする。
findOn関数はデータを返すが、find()関数が返却するのはカーソルのため、データにアクセスしなくて早い。
（性能は２桁以上変わるらしい）

### スワップ領域とは？
使っていないメモリの内容を一時的にしまっておくための場所。

[スワップ領域とは？](https://wa3.i-3-i.info/word1721.html)

### Redisでのデータ永続化方法

- **データベーススナップショット**

メモリ上のデータベースのダンプをファイルとして保存する機能。
スナップショットを取得するタイミングは「N時間あたりにM回以上の変更があったら」といった条件で指定できる。

- **追記ログ**

Redisに対するコマンドを逐次ファイルに保存していく機能。

どちらのオプションもメリットデメリットがあるので、ケースバイケースで使い分けるべき。

### Scored Set型
スコアによる順位づけされたSet型。値の重複は許容しないが、スコアの重複は許容する。
下記サイトで書いてるけど、リアルタイムランキング機能などが作りやすそう。

[今更Redisのsorted set を知ってリアルタイムランキングの実装が超楽だった件](https://qiita.com/niisan-tokyo/items/170ef3ac47ee39cfb46c)

### Redisをキャッシュサーバーとして使用する際の注意点
「必ずデータに有効期限を記載する」こと。
Redisuでは単純にデータを格納すると、有効期限が設定されない。
そのため、キャッシュのようにデータが無尽蔵に増えるような場合は、有効期限を設定しないとメモリが足りなくなってしまう。

### Redisの使いどころ
下記のような機能を作る際にいい感じ。

#### リアルタイムランキング
これまでは一定時間ごとにパッチ処理でランキングを更新するのが一般的だった。
しかしRedisのScored Set型を使用することで、非常に簡単にランキング機能を作れる。
[今更Redisのsorted set を知ってリアルタイムランキングの実装が超楽だった件](https://qiita.com/niisan-tokyo/items/170ef3ac47ee39cfb46c)

#### アクティブユーザの集計
RedisのSet型を利用すれば簡単に実装できる。
例えばログインのタイミングで、日付をキー、ユーザーIDを値にして、Setに追加する。
これによって日付ごとにアクティブユーザの集合が蓄積されるので、集合操作関数を利用すれば色々なデータを取得できる。

#### ジョブキュー
List型の「BLPOP」というコマンドを用いて実装する。
詳細は下記サイトをみる。

[Redisをジョブキューとして使う](https://hiroe-orz17.hatenadiary.org/entry/20120814/1344963552)

#### 排他処理
Redisのsetnxを利用すると、排他処理の実装できる。

[Redisのsetnxを使ってマルチサーバ環境での Web API ロック機構を実現する](https://dev.classmethod.jp/server-side/redis-lock/)

### Fluentdとは？
データのやりとりを管理するソフトウェア

### クォーラムとは？
過半数ノードによる多数決。データの複製に一貫性を持たせるために使用される概念。
詳しくは下記サイトがわかりやすかった。(とはいえ数式が死ぬほど出てくるので、また今度ちゃんと時間をとって読み解く)

[最近よく聞くQuorumは過半数(多数決)よりも一般的でパワフルな概念だった](https://qiita.com/everpeace/items/632831371da5ff215995)

### ベクトルタイムスタンプとは？
整合性保証するための考え方。（おそらくベクタークロックと同意義）
下のサイトがすごいわかりやすかった！神！（あとビジュアライズえぐすごい）

[分散データベースで因果一貫性を担保するための仕組み「ベクトルタイムスタンプ」がエモい](https://qiita.com/Sadalsuud/items/571b7a07215c4476755b)

### DHTとは？
分散ハッシュテーブル (Distributed Hash Table, DHT) のこと。
ハッシュテーブルを複数のピア（おそらくノードと同意義）で管理する技術のこと。
ハッシュテーブルの説明は下記がわかりやすかった。

[ハッシュテーブル(Hash Table)を簡単に理解しよう](https://qiita.com/tenten1010/items/da4084f937ad07e70164)

### Riakの特徴
Riakの他のNoSQLとの違いは

- **高可用性**

多少のハードウェアやネットワーク故障で停止することなく、どんなときも書き込み読み出しが可能。

- **高信頼性**

多少の不可でもシステムは安定したレスポンスとスループットを提供する。

- **拡張性**

データ量や負荷に応じて、無停止でシステムをスケールアウトできる。

- **低遅延**

どんなときも、ユーザーをまたせずにすぐにレスポンスが得られる。

- **予測可能性**

性能予測を裏切らない。安定したスケールアウト性。

こうやって特徴書いてたら、やっぱりAmazonga作ったデータベースやなってイメージ。

# 今日の一言
ベローチェの黒糖カフェオレ美味しい！
あとはデータベース専門家はかなり厳しいなといった所感を得た。
「専門家ではないけど、どういったデータベースを使用するかの判断基準は最低限ある」ところまで勉強するのが一番良さそうかな？（自分自身のキャリアとか価値を考えるなら）