当前位置: 首页 > news >正文

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

一、索引

1.索引是什么

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

2.索引的类型

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

3.索引的创建

-- 创建普通索引
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种)
-- 创建简单的视图
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;
  • 查询视图

    SELECT * FROM v_active_users;
    
  • 修改视图

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

    DROP VIEW v_active_users;
    

3.视图的使用场景

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

4.视图的注意事项

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

三、综合实例

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

1.表结构

  • employees表 员工表

    字段名类型主键外键约束说明
    employee_idINT✔️自增员工唯一标识
    first_nameVARCHAR(50)NOT NULL员工名字
    last_nameVARCHAR(50)NOT NULL员工姓氏
    ageINT年龄
    positionVARCHAR(100)职位(如:工程师)
    department_idINT✔️所属部门ID(外键)
    phoneCHAR(11)手机号
    hire_dateDATE入职日期
    salaryDECIMAL(10,2)薪资
  • departments表

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

2.创建表

-- 创建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}$')
);

  • 修改表中的字段类型和添加列(添加了 薪资和入职时间)
-- 修改表中的字段类型
ALTER TABLE employees
ADD COLUMN hire_date DATE,
ADD COLUMN salary DECIMAL(10,2),
MODIFY COLUMN phone CHAR(11);

  • 插入数据

    -- 插入部门数据
    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)

    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 = '技术部';
    
  • 统计各部门员工数量及平均薪资

    -- 方法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年的员工

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

4.数据维护操作

  • 更新员工部门

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

    -- 先删除部门(需要处理外键约束)
    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;
    
    
    
    • 问题:我发现我在定义外键的时候没有定义外键名,系统为我们自动定义了外键名,需要自行查询

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

5.索引优化示例

  • 设置普通的索引

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

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

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

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

    CREATE INDEX idx_dept_salary
    ON employees(department_id, salary DESC)
    INCLUDE (first_name, last_name);  -- 覆盖索引,不参与排序结构
    
    -- 查找市场部薪资最高的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条记录
        • 由数据已排序,不需要临时排序操作
  • 函数索引优化日期查询

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

6.视图示例

  • 部门员工统计视图

    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;
    
    -- 查看所有部门统计
    SELECT * FROM department_employee_stats;
     
    -- 筛选员工数超过50的部门
    SELECT * FROM department_employee_stats 
    WHERE employee_count > 50;
    

相关文章:

  • 【Python趣味】:爬取音乐
  • C# Winform 入门(2)之发送邮件
  • MyBatis基础五(动态SQL,缓存)
  • NFS 重传次数速率监控
  • xml中配置AOP织入
  • vxe-table 树表格启用树节点连接线的使用
  • 前端简单入门学习1——使用工具
  • 企业级NoSql数据库Redis集群
  • SQL Server 八大排序算法详解
  • 【Linux网络与网络编程】03.UDP Socket编程
  • Qt6调试项目找不到Bluetooth Component蓝牙组件
  • 实例中调用带有命名控件的成员
  • 判断一个字符串中排除空格和换行以外字符运行不同的逻辑
  • 剑指Offer(数据结构与算法面试题精讲)C++版——day2
  • AIGC SD出图有缺陷有哪些方法可以解决?
  • nginx rewrite的相关功能
  • 算力100问☞第100问:算力竞争的关键领域?
  • 数据仓库建模-CIF方法中3NF建模的核心作用解析
  • “壹号土”和“壹号土猪”都是已注册商标!
  • MongoDB 核心机制解析
  • 广州高端品牌网站建设后台管理便捷/国内重大新闻10条
  • 做商城购物网站/北京优化seo排名
  • 动易网站建设/甘肃seo技术
  • 云建站微网站/线上推广营销
  • 做动态的网站的参考资料有哪些/手机如何建网站
  • 东港网站建设/百度指数的搜索指数