Rails関連用語
DSL(ドメイン駆動言語)
ドメイン特化言語(DSL:Domain Specific Language)とは、 ある特定の種類の問題に特化したコンピュータ言語のことである。様々な問題に対応できる汎用的な言語ではない。
IDE
統合開発環境(とうごうかいはつかんきょう)、IDE (Integrated Development Environment) は、従来、コンパイラ、テキストエディタ、デバッガなどがばらばらで利用していたものをひとつの対話型操作環境(多くはGUI)から利用できるようにしたものを指す。
Bundler
BundlerとはRubyのライブラリ管理ツールのことを指す。gem同士の互換性を保ちながらパッケージの種類やバージョンを管理できる。
gem
Rubyで使われるライブラリやアプリケーションはGemと呼ばれる形式のパッケージにすることができる。多くのライブラリがGem形式でパッケージされ公開されており、これらはRubyGemsと呼ばれるパッケージ管理ツールを使ってダウンロードを行なったりインストールすることができる。これらのパッケージのことを単にGemとかGemパッケージなどと呼ぶ。
sqlite
サーバとしてではなくアプリケーションに組み込んで利用される軽量のデータベースである。 一般的なRDBMSに比べて大規模な仕事には不向きだが、中小規模ならば速度に遜色はない。 また、APIは単純にライブラリを呼び出すだけであり、データの保存に単一のファイルのみを使用することが特徴である。
Rack
Rackは、指定したファイルを独自のRuby DSLとして読み込み、DSLで指定した様々なミドルウェア、アプリケーションを組み合わせてWebサーバを立ち上げることができるrackupというコマンドを提供するライブラリである。
sass
SassはCSSのプリプロセッサーとしてつくられた。Sassで記述することで、CSSに変数や演算、関数や制御構文などが追加され、効率的に記述できるようになった。SassをコンパイルしてCSSに変換すれば、普通のCSSとしてブラウザが認識してくれる。
scss
Scssとは「Sassy CSS(生意気なCSS??)」の略 。上記のSassの機能をCSS3(Media Queries等含む)文法と互換性がある形で再実装したもの。CSSと書き方が似ているため、マークアップエンジニアには導入しやすい。
プリプロセッサー
プリプロセッサ (英: preprocessor) とは、一般にある処理を行うソフトウェアに対して、データ入力やデータ整形などの準備的な処理を行うソフトウェアのことである。
コンパイル処理において、プリプロセッサ (preprocessor) とは、コンパイラがソースコードをコンパイルする前に、一旦ソースコードに前処理を施すためのプログラムである。
uglifier
uglifierとは、UglifyJS2 という JavaScript のコード軽量化ライブラリを、Ruby で簡単に使えるようにしたgemである。
coffee script
JavaScriptのコードを生成するためのコンパクトなrubyライクなスクリプト言語である。
turbolinks
turbolinksとは、ページ遷移をAjaxに置き換え、JavaScriptやCSSのパースを省略することで高速化するgemで、Rails 4からはデフォルトで使用されるようになった。
Ajax
Ajaxは、ウェブブラウザ内で非同期通信を行いながらインターフェイスの構築を行うプログラミング手法である。XMLHttpRequest(HTTP通信を行うためのJavaScript組み込みクラス)による非同期通信を利用し、通信結果に応じてダイナミックHTML (DHTML) で動的にページの一部を書き換えるというアプローチを取る。
非同期通信
非同期通信とは、データの通信に際して送信側と受信側で厳密にクロック周波数や位相を一致させないで通信する方式のことである。送信者と受信者の両方がオンラインである必要がなく、片方が接続しているだけで通信が成立する。
非同期通信の仕組みは、典型的なものとしては電子メールを挙げることができる。電子メールは、相手がオンラインでもオフラインでも関係なく送信を行なうことができる。その構造はメールサーバーがデータを蓄積することによって実現されている。
byebug
byebug(ばいばぐ)とは、rubyで使用できるデバッグツールである。デバッグしたいコードに「byebug」というメソッドを仕込んでおくと、プログラムがそこを通過した時に止まり、デバッグモードが開始、対話形式でコマンドを打ち込んで自由にメソッドを実行したり変数の値を確認したりということができる。
WebConsole
View 内でコンソールを立ち上げて、変数や parameter などの状態を見る事の出来るデバック用のライブラリのことである。
Listen
ファイルの変更を検知してそれをフックに何か処理ができるgemとのこと。
Spring
Springとは、Rails4.1から標準で付属するようになったアプリケーションプリローダーである。
Rails内では様々なライブラリのロードなどの前処理が行われるので、コマンドを実行するための待ち時間がかかってしまう。
事前にバックグラウンドでライブラリをロードしておくことで、その待ち時間を短くするものがアプリケーションプリローダーである。
spring-watcher-listen
springのファイルシステムの変更検知方法をpollingからlistenに変更してくれるgemであう。
polling
ポーリング(polling)とは、通信やソフトウェアにおいて、競合を回避したり、送受信の準備状況を判断したり、処理を同期したりするために、複数の機器やプログラムに対して順番に定期的に問い合わせを行い、一定の条件を満たした場合に送受信や処理を行う通信及び処理方式のことである。
pg
pgとは、PostgreSQLリレーショナルデータベースにアクセスするためのライブラリである。汎用的リレーショナルデータベースアクセス用ライブラリのバックエンドライブラリとして使われることもある。
マイグレーション機能
SQLを書くことなくRubyでデータベース内にテーブルを作成することができる機能のことを指す。SQLを書く必要がない理由は、Ruby on Rails内のActiveRecordという機能がRubyをSQLに自動翻訳することができるためである。その仕組みを利用すれば、Rubyが記載された所定のファイルを使い翻訳処理を経由してSQLでデータベース操作ができる。
Active Record
Active Recordはデータベースからデータを読み出すためのアプローチである。データベーステーブルあるいはビューの1行が1つのクラスにラップされ、オブジェクトのインスタンスがそのデータベースの1つの行に結合される。このクラスはデータベースアクセスのカプセル化も行う。オブジェクトの生成後は、保存メソッドで新しい行がデータベースに追加される。 オブジェクトが更新されると、データベースの対応する行もまた更新される。ラッパークラスはテーブルあるいはビューの各カラムに対するアクセサメソッドを実装するが、それ以外の振る舞い(MVCのモデルが担当すべきロジック)も記述することができる。
Rake
Unixでは、ソースコードから実行用プログラムをビルドするために主にMakeというツールが使われてきた。Rakeはいわば、Rubyで記述することのできるRuby版のMakeといった言語である。Rails 4以前ではRakeを使っているため、古いRailsアプリケーションを扱うためにはRakeについて学ぶ必要がある。おそらくもっとも頻繁に使われていたRakeコマンドは、データベースのデータモデルを更新するためのrake db:migrateコマンドと、自動化されたテストスイートを実行するためのrake testコマンドの2つだろう。
erb
erbは"Embedded RuBy"の略である。 .html.erbファイルはRubyコードが組み込まれたhtm;ファイルのようなもの、と考えてよい。Railsはテンプレートエンジンとしてerbを標準で使っている。
REST(REpresentational State Transfer)
RESTは、インターネットそのものやWebアプリケーションなどの、分散・ネットワーク化されたシステムやアプリケーションを構築するためのアーキテクチャのスタイルの1つである。REST理論そのものはかなり抽象的ですが、RailsアプリケーションにおけるRESTとは、アプリケーションを構成するコンポーネント (ユーザーやマイクロポストなど) を「リソース」としてモデル化することを指す。
rbnev
Ruby環境のバージョン切り替えツールである。Ruby(に限らないが)はバージョンの差違によって、ソフトウェアが正常に動いたり動かなかったり、といったことが往々にしてある。そこで、特定のバージョンのみを使い続けるのではなく、バージョン切り替えツールでインストール・管理することで、使いたいソフトウェアや開発するプロジェクトに応じて複数のRuby環境を使い分けるのが最近のトレンドになっている。
HTTP
HTTPは、 「Hyper Text Transfer Protocol」の略である。 今やインターネットの代名詞となったWWW(World Wide Web)上でWebサーバとクライアントが、 HTML(Hyper Text Markup Language = Webページを記述するための言語)で書かれた文書などの情報をやりとりする時に使われる通信手順(プロトコル)を意味する。
HTTP (HyperText Transfer Protocol) には4つの基本的な操作があり、それぞれGET、POST、PATCH、DELETEという4つの動詞に対応づけられている。クライアント (例えばFirefoxやSafariなどのWebブラウザ) とサーバー (ApacheやNginxなどのWebサーバー) は、上で述べた4つの基本操作を互いに認識できるようになっている。
・GET
主にWeb上のデータを読み取る (get) ときに使われるHTTPリクエスト。ブラウザはhttp://www.google.com/やhttp://www.wikipedia.org/などのWebサイトを開くたびにGETリクエストをサイトに送信する。
・POST
ページ上のフォームに入力した値を、ブラウザから送信する時に使われるHTTPリクエスト。例えばユーザー登録フォームで新しいユーザーを作成するときは、POSTリクエストを送信する。
・PATCH,DELETE
PATCH、DELETEは、それぞれサーバー上の何かを更新したり削除したりするときに使われる。これら2つの操作は、GETやPOSTほどは使われていない。これは、ブラウザがPATCHとDELETEをネイティブでは送信しないからである。しかし、Ruby on Railsなどの多くのWebフレームワークは、ブラウザがこれらの操作のリクエストを送信しているかのように見せかける技術 (偽装) を駆使して、PATCHとDELETEという操作を実現している。
IDEF1XによるER図の記述
IDEF1X
IDEF1Xは,IDEF(Integration Definition)と呼ばれる,システムをさまざまな側面から分析してモデリングを行うための方法の1つで,おもにデータベースの概念設計においてER図を記述する方法としてよく使用される。IDEF1Xでは,ERモデルにおける実体を四角形として記述し,四角形との間に線を引くことによって関連を表現する。たとえば,「社員が部署に所属する」ということは,次のようにER図として記述することができる。
実態の記述
実体は四角形として表現され,四角形の上には実体名を記述する。また実体は,他の実体に依存せずに存在できる非依存実体(Identifier-IndependentEntity)と,依存して存在する依存実体(Identifier-Dependent Entity)に分けることができる。なお,依存実体は角の丸い四角形として記述される。たとえば,社員はいずれかの部署に必ず所属するということであれば,「社員」は依存実体ということとなる。
属性の記述
実体を表現する四角形の中には属性を記述する。属性については,四角形を線で上下に分け,四角形の上には主キー(Primary Key)となる属性(主キー属性;Primary-Key Attributes),下には主キーでない属性を記述する。また,外部キー(Foreign Key)となる属性には属性名の後ろに「FK」という文字をカッコで括って記述する。
主キーとなる属性は,その属性によって実体を一意に特定することができるものある。たとえば,「社員番号」を指定することにより,それに対応する「社員」が一人に特定できる場合,「社員番号」が「社員」において主キーとなる。また,外部キーとなる属性は,他の実体において主キーとなっているものである。たとえば,「社員」では「部署」の主キーである「部署番号」が外部キーとなる。
関連の記述
実体間の関連は四角形の間に線を引くことによって記述し,依存実体との関連には実線,非依存実体との関連には破線を使用する。線の横には関連名を記述する。また,関連によってつながった実体間には親子関係が成り立ち,子となる実体に結び付けられた線の先には黒く塗り潰された円を記述する。
なお,黒く塗り潰された円の横には関連の多重度(カーディナリティ)を記述することができる。多重度とは,実体間が何対何でつながっているかということを表現するものである。
データ型
テーブルを定義する際には,そのテーブルの列のデータ型を指定する必要がある。データ型とは,テーブルに格納するデータの取り扱いに関する形式のことであり,データの性質や範囲などを定義したものである。
プログラミングにおけるデータ型とデータベースにおけるデータ型では,どのようなデータ型を使用するかということの重要度が大きく異なる。データベースでは,指定したデータ型によって大量のデータが格納されるため,適切ではないデータ型を使用すると,必要以上にディスク容量を消費したり,性能への影響が発生することもある。
データベースにおいて使用できるデータ型は,標準SQL規格によって定義されている。標準SQL規格によって定義されているデータ型には以下のようなものがある。カッコ内にはデータ型の別名を記述している。
数値データ型: smallint,integer(int),real,double precision,float,decimal(dec),numeric 文字データ型: character(char),character varying(varchar),national character(nchar), national character varying(nvarchar),character large object(clob) 日付・時刻データ型: date,time,timestamp,interval ビット・バイナリデータ型: bit,bit varying,binary large object(blob) 論理値データ型: boolean
テーブルを定義する際には,上記のようなデータ型から適切なものを選択する。しかし,そのデータ型が実際に使用できるかどうかということはRDBMSによって異なる。
DB設計基礎
データベースの設計
データベース設計とは,データベースによってデータを管理できるように,現実の世界を抽象化してデータモデルを作成していく作業である。データモデルはデータベースをどのように構成するかということを定義したものである。
優れたデータベースを構築するためには、設計段階からデータの構成を工夫しなければならない。効率的なデータベースを設計するための方法論として、「正規化」という概念が存在する。また、この「正規化」の基本概念となるものに ER モデルというものがある。
データモデルを作成していく作業(データモデリング)は,一般的に概念設計,論理設計,物理設計という3つの段階を通して行われる。そして,それぞれの段階ではアウトプットとして概念モデル,論理モデル,物理モデルが作成される。
概念モデル
概念設計では,データベースによって管理の対象とするものを現実の世界から抽出して概念モデルを作成する。概念モデルは,最終的にリレーショナルデータベースでデータを管理するとしても,特定のデータモデルを意識して作成するものではない。
概念モデルの作成にあたっては,ERモデル(実体参照モデル)がよく使用される。ERモデルでは,その名のとおり,実体(エンティティ)と関連(リレーションシップ)によってモデルを作成していく。実体は現実の世界を構成する実体そのもの,関連は実体間のつながりを表現する。また,実体や関連は属性(アトリビュート)を持つことができる。
論理設計
論理設計では,概念設計によって作成された概念モデルを,特定のデータモデルに対応した論理モデルに変換する。したがって,リレーショナルデータベースによってデータを管理するのであれば,ERモデルからリレーショナルモデルを作成する。ERモデルからリレーショナルモデル,つまり,テーブル(リレーション)への変換は機械的に行うことができる。しかし,そのままテーブルに変換しただけでは,リレーショナルモデルとして適切な形式にならない場合がある。
そこで,論理設計ではテーブルをリレーショナルモデルとして適切な形式に変換する作業(正規化)を行う。テーブルを正規化することによってデータの冗長性や不整合の発生を減少させることができる。また,論理設計では,ERモデルにおける属性をテーブルの列としてデータ型を決定し,テーブルや列に対して制約を定義するといったことも,この段階において行う。
物理設計
物理設計の段階になって初めてデータベースとしての性能について考慮する。具体的には,論理設計において正規化したテーブルの定義を崩したり,インデックスを定義したりして性能が向上するようにモデルを修正していく。また,物理設計では使用するデータベースに依存する機能を使用することもある。
物理設計によって修正されたモデルを物理モデルと呼び,このモデルをもって実際にデータベースによって管理することができる形式となる。
ERモデル
実世界に存在するものの中で、データベースとして表現すべき対象物をエンティティ (entity:実体) と呼ぶ。また、エンティティとエンティティの相互関係をリレーションシップ (relationship:関連) と呼ぶ。そして、この関係を図示し、エンティティとエンティティの間のリレーションシップを分析する技法を ER(Entity-Relationship) モデルという。
エンティティとエンティティのリレーションシップには、次のような対応関係がある。
1:1
エンティティ A に対して、エンティティ B は一つしか存在しなくて、エンティティ B に対してもエンティティ A は一つしか存在しないようなリレーションシップの場合、1:1 の対応であるという。例えば、エンティティ「学生」とエンティティ「学生番号」のリレーションシップは 1:1 である。
1:N
エンティティ A に対して、エンティティ B が複数存在し、エンティティ B に対してはエンティティ A が一つしか存在しないようなリレーションシップの場合、1:N の対応であるという。例えば、エンティティ「父親」とエンティティ「子」のリレーションシップは 1:N です。
M:N
エンティティ A に対して、エンティティ B が複数存在し、エンティティ B に対してもエンティティ A が複数存在するようなリレーションシップの場合、M:N の対応であるという。例えば、エンティティ「講義」とエンティティ「受講生」のリレーションシップは M:N である。
正規化
正規化とは、実世界の事象や情報を、データベース上で効率よく利用できるようにモデル化することや、その手順のことを言う。リレーショナル型データベースでは、複雑なテーブルを特定の規則に従って単純なテーブルに分割することが正規化であるといえる。
まだ正規化されていないものを非正規形、正規化されたものを正規形という。正規形には、正規化の程度により、第一正規形から第五正規形まである。ほとんどの場合、第三正規形まで正規化すれば的確な正規化がなされたとしてよいとされている。ここでも第三正規形までについて説明する。
・関数従属性
ある列の値 X が決まると同時に、別の列の値 Y が自動的に決まるとき、Y は X に関数従属であるという。Y が X に関数従属であるとき、X → Y と表記する。
・推移的関数従属性
ある関数従属関係から、新たな関数従属関係が得られるような場合、推移的関数従属性を持つという。X → Y 及び Y → Z の関係があるとき、X → Z は推移的関数従属性を持つ。次に、それぞれの正規形について説明する。
・非正規形
全く正規化が行われていない状態のテーブルをいう。ER モデルの説明に用いた受注伝票を 1つのテーブルにしたものは、非正規形のテーブルである。
商品番号から合計金額の部分は、あと 4つ右へ続いているものとする。このように、非正規形のテーブルは非常に大きなものになり、同じ列が何度も繰り返される。この例の場合は、商品番号〜合計金額の部分が 5つあることになる。
・第一正規形
非正規形のテーブルを、繰り返し現れる列がない状態にしたものをいう。列を固定部分と繰り返し部分にグループ化し、固定部分と繰り返し部分をキーを用いて連結することをいう。
繰り返し部分を切り離して別のテーブルにする。ただし、そのまま切り離したのでは、受注番号と商品の関係などが不明になるので、受注番号と商品番号を連結キーとして分離する。分離したテーブルは上記のようになる。
・第二正規形
主キーとなる列の値が決まれば、他の列の値が決まるようにテーブルを分割した状態をいう。関数従属関係のある部分は、別テーブルに分割するということである。
第二正規形を作成するには、関数従属性を満たすテーブルに分割する必要がある。第一正規形の上のテーブルでは、受注番号→受注日、顧客名、顧客住所という関数従属関係が成立しているので、第二正規形の条件を満たしている。
次に下のテーブルについて、合計金額は単価と数量から計算されるものなので、この時点で取り除く。すると、(受注番号、商品番号) →数量、(商品番号) →商品名、単価という二つの関数従属関係が存在することがわかる。
第一正規形の場合は、主キー (受注番号、商品番号) の一部 (商品番号) により、商品名と単価が決まっている。このようなとき、商品名と単価は、主キーに対して部分関数従属しているという。第二正規形では、このような部分関数従属関係をなくすようにする。
・第三正規形
主キーとなる列以外の値によって、他の非主キー列の値が決まることがない状態にテーブルを分割した状態をいう。推移的関数従属関係である部分を、別テーブルに分割するということである。
第二正規形のテーブルのうち、一番上のテーブルを分割する。このテーブルでは、受注番号→顧客名、顧客名→顧客住所となっており、受注番号→顧客住所は推移的関数従属関係を形成している。よって、このような部分を別テーブルとする。真中のテーブル、一番下のテーブルは、推移的関数従属関係は持たないため、分割の必要はない。
正規化のメリット
・データ管理の容易化
データに変更の必要が生じたときに、変更する手間が大幅に削減される。
・データの部品化
正規化されたデータは他のシステムで利用できる可能性が高まる。
・データ容量の削減
データの関係を明確にすることにより、無駄な列を削除することができる。その結果、データ処理の効率も上がる。
正規化はデータベース設計には欠かせない概念である。しかし、正規化すれば必ず優れたデータベースになるとは限らない。正規化することにより、テーブルの数が増える。これにより検索などでテーブルを結合する場合は、その処理が複雑になることにより、パフォーマンスが低下する可能性もある。正規化することにより生ずるメリットと、デメリットのバランスを考えて正規化することが大切だ。
とはいっても、正規化によるメリットは、データの関係を明らかにすることにより生じる。ですから、パフォーマンスのことを考えて、正規化を最後までしないということではなく、正規化したものを、状況に応じて崩すという考え方が大切だ。
トランザクション
トランザクション
データの追加・更新・削除、SQL 文で言うと「INSERT 文」「UPDATE 文」「DELETE 文」についての処理のまとまりをトランザクションと呼ぶ。
上記 3つのデータ操作文は、お互いに関連をもっていて、連続して実行されることにより、意味のある一つの単位を構成することが少なくない。トランザクションとはこの一連の作業単位のことで、データの整合性を確保するため、またデータの障害復旧といった目的に利用される。
トランザクションの特性
トランザクションは、次の 4つの特性を満たさなければならない。これら 4つの特性は、それぞれの名前の頭文字をとって ACID 特性と呼ばれる。
・原子性 (ATOMICITY)
トランザクションは、それ以上分割することのできない最小の作業単位である。このため、トランザクションを構成する処理の結果がすべて有効になるか、またはすべて無効になるかのいずれかしかない。例えば、あるトランザクションに処理 A と処理 B があるとする。処理 A と処理 B が正しく実行されたときは両方の処理結果が有効になる。しかし、処理 A だけ、または処理 B だけが正しく実行された場合は、両方の処理結果が無効になる。
・一貫性 (CONSISTENCY)
トランザクションで処理されるデータは、実行前と後でデータの整合性を持ち、一貫したデータを確保しなければならない。
・隔離性 (ISOLATION)
処理対象が同じデータである複数のトランザクションを一度に実行する場合は、それぞれのトランザクションは隔離された (独立された) 状態でデータの変更を行わなければならない。
トランザクション A とトランザクション B がデータを共有している場合、トランザクション A で変更中のデータを、トランザクション B で処理することは認められないということです。トランザクション A が終了し、データが確定した後であればトランザクション B でデータを処理することができる。
・持続性 (DURABILITY)
トランザクションで処理されるデータの状態はトランザクションが終了するまで変化しない。トランザクションで処理を変更する SQL 文を実行するが、トランザクションの最後で変更を確定するまでは実際のデータの変更は行われない。これらのトランザクションの特性により、データベースへの同時アクセスを制御したり、障害発生時の処理を制御することができるようになる。
コミットとロールバック
トランザクションによるデータの変更処理が正常に終了した場合に、その変更処理を有効な結果と確定し、データベースに反映することをコミットと呼ぶ。また、トランザクションによるデータの変更処理の途中で何らかの障害が発生した場合に、それまでの変更処理を無効なものとし、トランザクションが実行される前の状態にもどすことをロールバックと呼ぶ。このコミットとロールバックによりトランザクションの ACID 特性が生きていると言える。
/* トランザクションの構文 */ (BEGIN WORK ; ) /* PostgreSQL の場合 */ INSERT 文 ; /* トランザクションの開始 */ COMMIT ; /* 処理の確定 */ (BEGIN WORK ; ) /* PostgreSQL の場合 */ UPDATE 文 ; /* トランザクションの開始 */ ROLLBACK ; /* 処理の取り消し */ (BEGIN WORK ; ) /* PosgreSQL の場合 */ DELETE 文 ; /* トランザクションの開始 */ SAVEPOINT sPOINT ; /* セーブポイントの設定 */ INSERT 文 ; ROLLBACK TO SAVEPOINT sPOINT ; /* セーブポイントへ戻る */ INSERT 文 ; COMMIT ; /* 処理の確定 */
排他制御
排他制御とは、あるトランザクションが実行中のときに、そのトランザクションが対象としているデータをロックし、他のトランザクションのアクセスを禁止することによって、データの整合性を確保しようとする仕組みである。トランザクションが完了すれば、ロックは解除され、他のトランザクションはデータにアクセスできるようになる。
ロック
排他制御は、前節でも説明したように、データをロックすることにより実現することができる。また、データベースへのアクセスのパフォーマンスなどの観点から、排他制御の方法にはいくつかの方法がある。排他制御の形態は、ロックの形態に左右される。ロックの形態は、そのロックの程度から分類すると共有ロックと排他ロックの 2 種類 (2 モード) がある。これはトランザクションの ACID 特性の一つである隔離性 (ISOLATION) のレベルにかかわってくる。
・共有ロック
トランザクションが SELECT 文によりデータを参照するものであるときのロックのモードである。共有ロックによりデータがロックされている間は、他のトランザクションからデータを参照することはできるが、データの変更はできない。
・排他ロック
トランザクションが INSERT 文、UPDATE 文及び DELETE 文であるときのロックのモードである。排他ロックされている間、他のトランザクションからデータの参照も変更もできない。
また、ロックするデータの範囲をロックの粒度またはロックレベルという。ロックするデータの範囲を、テーブル全体にするのか、行全体なのか、特定の列なのかを示すものである。同時実効性を高めるには、ロックの粒度は小さいほうが望ましいと言えるが、トランザクションが衝突する可能性が高くなるという欠点がある。逆に粒度が大きい場合は、トランザクションの衝突の可能性は減るが、同時実効性が低くなってしまう。
実行しようとするトランザクションが共有ロックであるのか、排他ロックであるのかは、後に述べる SET TRANSACTION 文で指定することができる。ロックの粒度も同じ構文で指定することができる。
デッドロック
データのロックにより発生するものに、デッドロックというものがある。これは複数のトランザクションが互いの処理に必要なデータをロックし合っているために、処理不能の状態になってしまうことである。
デッドロックを防ぐには、トランザクションを設計するときに、アクセスするデータの順を決めておくことがよいとされる。つまり、トランザクション A ではデータ A の次にデータ B を処理するという風にするならば、トランザクション B でもデータ A の次にデータ B を処理するという風にすればよいというわけである。
デッドロックを防ぐ方法として、二相ロック方式という考え方もある。これは、あるトランザクションが処理対象としているデータのすべてを、トランザクションの開始時にまとめてロックしてしまい、トランザクションが終了する直前にそのロックをすべて開放するというものである。二相ロック方式によりロックされたデータは、トランザクションで処理中でないデータに対しても、他のトランザクションはデータの変更などの処理をすることができなくなる。
SQL文実行の高速化
WHEREの左辺で算術演算子や関数を使わない
WHERE句の左辺に算術演算や関数を指定すると,インデックスが使われない。例えば,
SELECT NAME FROM CUSTOMERS WHERE SAL - TAX > 1000
とすると,たとえSALフィールドにインデックスが定義されていてもテーブル全体を走査してしまう。こうした場合は,
SELECT NAME FROM CUSTOMERS WHERE SAL > TAX + 1000
のように記述すれば良い。
「後方一致」検索はなるべく避ける
インデックスが付加されているフィールドであっても,LIKE '%AAA' のような「後方一致」を指定すると,インデックスを検索せずにデータ部の全表走査が行われる。したがって「後方一致」の使用はなるべく避けるようにする。どうしても必要であるなら,
・何らかの,少量まで絞り込める条件とAND条件で組み合わせる
・複数のフィールドに分割し,少しでも前方・完全一致できる範囲を広げる
といった方法を検討する。
IS NULL,IS NOT NULLを単独で使わない
条件を表すWHERE句にIS NULL/IS NOT NULLを指定したときは,インデックスを定義したフィールドであっても,全表走査が行われる。したがって,これらの条件を指定するときは,単独で指定するのではなく,何らかのかなり絞り込める条件を合わせて指定する。例えば,問い合わせの結果を変更せずに「B = 10」の条件を付加できるなら
…WHERE A IS NULL
とする代わりに
…WHERE A IS NULL AND B = 10
とする。
SELECT文で「*」を使わない
レコード長が長いときや,フィールド数が多いときには,すべてのフィールドを表す「*」を指定するのはできるだけ避けて,使用するフィールドだけを指定するようにする。「*」を指定すると,参照系のSQL文では,すべてのフィールドを繰り返してコピーするため,リソースを無駄に使うことになる。最低限度必要なフィールドだけを指定するのが基本である。
ORはある程度絞り込んでから使う
論理演算子ORを使用した場合,一応インデックスが使用されるものの,個々の条件が抽出する件数が少ない(数%程度)状態でないと,あまり効果がない。
DISTINCTの代りにEXISTSを使う
SELECT文にDISTINCT*Aを指定すると処理に非常に時間がかかる。DISTINCTを使用するのは極力避けるようにする。DISTINCTと同等の結果を得ることのできるSQL文にEXISTSがある。例えば,
SELECT DISTINCT a.ID1, a.NAME1 FROM TABLE1 a, TABLE2 b WHERE a.ID1 = b.ID2
のSQL文は,副問い合わせの条件としてEXISTSを指定して
SELECT a.ID1, a.NAME1 FROM TABLE1 a WHERE EXISTS ( SELECT 'X' FROM TABLE2 b WHERE a.ID1 = b.ID2)
と書き換えることができる。同様に,NOT INからNOT EXISTSに代替することによってパフォーマンスが向上することもある。
GROUP BY,ORDER BY,HAVINGは注意する
GROUP BY句,ORDER BY句,HAVING句は,余分なディスク入出力が発生したりディスク領域を使うので,自分もしくはほかのプログラムのパフォーマンスに悪影響を及ぼしかねない。このことを念頭において,使わずに済むならなるべく使わないようにする。
演算子の組み合わせで速度が変わる
検索条件に,「>」「<」「=」をANDで組み合わせるときは,指定の仕方によってインデックスの使われ方が異なる。等号と不等号の組み合わせは,等号のみインデックスが使われる。例えば,
SELECT NAME FROM CUSTOMERS WHERE JOB = 'MANAGER' AND SAL > 1000
とすると,「JOB = 'MANAGER'」にはインデックスが使われるが,「SAL > 1000」には使われない。また,不等号同士の組み合わせでは,先に指定した条件だけにインデックスが使われる。つまり
SELECT NAME FROM CUSTOMERS WHERE TAX > 100 AND SAL > 1000
テーブルの別名を利用する
テーブルに別名をつけて,フィールド名にはその別名をつけると,SQL文の解析処理を減らすことができる。例えば,
SELECT ID, NAME FROM CUSTOMERS WHERE SAL < 1000
よりも,
SELECT a.ID, a.NAME FROM CUSTOMERS a WHERE SAL < 1000
のほうが高速になる。
DB基礎知識
RDBMS
リレーショナルデータベースを管理するためのソフトウェアの総称である。リレーショナルデータベースのデータの2次元的広がりを効率的に扱うために用いられる。
RDBMSは大きく分けて,(1)SQL文の解釈などを実行する部分と,(2)ディスク・アクセスなどを管理する部分の二つで構成される。
リレーショナルデータベース
データの一つ一つをカラム(列)と、レコード(行)の中にまとめ、それらをテーブル(表)の中に並べるものである。リレーショナルデータベースを用いると、データ同士を比較する場合にはそれぞれ同じ位置のフィールドを見比べればよいので、データの結合や抽出が非常に容易になる。テーブルが複数であっても、あらかじめ割り振られたIDや主キーとなる項目を用いてデータ同士を関連付けることにより、テーブルを内部結合してひとつのテーブルであるかのように扱うこともできる。このとき、RDBMSでは、データベースとのやり取りに、SQL言語が用いられる。
リレーショナル・エンジン
リレーショナル・エンジンは,アプリケーションから受け取ったSQL文を解析し,文法チェックなどをしてから最終的にRDBMS内部で行う処理単位に分割する。この過程で,SQLを高速に実行できるように最適化も行う。例えば,推論によってSQL文を書き換えたり,統計的な情報を基にテーブルをアクセスする際にインデックスを使うべきかどうかを検討するなど,実際にディスクにアクセスをする前の準備としてさまざまな処理を行う。そして最も効率がよいと思われる内部処理命令の組を自動生成してくれる。
しかし、リレーショナル・エンジンは,人間が考えれば明らかに効率が悪いと思われる処理方法を,推論の結果わざわざ選んでしまうこともある。検索を高速化するために定義しておいたインデックスを使ってくれない,ということも起こりうるのでリレーショナル・エンジンが効率の良い処理をするように,ユーザーやアプリケーション側から出す命令を修正してみたり,指示を与える必要がある。
ストレージ・エンジン
リレーショナル・エンジンから受け取った処理命令を基に,ディスクにアクセスしてデータを読み込んだり書き込んだりするのが主な仕事である。RDBMSはデータベースを作成する際に,一つの大きなデータ・ファイルとしてディスク領域を確保したうえで,その中の領域を必要に応じてテーブルやレコードに割り当てていく。
SQL
関係データベース管理システム (RDBMS) において、データの操作や定義を行うためのデータベース言語(問い合わせ言語)、ドメイン固有言語である。リレーショナル・データベース管理システム(RDBMS)が問い合わせを実行する速度は,SQL文の書き方によって大きく異なる。
SQL文実行までの流れ
(1)SQL文の解析
RDBMSは,SQL文を受け取るとまず,そのSQL文を解析する。具体的には,そのSQL文が文法的に正しいかどうかをチェックしたり,選択,射影,結合*1といった処理がそれぞれどのように実施されるかという文の構造を把握する。データベースの管理情報を基に,SQL文に指定したテーブルやフィールドが実際に存在するかどうかや,ユーザーがそれらに対するアクセス権限を持っているかどうかをチェックする処理もここで行う。
(2)SQL文の書き換え
解析が終わると,次にRDBMSはSQL文をより高速に実行できるように書き換える。同じ結果を返すSQL文であっても,具体的な処理内容の違いによって,実行速度は大きく異なる。そこで,処理の手順を工夫したり,演算の種類を変更するといった書き換えをする。書き換えられたSQL文は,最終的にRDBMS内部の処理命令の集まりに変換される。
(3)実行計画の作成
RDBMSは,処理命令を実行する手続きを何通りか作成したうえで,その中から最も効率の良いものを選択する。こうして出来上がった,RDBMS内部の形式で表された一連の手続きのことを「実行計画」と呼ぶ。
ただ,複雑なSQL文の場合には,個々のテーブルのアクセス・パスなどの組み合わせは何千通りにもなることがある。これらをすべて調べていたのではそのために時間がかかってしまい,本末転倒になってしまう。そこで通常は,最速になりそうな実行計画の候補をある程度絞り込んだうえで比較検討する。OracleやMicrosoft SQL Server(以下,SQL Server)などのRDBMSでは,作成した実行計画をキャッシュに保存しておき,同じSQL文が発行されたときにはそのキャッシュ上の実行計画を利用するようになっている。
(1)~(3)の,SQL文を解析して内部形式で表した実行計画を作成するまでの処理を,SQL文の「コンパイル」と呼ぶことがある。(2)と(3)のSQL文を高速に実行するための処理のことを,「最適化(optimization)」と呼ぶ。(1)のSQL文の解析は,RDBMSの「パーサー」と呼ばれる機能が,(2)(3)の最適化の処理は「オプティマイザ」という機能が担当する。
オプティマイザは、ルール・ベース・アプローチかコスト・ベース・アプローチによって最適な実行計画を選ぶ。
ルール・ベース・アプローチ
アクセス・パスの「ランク」に基づいて実行計画を選択する。ランクは,インデックスを使用してアクセスするかどうかなど,操作の種類によって決まる効率の度合いを表す数値です。Oracleの場合,アクセス・パスのランクは15に分かれている。基本的にランクが上位のアクセス・パスの方が高速です。OracleやSQL Serverは,ツールを使用するとSQL文を実行する際の実行計画を表示することができる。
ルール・ベース・アプローチでは,ランクの上位にあるアクセス・パスを選択するのが基本です。アクセス・パスのランク付けは一般的な状況を前提にしているため,場合によっては遅いほうのパスを選択してしまうことがある。例えば,
SELECT * FROM emp WHERE eno > 500
のような範囲検索の場合,表全体の中で取り出すレコードの割合が少なければ,インデックスを使って検索したほうが高速でしょう。一方,取り出すレコードの割合が大きければ全表走査のほうが高速になる。しかし,ルール・ベース・アプローチでは,常にインデックスによる検索を選択してしまう。
これに対してコスト・ベース・アプローチでは,キーenoの統計情報から得たenoの値の範囲を基に「eno > 500」を満たすレコードの割合を推測する。そのうえで,高速と思われるほうを選択するので,こうした問題は発生しにくくなる。したがって現在では,コスト・ベース・アプローチが主流になっている。
コストベースアプローチ
使用可能なアクセス・パスやアクセスするオブジェクト(表やインデックスなど)に関する「統計情報」を使用して,アクセス・パスの「コスト」を計算する。そして,コストがもっとも低くなるものを実行計画として選択する。
ここで言うコストとは,処理に必要なリソースの消費量のことで,最も重要視されるのが処理に必要なディスク・アクセスの回数です。ほかにCPUの負荷やメモリーの使用量なども考慮される。統計情報は,テーブルのレコード数や,フィールドの値の最大値/最小値などで,RDBMSがテーブル定義などの情報とともに管理している。
キャッシュ
データを一時的に保存することで、データの処理速度を速める考え方、仕組みのこと。何度も繰り返し利用するデータを読み込み速度の早い記憶装置に保存したり、それらを物理的に近くに置くことで処理速度を上げることができる。
インデックス
インデックス(索引)は、データベースの性能を向上させる方法の一つです。インデックスは「探すレコードを識別するデータの項目」「対象レコードの格納位置を示すポインタ」で構成されており、これを利用してデータの格納位置を特定し、その位置を直接アクセスする事で、表の検索速度を上げることができる。インデックスが設定されていない場合の検索では、テーブルの最初から順番に1件ずつ探すため、時間がかかる。
Laravel基礎知識
MVCフレームワーク
Laravelは、MVCフレームワークを採用している。アプリケーションをModel-View-Controllerの各機能に分けて整理し、これらのパーツを作ることで開発を行う。
Modelとは、そのアプリケーションが扱う領域のデータと手続き(ビジネスロジック - ショッピングの合計額や送料を計算するなど)を表現する要素である。
Viewとは、モデルのデータを取り出してユーザが見るのに適した形で表示する要素である。すなわち、UIへの出力を担当する。例えば、ウェブアプリケーションではHTML文書を生成して動的にデータを表示するためのコードなどにあたる。
Controllerとは、ユーザからの入力(通常イベントとして通知される)をモデルへのメッセージへと変換してモデルに伝える要素である。すなわち、UIからの入力を担当する。モデルに変更を引き起こす場合もあるが、直接に描画を行ったり、モデルの内部データを直接操作したりはしない。
ComposerとSymfonyの導入
Larravelは、プログラムの土台部分にSymfonyを導入している。SymfonyはPHPの世界で古くから使われているフレームワークで、大規模な開発に多くの実績がある。
また、Laravelのインストールやソフトウェアのインストールなどは、全て「Composer」というパッケージ管理ツールを使用して行う。これにより、プログラムの管理が非常に容易になっている。
ORMやBladeテンプレート
Laravelでは、データベースアクセスに、ORMというデータベースとオブジェクト指向言語間の非相互なデータを変換するプログラミング技法を導入している。これにより、PHPのオブジェクトを扱うようにデータベースを利用できる。
また画面の表示には、Bladeというテンプレートエンジンを搭載している。Bladeとはクラスのように階層化したテンプレートエンジンで、ヘッダーやフッターなどの決まりきった共通部分は基底のテンプレート(親ビュー)に定義して、body の中だけを(子ビュー)で定義するといった使い方をする。
ルーティング
ルーティングとは、ブラウザから届いたリクエスト(HTTPメソッド+URL)に対して、コントローラーで定義したアクションを結びつける機能のことである。要は、「〇〇というアドレスにアクセスをしたら、xxxという処理を呼び出す」という関連付けを行う機能のことを指す。
このルーティングに関する情報をまとめているのが、routesフォルダである。