SQL ビューの説明: 例を使用して作成、使用、および落とし穴を回避する
ビューは、テーブルのように使用できる保存されたクエリです。ビューの作成方法、ビューによってレポートの一貫性が維持される理由、パフォーマンスのためにビューが行うことと行わないこと、およびビューを破る罠について学びます。
- ビューは、テーブルのように選択できる名前付きの保存されたクエリです。
- 通常のビューにはデータが保存されないため、常に現在の結果が表示されます。
- ビューは複雑なクエリを簡素化し、ビジネス ロジックの一貫性を保ち、列へのアクセスを制限できます。
- マテリアライズド ビューはそれ自体でクエリを高速化することはできませんが、クエリを高速化することはできます。
同じ 20 行のレポート クエリが 5 つのダッシュボードにコピーされており、各コピーは少しずれています。 1 つはキャンセルされた注文をカウントしますが、もう 1 つはカウントしません。 SQL ビュー は、そのロジックを明確な名前でデータベースに 1 回定義することで、この問題を解決します。
以下のすべての例を SQLite 3.50 で実行し、表示された結果はその実行から得られたものです。ビューは標準 SQL ですが、ビューによる更新、具体化されたビュー、依存関係の処理などの詳細はデータベースごとに異なるため、それらを指摘します。
ビューとは何ですか?
ビューは、名前を付けてデータベースに保存される SELECT ステートメントです。ビューにクエリを実行すると、データベースはその保存されたクエリを実行します。これは読み取り用のテーブルのように機能しますが、通常のビューはデータの独自のコピーを保持しません。
スプレッドシートに保存されたフィルターを考えてみましょう。フィルターはシートの 2 番目のコピーではありません。これは同じデータを調べる方法であり、常に最新の値が反映されます。
サンプルテーブル
CREATE TABLE customers (
id INT PRIMARY KEY, name TEXT, city TEXT, email TEXT, credit_limit INT
);
CREATE TABLE orders (
id INT PRIMARY KEY, customer_id INT, total INT, status TEXT
);
INSERT INTO customers VALUES
(1,'Asha','Pune','asha@example.com',50000),
(2,'Ben','Delhi','ben@example.com',20000),
(3,'Chitra','Pune','chitra@example.com',80000);
INSERT INTO orders VALUES
(101,1,1200,'paid'), (102,1,800,'paid'),
(103,2,300,'pending'), (104,3,2500,'paid');
ビューを作成する
このビューには、各顧客の注文が要約されます。 結合、グループ化、および CASE 式を 1 つの単純な名前の後ろに隠します。
CREATE VIEW customer_sales AS
SELECT c.id, c.name, c.city,
COUNT(o.id) AS orders,
COALESCE(SUM(CASE WHEN o.status = 'paid' THEN o.total END), 0) AS paid_total
FROM customers c
LEFT JOIN orders o ON o.customer_id = c.id
GROUP BY c.id, c.name, c.city;
これで、仕組みを知らなくても誰でも使用できるようになりました。
SELECT * FROM customer_sales ORDER BY paid_total DESC;
-- 3 | Chitra | Pune | 1 | 2500
-- 1 | Asha | Pune | 2 | 2000
-- 2 | Ben | Delhi | 1 | 0
SELECT name, paid_total FROM customer_sales WHERE city = 'Pune';
-- Asha | 2000
-- Chitra | 2500
ビューでは LEFT JOIN と COALESCE が使用されているため、Ben はゼロで表示されます。このような決定は、ビュー内で一度行われると、まさにレポートの一貫性を維持します。 NULL 処理についての理解を深めるには、SQL NULL 値 を参照してください。
ビューは常に最新です
通常のビューは毎回クエリを実行するため、新しいデータがすぐに表示されます。 Ben の有料注文を追加し、ビューを再度クエリしました。
INSERT INTO orders VALUES (105, 2, 900, 'paid');
SELECT name, paid_total FROM customer_sales WHERE name = 'Ben';
-- Ben | 900
更新手順や同期を保つためのコピーはありませんでした。これが、クエリ結果を別のテーブルに保存する場合との主な違いです。
列の非表示
ビューは、ユーザーまたはアプリケーションが必要とする列のみを公開するためによく使用されます。ここでは、電子メール アドレスとクレジット限度額は省略されています。
CREATE VIEW public_customers AS
SELECT id, name, city FROM customers;
-- columns: id, name, city
PostgreSQL、SQL Server、MySQL などの権限のあるデータベースでは、レポート ユーザーにビューへのアクセスを許可できますが、基になるテーブルへのアクセスは許可できません。 SQLite にはユーザー アカウントがないため、列制限自体を表示することしかできませんでした。ビューを 1 つの保護層として扱います。機密データには依然として適切なアクセス制御が必要であり、一部のデータベースでは、ユーザーごとに行をフィルタリングするための行レベルのセキュリティが提供されています。
パフォーマンス: ビューは速度向上にはなりません
よくある誤解は、ビューを使用するとクエリが高速になるというものです。通常のビューはクエリを実行するとその定義に置き換えられるため、データベースは完全なクエリを自分で作成した場合と同じ動作を実行します。実行計画では、ビューの結合とグループ化がクエリの一部として実行されることが示されています。
EXPLAIN QUERY PLAN SELECT * FROM customer_sales WHERE city = 'Pune';
-- CO-ROUTINE customer_sales
-- SCAN c ...
-- SEARCH o USING AUTOMATIC COVERING INDEX (customer_id=?) LEFT-JOIN
-- USE TEMP B-TREE FOR GROUP BY
-- SCAN customer_sales
したがって、遅いクエリに対するビューは依然として遅いクエリです。 SQL クエリの最適化 と SQL インデックスの説明 で説明されているように、速度はインデックスと優れたクエリ設計から生まれます。他のビューに基づいて構築されたビューにも注意してください。ネストのレイヤーにより、気づかずに同じ大きなテーブルを何度も簡単に結合できるようになります。
マテリアライズドビュー
マテリアライズド ビューは、キャッシュされたテーブルと同様に、その結果を保存します。読み取りは高速ですが、データの最新性は最後の更新時と同じです。
-- PostgreSQL
CREATE MATERIALIZED VIEW daily_sales AS
SELECT order_date, SUM(total) AS revenue FROM orders GROUP BY order_date;
REFRESH MATERIALIZED VIEW daily_sales;
| 特徴 | 通常のビュー | マテリアライズドビュー |
|---|---|---|
| データを保存します | いいえ | はい |
| 鮮度 | 常に最新の状態 | 前回の更新時点では |
| 読み取り速度 | クエリと同じ | 速い |
| 保管コスト | なし | はい |
| に良い | 簡素化、一貫性 | 大量のレポートとダッシュボード |
サポートはさまざまです。 PostgreSQL と Oracle にはマテリアライズド ビューがあり、SQL Server は独自のルールを持つインデックス付きビューを提供します。 SQLite と MySQL にはこれらの機能がないため、スケジュールに従って更新される定期的なサマリー テーブルが使用されます。この記事では PostgreSQL の例を実行しませんでした。
ヒント: マテリアライズド ビューを作成する前に、データがどの程度古くても許容されるかを決定してください。 「1 時間ごとに更新」はレポートを読む人に受け入れられるはずなので、そのように伝えます。
ビューを更新できますか?
それはデータベースとビューによって異なります。グループ化や DISTINCT を行わない単一テーブルの単純なビューは、多くの場合、PostgreSQL、MySQL、SQL Server で更新でき、変更はテーブルに反映されます。結合または集計を含むビューは、データベースがどの行を変更するかを判断できないため、通常は実行できません。
SQLite では、ビューへの直接書き込みはまったく許可されません。私たちの試みは失敗しました:
INSERT INTO customer_sales (name) VALUES ('X');
-- cannot modify customer_sales because it is a view
一部のデータベースはビューを書き込み可能にする INSTEAD OF トリガーをサポートしており、多くのデータベースはビューから見えない書き込みを停止する WITH CHECK OPTION を提供しています。実際には、ほとんどのチームはビューを読み取り専用にし、テーブルに書き込みます。
依存関係と破損
ビューは、読み取り元のテーブルに依存します。テーブルにビューを作成し、テーブルを削除しました。
CREATE TABLE ghost AS SELECT 1 AS x;
CREATE VIEW v_ghost AS SELECT x FROM ghost;
DROP TABLE ghost;
SELECT * FROM v_ghost;
-- no such table: main.ghost
SQLite はドロップを許可しましたが、後でビューが使用されたときにのみ失敗しました。 PostgreSQL などの他のデータベースは、ビューも削除する CASCADE を追加しない限り、ビューが依存するテーブルの削除を拒否します。いずれにせよ、列の名前を変更したり削除したりするとビューが壊れる可能性があるため、スキーマ変更後の回帰テストで確認してください。
SELECT *を視野に入れた微妙な罠もあります。 CREATE VIEW star AS SELECT * FROM customers を作成し、テーブルに列を追加しました。 SQLite では、ビューは新しい列を選択しました。 PostgreSQL などの他のデータベースでは、ビューの作成時に列リストが展開されるため、新しい列は表示されません。したがって、列を明示的にリストします。これはビューを文書化しており、どこでも同じように動作します。
ビューの管理
| タスク | 共通の構文 |
|---|---|
| 作成 | ビュー名を SELECT として作成 ... |
| 交換する | CREATE OR REPLACE VIEW (PostgreSQL、MySQL、Oracle) |
| SQL Server で置換する | ビューの作成または変更 |
| 削除 | ドロップビュー名 |
| 安全に取り外します | 名前が存在する場合はビューをドロップ |
ビューを削除すると、保存されたクエリのみが削除されます。私たちのテストでは、public_customers を削除した後も、customers テーブルには 3 行すべてが残っていました。移行とともにビュー定義をバージョン管理に保持することで、他のコードと同様に変更がレビューされます。
ビュー、CTE、テーブル
| オプション | 生涯 | データを保存します | こんな方に最適 |
|---|---|---|---|
| 見る | 落とすまで | いいえ | 多くのクエリで使用される共有ロジック |
| CTE | 1 つのステートメント | いいえ | 単一の複雑なクエリを整理する |
| マテリアライズドビュー | 落とすまで | はい | コストのかかる結果を高速に読み取る |
| テーブル | 落とすまで | はい | 実際のデータ |
よくある間違い
- 速度の向上が期待されます。 通常のビューは毎回クエリを実行します。
- ビューで
SELECT *を使用します。 テーブルが変更されたときの動作はデータベースによって異なります。 - 深いネスト。 ビューに基づいて構築されたビューは、負荷の高い結合を隠します。
- ビュー内での ORDER BY の使用。 クエリを実行するときに順序は保証されないため、外側のクエリで並べ替えます。
- 不明瞭な名前。
v_などの接頭辞、またはcustomer_salesなどの明確な名詞が役に立ちます。 - 移行中にビューを忘れる。 スキーマを変更するたびにビューをテストします。
まとめ
ビューは、重要なロジックをデータベースに保存する簡単な方法です。これらは、パフォーマンス上のトリックとしてではなく、レポートの一貫性を維持し、不要な列を非表示にするために使用します。まず、コード内の複数の場所に出現するクエリを見つけて、明示的な列を含むビューに変換し、各呼び出し元にそのクエリを指定します。
よくある質問
SQL のビューとは何ですか?
ビューは、名前を付けて保存された SELECT クエリです。テーブルのようにクエリを実行すると、データベースが基になるクエリを毎回実行するため、結果は常に最新になります。
SQL ビューにはデータが保存されますか?
通常のビューにはデータは保存されず、クエリのみが保存されます。マテリアライズド ビューには結果が保存されるため、最新の状態に保つには更新する必要があります。
ビューはテーブルよりも高速ですか?
いいえ。通常のビューは、その基礎となるクエリと同じ動作を行います。マテリアライズド ビューを使用すると、ストレージと鮮度を犠牲にして読み取りを高速化できます。
ビューに挿入できますか?
時々。単純な単一テーブル ビューは、多くの場合、PostgreSQL、MySQL、SQL Server で更新可能です。結合またはグループ化を含むビューは通常はそうではなく、SQLite ではそれが許可されません。
テーブルが削除された場合、ビューはどうなりますか?
それはデータベースによって異なります。ビューがテーブルに依存しているときにテーブルの削除を拒否するものもありますが、それを許可し、クエリ時にビューが失敗するものもあります。
学び続ける
テスト、WordPress、または SEO についてサポートが必要ですか?
私たちは、チームがより優れたソフトウェアを出荷し、サイトを成長させるのを支援します。あなたが取り組んでいることを教えてください。明確な次のステップを提案します。
詳しいガイドはこちら テスト、AI、最新の開発
この記事は気に入りましたか?トピックを選択して、最新のチュートリアルに直接アクセスしてください。
AI 幻覚の説明: 言語モデルが物事をでっち上げる理由とそれを軽減する方法
AI 幻覚について説明しました。幻覚とは何か、言語モデルが幻覚を生成する理由、一般的な種類、グラウンディングとプロンプトで幻覚を軽減する方法、そして私たちが実行した簡単なチェックです。
記事を読む →DevOps環境変数の説明: .env ファイル、シークレット、および設定が正しく行われている
実行した Python の例を使用して環境変数について説明します。環境変数の読み取りと設定、すべての値が文字列である理由、.env ファイル、プロセスの継承、シークレット、検証について説明します。
記事を読む →ソフトウェア開発API レート制限の説明: アルゴリズム、ヘッダー、および 429 エラーの処理
API レート制限については、実行したシミュレーションで説明します。トークン バケット、固定ウィンドウ、スライディング ウィンドウ、429 応答、レート制限ヘッダー、バックオフによる再試行、およびテスト制限です。
記事を読む →テスト自動化Python でのモッキング:unittest.mock、patch、およびテストを嘘にする間違い
Python でのunittest.mockによるモック、テスト済み: モックとreturn_value、side_effect、名前が使用されている場所のパッチ、仕様と自動仕様、日付のモック、およびよくある間違い。
記事を読む →ソフトウェアテストコードカバレッジの説明: 回線カバレッジとブランチカバレッジ、および 100% の実際の意味
実際のcoverage.pyの実行でコードカバレッジを説明: 行、分岐、条件のカバレッジ、レポートの読み取り、100%のカバレッジでもバグを見逃す可能性がある理由、および賢明なターゲット。
記事を読む →データベースとSQLSQL における DELETE、TRUNCATE、DROP: 違い、ロールバック、およびそれぞれをいつ使用するか
DELETE、TRUNCATE、DROP について、テスト済み SQL を使用して説明します。それぞれの削除内容、ロールバック、トリガー、ID リセット、速度、PostgreSQL、MySQL、SQL Server、SQLite の違いについて説明します。
記事を読む →データベースとSQLSQL ビューの説明: 作成、使用、落とし穴の回避、例を示します
SQL ビューについて、実行したクエリとともに説明しました。ビューの作成、ライブ結果、列の非表示、パフォーマンス、更新可能なビューと具体化されたビュー、壊れた依存関係、ベスト プラクティスについて説明します。
記事を読む →ソフトウェア開発TypeScript インターフェイスと型: 実際の違い、コンパイラでテスト
TypeScript インターフェイスと型、実際のコンパイラでチェック: 両方でできること、片方だけでできること、宣言のマージ、拡張と交差、および従うべき簡単なルール。
記事を読む →ソフトウェア開発Python *args と **kwargs の説明: 柔軟な関数と明確な例
Python の *args と **kwargs について、実行したコードで説明しました。パッキングとアンパッキング、パラメーターの順序、キーワードのみの引数と位置のみの引数、デコレーター、一般的なエラーです。
記事を読む →ソフトウェア開発Python Lambda 関数: 構文、実際の用途、および使用すべきでない場合
Python のラムダ関数について、実行したコードとともに説明します。構文、キーによるソート、マップとフィルター、クロージャー、遅延バインディング トラップ、通常の def がより適切な選択である場合。
記事を読む →人工知能AIエージェントとは何ですか?シンプルなエージェント ループを実行できる仕組み
AIエージェントとは何ですか?エージェント ループ、ツール、メモリ、ガードレール、実行した小さな Python ループ、実際のリスク、およびシンプルなチャットボットがより良い選択である場合についてのわかりやすいガイドです。
記事を読む →DevOpsモニタリングと可観測性: ログ、メトリクス、トレースによる本当の違い
モニタリングと可観測性について説明: 既知および未知の障害、ログ、メトリクスとトレース、チェックアウト インシデントのウォークスルー、ゴールデン シグナル、OpenTelemetry、および便利なアラート。
記事を読む →DevOpsDocker ボリュームとバインド マウント: コンテナ データを正しい方法で保持する
Docker ボリュームとバインド マウントについて説明します。コンテナ データが消える理由、名前付きボリューム、バインド マウント、tmpfs、Compose の例、バックアップ、アクセス許可、およびそれぞれをいつ使用するかについて説明します。
記事を読む →テスト自動化TDD と BDD: 主な違い、1 つの機能が両方の方法で構築され、それぞれをいつ使用するか
TDD と BDD は、両方の方法で構築された 1 つの割引機能で説明されています。実行したコードによるレッド-グリーン-リファクタリング、Given-When-Then シナリオ、ツール、トレードオフ、およびそれぞれをいつ使用するかです。
記事を読む →ソフトウェア開発Git mergeとrebaseの違い:例と使い分け
Git mergeとrebaseの違いを、実際のログ出力、比較表、rebaseの黄金律、安全なチームワークフローで解説します。
記事を読む →ソフトウェア開発Pythonのリスト内包表記:構文・例・使うべきでない場面
Pythonのリスト内包表記を解説:構文、フィルタ、if-else、ネストしたループ、実測した処理時間、そして通常のforループの方が良い場面。
記事を読む →データベースとSQLSQL JOINを例で解説(Inner・Left・Right・Full)
サンプルのテーブルとクエリでSQL JOINを順に解説。INNER、LEFT、RIGHT、FULL、CROSS、SELFに加え、よくある間違いとパフォーマンスのコツも紹介します。
記事を読む →