Skip to content

数据库

字数
4937 字
阅读时间
21 分钟

一、简介

  1. 数据库:长期存储在计算机内的、有组织的。简而言之,数据库就是一个存储数据的仓库
  2. 应用场景:
    1. 页面复杂数据正确性校验(功能测试,测页面功能)。如:统计每日新增用户多少
    2. 测试数据的构造(性能测试)。如:商城系统需要构造一些商品/用户信息
    3. 数据的清洗。如:系统上线前基础数据的去重,垃圾数据的清理等
  3. 数据库分类:
    1. 🌟关系型数据库:以形式存储数据
    2. 非关系型数据库:非表格存储数据【了解】
  4. 常见数据库管理系统(DBMS)
    1. 关系型(RDBMS):MySQL、Oracle
      • SQL语言只能用于操作关系型数据库,且关系型数据库的SQL语言基本都类似
    2. 非关系型:Redis、HBase
    • 数据库管理系统是下载MySQL、Oracle、Redis等数据库后默认自带有的,默认其中有数据库,也可以通过DBMS创建修改数据库

1.SQL

  • Structured Query Language(结构化查询语言),通过SQL语言可以对关系型数据库进行操作
  • 特点:
    • 通用性:常见都可以通过SQL语言操作
    • 简洁性:语言简洁,易学易用
  • SQL语句关键词:
    • 数据操作:insert(增)、delete(删)、update(改)、select(查)
    • 数据定义(对数据表和数据库):create(创建)、alter(修改)、drop(删除)

2.MySQL数据库

  • MySQL:企业级关系型数据库管理系统,目前是隶属于Oracle公司的产品
  • 构成:
    • 客户端:下发用户要执行的SQL语句,并显示服务器返回的执行结果。【命令行/第三方可视化界面】
      • 如:命令行客户端使用 mysql(.exe) -u root -p执行登录操作
    • 服务端:存储数据并解析编译后的SQL语句,将执行结果返回给客户端
  • MySQL数据库连接
    • 工具客户端:DataGrip、DBeaver、Navicat
    • 服务端:Vmware虚拟机(已安装mysqld服务)

二、数据库操作(针对整个数据库的操作) --> SQL语句

字符集:有相同属性的字符的组合。例如:支持中文符号的字符集utf8。utfmb4是utf8的扩展版
排序规则:将字符集转化为计算机识别的进制的规则。例如:支持中文字符集utf8的一般规则utf8_general_ci
  1. SQL语句规则:
    1. SQL不区分大小写
    2. SQL语句结束标志 --> 英文格式分号
    3. 变量名构成:字母、数字、下划线
  2. 数据库常见操作:
    1. 创建数据库:create database 数据库名 charset 字符集 collate 排序规则;
    2. 使用数据库:use 指定数据库名
    3. 查看正在使用的数据库:select database();
    4. 修改数据库:alter database 库名 charset 字符集 collate 排序规则;
    5. 删除数据库:drop database 库名; --> 数据库和数据表的删除都使用 drop

三、数据库引擎

MySQL 支持插件式存储引擎,不同引擎对应不同存储、索引、事务、并发策略,面试常问5 种核心引擎,重点是 InnoDB

0. 核心分类及特点

  • MySQL的核心特点是插件式存储引擎架构;数据库服务器与存储引擎分离,你可以为不同的表设置不同的存储引擎(一张表只能用一种),MySQL5.5及以后的默认存储引擎InnoDB(也是目前最主流的)
    • 简单的说:存储引擎决定了数据表【怎么存数据、怎么处理并发、支不支持回滚、崩了能不能恢复】
  • MySQL最核心、最实用的分类维度是是否支持事务,这直接决定了引擎的适用场景,分为两大类:
    1. 事务型存储引擎:支持 ACID 事务特性(原子性、一致性、隔离性、持久性),支持崩溃恢复、行级锁,适合有数据一致性要求的业务(如电商、金融)。
    2. 非事务型存储引擎:不支持事务,通常是表级锁,读写速度快,但崩溃后可能丢数据,适合只读/少写、对一致性要求低的静态数据业务。

1.主流存储引擎(必背)

仅InnoDB为事务型数据库,可使用show engines;命令查看MySQL支持的所有存储引擎

