始めまして、赤枝といいます。
現在はエンジニアとして働いているわけではありませんが、自己学習を進めており書籍:ゼロから始めるデータベース操作第2版を教材としてSQLの学習をしています。
今回、気になったのがビュー(view)機能についてです。
今までRailsを使用してアプリケーションの作成をしている中で、Viewといえばユーザーに表示される画面のデータ:HTMLのことをviewと呼んでいましたが、SQLにもviewが存在していることを知りました。
SQLのビューとは
データベースを操作するときSQLでSELECT文をあらかじめ保存しておく、いわゆるショートカット設定のことです。
これを使用することによって複雑なSELECT文を毎回書かなくてもショートカットとして保存することができ、再利用することができます。
CREATE VIEW <ビュー名> (新カラム名1, 新カラム名2)
AS
SELECT文;
DROP VIEW <ビュー名>;
\dv
\d <ビュー名>
ビューの特徴
ビューの特徴として、ビューを使用したSELECT文を見ると新たなテーブルを作成したSQL文のようになりますが、この機能は新たにテーブルを作成してデータをコピーしているのではなく、データベースに仮想的なテーブルとして保存したものです。なので作成したビューは新たなテーブルとしてデータベースに作成・保存されているわけではありません。
--通常のSELECT文
SELECT カラム名
FROM <テーブル名>;
--viewのSELECT文
SELECT カラム名
FROM <ビュー名>;
さらにビューで作成した仮想テーブルを対象に新たにビューを作成することもでき、より複雑なデータ処理をすることもできます。
CREATE VIEW ビューA (新カラム名1, 新カラム名2)
AS
SELECT ビューB.カラム名, ビューC.カラム名
--テーブル名にした場合、他のビューBの部分をテーブル名に合わせる
FROM ビューB(またはテーブル名)
INNER JOIN ビューC
ON ビューB.共通ID = ビューC.共通ID;
ビューを使用することによる利点
- ショートカットによる再利用性
- シンプルなSQL文
- 複雑なSELECTの事前に解析(実行計画)による処理の高速化
実務によってより複雑なSELECT文を書いて検索しなければいけない時、毎回SQL文を書いていると書く時間とタイポミスなど構文ミスを防ぐことができシンプルなSQL文になります。そして、より複雑なSELECT文かつデータ量の多い(何万件)になるほどそのSQL文を解読・処理時間もかかってしまうため、あらかじめビューに保存するこのによりすでに解読した状態のSQL文をディスクに保存した状態で扱うので、読み込み速度のパフォーマンスは非常に優れています。
ビューとマテリアライズド・ビュー(materialized view)
ビュー機能には通常のビューとマテリアライズド・ビュー(通称:マテビュー)という別の機能があります。
ビューとマテリアライズド・ビューの共通点として、ディスクにSQL文を保存するという部分は共通ですが、マテリアライズド・ビューはディスクにSQL文とそこから検索されたデータも保存することができます。
これによりより高速なデータ取得を行うことができます。
-
ビュー
・ディスク:SQL文
・データの実態:保存されません。算出する都度、毎回読み込んで算出します。 -
マテリアライズド・ビュー
・ディスク:SQL文 + 「算出されたデータ」
・データの実態:保存されます。ディスクに算出したデータも保存されるのでディスクの容量は消費しますが、人間が更新(リフレッシュ)命令をすることにより、最新のデータを取得することができます。
CREATE MATERIALIZED VIEW <マテビュー名>
AS
SELECT カラム名, カラム名
FROM <テーブル名>
WHERE 条件;
DROP MATERIALIZED VIEW <マテビュー名>;
\dm
マテリアライズド・ビューの更新命令
マテビューの更新命令には通常リフレッシュ命令と高速リフレッシュ命令の二種類があります。
- 通常リフレッシュ命令
・特徴:保存したディスクにあるデータを全て削除し、一からデータを全検算出し直す。
・メリット・デメリット:処理が少し重く、更新中、他の人がこのビューを確認することができない。
REFRESH MATERIALIZED VIEW <ビュー名>;
- 高速リフレッシュ命令
・特徴:保存したデータと元の参考にしたデータの差分のみを算出し追加・保存する。
・メリット・デメリット:通常リフレッシュよりも処理が速く、更新中、更新前の古いデータではあるが他の人がこの古いデータを検索することができる。
REFRESH MATERIALIZED VIEW CONCURRENTLY <ビュー名>;
これを調べた時、高速リフレッシュ命令だけでいいんしゃないかと思ったのですが、便利なぶん厳しい3つの制限があるそうです。
1.『絶対必須』「一意の目印(ユニークインデックス)がないとエラーになる
高速リフレッシュはデータベースから「どのレコードが更新・追加したのか」を正確に確認しないといけないため、マテビューのレコードの中で絶対に重複しない値(商品ID,登録番号など)のユニークインデックス(または主キー)として登録しないと、コマンドを打った時エラーになります。
2.テーブルをまたいだ複雑な集計(テーブルの結合など)が苦手
複数のテーブルを複雑に結合(JOIN)して作ったマテビューや、特定の複雑な条件を入れたマテビューの場合、データベース側が「差分だけを計算するルート」を処理できなくなり、高速リフレッシュが使えない場合がある。
3.最初の1回目は「通常のリフレッシュ」が必要
マテビューを作成した直後は、データがまだ空っぽ(または初回作成時のまま)なので、データが更新されたらまずは最初のリフレッシュを行う必要があります。
そのため普段は高速リフレッシュでいいと思いますが、保険と深夜ユーザーが使用しない時間帯の場合は制限がない通常リフレッシュ命令を実行したほうがいいそうです。
- 補足:PostgreSQLで CREATE MATERIALIZED VIEW を実行した時点で、自動的に最初の「全件計算(通常リフレッシュと同じ処理)」が裏で行われ、データがディスクに保存されます。そのため、1回目の前に手動で通常リフレッシュを挟む必要はないそうです。
最後に
SQLにも同じビューが存在しておりまだまだ知らない機能がいろいろあるのでこれからも学習を進めていきたいと思います。