3分でわかるマテリアライズド・ビュー -使い所と問題点を考える-

#想定読者
- マテリアライズド・ビューという言葉を聞いたことはあるがその意味や仕組みを知らない方
- 集計処理を実現する一つの手段としてマテリアライズド・ビューを検討している方
- マテリアライズド・ビューの実装にあたり必要な知識・注意点を把握したい方

#前提
以降の記載は以下のDBMSの使用を前提としています。

- Oracle Database 10g, 11g, 12c

#集計処理という敵とマテリアライズド・ビューという武器
システム開発を進める中で、何らかの集計処理が必要になることが多々あると思います。
例えば、売上高の集計処理（地域ごと・店舗ごと・期間ごとなど）や、特定の条件を満たす顧客の集計処理（商品名◯×を購入した顧客の合計数など）などです。
SQLで集計処理を実装すればよいのですが、実際に実装してみると以下のような問題が生じることがあります。

- 集計処理が遅い（複数テーブルの結合などに起因する処理性能低下）
- 集計データと集計元データの不整合

特に1つ目の問題は、システムに対するエンドユーザーの不満を高める危険性があります。

その策の一つとして検討していただきたいのが、**マテリアライズド・ビュー**(Materialized View)です。マテリアライズド・ビューをうまく使えば、**複雑な集計処理の高速化やデータ整合性の確保を簡単に実現することができます。**

