view databases.tex @ 26:4365c210d1cb

commit
author tatsuki
date Sun, 12 Feb 2017 01:51:51 +0900
parents 8d1f5ab7b420
children
line wrap: on
line source

%もう少し詳しく書く
\chapter{既存のデータベース}
本章では、既存のデータベースの例として、PostgreSQL・MongoDB・Cassandra・当研究室で開発しているJungle について記述する。

\section{PostgreSQL}
PostgreSQLは、列と行からなる2次元のテーブルにより実装されるデータベースである。
厳密な型を持つデータベースであり、きちんと設計を行えば、柔軟なクエリを用いてどんな検索にも対応できる力を持つ。

データベースへのアクセスは、SQLを用いて行う。
データの格納を行う際は、まずテーブルのデータの型と・制約を定義する。
テーブルの定義は{\tt CREATE TABLE}文を用いて行う。
ソースコード\ref{createTablePSQL}に{\tt int}型の{\tt id}と{\tt TEXT}型の{\tt name}を持つテーブル{\tt person}を作成するサンプルコードを記述する。

\begin{lstlisting}[frame=lrbt,numbers=left,label=createTablePSQL,caption=テーブルの作成]
create table person(id int,name TEXT);
\end{lstlisting}

%制約というのは、テーブルに値を入れる際に守らなければならない条件のことである。
%値の重複を許さない行を特定する際に用いる{\tt PRIMARY KEY}などがある。
%また、テーブル同士は{\tt PRIMARY KEY}を用いて参照を行うことが可能である。


テーブルへのデータの格納は、Insert文を用いて行う。
ソースコード\ref{insertPSQL}に、{\tt id}が{3}、{\tt name}が{kanagawa}の値を格納するサンプルコードを記述する。

\begin{lstlisting}[frame=lrbt,numbers=left,label=insertPSQL,caption=データの挿入]
insert into person(id,name) values(3,'kanagawa');
\end{lstlisting}

テーブルにデータを格納する際にはスキーマの定義に沿ってなければならない。
もし、スキーマに反するデータを格納した場合
エラーが発生しデータの格納に失敗する。



テーブルへのデータの検索は、select文を用いて行う。
select文では、表示するデータの指定などが行える。
ソースコード\ref{selectPSQL}に、テーブル{\tt person}から{\tt name}が{\tt kanagawa}のデータのidを取得するコードを記述する。
\begin{lstlisting}[frame=lrbt,numbers=left,label=selectPSQL,caption=データの検索]
select id from person where name='kanagawa';
\end{lstlisting}


PostgreSQLでは、Json形式をJson・JsonBという型を用いて格納する。
Json型は、Jsonデータを文字列で格納し、JsonBはバイナリで格納する。
Json型で格納した場合、データにアクセスするたびにパースする必要がある。
%JsonのIndex を張ることが可能になっている。
% Jsonデータのアップデートは、Jsonの大きさnに対してO(n)になってしまう。




\section{MongoDB}
MongoDB\cite{mongoDBDoc} は2009年に公開された NoSQL のデータベースである。
JSON フォーマットのドキュメントデータベースであり、スキーマレスと呼ばれる。

MongoDBでは、テーブルの代わりにコレクションにデータを保持する。
スキーマが無いため、事前にデータの定義を行う必要がなく、同じコレクションであっても、他のドキュメントが持っていないフィルドやデータ型をドキュメントに含めることができる。
そのためリレーショナルデータベースに比べてデータの追加・削除が行いやすい。
コレクションへのデータの格納は、{\tt insert()}を用いて行う。
ソースコード\ref{insertMongo}に、{\tt id}が{\tt 5}、{\tt name}が{\tt kanagawa}のデータをコレクション{\tt person}に挿入するサンプルコードを記述する。

\begin{lstlisting}[frame=lrbt,numbers=left,label=insertMongo,caption=データの検索]
db.person.insert({id:5,name:"kanagawa"});
\end{lstlisting}

また、Json形式のデータは任意の深さまでネストすることが可能である。


作成したコレクションからのデータの取得は、{\tt find}を用いて行う。
ソースコード\ref{findMongo}に、{\tt id}が{\tt 5}のユーザーの{\tt name}を取得するサンプルコードを記述する。

\begin{lstlisting}[frame=lrbt,numbers=left,label=findMongo,caption=データの検索]
db.person.find({id:5},{name:1});
\end{lstlisting}

findに引数を渡さなかった場合、コレクションの中身が全て表示される。

MongDBは、あらゆる箇所でJavaScriptを用いており、前述した{\tt insert()}・{\tt find()}といった関数もJavaScriptで実装されている。
dbですらJavaScriptのオブジェクトである。
findで使用するクエリもJavaScriptで記述できる。


