MySQL

数据库原理及其应用

MySQL安装---Linux系统

第一步:更新系统

bash 复制代码
sudo apt update && sudo apt upgrade -y

第二步:安装 MySQL 8.0

bash 复制代码
sudo apt install mysql-server -y

等待安装完成(约 1-3 分钟,取决于网速)。

第三步:启动并设置开机自启

bash 复制代码
sudo systemctl start mysql
sudo systemctl enable mysql

第四步:验证安装

bash 复制代码
# 查看版本
mysql --version

# 查看运行状态
sudo systemctl status mysql --no-pager

第五步:登录测试

bash 复制代码
# 方式一:使用 sudo
sudo mysql

# 方式二:使用密码(需先设置 root 密码)
mysql -u root -p

出错
sudo mysql
-- 设置 root 密码
ALTER USER 'root'@'localhost' IDENTIFIED WITH caching_sha2_password BY '你的强密码';

-- 刷新权限
FLUSH PRIVILEGES;

-- 退出
exit

$ mysql -u root -p
Enter password: 

成功登录后会显示:

sql 复制代码
Welcome to the MySQL monitor...
mysql>

退出 MySQL:

sql 复制代码
exit
复制代码
现在 Navicat 用 SSH 隧道连接:

**SSH 标签页**:
- 主机:`192.168.88.129`
- 端口:`22`
- 用户名:`lkx`
- 密码:(你的 lkx 密码)

**常规标签页**:
- 主机:`127.0.0.1`
- 端口:`3306`
- 用户名:`navicat`
- 密码:`123456`

开发

数据库基础知识

表约束

作用:限制字段数据,确保数据完整性与一致性。

