MySQL索引与视图综合应用示例解析

一、索引

1.索引是什么

  • 定义:索引是数据的"目录",用于快速定位数据、提升查询速度(以空间换时间)。
  • 核心作用:加速WHREE、JOIN、ORDER BY等操作,通过索引可以跳过全表扫描,显著提升查询效率。

2.索引的类型

索引类型 特点 示例
主键索引 唯一且非空,表只能有一个 PRIMARY KEY (user_id)
唯一索引 列值唯一,允许 NULL UNIQUE INDEX (email)
普通索引 加速查询,允许重复值 INDEX (username)
全文索引 针对文本内容的全文搜索(仅 InnoDB 支持) FULLTEXT (content)
组合索引 多列组合索引,遵循最左前缀原则 INDEX (last_name, first_name)

3.索引的创建

SQL 复制代码
-- 创建普通索引
CREATE INDEX idx_username ON users(username);

-- 创建唯一索引
CREATE UNIQUE INDEX idx_username on users(username);

-- 创建组合索引
CREATE INDEX idx_name ON users(last_name,first_name);

4.索引的注意事项

  • 不要过度索引:索引占用空间,且增删改查操作需要维护索引,影响写入性能

  • 选择合适的列:高频查询条件、JOIN字段、排序字段优先创建索引

  • 避免索引失效:

    • 对索引列使用函数或运算

    • 使用LIKE '%abc'

    • 类型不匹配

二、视图

1.视图是什么

  • 定义 :视图是虚拟表,基于SQL查询结果动态生成,不存储实际数据
  • 核心作用 :
    • 简化复杂查询(如多表联查)
    • 数据权限控制(隐藏敏感字段)提高数据安全性
    • 逻辑数据抽象(统计视图) 逻辑数据独立性

2.视图的操作

  • 创建不同的视图(3种)
SQL 复制代码
-- 创建简单的视图
CREATE VIEW v_active_users AS
SELECT id,name,email FROM users WHERE status = 'active';

-- 创建带有参数的视图
CREATE VIEW v_user_by_age(min_age) AS
SELECT id,name FROM users WHERE age>min_age;

-- 创建嵌套视图
CREATE VIEW v_summary AS
SELECT department, COUNT(*) AS staff_num 
FROM v_active_users 
GROUP BY department;
  • 查询视图

    SQL 复制代码
    SELECT * FROM v_active_users;
  • 修改视图

    SQL 复制代码
    CREATE OR REPLACE VIEW v_active_users AS
    SELECT id, name, email, phone FROM users WHERE status = 'active';
  • 删除视图

    SQL 复制代码
    DROP VIEW v_active_users;

3.视图的使用场景

  • 隐藏敏感字段(如工资)
  • 提供定制化数据视图
  • 简化多表关联查询
  • 实现权限控制

4.视图的注意事项

  • 简单视图性能直接接近查询
  • 复杂视图(含多表JOIN,子查询)性能较低
  • 可通过EXPLAN分析视图执行计划

三、综合实例

场景:员工管理系统 ,包含employees 表 和departments表

1.表结构

  • employees表 员工表

    字段名 类型 主键 外键 约束 说明
    employee_id INT ✔️ 自增 员工唯一标识
    first_name VARCHAR(50) NOT NULL 员工名字
    last_name VARCHAR(50) NOT NULL 员工姓氏
    age INT 年龄
    position VARCHAR(100) 职位(如:工程师)
    department_id INT ✔️ 所属部门ID(外键)
    phone CHAR(11) 手机号
    hire_date DATE 入职日期
    salary DECIMAL(10,2) 薪资
  • departments表

    字段名 类型 主键 说明
    department_id INT ✔️ 部门唯一标识
    department_name VARCHAR(100) NOT NULL 部门名称(如:技术部)

2.创建表

SQL 复制代码
-- 创建departments表 部门表
CREATE TABLE departments (
    department_id INT AUTO_INCREMENT PRIMARY KEY,
    department_name VARCHAR(100) NOT NULL
);

-- 创建employees表 员工表
CREATE TABLE employees (
	employee_id INT AUTO_INCREMENT PRIMARY KEY,
    first_name VARCHAR(50) NOT NULL,
    last_name VARCHAR(50) NOT NULL,
    age INT,
    position VARCHAR(100),
   	phone VARCHAR(11) NOT NULL COMMENT '手机号',
    department_id INT,
    
    FOREIGN KEY (department_id) REFERENCES departments(department_id),
    CONSTRAINT chk_phone_format check (phone REGEXP '^[0-9]{11}$')
);
  • 修改表中的字段类型和添加列(添加了 薪资和入职时间)
