作者:Gakki
什么是主键,和外键的区别是什么
-
主键
- 定义:表中唯一标识每一条记录的列(或列组合)。
- 特点:
- 唯一性:主键值必须唯一,不能重复。
- 非空:主键值不能为 NULL。
- 一个表只有一个主键(可以是单列或多列组合)。 - 作用:
- 确保表中每条记录的唯一性。
- 作为其他表引用该记录的依据(通过外键)。
-
外键
- 定义:一个表中引用另一个表主键的列,用于建立两个表之间的关联。
- 特点:
- 外键值必须与被引用表的主键值匹配(或为 NULL)。
- 一个表可以有多个外键,关联到不同表的主键。
- 作用:
- 维护数据一致性(参照完整性),防止无效关联。
- 建立表之间的关系(一对一、一对多等)。
-
区别
主键和外键的区别
什么是脏读?幻读?不可重复读?

什么是事物隔离级别?列举常见的级别
事务,由一个有限的数据库操作序列构成,这些操作要么全部执行,要么全部不执行,是一个不可分割的工作单位。
-
事物的特性:
- 原子性: 事务作为一个整体被执行,包含在其中的对数据库的操作要么全部都执行,要么都不执行。
- 一致性: 指在事务开始之前和事务结束以后,数据不会被破坏,假如A账户给B账户转10块钱,不管成功与否,A和B的总金额是不变的。
- 隔离性: 多个事务并发访问时,事务之间是相互隔离的,一个事务不应该被其他事务干扰,多个并发事务之间要相互隔离。。
- 持久性: 表示事务完成提交后,该事务对数据库所作的操作更改,将持久地保存在数据库之中。
事务隔离级别定义了数据库系统中多个并发事务之间的可见性和影响程度,主要解决并发事务可能引发的数据不一致问题。
-
事务的四大隔离级别:
- 读未提交(Read Uncommitted):就是一个事务可以读取另一个未提交事务的数据。
- 读已提交(Read Committed):一个事务要等另一个事务提交后才能读取数据。
- 可重复读(Repeatable Read):在开始读取数据(事务开启)时,不再允许修改操作。
- 串行化(Serializable):最高隔离级别,完全串行化执行事务。
数据库索引的作用是什么,优缺点有哪些?
索引的作用:提高数据检索速度
-
没有索引的情况:
- 需要全表扫描,逐行检查
- 时间复杂度:O(n),数据量大时性能急剧下降
-
有索引的情况:
- 通过B+树、哈希表等数据结构快速定位
- 时间复杂度:O(log n),极大提高查询效率
-
具体功能:
- 加速 WHERE 条件查询:快速找到满足条件的行
- 加速 JOIN 操作:提高表连接效率
- 加速排序(ORDER BY):索引已排序,避免临时排序
- 加速分组(GROUP BY):快速分组统计
- 保证数据唯一性:唯一索引确保列值不重复
- 优化 MIN / MAX 函数:直接取索引边界值
-
索引的优缺点
-
优点:
优点 -
缺点:
缺点
-
mysql有哪些数据类型,常用的有哪些?
主要可以分为几大类:数值类型、日期和时间类型、字符串类型、JSON 类型以及空间类型
数值类型
├── 整数类型
├── 定点数类型
└── 浮点数类型日期/时间类型
├── DATE
├── TIME
├── DATETIME
├── TIMESTAMP
└── YEAR字符串类型
├── CHAR / VARCHAR
├── TEXT
├── BLOB
├── ENUM
└── SET
- 空间类型
- JSON 类型
解释数据库的 ACID 特性。
- 原子性 (Atomicity) :事务要么全部完成,要么全部不做;
- 一致性 (Consistency) :事务前后数据状态必须合法;【事务执行前后,数据库必须从一个一致性状态转换到另一个一致性状态。】
- 隔离性 (Isolation) :并发事务互不干扰;
- 持久性 (Durability) :事务提交后永久保存;
为什么数据库索引失效后查询会很慢?
-
索引查询 vs 全表扫描
索引查询 vs 全表扫描
索引设计要重点考虑的点是什么?
- 为查询而设计,而非为表而设计。【针对你的 SQL 语句里的 where 条件,orderby 条件以及 group by 条件去设计】。
- 基数考虑:对于基数(即不同值的数量)较小的列,建立索引的效果较差,因此在这种情况下没有必要创建索引。【选择性 = 不同值的数量 / 总行数】
- 短索引:对于长字符串口列,应指定一个前缀长度来创建索引,以节省空间并提高查询效率。如果搜索词超过索引前缀长度,可以使
用索引排除不匹配的行,然后检查其余行是否可能匹配。 - 避免过度索引:过多的索引会占用额外的磁盘空间,并降低写操作的性能。在修改表内容时,索引需要更新甚至重构,索引列越多
这个时间就越长。因此,只保持必要的索引以支持查询即可。 - 外键列索引:定义有外键的数据列一定要建立索引,以确保数据的完整性和查询效率
- 更新频繁字段:对于更新频繁的字段,不适合创建索引,因为每次更新都会导致索引的修改,从而降低性能
- 区分度低的列:如果列不能有效区分数据(如性别,男女未知,最多也就三种),则不适合做索列,因为这样的索引对查询优化的帮助不大。
- 扩展索引:尽量扩展已有索引,而不是新建索引。例如,如果表中已经存在 a 的索引,现在要加(a,b)的索引,那么只需要修改原来的索引即可,这样可以节省空间并提高效率
- 避免不必要的索引:对于查询中很少涉及的列或重复值比较多的列,不要建立索引,因为这样的索引对查询性能的提升有限
- 数据类型口限制:对于定义为 text、image 和 bit 等数据类型的列,通常不适合建立索引,因为这些数据类型的数据量较大或具有特殊性,不利于索引的高效存储和检索。
创建索引的三种方式?
-- 方式1:CREATE INDEX 语句(最常用)
CREATE INDEX index_name ON table_name(column_name);
-- 方式2:ALTER TABLE 语句
ALTER TABLE table_name ADD INDEX index_name(column_name);
-- 方式3:建表时定义
CREATE TABLE table_name (
column1 type,
column2 type,
INDEX index_name(column_name)
);
如何删除索引?
- 方式1:DROP INDEX 语句(标准SQL)
-
DROP INDEX index_name ON table_name;
方式2:ALTER TABLE 语句 ALTER TABLE table_name DROP INDEX index_name;
-
百万级别以上的数据怎么删除?
- 删除整个表的数据:TRUNCATE TABLE(会重置自增主键) 或 DELETE FROM TABLE;
- 删除部分数据(带条件):分批次删除
-
- 基本分批删除【如按年区分】
- 方法1:使用 LIMIT 分批
- 方法2:循环分批删除
- 基于主键的分批删除
- 使用游标的分批删除(复杂条件)
-
- 有分区表 → 删除分区(最快)
- 自动化删除脚本
写一个sql语句删除重复数据(保留一条)
-- 【使用自连接删除】删除重复数据,保留id最小的记录
DELETE u1
FROM
users u1
INNER JOIN users u2 ON u1.username = u2.username
AND u1.email = u2.email
AND u1.phone = u2.phone
WHERE
u1.id > u2.id; -- 只保留u2(id小的)
解释 GROUP BY 和 HAVING 、WHERE 的作用?
GROUP BY 分组操作:将数据按指定列分组,每组返回一行汇总结果。
HAVING 分组过滤:对分组后的结果进行筛选(相当于分组后的WHERE)。
-
HAVING vs WHERE
HAVING vs WHERE
SQL 的 Select 语句它的执行顺序是什么?


