MySQL | SQLite経験者向け、30日で習得するMySQL:実務SQL力 - Day10 ビュー

SQL MySQL
スポンサーリンク

Day10 後半のゴール

「ビューの“できること・できないこと”を具体例で説明できるようになる」

前半では、ビュー=「保存されたSELECT文」「仮想テーブル」というイメージを作りました。
後半のゴールはここです。

ビュー経由でINSERT / UPDATEできる場合・できない場合を説明できる
ビューが遅くなりやすいパターンをイメージできる
「ビューでやるべきこと」と「やらない方がいいこと」の線引きを持つ

ここまで行くと、「とりあえずVIEW作る」から一歩抜け出せます。


更新可能なビューと更新できないビュー

「“単純な1テーブルビュー”は基本的に更新できる」

まず一番よく聞かれるところからいきます。

ビューって、INSERT / UPDATE / DELETE できるの?

答えは、

条件を満たす“単純なビュー”ならできる
複雑なビューは基本的にできない

です。

単純な1テーブルビューの例

前半で作った active_users を少し変えてみます。

CREATE VIEW active_users AS
SELECT
  id,
  name,
  email
FROM users
WHERE is_deleted = 0;
SQL

このビューに対して、こう書くことができます。

UPDATE active_users
SET name = '新しい名前'
WHERE id = 1;
SQL

これは、裏側で

UPDATE users
SET name = '新しい名前'
WHERE id = 1
  AND is_deleted = 0;
SQL

のようなイメージで処理されます。

ポイントは、

1つの元テーブル(users)だけを参照している
GROUP BY や集計がない
DISTINCT などで行が潰れていない

といった「素直なビュー」であることです。


更新できないビューの典型パターン

「JOIN・集計・DISTINCT が入ると“どこを直すか”が曖昧になる」

逆に、更新できないビューはどんなものか。

JOIN を含むビュー

CREATE VIEW user_orders AS
SELECT
  u.id        AS user_id,
  u.name      AS user_name,
  o.id        AS order_id,
  o.total     AS order_total
FROM users u
JOIN orders o
  ON o.user_id = u.id;
SQL

このビューに対して、

UPDATE user_orders
SET user_name = 'X'
WHERE user_id = 1;
SQL

と書いたとき、
DB側からすると「users を直すのか? orders を直すのか?」が曖昧です。
(この例ならusersだろう、と人間は思いますが、ビューの定義だけでは一般化しづらい)

MySQLは、こういう「どのテーブルをどう更新すべきか曖昧なビュー」は
基本的に更新不可とみなします。

集計ビュー

CREATE VIEW user_order_summary AS
SELECT
  u.id        AS user_id,
  u.name      AS user_name,
  SUM(o.total) AS total_amount
FROM users u
JOIN orders o
  ON o.user_id = u.id
GROUP BY u.id, u.name;
SQL

このビューに対して、

UPDATE user_order_summary
SET total_amount = 0
WHERE user_id = 1;
SQL

と書かれても、
「どの orders の行をどう変えれば total_amount=0 になるのか」が定義できません。

こういう「集計結果を持つビュー」も、当然更新不可です。


ビューのパフォーマンスの注意点

「ビューは“SQLを短くする”だけで、“自動で速くなる”わけではない」

ここが誤解されがちなポイントです。

ビューを作ったからといって、
クエリが自動的に速くなるわけではありません。

ビューはあくまで「SELECT文の別名」です。
SELECT * FROM user_orders を実行すると、
内部的にはビューに書かれたJOINやWHEREがそのまま展開されます。

ビューの上にさらに複雑なクエリを重ねると…

例えば、こういう構造を考えます。

user_orders ビュー
→ users × orders のJOIN

その上で、さらにこう書く:

SELECT
  user_id,
  SUM(order_total) AS total_amount
FROM user_orders
WHERE order_total >= 1000
GROUP BY user_id;
SQL

見た目はスッキリしていますが、
内部的には、

users × orders のJOIN
→ その結果に対して WHERE / GROUP BY

