DBまとめ
DB
まずは概要面に触れてなんとなく知る,くらいでOKです.
PostgreSQLの環境構築
SQLiteの仕組みとRDBMSとの違い
RDBMS(リレーショナルデータベースマネジメントシステム)はデータベースの機能を提供するソフトウェア
(PostgreSQLやMySQLなど)。処理はサーバマシンで行い、データベースを利用したい各ソフトウェアはクライアントとして接続するという方式。一方でSQLiteは組み込み型。ライブラリの形で提供され、ソフトウェアなどに内蔵される。
RDBとNoSQLの違い
NoSQLは読んで字の如く「SQLを使わない」。SQLとはリレーショナルデータベースを操作する言語のこと。
RDBは複雑なデータの関連性を扱えるようにしているデータベース。
それぞれのデータベースの違いをCAP定理に基づいて説明します。CAP定理とは、Consistency(一貫性)、Availability(可用性)、Partition-tolerance(ネットワーク分断性)の3つの要素からなり、ノード間でデータを複製した場合、この3要素を同時に保証することはできないと言われている考え方です。
リレーショナルデータベースの場合、C(一貫性)とA(可用性)が保証されます。P(ネットワーク分断耐性)がないために、ネットワーク上に分散したシステム全体で一つのデータベースを構成するには向いていません。
ネットワーク遅延や切断があると、データが保証されなくなってしまう形です。トランザクションを張ってから更新するのが一般的なため、何らかの分断があった場合、元に戻すことはできますが、データは更新されません。基本的にリレーショナルデータベースは単一のデータベースサーバとして運用されることが想定されています。
NoSQLデータベースの場合、データベース管理システムによって異なりますが、多くの形がP(ネットワーク分断耐性)を重視します。そのためCAP定理の組み合わせとしてはCとP(一貫性と分断耐性)またはAとP(可用性と分断耐性)を重視するものに分かれます。一部リレーショナルデータベース同様にCとAを重視するものもあります。
CとPを重視する形では、分散したデータベースを利用しつつも整合性が保持されます。分散している状態にもかかわらず、一貫性を保とうとするので、データの複製中はデータを使うことができません。データが使えないタイミングが発生することを想定したプログラムを組む必要がりあります。
AとPを重視する形では、データはいつでもアクセス可能な状態となり、単一障害点を発生させません。ただし、通信エラーやノードの故障によって、ノード間の一貫性が失われるケースが発生してしまいます。それを想定したサービスや、不整合を起こしたままでも処理を進めていくような設計方式が求められます。
ORM概要
ORMはObject-Relational Mappingの頭文字をとったもの。
オブジェクトと関係(関係データベース、RDB)とのマッピング(対応づけ)を行うもの。
多くのプログラミング言語はオブジェクトを扱うので、そのオブジェクトをRDBに保存できるように、対応付けを簡単にするためORMを使います。
もっと簡単にいうと、SQLを直接書くことなく、オブジェクトのメソッドでDB操作ができる、ということです。例えば、createメソッドで新規作成を行ったり、destroyメソッドで削除する、といった感じです。
これだけでは寂しい
メソッド名 | 内容 | 例 | SQL |
---|---|---|---|
find | 与えられたどのオプションにもマッチする「主キー」に対応するオブジェクトを取り出せます。 | Customer.find(10) | SELECT * FROM customers WHERE (customers.id = 10) LIMIT 1 |
複数のオブジェクトへのクエリを作成することもできます。これを行うには、findメソッドの呼び出し時に主キーの配列を渡します。これにより、指定の「主キー」にマッチするレコードをすべて含む配列が返されます。以下に例を示します。 | Customer.find([1, 10]) | SELECT * FROM customers WHERE (customers.id IN (1,10)) | |
take | レコードを1件取り出します。どのレコードが取り出されるかは指定されません。 | Customer.take | SELECT * FROM customers LIMIT 1 |
first | 主キー順の最初のレコードを取り出します。 | Customer.first | SELECT * FROM customers ORDER BY customers.id ASC LIMIT 1 |
orderを使って順序を変更したコレクションの場合、firstメソッドはorderで指定された属性に従って最初のレコードを返します。 | Customer.order(:first_name).first | SELECT * FROM customers ORDER BY customers.first_name ASC LIMIT 1 | |
last | 主キーの順序に従って最後のレコードを返します。 | Customer.last | SELECT * FROM customers ORDER BY customers.id DESC LIMIT 1 |
orderを使って順序を変更したコレクションの場合、lastメソッドはorderで指定された属性に従って最後のレコードを返します。 | Customer.order(:first_name).last | SELECT * FROM customers ORDER BY customers.first_name DESC LIMIT 1 | |
find_by | 与えられた条件にマッチするレコードのうち最初のレコードだけを返します | Customer.find_by first_name: 'Lifo' | SELECT * FROM customers WHERE (customers.first_name = 'Lifo') LIMIT 1 |
等値条件 | Book.where(out_of_print: true) | SELECT * FROM books WHERE (books.out_of_print = 1) | |
範囲条件 | Book.where(created_at: (Time.now.midnight - 1.day)..Time.now.midnight) | SELECT * FROM books WHERE (books.created_at BETWEEN '2008-12-21 00:00:00' AND '2008-12-22 00:00:00') | |
サブセット条件 | Customer.where(orders_count: [1,3,5]) | SELECT * FROM customers WHERE (customers.orders_count IN (1,3,5)) | |
NOT条件 | Customer.where.not(orders_count: [1,3,5]) | SELECT * FROM customers WHERE (customers.orders_count NOT IN (1,3,5)) | |
OR条件 | Customer.where(last_name: 'Smith').or(Customer.where(orders_count: [1,3,5])) | SELECT * FROM customers WHERE (customers.last_name = 'Smith' OR customers.orders_count IN (1,3,5)) | |
AND条件 | Customer.where(last_name: 'Smith').where(orders_count: [1,3,5])) | SELECT * FROM customers WHERE customers.last_name = 'Smith' AND customers.orders_count IN (1,3,5) |
インデックスの役割と活用
もうココらへんは深く理解するにはB-tree+などアルゴリズム側の理解が必要なので「なぜ使うのか」「どう使うのか」だけ覚えればオッケーです.
インデックスとは
テーブルのある行へのアクセスを集合住宅での荷物の配達に例えると、インデックスの有無は以下のように表現することができます。
- インデックス無 集合住宅を歩き回り、各戸の表札を見て配達先かどうか確かめる
- インデックス有 住民の情報が書かれた見取り図で配達先を確認して向かう
インデックスの効果は以下のような特徴を持つ表で特に現れやすいです。
- 行数が多い
- 検索対象の項目に値の重複、偏りが少ない
- 表の更新・追加・削除が少ない
一方以下のような表では効果が現れにくくなります。
- 行数が少ない
- 表のほとんどの行を取得する
先のように配達に例えると、数戸しかない集合住宅の場合やほとんどの部屋に届ける荷物がある場合はかたっぱしから回っても構わないということですね。
データベースはインデックスを使用するかどうかの判断を自動で行っています。より効率的だと判断された場合にはインデックスが使用されます。
インデックスの設計
インデックスは以下のような列に設定すると、効果を得やすいです。
- SQLの検索条件で頻出する列や、結合条件に指定されている列
- テーブル内の全データの量に対して、取得対象のデータが少ない列
- Bツリーインデックスの場合はカーディナリティが高い列(格納されている値の種類が多い列)、ビットマップインデックスの場合はカーディナリティが低い列
人のプロフィールを管理するテーブルの場合、血液型はA、B、O、ABのいずれかになるためカーディナリティが低く、逆に身長や体重といった情報は人によりばらつきが大きいためカーディナリティが高いです。
複数の列から成るインデックス(複合インデックス)を作成する場合は順序も重要です。
より対象のレコードを絞り込める列を先に配置することで、検索が効率的になります。
つまり、値の重なりが少ない(カーディナリティが高い)列を先にするとよいでしょう。
またSQL文の評価順序を意識し、より先に評価される列を先にしたほうが効果的です。
SQLの評価順序は以下です。
FROM→JOIN→WHERE→GROUP BY→HAVING→SELECT→ORDER BY→LIMIT
たとえばWHERE句とORDER BY句を条件に持つSQLで使用するインデックスを作成する場合、WHERE句で使われている列を先にしましょう。
インデックスへのアクセスのみで目的のデータを取得することができれば、より検索が効率的になります。取得対象の列のデータをすべて含むインデックスを「カバリングインデックス」といいます。
外部キー制約の役割と活用
外部キーとは、リレーショナルデータベース(RDB)で、テーブルのある列に、別のテーブルの特定の列に含まれる項目しか入力できないようにする制約。また、その際に指定する列。標準のSQLではFOREIGN KEY句を用いて設定できる。
Railsを使っていると生のSQLを使う機会は,小規模開発をしている限り非常に少ないですが,テーブル結合などRails側が提供する概念でも難しいところがあります.それらをしっかり理解するためにもORマッパー(ORM)に頼らない基礎知識を入れておくことは非常に重要です.
基本的なSQLの文法
飛ばす
さまざまなテーブル結合
-
内部結合
内部結合とは、リレーショナルデータベースのテーブルを連結する操作の一つで、二つのテーブルからそれぞれ特定のフィールドを指定し、両者の値が一致するレコード同士を連結するもの。SQL文ではSELECT文のINNER JOIN句で指定する。 -
外部結合
外部結合とは、リレーショナルデータベースのテーブルを連結する操作の一つで、二つのテーブルからそれぞれ特定のフィールドを指定し、両者の値が一致するレコード同士は連結し、一致するものが存在しないレコードはそのまま抽出するもの。SQL文ではSELECT文のOUTER JOIN句で指定する。SQL文中で左側(前方)で指名されたテーブルの行は一致する相手がいなくてもすべて抽出する方式を「左外部結合」(LEFT OUTER JOIN)、右側(後方)で指名されたテーブルの行をすべて抽出する方式を「右外部結合」(RIGHT OUTER JOIN)という。
Redisの活用
ジョブのキューイングという概念をしっかり掴みましょう.その上でRedisなどの揮発性DBの特性を掴むと良いでしょう.
実際,PostgreSQLを代わりに使うこともできます.
省略
DBのdumpと復元
とりあえずdumpと復元