1)InnoDB(MySQL 5.5+ 默认引擎)
  • 支持事务:ACID 完整事务、回滚、崩溃恢复
  • 行级锁:并发高、适合大量读写
  • 外键约束:唯一支持外键的引擎
  • 索引:聚簇索引(主键高效),支持 B+ 树
  • 适用场景:电商、金融、订单、支付、高并发业务
2)MyISAM(5.5 前默认)
  • 不支持事务、不支持外键
  • 表级锁:并发差,写入会阻塞全表
  • 查询极快:count (*) 直接读取元数据
  • 适用场景:只读 / 少写、日志系统、静态数据展示
3)Memory(Heap)
  • 数据存内存:速度极快
  • 重启丢失数据、不支持事务
  • 表级锁、支持哈希索引
  • 适用场景:临时表、缓存、会话数据
4) CSV
  • CSV 格式存储,可直接用 Excel 打开
  • 不支持索引、不支持大字段
  • 适用:数据交换、简单导入导出
5)Archive
  • 只支持 INSERT/SELECT,不支持删除 / 修改
  • 高压缩、占用空间极小
  • 适用:日志、审计、历史归档

2.核心对比(面试高频)

表格

引擎事务锁粒度索引适用场景
InnoDB支持行锁聚簇索引高并发、业务系统
MyISAM不支持表锁非聚簇读多写少
Memory不支持表锁哈希临时缓存

3.面试一句话总结

  • 90% 业务用 InnoDB:要事务、并发、安全就选它
  • MyISAM:老项目、纯查询用
  • Memory:临时数据、速度优先

四、数据表操作

  • 查表结构操作:desc 表名
  • 删除表:drop table 表名

五、常用SQL语法

  1. 去重查询:select distinct 字段名 from 表名 --> distinct 关键字去重
  2. 限定返回行数:select 字段名 from 表名 limit 行数 --> 返回 指定行数的数据
  3. 查询字段后将该字段改名:
    SQL
    select 
      字段1 as 别名1,
      字段2 as 别名2
     from 表名;
  4. 新增数据:insert into 表名 values(值1, 值2, ...), (值1, 值2, ...); --> 插入多条记录
    • 也可指定插入某几列的数据:insert into 表名 (列1, 列2, ...) values(值1, 值2, ...);
  5. 修改数据:update 表名 set 字段=值 where 条件; --> 常见条件:字段 = 值
  6. 删除表中的数据:delete from 表名 where 条件;
  7. 查询数据:select * from 表名; --> * 表示任意字段

数据复杂查询

别名
  • 复杂的名称可以起别名以便于编写语句
  1. 数据表起别名:表名 as 别名
  2. 字段起别名:字段名 as 别名
    • 起别名的关键字 as 可以省略,例如:表名 别名
  • 数据表起别名后,查询必须要使用表别名;字段别名看情况使用(不能用在 WHERE 和标准 GROUP BY 中)
练习用数据表:students、courses、scores