约束类型 关键字 说明
非空约束 NOT NULL 字段值不可为 NULL
唯一约束 UNIQUE 字段值全局唯一(允许多个 NULL
主键约束 PRIMARY KEY 非空 + 唯一,每表仅一个,常配合 AUTO_INCREMENT
默认约束 DEFAULT 插入时若未指定值,则使用默认值
外键约束 FOREIGN KEY 引用另一表的主键,维护表间引用完整性
检查约束 CHECK (expr) 限定字段取值范围(如 age >= 0),注:MySQL 8.0.16+ 才完全支持
自增 AUTO_INCREMENT 整型字段自动递增,通常用于主键

外键约束的更新/删除行为

定义外键时可指定关联表记录被更新或删除时的动作:

行为 说明
NO ACTION 默认行为,若子表存在关联记录,则拒绝操作(等同于 RESTRICT
CASCADE 级联操作:主表记录更新/删除 → 子表关联记录同步更新/删除
SET NULL 主表记录被删/改 → 子表外键字段设为 NULL(要求该字段允许 NULL

语法示例

sql 复制代码
FOREIGN KEY (dept_id) REFERENCES departments(id)
  ON UPDATE CASCADE
  ON DELETE SET NULL;

多表连接查询

笛卡尔积(Cartesian Product)

  • 无连接条件时,返回两表所有行的组合(m × n 行),通常需避免。

内连接(Inner Join)

  • 仅返回两表匹配的记录。
sql 复制代码
SELECT * FROM t1 INNER JOIN t2 ON t1.id = t2.t1_id;
-- INNER 可省略

外连接(Outer Join)

  • 左外连接(LEFT JOIN) :返回左表全部 + 右表匹配部分(无匹配则右表字段为 NULL
  • 右外连接(RIGHT JOIN):返回右表全部 + 左表匹配部分

自连接(Self Join)

  • 同一张表"自己连自己",需使用别名区分。
sql 复制代码
SELECT e.name, m.name AS manager 
FROM employees e 
LEFT JOIN employees m ON e.manager_id = m.id;

联合查询

合并多个 SELECT 结果集:

操作符 特点
UNION ALL 保留所有行(含重复)
UNION 自动去重(性能略低)

要求

各查询列数相同、对应列类型兼容、列名以第一个查询为准

子查询

SELECT / WHERE / FROM 中嵌套 SELECT

1.标量子查询

​ 返回单行单列(一个值)

sql 复制代码
SELECT name FROM users WHERE age > (SELECT AVG(age) FROM users);

2.列子查询

​ 返回单列多行

​ 常配合 IN / NOT IN / ANY / SOME / ALL

sql 复制代码
SELECT * FROM products 
WHERE category_id IN (SELECT id FROM categories WHERE active = 1);

3.行子查询

​ 返回一行多列

sql 复制代码
SELECT * FROM orders 
WHERE (customer_id, order_date) = (SELECT id, MAX(created_at) FROM customers);

4.表子查询(派生表)

​ 返回多行多列,作为临时表使用(需起别名)

sql 复制代码
SELECT t.avg_price, t.category 
FROM (SELECT AVG(price) AS avg_price, category FROM products GROUP BY category) AS t
WHERE t.avg_price > 100;

数据库进阶知识

事务

事务的基本操作命令
  • 查看当前会话的自动提交状态:

    mysql 复制代码
    SELECT @@autocommit;
    • 返回 1 表示开启自动提交(每条 DML 语句独立成事务)。
    • 返回 0 表示关闭自动提交(需手动控制事务边界)。
  • 关闭自动提交(进入手动事务模式):

    mysql 复制代码
    SET @@autocommit = 0;
  • 显式开启一个新事务(两种等效写法):

    mysql 复制代码
    START TRANSACTION;
    -- 或
    BEGIN;
  • 提交事务(使修改永久生效):

    mysql 复制代码
    COMMIT;
  • 回滚事务(撤销未提交的所有修改):

    mysql 复制代码
    ROLLBACK;

注意:

  • DDL 语句(如 CREATE, ALTER, DROP)会隐式提交当前事务。
  • 在自动提交模式下,每条 INSERT/UPDATE/DELETE 语句执行后立即提交,无法回滚。
事务的四大特性(ACID)
特性 说明
原子性(Atomicity) 事务是一个不可分割的工作单元,其中的操作要么全部成功,要么全部失败回滚。
一致性(Consistency) 事务执行前后,数据库必须从一个一致状态转移到另一个一致状态(如转账前后总金额不变)。
隔离性(Isolation) 并发执行的多个事务相互隔离,互不干扰。具体隔离程度由隔离级别决定。
持久性(Durability) 一旦事务提交,其对数据的修改将永久保存到存储介质中,即使系统崩溃也不会丢失。
事务隔离级别

MySQL 支持四种标准 SQL 隔离级别,通过以下命令查看和设置:

  • 查看当前会话的隔离级别:

    sql 复制代码
    SELECT @@transaction_isolation;
  • 设置当前会话的隔离级别(仅对当前连接生效):

    sql 复制代码
    SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
    SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
    SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
    SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;
四种隔离级别对比
隔离级别 脏读 不可重复读 幻读 说明
READ UNCOMMITTED 允许 允许 允许 性能最高,一致性最弱,一般不用于生产。
READ COMMITTED 禁止 允许 允许 每次读取都获取最新已提交数据(Oracle 默认)。
REPEATABLE READ 禁止 禁止 InnoDB 通过 MVCC + 间隙锁避免幻读 MySQL InnoDB 默认隔离级别,保证同一事务内多次读结果一致。
SERIALIZABLE 禁止 禁止 禁止 最高隔离,完全串行执行,性能最低。

说明:

  • 脏读:读到其他事务未提交的数据。
  • 不可重复读:同一事务内,两次读同一行数据结果不同(因其他事务已提交修改)。
  • 幻读:同一事务内,两次查询返回的行数不同(因其他事务插入/删除了满足条件的行)。
  • InnoDB 在 REPEATABLE READ 级别下,通过 Next-Key Lock(行锁 + 间隙锁) 解决幻读问题。

存储引擎

基本概念
  • 存储引擎是 MySQL 中用于管理表数据存储与检索的底层组件。
  • 引擎作用于表级别,而非数据库级别。同一数据库中的不同表可使用不同存储引擎。
  • 创建表时可通过 ENGINE = 引擎名 指定存储引擎,默认通常为 InnoDB。
查看与设置命令
mysql 复制代码
-- 查看当前 MySQL 支持的所有存储引擎及其状态
SHOW ENGINES;

-- 查看某张表的建表语句,包含所用引擎
SHOW CREATE TABLE 表名;

-- 创建表时显式指定引擎
CREATE TABLE 表名 (
    列定义...
) ENGINE = InnoDB;
主要存储引擎对比
特性 InnoDB MyISAM Memory
事务支持 支持(ACID) 不支持 不支持
外键约束 支持 不支持 不支持
锁机制 行级锁(高并发性能好) 表级锁(并发写入性能差) 行级锁(数据在内存)
崩溃恢复能力 支持自动恢复 无自动恢复,可能丢失数据 无持久性,重启后数据丢失
数据持久性
典型文件 .ibd(含数据和索引) .MYD(数据)、.MYI(索引) 仅 .sdi(结构),数据在内存
适用场景 用户系统、订单、支付等核心业务 只读或读多写少的静态数据 临时中间结果、会话缓存
文件结构说明
  • InnoDB
    • .ibd 文件:包含表的数据和索引(MySQL 5.6+ 默认开启 innodb_file_per_table)。
    • 表结构元数据存储在数据字典中(MySQL 8.0 起也以 .sdi 文件形式存在)。
  • MyISAM
    • .sdi:表结构定义
    • .MYD:表数据(MYData)
    • .MYI:索引数据(MYIndex)
  • Memory
    • 仅在内存中存储数据,.sdi 文件保存结构定义,服务重启后数据清空。
InnoDB 逻辑存储结构

InnoDB 的数据组织层级从上到下为:

  • Tablespace(表空间):如系统表空间或独立表空间(.ibd 文件)。
  • Segment(段):分为数据段、索引段等。
  • Extent(区):连续的 1MB 空间,由 64 个 Page 组成。
  • Page(页):最小 I/O 单位,默认 16KB。
  • Row(行):实际存储的记录。

该结构决定了即使查询单行数据,也可能触发整页(16KB)的磁盘读取。

MySQL 架构分层

MySQL 服务器逻辑上分为四层:

  1. 连接层:处理客户端连接、身份认证、安全校验。

  2. 服务层:SQL 解析、优化、缓存、内置函数执行(如日期、字符串函数)。

  3. 引擎层:插件式存储引擎接口,InnoDB、MyISAM 等在此实现。

  4. 存储层:物理文件系统,负责数据落盘或内存存储。

索引

索引的基本概念
  • 索引是帮助 MySQL 高效获取数据的有序数据结构
  • 类比:书籍的目录,通过目录可快速定位内容,而无需逐页翻阅。
索引的优缺点
优点 缺点
- 显著提高 SELECT 查询效率- 减少排序和分组(ORDER BY, GROUP BY)的 CPU 开销- 支持快速连接(JOIN - 占用额外磁盘空间- 降低 INSERTUPDATEDELETE 操作性能(需同步维护索引)- 增加 ALTER TABLE(如加列)的执行时间
常见索引结构

(1)B+Tree 索引(主流)

  • InnoDB 和 MyISAM 默认使用 B+Tree
  • 特点:
    • 所有数据记录都存储在叶子节点,非叶子节点仅存索引键和指针。

    • 叶子节点之间通过双向链表连接 ,支持高效范围查询(如 WHERE id BETWEEN 10 AND 100)。

    • 树高度低(通常 3~4 层),I/O 次数少,适合磁盘存储。

(2)Hash 索引

  • 仅 Memory 引擎原生支持;InnoDB 提供自适应哈希索引(内部优化,不可显式创建)。
  • 特点:
    • 基于哈希表实现,仅支持等值查询 (如 WHERE id = 100)。
    • 不支持范围查询、排序、最左前缀匹配
    • 查找时间复杂度为 O(1),但哈希冲突会降低性能。
为什么 InnoDB 选择 B+Tree 而非其他结构
对比项 二叉搜索树 B-Tree B+Tree(InnoDB 选择)
层级深度 深(O(log₂N)),I/O 多 较浅(多路平衡) 更浅(扇出更大),I/O 更少
范围查询 不支持高效遍历 可支持,但需中序遍历 叶子节点链表,高效范围扫描
数据存储位置 键与数据混存 键与数据可存于非叶节点 数据仅存于叶子节点,非叶节点更紧凑,单页可存更多键,树更矮
磁盘友好性 较好 最优(顺序 I/O + 高扇出)

关键结论: B+Tree 在磁盘 I/O 效率、范围查询支持、内存利用率三方面综合最优,特别适合数据库的读多写少、范围扫描频繁的场景。

索引类型

按逻辑功能分类

类型 说明
主键索引(PRIMARY KEY) 唯一、非空,自动聚簇(InnoDB 中数据按主键物理排序)。
唯一索引(UNIQUE) 值唯一(允许一个 NULL),用于保证字段唯一性。
普通索引(INDEX / KEY) 最基本的索引,无唯一性约束。
组合索引(复合索引) 多列组成的索引,遵循最左前缀原则
全文索引(FULLTEXT) 用于文本关键词搜索、用于 MATCH ... AGAINST 文本搜索,适用于大文本字段。

InnoDB 特有:按存储结构分类

  • 1.聚簇索引

    • 叶子节点直接存储整行数据主键即聚簇索引。若未定义主键,InnoDB 会隐式生成 6 字节 row_id 作为聚簇索引。
  • 2.二级索引

    • 叶子节点存储主键值,而非整行数据。 查询时需 回表:先查二级索引得主键,再用主键查聚簇索引获取完整行。
sql 复制代码
SELECT * FROM user WHERE id = 10;      -- 直接走聚簇索引,一次 I/O
SELECT * FROM user WHERE name = 'Arm'; -- 走 name 的二级索引,需回表,两次 I/O

结论:第一条效率更高。

B+Tree 高度估算(InnoDB)

  • InnoDB 页大小默认为 16KB(16384 字节)

  • 假设一行数据大小为 1KB ,则一页可存约 16 行

  • 主键为 BIGINT(8 字节),指针占 6 字节(页号)。

  • 对于非叶子节点(仅存键和指针),每个节点最多容纳键值数 n 满足:

    复制代码
    n * 8 + (n + 1) * 6 ≤ 16384
    => 14n + 6 ≤ 16384
    => n ≈ 1170
  • 叶子节点每页存 16 行,总记录数 N:

    • 高度为 2:最多支持 1170 * 16 ≈ 18,720
    • 高度为 3:1170 * 1170 * 16 ≈ 2190 万
    • 高度为 4:超 250 亿

结论:绝大多数业务表 B+Tree 高度为 3,查询只需 3 次磁盘 I/O。

索引语法
sql 复制代码
-- 创建索引
CREATE [UNIQUE] INDEX index_name ON table_name (column_list);

-- 查看表的所有索引
SHOW INDEX FROM table_name;

-- 删除索引
DROP INDEX index_name ON table_name;

示例:为 name 字段创建普通索引

sql 复制代码
CREATE INDEX idx_name ON user(name);
SHOW INDEX FROM user;
SQL 性能分析

查看 SQL 执行频率

sql 复制代码
SHOW GLOBAL STATUS LIKE 'Com_%';
  • Com_selectCom_insert 等表示各类语句执行次数。

慢查询日志

  • 默认关闭,需在配置文件(如 my.cnf)中开启:

    ini 复制代码
    slow_query_log = 1
    slow_query_log_file = /var/log/mysql/slow.log
    
    long_query_time = 2   -- 超过 2 秒的查询记为慢查询
    log_queries_not_using_indexes = 1  -- 可选:记录未用索引的查询
  • 开启后,定期分析慢日志,定位性能瓶颈。

使用 SHOW PROFILES

sql 复制代码
SELECT @@have_profiling;  -- 查看是否支持
SET profiling = 1;        -- 开启

-- 执行 SQL
SHOW PROFILES;            -- 列出所有查询 ID 和耗时
SHOW PROFILE FOR QUERY 1; -- 查看 ID=1 的详细阶段耗时

EXPLAIN 执行计划

sql 复制代码
EXPLAIN SELECT * FROM user WHERE name = 'Arm';

关键字段说明:

字段 说明
id 查询序号。相同值按从上到下执行;值越大越先执行(子查询场景)。
select_type 查询类型(SIMPLE、PRIMARY、SUBQUERY 等)。
type 访问类型(最重要) ,性能从优到劣:NULL > system > const > eq_ref > ref > range > index > ALL- const/eq_ref:主键或唯一索引等值查询- ref:普通索引等值查询- range:范围查询(如 BETWEEN, IN)- ALL:全表扫描(需优化)
possible_keys 可能使用的索引。
key 实际使用的索引。若为 NULL,表示未命中索引。
key_len 使用索引的字节数,可判断是否用到组合索引的全部列。
rows 预估扫描行数,越小越好。
filtered 百分比,表示存储引擎返回的数据经 Server 层过滤后剩余比例。
Extra 附加信息,重点关注:- Using index:覆盖索引(无需回表)- Using where:Server 层过滤- Using filesort:需额外排序(性能差)- Using temporary:使用临时表(性能差)
索引使用

索引效率验证

  1. 执行原始查询(未建索引)

    sql 复制代码
    SELECT * FROM table_name WHERE column_name = 'value';
    • 观察执行时间或通过 EXPLAIN 确认是否发生全表扫描(type = ALL)。
  2. 创建索引

    sql 复制代码
    CREATE INDEX idx_column ON table_name (column_name);
  3. 再次执行相同查询并分析执行计划

    sql 复制代码
    EXPLAIN SELECT * FROM table_name WHERE column_name = 'value';
    • key 字段显示所建索引名,且 typerefconstrange,说明索引生效。
    • 实际执行时间应显著降低(尤其在数据量较大时)。

索引失效的常见场景

  1. 最左前缀法则(联合索引)
  • 对于联合索引 (col1, col2, col3),查询条件必须从最左侧列开始,且不能跳过中间列

  • 有效用法:

    sql 复制代码
    WHERE col1 = ?
    WHERE col1 = ? AND col2 = ?
    WHERE col1 = ? AND col2 = ? AND col3 = ?
  • 失效用法:

    sql 复制代码
    WHERE col2 = ?                     -- 跳过 col1
    WHERE col1 = ? AND col3 = ?        -- 跳过 col2
  1. 范围查询的影响
  • 在联合索引中,范围条件(>, <, BETWEEN, != 等)右侧的列无法使用索引

  • 示例(索引:(col_a, col_b)):

    sql 复制代码
    WHERE col_a = 1 AND col_b > 100    --  col_a 等值,col_b 范围,索引可用
    WHERE col_a > 1 AND col_b = 100    --  col_a 范围,col_b 索引失效

3.索引列参与运算或函数

  • 在索引列上使用函数、表达式或计算会导致索引失效。

  • 错误示例:

    sql 复制代码
    WHERE YEAR(date_column) = 2025
    WHERE price + tax > 100
  • 正确改写:

sql 复制代码
WHERE date_column >= '2025-01-01' AND date_column < '2026-01-01'
WHERE price > 100 - tax   -- 若 tax 为常量
  1. 字符串值未加单引号(隐式类型转换)
  • 当索引列为字符串类型时,查询值必须用单引号包裹。

  • 错误:

    sql 复制代码
    WHERE varchar_column = 12345   -- 触发隐式转换,索引失效
  • 正确:

sql 复制代码
WHERE varchar_column = '12345'
  1. 模糊查询(LIKE)规则
  • 前缀匹配(尾部模糊)可使用索引

    sql 复制代码
    WHERE text_column LIKE 'prefix%'   -- 可用索引
  • 非前缀匹配(含头部通配符)索引失效

    sql 复制代码
    WHERE text_column LIKE '%suffix'   --  全表扫描
    WHERE text_column LIKE '%contain%' --  全表扫描
  1. OR 条件的索引使用
  • OR 连接的多个条件中,任一列无索引,则整个 OR 子句可能无法使用索引

  • 风险示例(仅 col_x 有索引):

    sql 复制代码
    WHERE col_x = 'A' OR col_y = 'B'   -- col_y 无索引,可能导致全表扫描
  • 优化方案:

    • 为所有 OR 涉及列建立索引;

    • 或改写为 UNION

      sql 复制代码
      SELECT * FROM table_name WHERE col_x = 'A'
      UNION
      SELECT * FROM table_name WHERE col_y = 'B';
  1. 数据分布影响优化器决策
  • 即使存在索引,若 MySQL 估算使用索引的 I/O 成本高于全表扫描(如高选择性低的字段),则会放弃索引。

  • 典型场景:性别、状态等低区分度字段。

8.SQL 索引提示

用于显式控制优化器对索引的选择:

sql 复制代码
-- 建议使用指定索引(优化器可忽略)
SELECT * FROM table_name USE INDEX (index_name) WHERE ...;

-- 忽略指定索引
SELECT * FROM table_name IGNORE INDEX (index_name) WHERE ...;

-- 强制使用指定索引(若不可用则报错)
SELECT * FROM table_name FORCE INDEX (index_name) WHERE ...;

9.覆盖索引

  • 定义:查询所需的所有列均包含在索引中,无需回表查询聚簇索引。
  • 优势
    • 避免回表(减少 I/O 操作);
    • 提升查询性能,尤其在高并发场景;
    • EXPLAINExtra 字段显示 Using index 表示命中覆盖索引。
  • 使用建议
    • 避免 SELECT *,明确指定所需字段;

    • 若查询字段均为索引列,优先构建包含这些字段的联合索引。

10.前缀索引

  • 适用场景 :对长字符串列(如 VARCHAR(255))建立完整索引成本高。

  • 方法 :仅对字符串的前 N 个字符建立索引。

    sql 复制代码
    CREATE INDEX idx_prefix ON table_name (column_name(N));
  • 注意事项

    • 前缀长度需保证足够高的区分度 (可通过 SELECT COUNT(DISTINCT LEFT(column_name, N)) / COUNT(*) 估算);
    • 前缀索引不支持覆盖索引(因索引中不含完整列值);
    • 无法用于 ORDER BYGROUP BY 的完整排序(除非前缀足以区分)。

11.单列索引 vs 联合索引的选择

场景 推荐策略
仅单一条件高频查询 单列索引即可
多个字段组合查询(如 WHERE a = ? AND b = ? 优先使用联合索引 (a, b)
同时存在 WHERE aWHERE a AND b 查询 联合索引 (a, b) 可同时满足
多个独立高频查询(如 WHERE aWHERE b 互不相关) 可分别建单列索引,或评估是否用联合索引覆盖
索引设计通用原则
  1. 针对大数据量且查询频繁的表建索引

    • 小表(如配置表 < 1000 行)通常无需索引。
  2. 索引应覆盖常见查询模式

    • 包括 WHERE 条件、ORDER BYGROUP BYJOIN 关联字段。
  3. 优先考虑高区分度字段

    • 区分度 = COUNT(DISTINCT column) / COUNT(*),越接近 1 越适合建索引;
    • 唯一索引(如用户 ID、订单号)是理想选择。
  4. 控制索引数量

    • 每增加一个索引,会降低写操作(INSERT/UPDATE/DELETE)性能;
    • 避免重复或冗余索引(如 (a)(a, b) 共存时,(a) 可能冗余)。
  5. 优先使用联合索引,合理应用前缀索引

    • 联合索引可减少索引数量,提升复合查询效率;
    • 对长字符串,使用前缀索引平衡空间与性能。
  6. 避免过度索引

    • 不为低频查询、低区分度字段(如性别、状态)建索引;
    • 定期审查并删除未使用的索引(可通过 sys.schema_unused_indexes 或慢日志分析)。

存储过程

运维

相关推荐
2301_813599552 小时前
CSS如何解决CSS引入后的样式覆盖_理解优先级原则避免重写
jvm·数据库·python
betazhou2 小时前
TDSQL-PG创建测试表并定时插入数据模拟生产
前端·javascript·数据库·tdsql·tdsql-pg
kiku18182 小时前
NoSQL之Redis配置与优化
数据库·redis·非关系型数据库
喵了几个咪2 小时前
MySQL 运维实战:ibd 文件批量转换为 SQL 完整指南(基于 ibd2sql)
运维·sql·mysql
跃渊Yuey2 小时前
【MySQL】MySQL库的操作
数据库·mysql
weixin_408717772 小时前
PHP8.1新特性对AI开发帮助_JIT编译优势【解答】
jvm·数据库·python
瀚高PG实验室2 小时前
瀚高数据库安全版4.5.10及其以上版本使用pg_cron定时任务
服务器·数据库·瀚高数据库
2401_871696522 小时前
golang如何实现Trie前缀树_golang Trie前缀树实现解析
jvm·数据库·python
2401_887724502 小时前
Go语言怎么做HTTP连接池_Go语言HTTP连接池教程【基础】
jvm·数据库·python