MySQL 视图

1.简介

视图(View)是一个存储在数据库中的查询语句,可以被重复使用。

视图本身不包含数据,数据库中只存储视图的定义语句。视图在许多情况下可以当作表来使用,因此也被称为虚拟表(Virtual Table)。
在这里插入图片描述
MySQL 中,存储例程包括存储过程和函数。存储程序包括存储例程、触发器和事件。存储对象包括存储程序和视图。

2.优缺点

视图是从一个或多个表中派生的虚拟表,它允许用户定义复杂的查询,并将其封装为一个单独的对象。

合理使用视图可以给我们带来许多好处:

  • 简化查询。将复杂的查询语句定义为视图,然后使用视图进行查询,可以隐藏具体的实现。
  • 统一接口。在视图的定义中增加业务逻辑,对外提供统一的接口;当底层表结构发生变化时,只需要修改视图接口,而不需要修改外部应用,可以简化代码的维护并减少错误。
  • 安全控制。通过视图为用户提供数据访问,而不是直接访问表;同时可以限制允许访问某些敏感信息,例如身份证号、工资等。
  • 数据抽象。视图可以将多个表的数据结合在一起,提供更具体、更有意义的数据视图。这对于业务报表和分析非常有用。

另一方面,视图使用不当也可能导致性能问题。

  • 性能开销。视图的定义中如果包含了复杂的查询,例如嵌套的子查询和多个表的连接查询,可能导致使用视图进行查询时性能不佳。因此,在使用视图之前最好进行相关的性能测试。
  • 更新限制:视图一般是只读的,某些情况下无法进行更新操作。
  • 复杂性:过多的视图可能导致数据库变得复杂难以维护。

MySQL 视图是一个强大的工具,可以简化查询、提高安全性和数据抽象能力。虽然视图可能带来一些性能开销,并且有一些限制,但在合适的场景下,使用视图可以显著改善数据库查询和数据管理的体验。

3.可更新视图

通常来说,视图主要用于查询数据。但是某些视图也可以用于修改数据,这种视图被称为可更新视图(Updatable View)。

可更新视图是指通过视图更新底层表,对视图的 INSERT、UPDATE、DELETE 等操作最终会转换为针对底层基础表的相应操作。

MySQL 可更新视图和基础表的数据行之间必须存在一一对应的关系,并且视图定义中不能出现以下内容:

  • 聚合函数或窗口函数,例如 AVG、SUM、COUNT 等。
  • DISTINCT、GROUP BY、HAVING 子句。
  • UNION 和 UNION ALL。
  • SELECT 列表中的子查询。非关联子查询不支持 INSERT,但是支持 UPDATE 和 DELETE;关联子查询不支持所有的 DML 语句。
  • 外连接查询。
  • 在 FROM 子句中引用其他不可更新视图。
  • WHERE 子句中的子查询引用 FROM 子句中的表。
  • 视图只引用了常量值(没有使用任何基础表)。
  • ALGORITHM = TEMPTABLE,使用临时表的视图。
  • 多次引用基础表中的某个字段(不支持 INSERT,但是可以 UPDATE 或者 DELETE)。

有时候多表连接视图也可以更新,前提是只能使用内连接查询。不过,只有其中一个表可以被更新,因此 SET 子句只能修改视图中同一个表中的字段。

4.创建视图

4.1 语法

MySQL 使用 CREATE VIEW 语句创建视图。

CREATE
    [OR REPLACE]
    [ALGORITHM = {UNDEFINED | MERGE | TEMPTABLE}]
    [DEFINER = user]
    [SQL SECURITY { DEFINER | INVOKER }]
    VIEW view_name [(column_list)]
    AS select_statement
    [WITH [CASCADED | LOCAL] CHECK OPTION]

其中,OR REPLACE 表示如果视图已经存在,则替换视图的定义。

view_name 是视图名称。指定视图名称时可以显示指定视图属于哪个数据库,即 db_name.view_name。在数据库中,基表和视图共享相同的名称空间,因此基表和视图不能具有相同的名称。

column_list 是可选的逗号分隔的字段名,字段数必须与 SELECT 语句检索的列数相同。省略时使用查询语句返回的字段名。

select_statement 是视图的定义,也就是一个 SELECT 语句。

ALGORITHM

ALGORITHM 子句是 MySQL 对标准 SQL 的扩展,用于指定在创建视图时要使用的查询优化算法。

ALGORITHM 有三个值 UNDEFINED | MERGE | TEMPTABLE。

(1)MERGE