#マテリアライズド・ビューとは何か
[e-Words](http://e-words.jp/w/%E3%83%9E%E3%83%86%E3%83%AA%E3%82%A2%E3%83%A9%E3%82%A4%E3%82%BA%E3%83%89%E3%83%93%E3%83%A5%E3%83%BC.html)に聞いてみました。
>マテリアライズドビューとは、リレーショナルデータベースで、テーブルからの検索結果であるビューにある程度の永続性を持たせ、参照するごとに再検索しなくてもいいようにしたもの。あるビューを頻繁に参照する場合に、毎回検索処理を実行しなくてよくなるため性能が向上する。

一言でいうなら、**「SQLの結果をテーブルとして保持する仕組み」**といったところでしょうか。マテリアライズド・ビューは「ビュー」として捉えるよりも「テーブル」として捉えたほうがわかりやすいと思います。

##マテリアライズド・ビューの仕組み
私が調べた限り、以下の記事の図解が一番わかりやすかったです。
[Oracleの機能を使って表の結合を高速化する (1/4)](http://www.atmarkit.co.jp/ait/articles/0504/21/news105.html)

##ビューとマテリアライズド・ビューの違い
|比較項目|View|Materialized View|
|:--|:--|:--|
|主な利用目的|セキュリティ確保等*1|パフォーマンス向上|
|データ保持|しない|する|
|参照時の動作|SQLを実行して結果を返却|保持しているSQLの結果を返却|
|処理速度|遅い|速い|
<font color="grey">*1 参照可能なカラムを権限ごとに定義する必要がある場合にビューを使用します。Oracle先生にいい記事があったので参照してみてください。
[アクセスコントロールと権限管理](http://www.oracle.com/technetwork/jp/database/articles/pickup/index-1598220-ja.html)
</font>

上記の通り、ビューは参照の度にSQLを実行するのに対し、マテリアライズド・ビューは保持しているSQLの結果を返却するため、複雑な集計処理に際してはマテリアライズド・ビューが圧倒的なパフォーマンスを発揮します。

##なぜマテリアライズド・ビューか？
集計結果を保持するためのテーブルを作成してバッチで集計すればよいのでは？と思われる方もいるかと思うので、ここで説明したいと思います。

マテリアライズド・ビューにできて、バッチでは実現できないこと、それは**変化点のみの更新**（高速リフレッシュ）です。厳密にいうとこれもバッチでできないことはありません。更新日時や更新済みフラグなどを用いて変化点のみを更新することは可能です。**ただ、あるデータが「変化したかどうか」をムダな判定処理が入るのも事実です。**

変化点のみに着目した更新が可能となるため、例えば大量データの集計処理であっても集計結果を高速に算出することが可能です。

#マテリアライズド・ビューを作ってみる
四の五の言わずに現物見ましょう！
説明は省きますが、実際のSQLのイメージだけでも掴んでみてください。

```sql
CREATE MATERIALIZED VIEW TEST_MV
REFRESH FAST --高速リフレッシュ
START WITH SYSDATE
NEXT SYSDATE + 1/24/60*10 --10分間隔でリフレッシュ実行
AS --この下にSQLを書く
SELECT NAME, SUM(SALES)
FROM TEST_TABLE
GROUP BY NAME
```

#マテリアライズド・ビューを使う前に知っておくべきこと
マテリアライズド・ビューを使う前に知っておきたい最低限の知識について説明します。なお、以下の説明では主要な機能・仕様のみの説明であり、省略している部分がありますのでご了承ください。
詳細はここらへんをチェック！

- [マテリアライズド・ビューの概要とアーキテクチャ](https://docs.oracle.com/cd/E57425_01/121/REPLN/repmview.htm#BABIIDJC)
- [CREATE MATERIALIZED VIEW](https://docs.oracle.com/cd/E57425_01/121/SQLRF/statements_6002.htm)

##更新方法

|更新方法|別名|説明|
|:--|:--|:--|
|complete|完全リフレッシュ|保持していたデータを全削除し、再実行したSQLの結果を保持する|
|fast|高速リフレッシュ|前回リフレッシュ時点から更新のあった箇所のみを再計算する|
|force|(default)|高速リフレッシュが実行できるSQLであれば高速リフレッシュを実行し、不可能であれば完全リフレッシュを実行する|
非常に便利な高速リフレッシュですが、SQLへの制約が厳しいので注意が必要です。
また、**高速リフレッシュのマテリアライズド・ビューをCREATEする前にマテリアライズド・ビュー・ログをCREATEしてください。**
[CREATE MATERIALIZED VIEW LOG](https://docs.oracle.com/cd/E57425_01/121/SQLRF/statements_6003.htm)

前回のリフレッシュからの変更点を記録するデータなので高速リフレッシュを指定してマテリアライズド・ビューを生成する場合は必要となります。ない場合はエラーとなります。なお、完全リフレッシュの場合は、マテリアライズド・ビュー・ログは必要ありません。

##更新タイミング
|更新方法|説明|
|:--|:--|
|start with...next|指定された時間間でリフレッシュする|
|on commit|参照元テーブルに対してコミットが実行されたタイミングにリフレッシュする|
高速リフレッシュ同様、on commitの制約も厳しいです。リファレンスを読んでOracle先生と戦ってください。

##番外編
###Q. マテリアライズド・ビューでGROUP BYやUNIONは使えるか？
A. 使用可能です。しかし、高速リフレッシュの場合は数ある制約をくぐりぬける必要があるので覚悟してください。

###Q. マテリアライズド・ビュー・ログは大量に増えていったりしないか？
A. マテリアライズド・ビュー・ログの削除方法も設定可能です。
デフォルトの場合、マテリアライズド・ビューの参照元として設定されたすべてのマテリアライズド・ビューがリフレッシュされると自動的に削除される仕様となっています。

###Q. 複数のマテリアライズド・ビューを同時にリフレッシュさせることはできるか？
A. マテリアライズド・ビュー・グループを使用すると、1回のトランザクションで複数のマテリアライズド・ビューを更新することができます。

###Q. マテリアライズド・ビューがリフレッシュしている間にマテリアライズド・ビューにアクセスするとどうなるか？
A. リフレッシュ中であっても、直近のリフレッシュ後データを参照し続けることができます。

#最後に
マテリアライズド・ビューの概要、利点、及び使用方法について簡単に説明してきました。マテリアライズド・ビューについて少しでも理解が深まったのであれば幸いです。