1)🌟条件查询(重要,不难)
空字符串 -->  字符 = ""
  • 基础语法:select * from 表名 where 条件;

  • 常见条件构成分类:

    1. 比较运算符条件 --> 字段 比较运算符 值,例如:id = 1 (=, !=, >=, <=, >, <)
    2. 逻辑运算符条件 --> 条件1 逻辑关系 条件2,例如:name = "张三" and id = 2 (and, or, not)
    3. 模糊查询:%表示 匹配任意长的值,_ 表示匹配单个长度的值 (这两个条件不能一起用)
      SQL
      --  不指定长度

    字段 like '模糊值' -- 例如:name like "张%"

     -- 指定长度    
     字段 like '模糊值'   -- 例如:name like "张_" 
     ```
    
    1. 范围查询:
      SQL
      非连续: 字段 in (值1, 值2, ...)             例如:city in ("北京", "上海")
      连续:字段 between 值1 and 值2        例如:age between 18 and 25
    2. 空判断:字段 is null
      • 非空判断:字段 is not null 或 not 字段 is null (条件前加 not 表示条件取反)
2)排序
  • 应用场景:按照大小规则进行查询所需要的数据。例如:年龄从小到大排序显示人员信息。常用于页面级数据的高低大小的确认
  • 语法格式:select * from 表名 order by 字段名 asc/desc; --> 升序asc / 降序desc (默认升序)
SQL
-- eg:查询所有学生信息,按年龄从大到小排序,年龄相同时,按学号从小到大排序
select * from students order by age desc, studentNo;
3)🌟聚合函数
  • 应用场景:对列表数据的统计计算方法。例如:统计这个 班级的平均年龄
  • 语法:select 聚合函数 from 表名 --> select后的聚合函数可以用多个,多个之间用英文逗号分割
    • 例如:select name ,max(age) from students 只会返回一条最大age的数据,其他返回的普通列可能是随机拼接的(若分组,则每个分组只会返回一个max)
    • 使用了聚合函数后,每组只会返回一条记录
  • 聚合函数常见分类
    • count():统计表中所有的记录数,通过count(*)表示 (count内的参数可以是某个字段,也可以是所有记录 --> *)
      • count(*):统计所有记录数,包含某列为空值的记录数
      • count(字段):统计某列非空的所有记录数
    • max():计算某列的最大值,通过max(字段)表示
    • min():计算某列的最小值,通过min(字段)表示
    • sum():计算某列的和,通过sum(字段)表示
    • avg():计算某列的平均值,通过avg(字段)表示
4)分组查询(有难度)
  • 应用场景:表中数据量过大时,可以先将数据分组,然后再查询提高查询效率(一般需求中出现“每种、每个、各个”这类词汇时可以考虑)
  • 语法:
    • 普通分组查询:select 字段1, 字段2, 聚合.. from 表名 group by 字段1, 字段2, ...;
    • 带条件分组查询:select 字段1, 字段2, 聚合.. from 表名 group by 字段1, 字段2, ... having 条件;
      • where与having的区别:
        1. where是对原始数据进行筛选,所以where后不能带聚合函数的条件,但having可以(having带聚合函数条件必须先分组,聚合函数会计算分组后的结果)
        2. having是对分组之后的结果进行筛选,因而不能单独使用,必须和分组结合使用
        3. having后面如果跟普通字段构成的条件,必须是分组之后的字段
SQL
-- 查询各种性别的人数
select sex, count(*) from students group by sex;  -- 按照性别分组,并统计每个组的所有记录条数

-- 查询每个班级中各个性别的人数
select count(*) from students group by class, sex;  -- 先按班级分组,同一个班级再按性别分组,记录每个组的人数(以最小的组为一组)

-- 查询每个平均年龄大于22的班级有哪些
select class from students group by class having avg(age) > 22;

-- 查询每个班级中女生的平均年龄大于22岁的班级有哪些
-- 在数据量大的情况下推荐先进行分组再使用having筛选(分组前先where筛选效率太低,分组后筛选效率高)
select class from students group by class, sex having avg(age) > 22 and sex = '女'; -- avg函数会计算每个分组的平均年龄(先按班级分组,再按性别分组,计算出分组的平均年龄后,再筛选出性别女生即可)
select class from students where sex='女' group by class having avg(age) > 22; -- 另一种解法
-- 该SQL语句会先筛选出性别为女的所有记录,然后再按class分组,再取出剩余记录的分组进行avg计算,最后再根据select class 取出指定字段的记录
5)分页查询
  • 应用场景:取最大/最小值记录数据时使用,通常结合排序,排序后针对当前页面,从start位置开始,返回 count 条数据
  • 常见应用:分页常常和排序结合使用,对应最大最小值条件的应用
  • 语法:select * from 表名 limit start, count
    • start:下标/索引,表示从第几条开始(数据位置),默认从0开始计数
    • count:需要显示的记录数
    • select * from 表名 limit 2 :只取前两行(开始位置下标默认为0)
SQL
select * from students limit 0, 3
select * from students limit 3 -- 这两行语句作用一致
6)连接查询(有难度,代码量大)
1. 当内连接/外连接出现多个内连接/外连接同时使用时(多个内连接,多个外连接这两种情况),每次连接都是基于上一次操作得到的“临时表”作为左表(或参与连接的表),再与下一个表进行连接。
2. 一般多个外连接都是使用同一种外连接,例如:第一次使用left join,后续就都使用left join,避免复杂化问题
3. 内/外连接从左到右,都基于原表关联
   例如:
	SELECT *
		FROM students s
		LEFT JOIN scores sc ON s.id = sc.student_id
		LEFT JOIN awards aw ON s.id = aw.student_id; -- 都使用原表进行关联
  • 应用场景:将相关联的多张表进行连接,并查询所需要的数据
  • 本质:两张表中有公共列(不一定是主键和外键,但匹配列的值一定要相等)
  • 分类:
    1. 内连接:左右两张表都能匹配到的公共列
      • 取两张表的公共列对应的记录,根据公共列(有数据的公共列)将两表的其他列拼接起来,形成一张新表,记录数与两者公共列的最小值等同
      • 语法:select * from 表1 inner join 表2 on 表1.列=表2.列
    2. 外连接:需求中出现一张表需要显示全部数据时考虑使用
      • 能用左连接就一定能用右连接
      1. 左连接:左右两边的公共数据+左表特有的数据(即:左表显示全部数据),右表只显示与公共列匹配的数据,不存在的数据用null表示
        • 不存在的数据-->左表有但右表没有的数据
        • 语法:select * from 表1 left join 表2 on 表1.列=表2.列
      2. 右连接:左右两边的公共数据+右表特有的数据(即:右表显示全部数据),左表只显示与公共列匹配的数据,不存在的数据用null表示
        • 语法:select * from 表1 right join 表2 on 表1.列=表2.列
    • 图例:
SQL
-- 内连接
	-- 查询学生信息及成绩(信息和成绩存储在两张不同的表中,但这两张表都有一个公共列:studentNo)。
	-- 内连接选择的是两张表的公共数据,记录数取两表最小
	-- 该SQL的意思是,将students表和scores表进行内连接,公共列是studentNo
select * from students inner join scores on students.studentNo = scores.studentNo; 
select * from students st inner join scores sc on st.studentNo = sc.studentNo; -- 起别名
	-- 多张表的关联
	-- 查询学生信息及学生的课程对应的成绩
select st.*, co.name, sc.score from student st
	inner join scores sc on st.studentNo = sc.studentNo
	inner join courses co on sc.courseNo = co.courseNo;
SQL
-- 右连接(显示右表全部信息,左表没有的用null填充)
	-- 查询所有学生的成绩,包括没有成绩的学生 -->  需要成绩信息和学生信息(包括有成绩和无成绩的学生信息)
	-- 学生信息需要显示全部
select * from scores sc
	right join students st on sc.studentNo = st.studentNo
	-- 一般认为第一张表是左表,另一张是右表
SQL
-- 左连接
select * from students st
	left join scores sc on sc.studentNo = st.studentNo
7)子查询(理解有难度,使用不难)
  • 应用场景:涉及多表关联,想办法在一张表中查到结果【过滤条件或临时表需要另一个SQL查询的场景】
  • 子查询构成:
    1. 主查询:括号外面的select查询
    2. 子查询:括号里面的select查询
  • 子查询具体应用 :
    1. 作为条件:子查询结果如果是一行一列/多行一列/一行多列,可以直接作为查询条件(where后的条件)
    2. 作为数据源(临时表):子查询结果是多行多列(临时表),需要结合连接查询
SQL
-- 情况1:作为条件
	-- 查询大于平均年龄的学生信息
select * from students where age > (
	select avg(age) from students
);

	-- 查询与李明同班级同年龄的学生信息
select * from students where (class, age) =(
	select class, age from students where name='李明'
);

	-- 查询18岁学生的成绩(子查询返回结果大于 1 条记录)
select score from scores where studentNo in (
	select studentNo from students where age=18
);
SQL
-- 情况2:作为数据源(临时表)
	-- 查询数据库和系统测试这两门课程的成绩
select tmp.name, sc.score from scores sc 
	inner join (select * from courses where name in ('数据库', '系统测试')) tmp -- 给临时表起别名为tmp 
	on sc.courseNo = tmp.courseNo;

SQL语句的书写顺序

  • 总顺序:select ... from 表名 inner join 表名 on ... where 条件 group by ... having ... order by ... limit ...

贡献者

The avatar of contributor named as freeway348 freeway348

文件历史

撰写