学习MySQL数据库的高级特性(上)
目录
一、主键(Primary Key)
特性
作用
创建
修改
二、外键(Foreign Key)
特性
作用
创建
修改
三、索引(Index)
特性
类型
创建索引
查看索引
索引的过程追踪
四、存储过程(Stored Procedure)
特性
优点
查看指定数据库的存储过程
创建一个简单的存储过程
调用存储过程
五、触发器(Trigger)
特性
触发器的类型
创建
查看
Before与After区别
一、主键(Primary Key)
特性
-
唯一标识一条记录,不能有重复值
-
一个表只能有一个主键
-
可以是单列或多列的组合
-
自动定义为 NOT NULL
作用
-
数据的唯一性标识:通过为主表中的每一行数据分配一个唯一的主键值,可以在整个表甚至整个数据库的范围内准确地识别和区分每一条记录。
-
数据的完整性维护:主键的非空和唯一性约束强制保证了数据的完整性。当插入或更新数据时,数据库会自动检查主键值是否满足要求,若不满足则拒绝操作,防止出现重复或无效的数据。
-
提高查询性能:由于主键自带索引,在根据主键进行查询时,数据库能够快速定位到目标记录,大大减少了查询所需的时间和资源,尤其是在处理大型数据集时效果更为显著。
-
建立表间关系的基础:在关系型数据库中,主键常用于建立不同表之间的关联关系。通过将一个表的主键作为另一个表的外键,可以实现多表之间的数据关联和操作,如连接查询、级联操作等。
创建
创建主表
mysql> create table users (id int primary key auto_increment,username varchar(50),password varchar(50));
mysql> desc users;
+----------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------+-------------+------+-----+---------+----------------+
| id | int | NO | PRI | NULL | auto_increment |
| username | varchar(50) | YES | | NULL | |
| password | varchar(50) | YES | | NULL | |
+----------+-------------+------+-----+---------+----------------+
修改
不直接支持修改现有的主键约束,但你可以删除并重新创建它;
注意:自动增长列不能直接删除。
ALTER TABLE users DROP PRIMARY KEY;
ALTER TABLE users ADD PRIMARY KEY (id);
二、外键(Foreign Key)
特性
-
确保子表中的数据在父表中有对应值
-
可以实现级联更新和删除
-
外键一定是某一张表的主键
作用
-
维护数据一致性:外键约束强制从表中的外键值必须与主表中的主键值相对应,防止出现孤立的数据或无效的引用。当在主表中删除或更新一条记录时,数据库会根据外键约束的设置,自动处理从表中与之相关的记录,确保数据的一致性和完整性。
-
实现多表关联操作:通过外键可以方便地将多个表关联起来,以便在查询和操作数据时能够从多个相关表中获取所需的信息。这种关联使得数据库能够模拟现实世界中的复杂关系,如客户与订单、学生与课程等关系,从而更好地组织和管理数据。
-
简化数据模型设计:使用外键可以清晰地表达不同表之间的关系,使数据库的数据模型更加规范化和易于理解。在设计数据库结构时,合理地使用外键可以避免数据的冗余存储,提高数据的存储效率和可维护性。
创建
创建从表
mysql> create table orders (order_id int auto_increment,user_id int,owner varchar(50),level int,age int,primary key (order_id),foreign key (user_id)references users (id));
Query OK, 0 rows affected (0.02 sec)mysql> desc orders;
+----------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------+-------------+------+-----+---------+----------------+
| order_id | int | NO | PRI | NULL | auto_increment |
| user_id | int | YES | MUL | NULL | |
| owner | varchar(50) | YES | | NULL | |
| level | int | YES | | NULL | |
| age | int | YES | | NULL | |
+----------+-------------+------+-----+---------+----------------+
修改
通常,外键是在创建表的时候一同定义的,修改外键需要先删除再重新创建;
ALTER TABLE orders DROP FOREIGN KEY oders_ibfk_1;
ALTER TABLE orders ADD CONSTRAINT oders_ibfk_1 FOREIGN KEY (user_id) REFERENCES new_users(id);
add constraaint: 添加约束条件
references: 表示引用关系的关键字
注意:
添加数据:先主后从;
删除数据:先从后主。
三、索引(Index)
特性
-
通过快速定位数据来提高查询速度
-
可以是唯一的(unique)或非唯一的
类型
-
按数据结构分类可分为:B+tree索引、Hash索引、Fulltext索引。
-
按物理存储分类可分为:聚簇索引、二级索引(辅助索引)。
-
按字段特性分类可分为:主键索引、普通索引、前缀索引。
-
按字段个数分类可分为:单列索引、联合索引(复合索引、组合索引)。
创建索引
#创建普通索引
CREATE INDEX idx_username ON users(username);
查看索引
show index from users;
索引的过程追踪
explain
操作案例
插入数据到表中
mysql> insert into users (username,password) values('zhou','123.com'),('wang','123');
Query OK, 2 rows affected (0.00 sec)
Records: 2 Duplicates: 0 Warnings: 0mysql> select * from users;
+----+----------+----------+
| id | username | password |
+----+----------+----------+
| 1 | zhou | 123.com |
| 2 | wang | 123 |
+----+----------+----------+
2 rows in set (0.00 sec)
创建普通索引
mysql> create index idx_username on users(username);
Query OK, 0 rows affected (0.05 sec)
Records: 0 Duplicates: 0 Warnings: 0
查看索引
mysql> show index from users;
+-------+------------+--------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | Visible | Expression |
+-------+------------+--------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| users | 0 | PRIMARY | 1 | id | A | 2 | NULL | NULL | | BTREE | | | YES | NULL |
| users | 1 | idx_username | 1 | username | A | 2 | NULL | NULL | YES | BTREE | | | YES | NULL |
+-------+------------+--------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
2 rows in set (0.00 sec)
索引过程追踪
mysql> explain select * from users where id=2;
+----+-------------+-------+------------+-------+---------------+---------+---------+-------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+-------+---------------+---------+---------+-------+------+----------+-------+
| 1 | SIMPLE | users | NULL | const | PRIMARY | PRIMARY | 4 | const | 1 | 100.00 | NULL |
+----+-------------+-------+------------+-------+---------------+---------+---------+-------+------+----------+-------+mysql> explain select * from users where username='wang';
+----+-------------+-------+------------+------+---------------+--------------+---------+-------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+--------------+---------+-------+------+----------+-------+
| 1 | SIMPLE | users | NULL | ref | idx_username | idx_username | 203 | const | 1 | 100.00 | NULL |
+----+-------------+-------+------------+------+---------------+--------------+---------+-------+------+----------+-------+mysql> explain select * from users where password='123';
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
| 1 | SIMPLE | users | NULL | ALL | NULL | NULL | NULL | NULL | 2 | 50.00 | Using where |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
可以看出,当使用“id”进行查询时使用的是“主键”索引;当使用“username”进行查询时,使用的是“idx_username”索引;当使用“password”进行查询时,没有使用索引。
四、存储过程(Stored Procedure)
一组为了完成特定功能而预先编译好并存储在数据库中的 SQL 语句集合。
特性
-
封装一段SQL语句,便于复用和维护
-
可以包含业务逻辑
优点
- 提高性能
- 增强安全性
- 简化复杂操作
- 减少网络流量
查看指定数据库的存储过程
SHOW PROCEDURE status where Db='databaseName'\G;
创建一个简单的存储过程
DELIMITER // -- 修改语句结束符号为“//”
CREATE PROCEDURE get_users_info(IN users_id INT)
BEGIN
SELECT * FROM users WHERE id = users_id;
END //
DELIMITER ; -- 修改为“;”
调用存储过程
CALL get_users_info(1001); --调用上述创建的存储过程
操作案例
mysql> DELIMITER //
mysql> CREATE PROCEDURE get_users_info(IN users_id INT)-> BEGIN-> SELECT * FROM users WHERE id = users_id;-> END //
Query OK, 0 rows affected (0.01 sec)mysql> DELIMITER ;
mysql> show procedure status where db='jx'\G;
*************************** 1. row ***************************Db: jxName: get_users_infoType: PROCEDUREDefiner: root@localhostModified: 2025-10-13 19:52:09Created: 2025-10-13 19:52:09Security_type: DEFINERComment:
character_set_client: utf8mb4
collation_connection: utf8mb4_0900_ai_ciDatabase Collation: utf8mb4_0900_ai_ci
1 row in set (0.00 sec)
mysql> select * from users;
+----+----------+----------+
| id | username | password |
+----+----------+----------+
| 1 | zhou | 123.com |
| 2 | wang | 123 |
+----+----------+----------+
2 rows in set (0.00 sec)mysql> call get_users_info (1);
+----+----------+----------+
| id | username | password |
+----+----------+----------+
| 1 | zhou | 123.com |
+----+----------+----------+
1 row in set (0.00 sec)Query OK, 0 rows affected (0.00 sec)
五、触发器(Trigger)
一种特殊类型的存储过程,它与表紧密关联,会在特定的表操作事件发生时自动执行相应的 SQL 语句块 。
特性
-
在 INSERT、UPDATE 或 DELETE 操作之前或之后自动执行
-
用于自动化维护数据的完整性或实施业务规则
触发器的类型
-
按触发事件分类
-
INSERT 触发器:在向表中插入数据时触发。例如,在一个员工信息表中插入新员工记录时,可以通过 INSERT 触发器自动向其他相关表中插入相应的关联数据,或者对插入的数据进行一些合法性检查和预处理。
-
UPDATE 触发器:当表中的数据被更新时触发。比如,在更新员工工资表中的工资数据时,UPDATE 触发器可以自动计算并更新与工资相关的其他统计数据,如平均工资、工资总额等。
-
DELETE 触发器:在从表中删除数据时触发。假设在删除某个部门的信息时,DELETE 触发器可以自动删除该部门下的所有员工记录,或者将这些员工记录转移到其他部门,以保证数据的完整性和关联性。
-
-
按触发时间分类
-
BEFORE 触发器:在触发事件(如 INSERT、UPDATE、DELETE)发生之前执行。它可以用于在数据真正被修改之前进行一些预处理操作,如数据验证、默认值设置等。如果在 BEFORE 触发器中执行了 ROLLBACK 语句,那么触发事件将被取消,数据不会被修改。
-
AFTER 触发器:在触发事件发生之后执行。通常用于在数据修改完成后进行一些后续处理操作,如记录日志、更新缓存、发送通知等。由于 AFTER 触发器是在数据修改后执行,所以它无法阻止触发事件的发生,但可以根据数据的修改情况进行相应的处理。
-
创建
创建一个BEFORE INSERT触发器,用于在向orders表中插入新订单时设置订单日期为当前日期
DELIMITER //
CREATE TRIGGER set_order_date_before_insert
BEFORE INSERT ON orders
FOR EACH ROW
BEGIN
SET NEW.order_date = CURDATE();
END //
DELIMITER ;
查看
show triggers\G;
操作案例
往orders表中添加一列数据
mysql> alter table orders add column order_date date;
mysql> desc orders;
+------------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+-------------+------+-----+---------+----------------+
| order_id | int | NO | PRI | NULL | auto_increment |
| user_id | int | YES | MUL | NULL | |
| owner | varchar(50) | YES | | NULL | |
| level | int | YES | | NULL | |
| age | int | YES | | NULL | |
| order_date | date | YES | | NULL | |
+------------+-------------+------+-----+---------+----------------+
创建before insert 触发器
mysql> DELIMITER //
mysql> CREATE TRIGGER set_order_date_before_insert-> BEFORE INSERT ON orders-> FOR EACH ROW-> BEGIN-> SET NEW.order_date = CURDATE();-> END //
Query OK, 0 rows affected (0.01 sec)mysql> DELIMITER ;
查看
mysql> show triggers \G;
*************************** 1. row ***************************Trigger: set_order_date_before_insertEvent: INSERTTable: ordersStatement: BEGINSET NEW.order_date = CURDATE();
ENDTiming: BEFORECreated: 2025-10-13 20:37:46.08sql_mode: ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTIONDefiner: root@localhost
character_set_client: utf8mb4
collation_connection: utf8mb4_0900_ai_ciDatabase Collation: utf8mb4_0900_ai_ci
1 row in set (0.00 sec)
插入数据
mysql> insert into orders (user_id,owner,level,age,order_date) value(1,'jackson',10,18,'2025-11-11');
Query OK, 1 row affected (0.00 sec)
查询orders表
mysql> select * from orders;
+----------+---------+---------+-------+------+------------+
| order_id | user_id | owner | level | age | order_date |
+----------+---------+---------+-------+------+------------+
| 1 | 1 | jackson | 10 | 18 | 2025-10-13 |
+----------+---------+---------+-------+------+------------+
Before与After区别
-
BEFORE触发器是在实际数据更改操作之前执行的。它们通常用于验证将要插入、更新或删除的数据是否符合特定的条件,以及在执行操作之前对其进行修改。BEFORE触发器还可以用于检查外键约束或确保数据的完整性。
-
AFTER触发器是在数据插入、更新或删除操作已经完成之后执行的。它们通常用于记录日志或执行其他操作,这些操作可能需要在数据进行更改后才能执行。AFTER触发器还可以用于计算汇总值或执行其他聚合操作。