という処理が行われます。

ビューを使わずに最初から書いても、
ほぼ同じ実行計画になります。

つまり、

ビューは「読みやすさ・再利用性」を上げる道具であって、
それだけで性能が上がる魔法ではない

ということです。


ビューを乱用したときの“つらさ”

「ビューの上にビューを重ねると、何が起きているか分からなくなる」

実務でよくある失敗パターンがこれです。

view_a … そこそこ複雑なSELECT
view_b … view_a をさらに加工したビュー
view_c … view_b をさらに加工したビュー

そしてアプリからは SELECT * FROM view_c

こうなると、

どのテーブルがどれだけJOINされているのか
どこでフィルタされているのか
どこにインデックスを張れば効くのか

が、だんだん見えなくなっていきます。

パフォーマンスが悪くなったときに、
原因を追いかけるのが一気に難しくなります。

Day10 の段階では、

ビューは「1段か2段まで」に抑える
ビューの上にビューを重ねすぎない

という感覚だけ持っておけば十分です。


マテリアライズドビューとの違い

「MySQLのVIEWは“生のSELECT”、キャッシュではない」

他のDB(PostgreSQLなど)には、
「マテリアライズドビュー」という機能があります。

マテリアライズドビュー
SELECTの結果を一度テーブルとして保存しておき、
必要なタイミングでリフレッシュする仕組み

これは「ビュー+キャッシュ」のようなイメージです。

MySQLのVIEWは、
少なくとも標準的な機能としては「マテリアライズドビュー」ではありません。

毎回、元テーブルに対してSELECTが実行される
→ 結果を保存しておくわけではない

という点を押さえておいてください。

もし「重い集計結果をキャッシュしたい」なら、

集計結果を格納する専用テーブルを作る
バッチやトリガーでそのテーブルを更新する

といった設計を自分で組む必要があります。


ビューを使うべきところ・避けるべきところ

「“意味を名前にする”ところで使う、“重い処理の隠れ蓑”にはしない」

ここまでの話を、実務目線で一言にまとめるとこうなります。

ビューを使うべきところ
意味のある概念に名前を付けたいとき(active_users, user_orders など)
見せてよいカラムだけを切り出したいとき(users_public など)
複雑なJOINやWHEREを1か所に集約したいとき

ビューを避けるべきところ
重い集計やJOINを「見えなくするため」に隠すだけのとき
ビューの上にさらにビューを重ねて、実行計画が追えなくなりそうなとき
「速くなるはず」と期待して、とりあえずVIEWにしているだけのとき

特にセキュリティの観点では、

ビューは「見せる範囲を制限する窓」としてはとても有効
ビューは「重い処理を隠すカーテン」として使うと危険

という線引きをしておくと、
設計の判断がブレにくくなります。


Day10 後半のまとめ

MySQL のビューは「保存されたSELECT文」であり、単純に1つのテーブルだけを参照し、GROUP BY や DISTINCT などで行を潰していないビューであれば、UPDATE active_users SET name = ... のようにビュー経由で更新できるが、JOIN や集計を含むビューは「どの元テーブルをどう更新すべきか」が曖昧になるため、基本的に更新不可とみなされる。
ビューはテーブルのように SELECT * FROM view_name で使えるものの、内部的には毎回元テーブルに対してSELECTが展開されるだけで、「ビューにしたから速くなる」ということはなく、むしろビューの上にビューを重ねていくと、どれだけJOINされているか・どこでフィルタされているかが見えにくくなり、パフォーマンス問題の原因追跡が難しくなる。
他のDBにある「マテリアライズドビュー」のように結果を物理的にキャッシュする仕組みは、MySQLの通常のVIEWにはなく、重い集計結果をキャッシュしたい場合は専用テーブル+バッチ更新などを自分で設計する必要があるため、ビューは「意味のある概念に名前を付ける」「見せてよいカラムだけを切り出す」といった用途に絞り、「重い処理を隠すためのカーテン」として乱用しない、という線引きが実務では重要になる。

タイトルとURLをコピーしました