索引与视图
索引和视图是MySQL数据库中两个非常重要的概念。索引可以显著提高查询性能,而视图则可以简化复杂查询并提高数据安全性。本章将详细介绍MySQL中索引和视图的创建、使用和管理方法,以及MySQL 8.0引入的一些新特性。
6.1 索引简介
索引是一种特殊的数据结构,它可以帮助MySQL快速查找表中的数据。索引类似于书籍的目录,通过目录可以快速定位到需要的内容,而不需要逐页查找。
6.1.1 索引的含义和特点
索引是对数据库表中一列或多列的值进行排序的一种结构,使用索引可以快速访问数据库表中的特定信息。索引的主要特点包括:
- 提高查询速度:索引可以大大加快数据的查询速度,特别是在处理大量数据时
- 降低写操作性能:创建和维护索引需要额外的磁盘空间,并且会降低数据的插入、更新和删除操作的性能
- 独立于表的数据:索引是物理上和逻辑上独立于表的数据的一种结构
- 由数据库自动维护:当表中的数据发生变化时,数据库会自动更新索引
提示:索引不是越多越好。为表创建太多的索引会增加磁盘空间的消耗,并且会降低数据修改操作的性能。应该根据实际的查询需求来创建索引。
6.1.2 索引的分类
MySQL支持多种类型的索引,常见的索引类型包括:
- 普通索引:最基本的索引,没有唯一性限制
- 唯一索引:索引列的值必须唯一,但允许有NULL值
- 主键索引:一种特殊的唯一索引,不允许有NULL值,通常在创建表时指定
- 组合索引:基于多个列创建的索引,遵循最左前缀原则
- 全文索引:用于全文搜索的索引,适用于CHAR、VARCHAR和TEXT类型的列
- 空间索引:用于地理空间数据类型的索引
- 前缀索引:仅对字符串列的前缀部分建立索引,可以减少索引的大小
6.1.3 索引的设计原则
创建高效的索引需要遵循一定的设计原则:
- 选择唯一性高的列作为索引:唯一性高的列(如身份证号、手机号等)的索引效率更高
- 为经常用于查询条件、排序和分组的列创建索引:这些列是索引的最佳候选
- 避免对经常更新的列创建索引:频繁的更新会导致索引重建,影响性能
- 控制索引的数量:一个表不要创建过多的索引,一般不超过5个
- 使用前缀索引:对于较长的字符串列,可以只对其前缀部分创建索引
- 考虑数据分布:如果列的数据分布不均匀,索引的效果可能会大打折扣
- 避免在WHERE子句中对索引列进行计算或函数操作:这会导致索引失效
- 对于复合索引,遵循最左前缀原则:查询时应该优先使用复合索引中的最左列
6.2 创建索引
在MySQL中,可以通过多种方式创建索引。以下是常见的创建索引的方法。
6.2.1 创建表的时候创建索引
可以在创建表的同时创建索引,这种方式比较方便和直观。
CREATE TABLE 表名 (
字段1 数据类型 [约束],
字段2 数据类型 [约束],
...
[索引类型] INDEX [索引名] (字段1 [, 字段2, ...])
);
示例:创建表的时候创建索引
-- 创建普通索引
CREATE TABLE users (
id INT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(50) NOT NULL,
email VARCHAR(100) NOT NULL,
INDEX idx_username (username)
);
-- 创建唯一索引
CREATE TABLE products (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(100) NOT NULL,
sku VARCHAR(20) NOT NULL,
UNIQUE INDEX idx_sku (sku)
);
-- 创建复合索引
CREATE TABLE orders (
id INT PRIMARY KEY AUTO_INCREMENT,
customer_id INT NOT NULL,
order_date DATETIME NOT NULL,
total_amount DECIMAL(10,2) NOT NULL,
INDEX idx_customer_date (customer_id, order_date)
);
-- 创建全文索引
CREATE TABLE articles (
id INT PRIMARY KEY AUTO_INCREMENT,
title VARCHAR(200) NOT NULL,
content TEXT NOT NULL,
FULLTEXT INDEX idx_content (content)
);
-- 创建前缀索引
CREATE TABLE long_texts (
id INT PRIMARY KEY AUTO_INCREMENT,
description VARCHAR(1000) NOT NULL,
INDEX idx_desc_prefix (description(100)) -- 只对description的前100个字符创建索引
);
6.2.2 在已经存在的表上创建索引
对于已经存在的表,可以使用ALTER TABLE语句或CREATE INDEX语句来创建索引。
-- 使用ALTER TABLE语句创建索引
ALTER TABLE 表名
ADD [索引类型] INDEX [索引名] (字段1 [, 字段2, ...]);
-- 使用CREATE INDEX语句创建索引
CREATE [索引类型] INDEX [索引名]
ON 表名 (字段1 [, 字段2, ...]);
示例:在已经存在的表上创建索引
-- 使用ALTER TABLE语句创建普通索引
ALTER TABLE users
ADD INDEX idx_email (email);
-- 使用ALTER TABLE语句创建唯一索引
ALTER TABLE products
ADD UNIQUE INDEX idx_name (name);
-- 使用ALTER TABLE语句创建复合索引
ALTER TABLE orders
ADD INDEX idx_customer_amount (customer_id, total_amount);
-- 使用CREATE INDEX语句创建普通索引
CREATE INDEX idx_username
ON users (username);
-- 使用CREATE INDEX语句创建复合索引
CREATE INDEX idx_product_category_price
ON products (category_id, price);
-- 使用CREATE INDEX语句创建前缀索引
CREATE INDEX idx_description_prefix
ON products (description(150));
6.3 删除索引
当索引不再需要或者索引已经影响到数据修改操作的性能时,可以删除索引。在MySQL中,可以使用ALTER TABLE语句或DROP INDEX语句来删除索引。
-- 使用ALTER TABLE语句删除索引
ALTER TABLE 表名
DROP INDEX 索引名;
-- 使用DROP INDEX语句删除索引
DROP INDEX 索引名
ON 表名;
示例:删除索引
-- 使用ALTER TABLE语句删除索引
ALTER TABLE users
DROP INDEX idx_username;
-- 使用ALTER TABLE语句删除唯一索引
ALTER TABLE products
DROP INDEX idx_sku;
-- 使用DROP INDEX语句删除索引
DROP INDEX idx_customer_date
ON orders;
-- 删除前缀索引
DROP INDEX idx_desc_prefix
ON long_texts;
警告:删除索引可能会影响查询性能。在删除索引之前,应该评估其对系统的影响。可以使用EXPLAIN语句来分析查询是否使用了特定的索引。
6.4 MySQL 8.0的新特性1——支持降序索引
在MySQL 8.0之前,虽然可以在创建索引时指定列的排序方向(ASC或DESC),但实际上这些指定会被忽略,索引总是按照升序存储。MySQL 8.0开始真正支持降序索引(Descending Index),这对于需要频繁进行降序排序的查询非常有用。
6.4.1 降序索引的优势
降序索引的主要优势包括:
- 提高降序排序查询的性能:当查询需要按某个列的降序排序时,使用降序索引可以避免MySQL在查询时进行额外的排序操作
- 优化复合索引:在复合索引中,可以同时包含升序和降序的列,这对于某些复杂查询非常有用
示例:创建和使用降序索引
-- 创建包含降序列的复合索引
CREATE TABLE products (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(100) NOT NULL,
price DECIMAL(10,2) NOT NULL,
category_id INT NOT NULL,
created_at DATETIME NOT NULL,
INDEX idx_category_price_date (category_id, price DESC, created_at DESC)
);
-- 或者在已存在的表上创建降序索引
ALTER TABLE products
ADD INDEX idx_category_price_date (category_id, price DESC, created_at DESC);
-- 查询示例:按照价格降序和创建时间降序排序
-- 这个查询可以充分利用降序索引,不需要额外的排序操作
SELECT * FROM products
WHERE category_id = 5
ORDER BY price DESC, created_at DESC;
-- 查看执行计划,确认是否使用了降序索引
EXPLAIN SELECT * FROM products
WHERE category_id = 5
ORDER BY price DESC, created_at DESC;
-- 输出示例(可能会有所不同)
+----+-------------+----------+------------+------+------------------------+------------------------+---------+-------+------+----------+----------------+-
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+----------+------------+------+------------------------+------------------------+---------+-------+------+----------+----------------+-
| 1 | SIMPLE | products | NULL | ref | idx_category_price_date | idx_category_price_date | 4 | const | 5 | 100.00 | Using index condition; Using where |
+----+-------------+----------+------------+------+------------------------+------------------------+---------+-------+------+----------+----------------+-
-- 比较使用降序索引和不使用降序索引的性能
-- 可以使用SHOW PROFILE语句来查看查询的执行时间
提示:降序索引目前只在InnoDB存储引擎中支持,并且需要MySQL 8.0或更高版本。在使用降序索引时,应该确保查询的ORDER BY子句与索引的排序方向一致,这样才能充分利用降序索引的优势。
6.5 MySQL 8.0的新特性2——统计直方图
MySQL 8.0引入了统计直方图(Statistics Histogram)功能,它可以帮助查询优化器更好地了解表中数据的分布情况,从而生成更优的查询执行计划。直方图特别适用于那些数据分布不均匀的列,或者没有索引的列。
6.5.1 直方图的优点
直方图的主要优点包括:
- 提高查询优化器的准确性:直方图提供了列数据分布的详细信息,帮助优化器更准确地估计查询结果的行数
- 优化没有索引的列的查询:对于没有索引的列,直方图可以提供有关数据分布的信息,帮助优化器做出更好的决策
- 适用于数据分布不均匀的列:对于数据分布不均匀的列,直方图比简单的索引统计信息更有用
6.5.2 直方图的基本操作
MySQL提供了一系列语句来创建、更新、查看和删除直方图。
示例:直方图的基本操作
-- 创建直方图
-- 使用ANALYZE TABLE语句并指定FOR COLUMNS子句来创建直方图
ANALYZE TABLE products
UPDATE HISTOGRAM ON price WITH 100 BUCKETS;
-- 创建多个列的直方图
ANALYZE TABLE products
UPDATE HISTOGRAM ON category_id, created_at WITH 100 BUCKETS;
-- 查看直方图信息
-- 使用SHOW HISTOGRAM语句查看直方图的详细信息
SHOW HISTOGRAMS
FROM products
FOR price;
-- 查看直方图的数据
-- 直方图数据存储在information_schema.COLUMN_STATISTICS表中
SELECT *
FROM information_schema.COLUMN_STATISTICS
WHERE table_name = 'products'
AND column_name = 'price';
-- 更新直方图
-- 当表中的数据分布发生显著变化时,应该更新直方图
ANALYZE TABLE products
UPDATE HISTOGRAM ON price WITH 100 BUCKETS;
-- 删除直方图
-- 使用DROP HISTOGRAM语句删除直方图
ALTER TABLE products
DROP HISTOGRAM ON price;
-- 删除多个列的直方图
ALTER TABLE products
DROP HISTOGRAM ON category_id, created_at;
-- 自动收集直方图统计信息
-- 可以通过设置innodb_stats_auto_recalc参数来启用自动收集直方图统计信息
-- 注意:这会影响所有的统计信息,不仅仅是直方图
SET GLOBAL innodb_stats_auto_recalc = ON;
-- 也可以在表级别设置
ALTER TABLE products
SET STATS_AUTO_RECALC = ON;
提示:直方图的桶数(BUCKETS)是一个重要的参数。桶数越多,直方图的精度越高,但占用的存储空间也越大。通常,100个桶对于大多数应用场景已经足够。
6.6 视图概述
视图是一个虚拟表,其内容由查询定义。视图本身不存储数据,而是根据定义视图的查询动态生成结果集。视图可以简化复杂查询,提高数据安全性,并提供数据的逻辑独立性。
6.6.1 视图的含义
视图是基于一个或多个表的查询结果集的可视化表示。视图可以看作是存储的查询,每次访问视图时,MySQL都会执行该查询并返回结果。
6.6.2 视图的作用
视图在数据库中的主要作用包括:
- 简化复杂查询:视图可以将复杂的查询封装起来,用户只需要查询视图即可,不需要了解底层的表结构和查询逻辑
- 提高数据安全性:通过视图,可以限制用户只能访问特定的数据,而不是整个表
- 提供数据的逻辑独立性:即使底层表的结构发生变化,只要视图的定义保持不变,应用程序就不需要修改
- 合并和分割数据:可以将多个表的数据合并到一个视图中,或者将一个表的数据分割成多个视图
- 重复使用SQL语句:视图可以看作是一种复用SQL查询的方式
6.7 创建视图
在MySQL中,使用CREATE VIEW语句来创建视图。
CREATE [OR REPLACE] VIEW 视图名 [(字段列表)]
AS 查询语句
[WITH [CASCADED | LOCAL] CHECK OPTION];
其中:
OR REPLACE
:可选,如果视图已经存在,则替换它视图名
:要创建的视图的名称字段列表
:可选,指定视图中字段的名称,如果不指定,则使用查询语句中字段的名称查询语句
:定义视图的SELECT语句WITH CHECK OPTION
:可选,指定对视图进行更新操作时的检查选项CASCADED
:可选,级联检查,检查所有相关的视图LOCAL
:可选,本地检查,只检查当前视图
6.7.1 创建视图的语法形式
示例:创建视图的基本语法
-- 基本语法示例
CREATE VIEW view_name AS
SELECT column1, column2, ...
FROM table_name
WHERE condition;
-- 使用OR REPLACE选项
CREATE OR REPLACE VIEW view_name AS
SELECT column1, column2, ...
FROM table_name
WHERE condition;
-- 指定字段名
CREATE VIEW view_name (alias1, alias2, ...) AS
SELECT column1, column2, ...
FROM table_name
WHERE condition;
-- 使用WITH CHECK OPTION
CREATE VIEW view_name AS
SELECT column1, column2, ...
FROM table_name
WHERE condition
WITH CHECK OPTION;
6.7.2 在单表上创建视图
最简单的视图是基于单个表创建的视图。
示例:在单表上创建视图
-- 假设有一个employees表
CREATE TABLE employees (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(50) NOT NULL,
department VARCHAR(50) NOT NULL,
position VARCHAR(50) NOT NULL,
salary DECIMAL(10,2) NOT NULL,
hire_date DATE NOT NULL
);
-- 创建一个简单的视图,只包含特定的列
CREATE VIEW employee_basic_info AS
SELECT id, name, department, position
FROM employees;
-- 创建一个包含条件的视图,只显示技术部的员工
CREATE VIEW tech_department_employees AS
SELECT *
FROM employees
WHERE department = '技术部';
-- 创建一个包含计算列的视图
CREATE VIEW employee_salary_info AS
SELECT
id,
name,
department,
salary,
salary * 12 AS annual_salary,
CASE
WHEN salary >= 10000 THEN '高工资'
WHEN salary >= 5000 THEN '中等工资'
ELSE '低工资'
END AS salary_level
FROM employees;
-- 创建一个重命名字段的视图
CREATE VIEW employee_aliases (员工ID, 员工姓名, 部门, 职位) AS
SELECT id, name, department, position
FROM employees;
6.7.3 在多表上创建视图
视图也可以基于多个表的连接查询创建,这对于简化复杂的多表查询非常有用。
示例:在多表上创建视图
-- 假设有两个表:orders和customers
CREATE TABLE customers (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(100) NOT NULL,
email VARCHAR(100) NOT NULL,
phone VARCHAR(20) NOT NULL
);
CREATE TABLE orders (
id INT PRIMARY KEY AUTO_INCREMENT,
customer_id INT NOT NULL,
order_date DATETIME NOT NULL,
total_amount DECIMAL(10,2) NOT NULL,
FOREIGN KEY (customer_id) REFERENCES customers(id)
);
-- 创建一个基于两表连接的视图
CREATE VIEW customer_orders AS
SELECT
o.id AS order_id,
c.id AS customer_id,
c.name AS customer_name,
c.email AS customer_email,
o.order_date,
o.total_amount
FROM
orders o
JOIN
customers c ON o.customer_id = c.id;
-- 创建一个包含分组和聚合函数的视图
CREATE VIEW monthly_sales AS
SELECT
YEAR(order_date) AS year,
MONTH(order_date) AS month,
COUNT(*) AS order_count,
SUM(total_amount) AS total_sales
FROM
orders
GROUP BY
YEAR(order_date),
MONTH(order_date);
-- 创建一个基于多个表连接的复杂视图
-- 假设有products和order_items表
CREATE TABLE products (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(100) NOT NULL,
price DECIMAL(10,2) NOT NULL
);
CREATE TABLE order_items (
id INT PRIMARY KEY AUTO_INCREMENT,
order_id INT NOT NULL,
product_id INT NOT NULL,
quantity INT NOT NULL,
unit_price DECIMAL(10,2) NOT NULL,
FOREIGN KEY (order_id) REFERENCES orders(id),
FOREIGN KEY (product_id) REFERENCES products(id)
);
-- 创建一个详细的订单信息视图
CREATE VIEW order_details AS
SELECT
o.id AS order_id,
c.name AS customer_name,
o.order_date,
p.name AS product_name,
oi.quantity,
oi.unit_price,
oi.quantity * oi.unit_price AS item_total
FROM
orders o
JOIN
customers c ON o.customer_id = c.id
JOIN
order_items oi ON o.id = oi.order_id
JOIN
products p ON oi.product_id = p.id;
-- 使用WITH CHECK OPTION创建视图
CREATE VIEW high_value_orders AS
SELECT *
FROM orders
WHERE total_amount > 1000
WITH CHECK OPTION;
-- 使用WITH LOCAL CHECK OPTION创建视图
-- 基于另一个视图创建视图,并指定LOCAL CHECK OPTION
CREATE VIEW very_high_value_orders AS
SELECT *
FROM high_value_orders
WHERE total_amount > 5000
WITH LOCAL CHECK OPTION;
6.8 查看视图
在MySQL中,可以使用多种方法来查看视图的定义和信息。
6.8.1 使用DESCRIBE语句查看视图的基本信息
可以使用DESCRIBE或DESC语句来查看视图的字段信息,这与查看表的字段信息的方式相同。
DESCRIBE 视图名;
-- 或
DESC 视图名;
示例:使用DESCRIBE语句查看视图的基本信息
-- 查看employee_basic_info视图的基本信息
DESCRIBE employee_basic_info;
-- 输出示例(可能会有所不同)
+------------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+------------+-------------+------+-----+---------+-------+
| id | int | NO | | NULL | |
| name | varchar(50) | NO | | NULL | |
| department | varchar(50) | NO | | NULL | |
| position | varchar(50) | NO | | NULL | |
+------------+-------------+------+-----+---------+-------+
6.8.2 使用SHOW TABLE STATUS语句查看视图的基本信息
可以使用SHOW TABLE STATUS语句来查看视图的基本信息,包括引擎、版本、行数等。
SHOW TABLE STATUS LIKE '视图名';
示例:使用SHOW TABLE STATUS语句查看视图的基本信息
-- 查看employee_basic_info视图的基本信息
SHOW TABLE STATUS LIKE 'employee_basic_info';
-- 输出示例(可能会有所不同)
+---------------------+--------+---------+------------+------+----------------+-------------+-----------------+--------------+-----------+----------------+---------------------+---------------------+------------+-----------------+----------+----------------+---------+
| Name | Engine | Version | Row_format | Rows | Avg_row_length | Data_length | Max_data_length | Index_length | Data_free | Auto_increment | Create_time | Update_time | Check_time | Collation | Checksum | Create_options | Comment |
+---------------------+--------+---------+------------+------+----------------+-------------+-----------------+--------------+-----------+----------------+---------------------+---------------------+------------+-----------------+----------+----------------+---------+
| employee_basic_info | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | 2023-04-15 10:30:00 | NULL | NULL | utf8mb4_0900_ai_ci | NULL | | VIEW |
+---------------------+--------+---------+------------+------+----------------+-------------+-----------------+--------------+-----------+----------------+---------------------+---------------------+------------+-----------------+----------+----------------+---------+
6.8.3 使用SHOW CREATE VIEW语句查看视图的详细信息
可以使用SHOW CREATE VIEW语句来查看创建视图的完整SQL语句。
SHOW CREATE VIEW 视图名;
示例:使用SHOW CREATE VIEW语句查看视图的详细信息
-- 查看employee_basic_info视图的创建语句
SHOW CREATE VIEW employee_basic_info;
-- 输出示例(可能会有所不同)
+---------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| View | Create View |
+---------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| employee_basic_info | CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `employee_basic_info` AS select `employees`.`id` AS `id`,`employees`.`name` AS `name`,`employees`.`department` AS `department`,`employees`.`position` AS `position` from `employees` |
+---------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
6.8.4 在views表中查看视图的详细信息
MySQL的information_schema数据库中包含一个VIEWS表,可以查询该表来获取视图的详细信息。
SELECT *
FROM information_schema.VIEWS
WHERE table_schema = '数据库名'
AND table_name = '视图名';
示例:在views表中查看视图的详细信息
-- 查看employee_basic_info视图的详细信息
SELECT *
FROM information_schema.VIEWS
WHERE table_schema = 'test_db'
AND table_name = 'employee_basic_info';
-- 也可以只查询特定的列
SELECT
table_name,
view_definition,
check_option,
is_updatable
FROM information_schema.VIEWS
WHERE table_schema = 'test_db'
AND table_name = 'employee_basic_info';
-- 输出示例(可能会有所不同)
+---------------------+-------------------------------------------------------------------------------------------------------------------------------+-------------+-------------+
| table_name | view_definition | check_option | is_updatable |
+---------------------+-------------------------------------------------------------------------------------------------------------------------------+-------------+-------------+
| employee_basic_info | select `test_db`.`employees`.`id` AS `id`,`test_db`.`employees`.`name` AS `name`,`test_db`.`employees`.`department` AS `department`,`test_db`.`employees`.`position` AS `position` from `test_db`.`employees` | NONE | YES |
+---------------------+-------------------------------------------------------------------------------------------------------------------------------+-------------+-------------+
6.9 修改视图
当需要更改视图的定义时,可以使用ALTER VIEW语句或CREATE OR REPLACE VIEW语句来修改视图。
6.9.1 使用CREATE OR REPLACE VIEW语句修改视图
CREATE OR REPLACE VIEW语句可以用来创建一个新视图,或者替换一个已有的视图。
CREATE OR REPLACE VIEW 视图名 [(字段列表)]
AS 查询语句
[WITH [CASCADED | LOCAL] CHECK OPTION];
示例:使用CREATE OR REPLACE VIEW语句修改视图
-- 修改employee_basic_info视图,添加hire_date字段
CREATE OR REPLACE VIEW employee_basic_info AS
SELECT id, name, department, position, hire_date
FROM employees;
-- 修改tech_department_employees视图,添加排序
CREATE OR REPLACE VIEW tech_department_employees AS
SELECT *
FROM employees
WHERE department = '技术部'
ORDER BY hire_date DESC;
6.9.2 使用ALTER语句修改视图
ALTER VIEW语句专门用于修改已有的视图。
ALTER VIEW 视图名 [(字段列表)]
AS 查询语句
[WITH [CASCADED | LOCAL] CHECK OPTION];
示例:使用ALTER语句修改视图
-- 使用ALTER VIEW语句修改视图
ALTER VIEW employee_basic_info AS
SELECT id, name, department, position, hire_date, salary
FROM employees;
-- 修改视图的CHECK OPTION
ALTER VIEW high_value_orders AS
SELECT *
FROM orders
WHERE total_amount > 1000
WITH LOCAL CHECK OPTION;
6.10 更新视图
在某些情况下,可以通过视图来更新底层表的数据。不过,不是所有的视图都可以更新,这取决于视图的定义。
可更新视图的条件:
- 视图必须只包含一个表中的列,或者多个表通过主键连接
- 视图中不能包含聚合函数(如SUM、AVG、COUNT等)
- 视图中不能包含GROUP BY、HAVING或DISTINCT子句
- 视图中不能包含UNION或UNION ALL操作
- 视图中的列不能是计算列或常量
示例:更新视图
-- 更新视图中的数据(实际上是更新底层表的数据)
-- 假设有一个可更新的视图employee_basic_info
UPDATE employee_basic_info
SET department = '研发部'
WHERE name = '张三';
-- 插入数据到视图(实际上是插入到底层表)
-- 注意:需要确保插入的字段在视图中存在,并且底层表的所有NOT NULL字段都有值
INSERT INTO employee_basic_info (name, department, position, hire_date)
VALUES ('王五', '市场部', '销售经理', '2023-01-15');
-- 删除视图中的数据(实际上是删除底层表的数据)
DELETE FROM employee_basic_info
WHERE name = '李四';
-- 使用WITH CHECK OPTION的视图更新
-- 假设有一个视图high_value_orders,定义为total_amount > 1000 WITH CHECK OPTION
-- 以下更新是允许的,因为更新后仍然满足条件
UPDATE high_value_orders
SET total_amount = 1500
WHERE id = 1;
-- 以下更新是不允许的,因为更新后不满足条件
-- 会返回错误:Check option failed 'test_db.high_value_orders'
UPDATE high_value_orders
SET total_amount = 800
WHERE id = 2;
警告:通过视图更新数据需要谨慎。虽然这在某些情况下很方便,但可能会导致意外的数据修改。在更新视图之前,应该了解视图的定义和它所基于的底层表结构。
6.11 删除视图
当视图不再需要时,可以使用DROP VIEW语句来删除它。
DROP VIEW [IF EXISTS] 视图名 [, 视图名, ...];
其中:
IF EXISTS
:可选,如果视图不存在,则不报错视图名
:要删除的视图的名称,可以同时删除多个视图
示例:删除视图
-- 删除单个视图
DROP VIEW employee_basic_info;
-- 使用IF EXISTS选项
DROP VIEW IF EXISTS tech_department_employees;
-- 同时删除多个视图
DROP VIEW IF EXISTS employee_salary_info, customer_orders, order_details;
-- 删除级联视图
-- 如果一个视图基于另一个视图,删除基础视图会导致依赖它的视图无效
-- 假设有一个视图view1,和一个基于view1的视图view2
DROP VIEW view1;
-- 现在view2仍然存在,但查询它会返回错误
-- 应该同时删除依赖的视图
DROP VIEW view1, view2;
提示:删除视图不会影响底层表的数据,只会删除视图的定义。如果有应用程序依赖于某个视图,删除该视图可能会导致应用程序出错。在删除视图之前,应该确保没有应用程序正在使用它。