使用 MERGE 时,将引用视图的语句和视图定义合并在一起,以便优化执行计划。

假设有一个视图 v_merge 具有以下定义:

CREATE ALGORITHM = MERGE VIEW v_merge (vc1, vc2) AS
SELECT c1, c2 FROM t WHERE c3 > 100;

假设我们写出下面的查询语句:

SELECT * FROM v_merge;

MySQL对语句的处理如下:

  • v_merge 变成 t
  • * 变成 vc1, vc2 对应 c1, c2
  • 添加视图 WHERE 子句

执行的结果语句变为:

SELECT c1, c2 FROM t WHERE c3 > 100;

再比如我们写出下面的查询语句:

SELECT * FROM v_merge WHERE vc1 < 100;

那么引用视图的语句和视图定义合并在一起后的结果是:

SELECT c1, c2 FROM t WHERE (c3 > 100) AND (c1 < 100);

(2)TEMPTABLE

使用 TEMPTABLE 时,视图的结果被检索到临时表中,然后使用该临时表来执行语句。这个算法可能会导致性能下降,因为它涉及到额外的临时表创建和数据处理。

显式指定 TEMPTABLE 的一个原因是,可以在创建临时表之后、使用临时表完成语句处理之前释放基础表上的锁。 这可能会导致比 MERGE 算法更快的锁定释放,以便使用该视图的其他客户端不会被阻塞太久。

(3)UNDEFINED

使用 UNDEFINED,MySQL 自动选择使用哪个算法。如果可能的话,它更倾向于 MERGE 而不是 TEMPTABLE,因为MERGE通常更有效,而且如果使用临时表,则视图无法更新。

如果不存在 ALGORITHM 子句,则默认算法由 optimizer_switch 系统变量的 derived_merge 标志的值确定。

权限

DEFINER 和 SQL SECURITY 子句确定在执行视图的语句时检查视图的访问权限时要使用哪个 MySQL 帐户。有效的 SQL SECURITY 特征值为 DEFINER(默认值)和 INVOKER。 这些表明所需的权限必须分别由定义或调用视图的用户拥有。

如果存在 DEFINER 子句,则用户值应为指定为 ‘user_name’@‘host_name’、CURRENT_USER 或 CURRENT_USER() 的 MySQL 帐户,允许的用户值取决于您拥有的权限。缺省为当前执行创建操作的用户。

WITH CHECK OPTION

WITH CHECK OPTION 是在创建可更新视图(Updatable View)时的一个子句,以防止插入或更新行(select_statement 中的WHERE 子句为 true 的行除外),从而保持视图和基础表的一致性。

假设您有一个可更新视图 employee_view,它从一个基础表 employees 中选择部分数据。您可以使用 WITH CHECK OPTION 子句来限制只有工资大于等于 3000 的员工数据才能被插入到视图中:

CREATE OR REPLACE VIEW employee_view AS
SELECT employee_id, first_name, last_name, salary
FROM employees
WHERE salary >= 3000
WITH CHECK OPTION;

在这个示例中,如果您尝试插入工资低于 3000 的数据到 employee_view 中,MySQL 将阻止此操作并抛出错误。

需要注意的是,WITH CHECK OPTION 子句仅在创建可更新视图时使用,用于保持视图和基础表之间的一致性。

在可更新视图的 WITH CHECK OPTION 子句中,当根据另一个视图定义该视图时,LOCAL 和 CASCADED 关键字确定检查测试的范围。 LOCAL 关键字将 CHECK OPTION 限制为仅针对正在定义的视图。 CASCADED 也会对依赖的视图进行检查。缺省为 CASCADED。

MySQL 系统视图 INFORMATION_SCHEMA.VIEWS 中记录了视图是否可以更新以及 CHECK OPTION 选项。

SELECT table_name, is_updatable, check_option
FROM INFORMATION_SCHEMA.VIEWS
WHERE table_schema = 'db_name';

4.2 示例

可以从多种 SELECT 语句创建视图。 它可以引用基表或其他视图。 它可以使用 JOIN、UNION 和子查询。

SELECT 甚至不需要引用任何表。

CREATE VIEW v_today (today) AS SELECT CURRENT_DATE;

以下示例定义了一个视图,该视图从另一个表中选择两列,以及根据这些列计算的表达式。

