數據庫:簡單與。複雜與。物化視圖
一、概述
當我們使用 SQL 數據庫時,我們可能希望創建一個視圖來表示一個或多個表中的數據。我們有不同類型的觀點。但是,主要區別在於視圖是否僅用作限制並簡化查詢或提高對我們定期獲取的某些數據的訪問性能。這就是為什麼我們談論通用 SQL 視圖(簡單或複雜),或者,例如,將視圖數據存儲為緩存的物化視圖。
在本教程中,我們將通過一些實際示例討論簡單和復雜的 SQL 視圖,以及它們與物化視圖的區別。
2. 為什麼我們需要視圖
視圖是存儲在數據庫中的帶有名稱的 SQL 語句。它就像一個虛擬表,顯示一個或多個表中的數據子集。
假設我們有一個我們經常重用或公開給 Web 應用程序的查詢。在視圖中,我們為這個查詢命名並將其存儲在數據庫中。
視圖使語句更具可讀性,例如,如果查詢連接一個或多個數據庫中的表。例如,為了提高安全性,我們可以授予視圖權限以隱藏某些用戶的敏感信息。
此外,我們還將了解如何在使用物化視圖時考慮縮放查詢。
在繼續之前,讓我們考慮一下我們經常使用的子查詢語法:
SELECT * FROMm
(
SELECT
column1,
column2
FROM
some_table
) s;
值得注意的是,我們可以將此子查詢稱為Inline view
。所有視圖都使用相同的概念,但也使用DDL命令將此查詢存儲為可重用語句。
3.數據庫示例
首先,讓我們使用例如PostgresSql創建一個Employee-Department數據庫測試。我們想要一個帶有 ID 和名稱的department
表:
CREATE TABLE department (
department_id int8 NOT NULL,
department_name varchar(255) NOT NULL,
CONSTRAINT department_id_pkey PRIMARY KEY (department_id)
);
我們還定義一個帶有department
外鍵的employee
表:
CREATE TABLE employee (
employee_id int8 NOT NULL,
employee_name varchar(255) NOT NULL,
department_id int8 NOT NULL,
salary int8 NOT NULL,
CONSTRAINT empolyee_id_pkey PRIMARY KEY (empolyee_id),
CONSTRAINT fk_department_department_id FOREIGN KEY (department_id) REFERENCES department(department_id)
);
4. 簡單和復雜的觀點
如果查詢不是資源密集型的並且結果經常變化,我們可以查看簡單或複雜的視圖。
4.1.簡單視圖
一個簡單的視圖只包含一個基表或只從一個表中獲取數據。
假設我們想通過 Web 應用程序或向數據庫用戶顯示員工信息。我們可以創建一個隱藏所有工資詳細信息的視圖。例如,我們將只顯示 ID 和名稱。因此,對於非管理員用戶,我們可以授予對該視圖的訪問權限並隱藏員工表。
讓我們為普通用戶創建一個簡單的員工表視圖:
CREATE VIEW employee_details AS
SELECT
employee_id,
employee_name
FROM employee;
創建視圖後,我們可以從中選擇,因為它是一個表:
SELECT employee_id, employee_name
FROM employee_details;
我們可以看到視圖的輸出示例:
4.2.複雜視圖
複雜視圖包含多個基表。此外,它可以具有分組依據、不同、由表達式定義的列和聚合函數。
讓我們從員工加入部門表的視圖開始:
CREATE VIEW employee_department AS
SELECT
e.employee_id,
e.employee_name,
d.department_name
FROM employee e
INNER JOIN department d ON e.department_id = d.department_id;
同樣,我們可以從中讀到:
SELECT employee_name, department_name
FROM employee_department;
我們可以檢查顯示員工及其部門數據的結果集:
此外,讓我們創建一個具有更複雜查詢的視圖。例如,讓我們使用聚合創建每個部門的薪水視圖:
CREATE VIEW department_salary AS
SELECT
d.department_id,
d.department_name,
COUNT(e.*) AS employee_count,
SUM(e.salary) AS total_salary
FROM department d
INNER JOIN employee e ON d.department_id = e.department_id
GROUP BY d.department_id, d.department_name;
同樣,讓我們查詢此視圖以獲取結果集:
由於我們可以將視圖視為表,因此可以對其應用where condition
:
SELECT department_id,
department_name,
employee_count,
total_salary
FROM department_salary
WHERE department_id = 2;
4.3.視圖上的 DML
雖然不推薦,但我們可以通過視圖執行DML操作,例如INSERT
、 DELETE
或UPDATE
。
例如,我們可以更新員工的姓名:
UPDATE employee_details
SET name = 'Eric Johnson'
WHERE employee_id = 6;
在包含單個表的簡單視圖上可以使用 DML 語句。我們不能直接在復雜視圖上應用 DML。
5.物化視圖
物化視圖存儲查詢的結果。例如,我們可能有帶有子查詢連接和聚合的昂貴語句。保存結果集可以顯著提高性能。因此,我們經常對需要在恆定時間內訪問的大型數據集使用物化視圖。
不幸的是,並不是所有的 SQL 數據庫都對物化視圖有相同的用法。
例如, MySQL沒有內置系統。因此,我們可能需要使用LeapDB等插件。
使用 PostgreSQL,我們有一個用於物化視圖的DDL命令。但是,如果我們需要最新的數據,我們需要手動刷新。
不同的是,更面向DataWarehouse 的Oracle數據庫具有高級DDL定義,具有諸如按計劃刷新或提交等功能。這是使用物化視圖日誌完成的,該日誌記錄了對數據的所有更改並且可以增量刷新。
讓我們看看我們如何使用 PostgreSQL 為我們之前看到的按部門查詢分組的員工工資創建物化視圖:
CREATE MATERIALIZED VIEW materialized_department_salary AS
SELECT d.department_id,
d.department_name,
COUNT(e.*) AS employee_count,
SUM(e.salary) AS total_salary
FROM department d INNER JOIN employee e ON d.department_id = e.department_id
GROUP BY d.department_id, d.department_name;
例如,我們可以使用where condition
進行查詢:
SELECT *
FROM materialized_department_salary
WHERE department_id = 5;
然後我們可以看看結果集:
最後,由於視圖就像數據庫表,我們不妨對其應用索引或分區來提高查詢性能。
例如,我們可以在工資部門視圖中添加一個索引:
CREATE UNIQUE INDEX ON materliazed_department_salary (
department_id,
employee_count,
total_salary
);
6. 簡單視圖和復雜視圖與物化視圖有何不同
使用常規視圖(簡單或複雜),我們可以通過將其使用權授予我們數據庫的某些特定用戶或租戶來簡化查詢語句或限制對數據庫數據的訪問。但是,每次我們訪問它時,它都會運行相關查詢。
實體化視圖將數據存儲在磁盤上。它用作數據的快照視圖。雖然它是靜態數據,但如果需要,我們可以刷新它。物化視圖可以提高查詢性能。因此,數據被預先計算並存儲在表中以便更快地訪問。
當需要快速執行和訪問數據時,我們可以選擇物化視圖。但是,我們訪問的數據可能不會刷新,因此我們可能看不到它的最新版本。
儘管現在視圖仍在使用,但由於 NoSQL 數據庫(例如鍵值存儲)的興起,它們正在被棄用,它提供了非常低的數據訪問延遲。
儘管如此,我們仍然可以看到正在使用的物化視圖,例如,在 SQL 分析數據庫或離線數據訪問中。
七、結論
在本教程中,我們了解了常規視圖(簡單或複雜)與物化視圖的不同之處。簡單或複雜的視圖在我們每次訪問它們時都會運行查詢。
物化視圖將數據存儲在磁盤上。根據視圖定義,數據有時會更新。我們可以將索引或分區應用於物化視圖,或者從已經索引或分區的表中創建它。
簡單或複雜的視圖主要用於安全性。物化視圖仍然普遍用於 DataWarehouse 或數據庫中進行分析。