我们先执行 from,join 来确定表之间的连接关系,得到初步的数据;where 对数据进行普通的初步的筛选;group by 分组;各组分别执行 having 中的普通筛选或者聚合函数筛选。然后把再根据我们要的数据进行 select ,可以是普通字段查询也可以是获取聚合函数的查询结果,如果是集合函数,select 的查询结果会新增一条字段将查询结果去重 distinct;最后合并各组的查询结果,按照 order by 的条件进行排序。
口诀:
查询数据有顺序,
FROM WHERE GROUP BY。
HAVING过滤聚合值,
SELECT ORDER LIMIT。
WHERE 行滤 HAVING组,
聚合函数要记住。
先滤行来后分组,
性能优化第一步。
UNION 和 UNIONALL 的区别是什么?

MySQL 中的 IN 和 EXISTS 有什么区别?
EXISTS 运算符用于判断查询子句是否有记录,如果有一条或多条记录存在返回 True,否则返回 False。
-
核心区别概览
核心区别概览 -
IN 的执行流程
- 示例查询
SELECT * FROM employees e
WHERE e.department_id IN (
SELECT d.id FROM departments d
WHERE d.location = 'New York'
);
- 执行步骤:
- 1. 执行子查询:SELECT d.id FROM departments d WHERE d.location = 'New York'
- → 返回结果集:[10, 20, 30]
- 2. 将结果集缓存到临时表(可能会去重)
- 3. 执行主查询:SELECT * FROM employees e;逐行比较 e.department_id 是否在临时表 [10, 20, 30] 中
- 4. 返回匹配的行
-
EXISTS 的执行流程
-- 示例查询
SELECT * FROM employees e
WHERE EXISTS (
SELECT 1 FROM departments d
WHERE d.id = e.department_id
AND d.location = 'New York'
);- 执行步骤:
- 从 employees 表取第一行
- 执行子查询,检查是否存在满足条件的记录
- 将当前行的 e.department_id 代入子查询
- 执行:SELECT 1 FROM departments d WHERE d.id = [当前department_id] AND d.location = 'New York'
- 如果找到至少一行,返回 TRUE,否则 FALSE
- 执行子查询,检查是否存在满足条件的记录
- 如果子查询返回 TRUE,保留该行
- 移动到 employees 表的下一行,重复步骤2-3
- 返回所有满足条件的行
- 执行步骤:
数据库连接池的作用是什么?
- 核心作用:连接复用,避免重复创建销毁。
- 没有连接池:
- 应用请求 → 创建连接 → 执行SQL → 关闭连接 → 销毁连接
- 每个请求都重复这个过程,开销巨大
- 有连接池:
- 应用请求 → 从池中获取连接 → 执行SQL → 归还连接到池
- 连接在池中保持,供后续请求复用
- 最大连接数:防止数据库因为连接过多而导致崩溃;
- 最小连接数:预创建连接,减少冷启动延迟。
如何监控数据库的CPU和内存使用情况?
-
使用系统命令查看数据库进程资源消耗:
- top / htop:实时查看 CPU 使用率和进程内存占用;
- vmstat:分析内存分页和 CPU 上下文切换;
- iostat:监控磁盘 I / O 负载。
部署第三方监控平台,实现自动化、可视化监控:Prometheus + Grafana, Zabbix, 云平台自带监控
联合查询?
- 内连接(INNER JOIN):返回两个表中匹配的行。
- 外连接(OUTER JOIN):返回一个表中的所有行,以及另一个表中匹配的行(如果没有匹配,则返回NULL)。
- 左连接(LEFT JOIN)
- 右连接(RIGHT JOIN)
- 全连接(FULL JOIN)
- 交叉连接(CROSS JOIN):返回两个表的笛卡尔积。
- 自连接(SELF JOIN):一个表与其自身连接。
- 自然连接(NATURAL JOIN):自动根据两个表中的同名列进行等值连接。
- 使用 USING 子句的连接:指定连接列(列名必须相同)。
- 多表连接:三个或更多表连接。