mysql> CREATE TABLE t (qty INT, price INT);
mysql> INSERT INTO t VALUES(3, 50), (5, 60);
mysql> CREATE VIEW v AS SELECT qty, price, qty*price AS value FROM t;
mysql> SELECT * FROM v;
+------+-------+-------+
| qty  | price | value |
+------+-------+-------+
|    3 |    50 |   150 |
|    5 |    60 |   300 |
+------+-------+-------+
mysql> SELECT * FROM v WHERE qty = 5;
+------+-------+-------+
| qty  | price | value |
+------+-------+-------+
|    5 |    60 |   300 |
+------+-------+-------+

5.查看视图

SHOW FULL TABLES 语句除了可以列出当前数据库中所有表之外,也可以用于查看视图。

SHOW FULL TABLES 
WHERE table_type = 'VIEW';

+------------------------------+------------+
| Tables_in_prod_center_dev_db | Table_type |
+------------------------------+------------+
| v                            | VIEW       |
+------------------------------+------------+
1 row in set (0.06 sec)

使用 SHOW CREATE VIEW 语句查看视图的定义。

SHOW CREATE VIEW v;

*************************** 1. row ***************************
                View: v
         Create View: CREATE ALGORITHM=UNDEFINED DEFINER=`test`@`%` SQL SECURITY DEFINER VIEW `v` AS select `t`.`qty` AS `qty`,`t`.`price` AS `price`,(`t`.`qty` * `t`.`price`) AS `value` from `t`
character_set_client: utf8
collation_connection: utf8_general_ci

视图的完整信息可以从 INFORMATION_SCHEMA 数据库的系统视图 VIEWS 中查看。

SELECT view_definition
FROM INFORMATION_SCHEMA.VIEWS
WHERE table_name = 'v';

+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| view_definition                                                                                                                                                                                         |
+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| select `prod_center_dev_db`.`t`.`qty` AS `qty`,`prod_center_dev_db`.`t`.`price` AS `price`,(`prod_center_dev_db`.`t`.`qty` * `prod_center_dev_db`.`t`.`price`) AS `value` from `prod_center_dev_db`.`t` |
+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+

6.修改视图

如果需要修改视图的定义,可以使用 CREATE OR REPLACE VIEW 语句,或者使用 ALTER VIEW 语句。

ALTER
    [ALGORITHM = {UNDEFINED | MERGE | TEMPTABLE}]
    [DEFINER = user]
    [SQL SECURITY { DEFINER | INVOKER }]
    VIEW view_name [(column_list)]
    AS select_statement
    [WITH [CASCADED | LOCAL] CHECK OPTION]

ALTER VIEW 语句和 CREATE VIEW 语句的参数完全一致。待修改的视图必须存在,否则报错。

比如修改前文创建的视图 t,修改 value 列名为 total_price。

ALTER VIEW v
AS
SELECT qty, price, qty*price AS total_price FROM t;

mysql> SELECT * FROM v;
+------+-------+-------------+
| qty  | price | total_price |
+------+-------+-------------+
|    3 |    50 |         150 |
|    5 |    60 |         300 |
+------+-------+-------------+

另外,RENAME TABLE 语句也可以用于视图重命名。

RENAME TABLE
    tbl_name TO new_tbl_name
    [, tbl_name2 TO new_tbl_name2] ...

比如将视图 v 重命名为 price_view。

RENAME TABLE v TO price_view;

7.删除视图

MySQL 使用 DROP VIEW 命令删除视图。

DROP VIEW [IF EXISTS]
    view_name [, view_name] ...
    [RESTRICT | CASCADE]

如果删除不存在的视图将返回错误,指定 IF EXISTS 不会产生错误。

RESTRICT(缺省) 或 CASCADE 关键字来指定在删除视图时如何处理相关的对象和依赖关系。

使用 RESTRICT,则 MySQL 将检查视图是否存在与其相关联的其他依赖关系,如触发器、存储过程或其他视图。如果存在任何依赖关系,MySQL 将阻止删除视图,并抛出一个错误。这是一种保护机制,用于防止意外删除视图并影响依赖关系。

使用 CASCADE,则 MySQL 将删除视图的同时,会递归删除所有与之相关的依赖关系。这意味着视图、触发器、存储过程等会被一并删除。使用 CASCADE 可以方便地删除视图及其所有相关对象,但要注意潜在的影响。


参考文献

MySQL 8.0 Reference Manual :: 25.5 Using Views
25.5.3 Updatable and Insertable Views
13.1.23 CREATE VIEW Statement
13.7.7.39 SHOW TABLES Statement
13.1.11 ALTER VIEW Statement
13.1.36 RENAME TABLE Statement
13.1.35 DROP VIEW Statement
MySQL 入门教程》第 29 篇 视图

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值