SQL 复制代码
-- 修改表中的字段类型
ALTER TABLE employees
ADD COLUMN hire_date DATE,
ADD COLUMN salary DECIMAL(10,2),
MODIFY COLUMN phone CHAR(11);
  • 插入数据

    SQL 复制代码
    -- 插入部门数据
    INSERT INTO departments (department_name) VALUES
    ('技术部'),
    ('市场部'),
    ('人力资源部');
    
    -- 插入员工信息(23条数据)
    INSERT INTO employees (first_name,last_name,age,position,department_id,phone,hire_date,salary)
    VALUES 
    ('张三','伟',28,'高级工程师',1,'15138364800','2025-4-1',12000.00),
    ('李三','强',28,'产品经理',2,'15138364801','2025-3-20',18000.00),
    ('王二','狗',28,'HR专员',3,'15138364802','2025-2-17',11000.00),
    ('赵六','明',32,'技术总监',1,'15138364803','2025-1-15',25000.00),
    ('钱七','芳',29,'UI设计师',1,'15138364804','2024-12-22',15000.00),
    ('孙八','勇',35,'项目经理',1,'15138364805','2024-11-30',22000.00),
    ('周九','婷',27,'测试工程师',1,'15138364806','2024-10-18',13000.00),
    ('吴十','磊',31,'系统架构师',1,'15138364807','2024-9-5',28000.00),
    ('郑十一','敏',26,'前端开发',1,'15138364808','2024-8-12',16000.00),
    ('王十二','浩',33,'Java开发',1,'15138364809','2024-7-19',17000.00),
    ('冯十三','娜',30,'市场总监',2,'15138364810','2024-6-25',23000.00),
    ('陈十四','强',28,'市场分析师',2,'15138364811','2024-5-14',19000.00),
    ('褚十五','丽',34,'品牌经理',2,'15138364812','2024-4-3',20000.00),
    ('卫十六','飞',29,'市场专员',2,'15138364813','2024-3-21',12000.00),
    ('蒋十七','静',27,'公关主管',2,'15138364814','2024-2-28',14000.00),
    ('沈十八','伟',36,'人力资源总监',3,'15138364815','2024-1-16',35000.00),
    ('韩十九','娟',31,'薪酬经理',3,'15138364816','2023-12-24',18000.00),
    ('杨二十','刚',29,'招聘主管',3,'15138364817','2023-11-11',16000.00),
    ('朱廿一','琳',33,'培训经理',3,'15138364818','2023-10-9',21000.00),
    ('秦廿二','超',27,'员工关系专员',3,'15138364819','2023-9-7',11000.00),
    ('尤廿三','敏',30,'绩效主管',3,'15138364820','2023-8-5',15000.00),
    ('许廿四','强',35,'组织发展经理',3,'15138364821','2023-7-3',24000.00),
    ('何廿五','娜',28,'HRBP',3,'15138364822','2023-6-1',17000.00);

3.常规查询

  • 查询技术部所有员工信息 (包括部门名称,不显示部门ID)

    SQL 复制代码
    SELECT e.first_name,e.last_name,e.age,e.position,e.phone,e.hire_date,e.salary,d.department_name
    FROM employees e
    JOIN departments d ON e.department_id=d.department_id
    WHERE d.department_name = '技术部';
  • 统计各部门员工数量及平均薪资

    SQL 复制代码
    -- 方法1
    SELECT 
        d.department_name,
        (SELECT COUNT(*) 
         FROM employees e 
         WHERE e.department_id = d.department_id) AS employees_number,
        (SELECT AVG(salary) 
         FROM employees e 
         WHERE e.department_id = d.department_id) AS avg_salary
    FROM departments d;
    
    -- 方法2:
    SELECT 
    	d.department_name,
    	COUNT(e.employee_id) AS employees_number,
    	AVG(e.salary) AS avg_salary
    FROM departments d
    JOIN employees e ON e.department_id = d.department_id
    GROUP BY d.department_id, d.department_name;
  • 查找入职超过1年的员工

    SQL 复制代码
    -- 分析:只有入职的时间,我需要获取与当下的时间差
    SELECT 
    	first_name,
        last_name,
        hire_date,
        DATEDIFF(CURDATE(), hire_date) AS days_since_hire
    FROM employees
    WHERE DATEDIFF(CURDATE(), hire_date) > 365;

