无论是数据分析师、数据库管理员还是开发人员,掌握MySQL的高级应用技巧都是职业生涯中不可或缺的技能
本文将通过一系列精心设计的MySQL数据库高级练习题,带领读者深入探索MySQL的高级功能,包括但不限于索引优化、查询优化、事务处理、存储过程与触发器、以及分区与复制等
这些练习题旨在提升你的实战能力,让你在面对复杂数据库场景时更加游刃有余
一、索引优化与查询性能调优 练习题1:创建并优化索引 假设你有一个名为`employees`的表,包含以下字段:`employee_id`(主键)、`first_name`、`last_name`、`department_id`、`salary`、`hire_date`
频繁执行的查询包括按`last_name`搜索员工、按`department_id`和`salary`范围筛选员工
请设计并创建合适的索引以优化这些查询
解析与实践: 1.单列索引:首先,为last_name创建一个单列索引,因为按姓氏搜索是常见操作
sql CREATE INDEX idx_last_name ON employees(last_name); 2.复合索引:考虑到按部门ID和薪水范围筛选的需求,可以创建一个包含`department_id`和`salary`的复合索引
注意索引的列顺序,通常应将选择性较高的列放在前面
sql CREATE INDEX idx_dept_salary ON employees(department_id, salary); 3.使用EXPLAIN分析:执行查询前,使用`EXPLAIN`关键字查看查询计划,确认索引是否被正确使用
sql EXPLAIN SELECT - FROM employees WHERE last_name = Smith; EXPLAIN SELECT - FROM employees WHERE department_id =5 AND salary BETWEEN50000 AND70000; 进阶思考:索引虽好,但过多或不当的索引会导致插入、更新操作变慢,因此需权衡读写性能
练习题2:查询重写与优化 给定一个复杂的查询,要求检索每个部门中薪水最高的员工信息
原始查询可能涉及子查询或多表连接,尝试重写并优化该查询
解析与实践: 1.子查询方法(可能效率较低): sql SELECT e1. FROM employees e1 WHERE e1.salary =(SELECT MAX(e2.salary) FROM employees e2 WHERE e1.department_id = e2.department_id); 2.使用JOIN优化: sql SELECT e1. FROM employees e1 JOIN(SELECT department_id, MAX(salary) AS max_salary FROM employees GROUP BY department_id) e2 ON e1.department_id = e2.department_id AND e1.salary = e2.max_salary; 3.利用窗口函数(MySQL 8.0及以上版本支持): sql SELECT FROM(SELECT, ROW_NUMBER() OVER (PARTITION BY department_id ORDER BY salary DESC) as rn FROM employees) e WHERE rn =1; 通过比较执行计划(使用`EXPLAIN`)和实际运行时间,选择最优方案
二、事务处理与锁机制 练习题3:实现银行转账事务 设计并实现一个简单的银行转账功能,确保转账过程要么完全成功,要么在遇到错误时完全回滚,保持数据一致性
解析与实践: 1.事务开始:使用`START TRANSACTION`开启事务
2.执行转账操作:更新两个账户余额,一个增加,一个减少
3.提交或回滚:根据操作结果,使用COMMIT提交事务或`ROLLBACK`回滚
sql START TRANSACTION; --假设有两个账户,account_id为1和2,转账金额为1000 UPDATE accounts SET balance = balance -1000 WHERE account_id =1; UPDATE accounts SET balance = balance +1000 WHERE account_id =2; -- 检查是否有错误发生(这里简化处理,实际应捕获异常) --如果没有错误,提交事务 COMMIT; -- 如果发生错误,回滚事务 -- ROLLBACK; 进阶思考:考虑并发情况下的锁机制,如使用行级锁(通过InnoDB存储引擎)来保证数据一致性
三、存储过程与触发器 练习题4:创建存储过程管理员工信息 设计一个存储过程,用于新增员工信息,并在添加成功后自动更新部门员工总数
解析与实践: 1.创建存储过程: sql DELIMITER // CREATE PROCEDURE AddEmployee( IN p_first_name VARCHAR(50), IN p_last_name VARCHAR(50), IN p_department_id INT, IN p_salary DECIMAL(10,2) ) BEGIN --插入新员工记录 INSERT INTO employees(first_name, last_name, department_id, salary, hire_date) VALUES(p_first_name, p_last_name, p_department_id, p_salary, CURDATE()); -- 更新部门员工总数(假设有departments表记录部门信息) UPDATE departments SET employee_count = employee_count +1 WHERE department_id = p_department_id; END // DELIMITER ; 2.调用存储过程: sql CALL AddEmployee(John, Doe,3,60000); 练习题5:创建触发器记录数据变更 为`employees`表创建一个触发器,当员工信息被更新时,将旧记录保存到一个历史表中
解析与实践: 1.创建历史表: sql CREATE TABLE employees_history LIKE employees; 2.创建触发器: sql DELIMITER // CREATE TRIGGER after_employee_update AFTER UPDATE ON employees FOR EACH ROW BEGIN INSERT INTO employees_history(employee_id, first_name, last_name, department_id, salary, hire_date, updated_at) VALUES(OLD.employee_id, OLD.first_name, OLD.last_name, OLD.department_id, OLD.salary, OLD.hire_date, NOW()); END // DELIMITER ; 四、分区与复制 练习题6:实现表分区 针对一个包含大量历史数据的`sales`表,根据销售日期进行分区,以提高查询性能
解析与实践: 1.创建分区表: sql CREATE TABLE sales(