MongoDBは実装にmmapを使用しているため、トランザクションを安全に行うことが難しい。
そのためデータの喪失などが発生することが知られている。





\section{Cassandra}
Cassandraは2008年7月にFacebookによって開発された Key-Value なデータベースである。
Cassandraは、分散環境下では複数のノードにデータのレプリカを置くことで、データの信頼性を確保する。
いくつのノードにレプリカを置くかはレプリケーション係数を指定することで決定する。
またノードの集合をデータセンターとして管理している。

Cassandraはデータを
{\tt [KeySpace][ColumnFamily][Key][Column]}\\
の4次元の連想配列で持つ。
データを格納する場合初めにKeySpaceを構築する。
KeySpaceを作る際は、データセンターの設定とレプリケーション係数の設定を同時に行う。
ソースコード\ref{createKeySpace}に単一のデータセンターにレプリケーションを一つしか持たないKeySpaceである{\tt testKeySpace}を作成するサンプルコードを記述する。



\begin{lstlisting}[frame=lrbt,numbers=left,label=createKeySpace,caption=KeySpaceの作成]
create keyspace testKeySpace with replication = {'class':'SimpleStrategy', 'replication_factor':1};
\end{lstlisting}

KeySpaceは、PostgreSQLでいうところのデータベースに近い働きをする。

次は、作成した KeySpace に対してColumnFamily を構築する。
ColumnSpaceは、RDBでいうテーブルに似た働きをする。
ソースコード\ref{createColumnFamily}に、{\tt int}型の{\tt id}と{\tt text}型の{name}を持つColumnSpaceを作成するサンプルコードを記述する。

\begin{lstlisting}[frame=lrbt,numbers=left,label=createColumnFamily,caption=ColumnFamilyの作成]
create table person (id int PRIMARY KEY, name text);
\end{lstlisting}


また、ColumnSpaceの定義を行う際最低1つKeyに値を特定するためのPRIMARY KEY を指定する必要がある。

作成したColumnFamily への値の挿入は、insert文を用いて行う。
ソースコード\ref{insertCassandra}に、{\tt id}が{1}、{\tt name}が{\tt kanagawa}のデータを挿入するサンプルコードを記述する。

\begin{lstlisting}[frame=lrbt,numbers=left,label=insertCassandra,caption=ColumnFamilyの作成]
insert into person(id,name) values(1,'kanagawa');
\end{lstlisting}

作成した ColumnFamily からのデータの取得は、select文を用いて行う。
ソースコード\ref{findCas}に、{\tt id}が{\tt 1}のユーザーの{\tt name}を取得するサンプルコードを記述する。

\begin{lstlisting}[frame=lrbt,numbers=left,label=findCas,caption=ColumnFamilyの作成]
 select name from person where id = 1;
\end{lstlisting}


Cassandraはデータの読み書きをいくつのノードに行うかをConsistteency Levelで設定する。
Consistency Levelは主に、ONE、QUORAM、ALLがある。
データの複製であるレプリケーションの数をNとした場合、ONEは1つのノード、QUERUMはN/2 + 1のノード、ALLはNのノードへと読み書きを行う。
CassandraはConsistency Levelを変えることで、最新のデータを取得するかどうかを決めることができる。
しかし、最新のデータを取得するために、Consistency LevelをQUERUMやALLに変えた場合、データの読み書き時に問い合わせるノードが増えるため速度は落ちてしまう問題もある。



\section{非破壊的木構造データベースJungle}
Jungleは、当研究室で開発を行っているデータベースで、Javaを用いて実装されている。
Jungleは名前付きの複数の木の集合からなり、木は複数のノードの集合で出来ている。
ノードは自身の子のリストと属性名と属性値の組でデータを持ち、データベースのレコードに相当する。
通常のレコードと異なるのは、ノードに子供となる複数のノードが付くところである。
Jungleでは、親から子への片方向の参照しか持たない。

通常のRDBと異なり、Jungleは木構造をそのまま読み込むことができる。例えば、XMLやJsonで記述された構造を、データベースを設計することなく読み込むことが可能である。
また、この木を、そのままデータベースとして使用することも可能である。しかし、木の変更の手間は木の構造に依存する。
特に非破壊木構造を採用しているJungleでは、木構造の変更の手間はO(1)からO(n)となりえる。つまり、アプリケーションに合わせて木を設計しない限り、
十分な性能を出すことはできない。逆に、正しい木の設計を行えば高速な処理が可能である。

Jungleは基本的にon memoryで使用することを考えており、一度、木のルートを取得すれば、その上で木構造として自由にアクセスして良い。
Jungleは分散データベースを構成するように設計されており、分散ノード間の通信は木の変更のログを交換することによって行われる。
持続性のある分散ノードを用いることでJungleの持続性を保証することができる。
詳しいAPIについては次章で記述する。