4.数据维护操作

  • 更新员工部门

    SQL 复制代码
    UPDATE employees
    SET department_id = '2'
    WHERE employee_id = 1; -- 将张三调整到市场部门
  • 删除部门及其关联员工

    SQL 复制代码
    -- 先删除部门(需要处理外键约束)
    DELETE FROM departments
    WHERE department_id = 3; --删除人力资源部
    
    -- 使用级联删除(我们先开始定义表的时候,没有设置级联删除)
    
    -- 删除
    ALTER TABLE employees DROP CONSTRAINT employees_ibfk_1;-- 删除约束
    
    -- 删除+重建
    ALTER TABLE employees
    DROP CONSTRAINT employees_ibfk_1,
    ADD CONSTRAINT fk_department
    FOREIGN KEY (department_id) 
    REFERENCES departments(department_id)
    ON DELETE CASCADE;
    • 问题:我发现我在定义外键的时候没有定义外键名,系统为我们自动定义了外键名,需要自行查询

      SQl 复制代码
      SELECT CONSTRAINT_NAME
      FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS -- 数据库的管理系统
      WHERE TABLE_NAME = 'employees'
      AND CONSTRAINT_TYPE = 'FOREIGN KEY';
      
      -- 输出结果:employees_ibfk_1

5.索引优化示例

  • 设置普通的索引

    SQL 复制代码
    -- 将部门id设置为索引
    CREATE INDEX idx_department ON employees(department_id);
    
    -- 将入职时间设置为索引
    CREATE INDEX idx_hire_date ON employees(hire_date);
    • 将department_id设置为索引的原因:

      • 查询频率:部门关联查询的核心字段 :部门人数,查询部门成员

      • 选择性原则:作为外键具有天然的高选择性

  • 设置复合索引优化部门查询

    SQL 复制代码
    CREATE INDEX idx_dept_salary
    ON employees(department_id, salary DESC)
    INCLUDE (first_name, last_name);  -- 覆盖索引,不参与排序结构
    SQL 复制代码
    -- 查找市场部薪资最高的10名员工
    SELECT TOP 10 
        first_name, 
        last_name, 
        salary 
    FROM employees
    WHERE department_id = (SELECT department_id FROM departments WHERE department_name = '市场部')
    ORDER BY salary DESC;
    • 使用复合索引 (department_id, salary DESC) 的查询流程:

      • 索引定位:

        • 从根节点 开始,比较department_id=3 的范围
        • 快速导航到department_id的索引区域
      • 有序扫描:

        • 在·department_id =3的范围内,数据已按salary DESC预排序
        • 直接从该部门薪资最高的记录开始顺序读取
      • 数据获取:

        ​ (覆盖索引)

        • 直接从索引子节点获取first_name,last_name,salary

        • 不需要访问主表(避免"回表"操作)

          (普通索引)

        • 通过索引找到主键/行指针

        • 回主表查找完整记录(额外的I/O操作)

      • 结果返回:

        • 按顺序返回前10条记录
        • 由数据已排序,不需要临时排序操作
  • 函数索引优化日期查询

    SQL 复制代码
    CREATE INDEX idx_hire_year
    ON employees(YEAR(hire_date));
    SQL 复制代码
    -- 统计2024年入职员工数量
    SELECT COUNT(*)
    FROM employees
    WHERE YEAR(hire_date) = 2024;

6.视图示例

  • 部门员工统计视图

    SQL 复制代码
    CREATE VIEW department_employee_stats AS 
    SELECT 
    	d.department_name,
        COUNT(e.employee_id) AS employee_count,
        ROUND(AVG(e.salary), 2) AS avg_salary,
        MAX(e.hire_date) AS latest_hire_date
    FROM departments d
    LEFT JOIN employees e ON d.department_id = e.department_id
    GROUP BY d.department_name;
    SQL 复制代码
    -- 查看所有部门统计
    SELECT * FROM department_employee_stats;
     
    -- 筛选员工数超过50的部门
    SELECT * FROM department_employee_stats 
    WHERE employee_count > 50;
相关推荐
wangruofeng3 小时前
AI Models 1.1.0 发布,查大模型价格、对比模型和找 API 地址
前端·aigc·ai编程
wangruofeng4 小时前
给前端开发者的 100 个设计参考网站
前端·设计
LinXunFeng7 小时前
拿竞品 App 一扫,技术栈全暴露了
android·flutter·开源
星栈7 小时前
视频即代码,Remotion 能做什么、不能做什么
前端·音视频开发
广州华水科技7 小时前
单北斗GNSS位移监测系统的应用与技术解析
前端
用户47949283569157 小时前
从一句话或代码仓到可交互 HTML:开源 Agent 画图技能 Archify v3.2 实测与选型边界
前端·后端·面试
风骏时光牛马9 小时前
生成一个AI多模态标题,仅输出一条标题,无额外文字、问句、备选、配图、文案等任何附加内容,不需要其他的任务服务 只要标题。
前端
Gracker9 小时前
AIW:从系统机制到性能排查,一本可以对照源码的 Android 电子书
android
三少爷的鞋10 小时前
代码越来越便宜,判断力越来越贵:AI 时代的 Android 架构与协程避坑指南
android
Decay__10 小时前
VMware 安装 SQL Server 双节点 AlwaysOn 可用性组教程 —— WSFC、AG 与侦听器完整部署(系列核心篇)
运维·数据库·sql·mysql·架构