探秘数据库——MySQL基础(四)

九、MySQL锁

1、全局锁(Global Lock)

(1)定义

作用于整个 MySQL 实例的锁,加锁后,整个实例只允许读,不允许任何写。

复制代码
FLUSH TABLES WITH READ LOCK;

(2)解决什么问题

全局锁可以保证全库数据的一致性快照,主要用于逻辑备份。

(3)特点

会阻塞所有的INSERT/UPDATE/DELETE以及DDL。但是它不会阻塞普通的SELECT。

(4)生命周期

直到执行了

复制代码
UNLOCK TABLES;

或者断开了连接,生命周期才算结束。

(5)典型场景

使用 mysqldump --single-transaction 之前(非 InnoDB)

(6)易错点

在线上的业务是禁止使用的。同时,全局锁的锁粒度最大,影响的范围也是最广的。

2、表级锁(Table Lock)

(1)定义

直接锁住整张表,任何对该表的并发访问都要受限。

(2)类型

1)表读锁(READ)
复制代码
LOCK TABLE t READ;

使用表读锁时,允许多个会话都可以读,但是禁止所有会话写。

2)表写锁(WRITE)
复制代码
LOCK TABLE t WRITE;

使用表写锁的时候,允许当前对话读写,禁止其他所有会话读写。

(3)使用场景

主要使用在MyISAM引擎中和一些特殊的运维场景。

(4)在InnoDB中的地位如何

在InnoDB中支持但是不推荐使用,InnoDB中主要使用和推荐使用的是行锁。

(5)易错点

表锁不等于意向锁,两者作用完全不同,表锁是可以真正"限制访问"的锁,但是意向锁只是起声明作用的。

3、意向锁(Intention Lock )

(1)定义

意向锁是表级锁,用于声明"事务将要在表中某些行上加什么类型的锁"。

(2)为什么需要

如果没有意向锁的话,会导致行锁与表锁发生冲突时,需要扫描整张表的行锁,发生性能灾难。

(3)类型

类型 含义
IS 将在行上加 S 锁
IX 将在行上加 X 锁

(4)加锁规则

在加锁的时候,需要先加意向锁,再去加锁,这一过程用户是无法手动去控制的。

(5)是否会阻塞

意向锁几乎不会出现阻塞,只用于判断表锁能不能加。

(6)易错点

意向锁不会锁数据,这也是与行锁最本质的区别,也不会影响普通的DML操作。

4、行级锁(Row Lock)

(1)记录锁(Record Lock)

**定义:**锁住索引中的某一条记录,不包含间隙

触发方式:

复制代码
SELECT * FROM t WHERE id = 10 FOR UPDATE;

**特点:**可以精确锁定,而且并发度最高。

**注意:**记录锁必须走索引,否则会升级为更大范围的锁

(2)间隙锁(Gap Lock)

**定义:**间隙锁用于锁住索引记录之间的"区间",不锁具体的记录。

**解决的问题:**可以防止新行的插入,避免了幻读。

**生效条件:**在RR隔离级别且是范围查询。

**易错点:**间隙锁不会阻塞读,只会阻塞INSERT。

(3)临键锁(Next-Key Lock)

**定义:**由记录锁加上前一个间隙锁组成,这是InnoDB默认的行锁方式。

**作用:**可以同时防止当前记录被修改和区间被插入新行(即幻读)。

**易错点:**你写的"等值查询",实质上是加的临键锁(取决于索引)。

5、共享锁(S Lock)

(1)定义

允许多个事务可以读,但是禁止写。

复制代码
SELECT ... LOCK IN SHARE MODE;

(2)行为

读锁与读锁是兼容的,但是读写与写锁是不兼容的。

(3)使用场景

需要保证读到的数据是不可被修改的。

6、排他锁(X Lock)

(1)定义:

排他锁是独占锁的,且禁止其他任何的读写。

复制代码
SELECT ... FOR UPDATE;

(2)特点:

写操作会自动加X锁,只有当事务提交时才会释放X锁(严格2PL).

7、元数据锁(DML)

(1)定义

元数据锁是用于保护表结构的一致性的锁。

(2)行为

当你对一张表执行DML语句时,MySQL会自动在这张表上加一个MDL读锁。

当你对一张表执行DDL语句时,MySQL会自动在这张表上加一个MDL写锁。

(3)典型事故

①长事务持有MDL锁

长事务会长期持有MDL锁,不会影响其他的DML操作、SELECT,系统看着没有任何问题。MDL锁只有在提交时才会释放,如果永远不提交就永远不会释放,这张表就永远不可能被安全的修改结构。

对于下面的代码,在SELECT执行瞬间MySQL就自动给user表加MDL锁了。

复制代码
SELECT * FROM user WHERE id = 1;

只要满足下面任意一条,就叫长事务:

  • BEGIN长时间不 COMMIT / ROLLBACK

  • 开启事务后执行了 SELECT

  • 或执行了 DML

②DDL请求MDL写锁

当MySQL执行SQL前必须在执行的表上获取MDL写锁,而MDL写锁的规则是必须等所有MDL读锁释放后才能获得,于是就导致DDL被阻塞,进入MDL写锁等待队列。DDL不会失败,也不会超时,会一直等着。

③后续所有DML都被阻塞

新的 DML 进来时会发生什么?

复制代码
SELECT * FROM user WHERE id = 2;

这条 DML 本来只需要 MDL 读锁,按理说读读是兼容的,对吧?

但是,因为 MySQL 的 MDL 锁有"公平队列"规则

一旦有 MDL 写锁在等待,后续任何新的 MDL 读锁请求都必须排在它后面。

原因是为了防止 DDL 被永久饿死,否则,只要源源不断的 DML,DDL 永远执行不了。

最终结果:
时间点 状态
T1 长事务持有 MDL 读锁
T2 DDL 请求 MDL 写锁(等待)
T3 新 DML 请求 MDL 读锁 → 排队等待 DDL

导致整张表的所有新DML全部阻塞。

8、自增锁(AUTO-INC Lock)

(1)定义

自增锁(AUTO-INC Lock)是 InnoDB 在生成 AUTO_INCREMENT 列值时使用的一种"表级内部锁",用于保证自增值分配的正确性和唯一性。

有几个关键的点需要注意一下:

**表级:**自增锁的作用范围是"整张表的自增计数器",而不是某一行数据。

**内部锁:**这是InnoDB引擎自己使用的锁,不暴露给SQL层,也不直接体现在用户可见的语义中。

**只为生成自增值服务:**保证AUTO_INCREMENT 值在并发环境下分配正确、唯一。

**不是行锁,也不是MDL:**不是行锁,因为行还不存在,没有row_id可以锁,它也不遵循行锁的两阶段锁协议和事务级持有;不是MDL,是因为MDL的作用是保护表结构不被并发修改;是自增锁,是因为自增锁完全不关心表结构,表结构不变但自增锁照样存在,即使没有DDL也可以频繁触发。

(2)为什么需要自增锁

①AUTO_INCREMENT 的本质问题

假设有表:

复制代码
CREATE TABLE t (
  id BIGINT AUTO_INCREMENT PRIMARY KEY,
  name VARCHAR(20)
) ENGINE=InnoDB;

现在并发发生:

  • 事务 T1:INSERT

  • 事务 T2:INSERT

  • 事务 T3:INSERT

那么这时候就会发现一个问题:谁用1?谁用2?谁用3?

如果不加锁,就会让多个线程同时计算"下一个自增值",这样就极容易产生重复主键。

②为什么不能用行锁?

因为在插入之前还没有那一行,也就没有行可以锁,所以只能在表级协调。所以在自增值生成阶段,必须使用一种表级同步机制自增锁。

(3)自增锁锁的是什么

自增锁并不是锁表数据,而是锁"自增值分配过程",也就是说,自增锁不会阻塞普通的SELLECT,不会阻塞UPDATE/DELETE,只影响并发INSERT中自增值的生成。

(4)加锁时机

自增锁 只在下面这个阶段存在

InnoDB 为 INSERT 语句分配 AUTO_INCREMENT 值的瞬间

而不是整个事务生命周期。

(5)不同的INSERT形式,对自增锁的影响完全不同

①单行INSERT
复制代码
INSERT INTO t(name) VALUES ('A');

特点是只需要一个自增值且自增锁持有的时间极短。并发性能很好。

②多行INSERT
复制代码
INSERT INTO t(name) VALUES ('A'), ('B'), ('C');

特点是一次要分配一段连续自增值,会导致自增锁持有的时间明显变长。在高并发下容易成为瓶颈。

③INSERT ... SELECT
复制代码
INSERT INTO t(name)
SELECT name FROM t2;

特点是插入行数执行前是未知的,所以InnoDB只能全程持有自增锁,直到语句结束才释放。这是自增锁导致"插入性能雪崩"的典型场景。

(6)innodb_autoinc_lock_mode

这是控制 自增锁行为策略 的关键参数。

复制代码
SHOW VARIABLES LIKE 'innodb_autoinc_lock_mode';
①模式0:传统模式(Traditional)

行为:所有的INSERT都使用表级自增锁,锁持有到语句结束。

特点:自增值要求严格连续,且并发性能最差。

适用:老版本兼容,现在极少适用。

②模式 1:连续模式(Consecutive,默认)

行为:简单INSERT(VALUES)自增锁只在分配阶段短暂持有,INSERT...SELECT/批量插入这种情况任然使用表级自增锁。

特点:性能明显提升且自增值基本连续。

③模式 2:交错模式(Interleaved,推荐)

行为:完全不使用表级自增锁,通过原子操作分配自增值。

特点:并发性能最高且自增值不保证连续。

适用:适合高并发写入但是不要求自增值连续的场景。

(7)自增锁与事务回滚的关系

复制代码
INSERT INTO t(name) VALUES ('A');
ROLLBACK;

自增值不会回退,因为自增值是全局计数器,不是事务资源。

所以你可能会看见:

复制代码
1(回滚)
2(下一次插入)

这是设计导致的,不是bug。

9、死锁&锁等待

死锁是循环等待,InnoDB的自动检查,是回滚代价小的事务。

锁等待是非循环的,是超时抛异常的。

10、当前读和快照读有什么区别

快照读:读的是"事务开始时"或"读视图生成时"能看到的历史版本,不加行锁;
当前读:读的是"此刻数据库中最新已提交的数据",并且通常会加锁。

快照:历史版本

当前:最新版本+锁

(1)什么是快照读(Snapshot Read)

定义:

快照读是基于 MVCC,通过 Read View 读取符合可见性规则的历史版本数据的读操作。

常见的SQL形式:
复制代码
SELECT * FROM t WHERE id = 1;

没有 FOR UPDATE / LOCK IN SHARE MODE

读的什么数据:

读的不是最新的数据,是当前事务可见的版本。也即是说,如果别的事务在你之后提交了更新,那么这个更新是看不见的。

是否加锁:

不加行锁,不阻塞写,不被写阻塞,这就是高并发性能的根本来源。

快照何时生成:

取决于隔离界别:

隔离级别 Read View 生成时机
READ COMMITTED 每次 SELECT 都生成
REPEATABLE READ(默认) 第一次快照读时生成一次

(2)什么是当前读(Current Read)

定义:

当前读是直接读取记录的最新版本,并在读取时对记录加锁,保证后续操作的正确性。

触发当前读的SQL:

以下语句一定是当前读:

复制代码
SELECT ... FOR UPDATE;
SELECT ... LOCK IN SHARE MODE;

UPDATE ...
DELETE ...
INSERT ...

所有的DML都是当前读,即使你没有写FOR UPDATE。

读的什么数据:

读的是当前最新版本的数据,如果其他事务未提交,则等待提交,如果已提交就读最新的。

是否加锁:

会加行锁,在RR隔离级别下,可能还会加Next-Key Lock(行锁+间隙锁)。

(3)对比

对比点 快照读 当前读
读的数据 历史版本 最新版本
是否加行锁
是否阻塞写
是否被写阻塞
使用 MVCC ❌(直接读当前)
典型语句 SELECT SELECT ... FOR UPDATE / UPDATE

(4)要点

UPDATE 在修改数据前,一定会先做一次当前读。

例如:

复制代码
UPDATE t SET name='C' WHERE id=1;

这段代码的逻辑是:当前读,读取id=1的最新版本,对该行加锁,生成新版本,然后写Undo Log,所以UPDATE永远不会基于快照去该数据。

(5)和隔离级别的关系

READ COMMITTED

  • 快照读:每次看到最新已提交

  • 当前读:一样加锁

REPEATABLE READ(默认)

  • 快照读:事务内多次 SELECT 结果一致

  • 当前读:无论如何都是最新 + 加锁

隔离级别不会改变"当前读"的本质


十、MySQL性能优化

1、定位性能瓶颈

优化前必须先定位瓶颈,避免盲目操作。核心工具和方法:

(1)核心监控工具

  • SHOW STATUS :查看数据库运行状态(如Com_select/Com_insert统计 SQL 执行次数,Innodb_rows_read/Innodb_rows_updated统计行操作);
  • SHOW PROCESSLIST :实时查看当前连接和 SQL 执行状态(重点关注State列,如Sending data/Locked/Creating tmp table等异常状态);
  • EXPLAIN/EXPLAIN ANALYZE:分析单条 SQL 执行计划(核心中的核心,下文重点讲);
  • Performance Schema/Sys Schema:MySQL 5.6 + 内置的性能监控模块,可追踪 SQL 执行、锁等待、索引使用、IO 开销等;
  • 慢查询日志 :开启后记录执行时间超过long_query_time(默认 10 秒,建议设 1 秒)的 SQL,配合pt-query-digest/mysqldumpslow分析慢查询 Top;
  • 操作系统监控top/iostat/vmstat/dstat,定位 CPU / 内存 / 磁盘 IO / 网络瓶颈(如iostat -x 1看磁盘利用率 % util 是否接近 100%)。

(2)瓶颈类型判断

瓶颈类型 典型特征
CPU 瓶颈 top 中 MySQL 进程 CPU 占比高,多为复杂查询(如多表关联、排序、聚合)、索引失效导致全表扫描
IO 瓶颈 iostat 显示 % util 接近 100%,InnoDB 缓冲池命中率低(Innodb_buffer_pool_reads/Innodb_buffer_pool_read_requests比值 < 99%)
内存瓶颈 系统 Swap 频繁使用,MySQL 缓存(如缓冲池、查询缓存)命中率低
锁等待 SHOW ENGINE INNODB STATUS 显示大量锁等待,业务出现超时 / 阻塞

2、索引优化------核心优化

索引是提升查询效率的关键,但不合理的索引会导致写入变慢、索引膨胀,需遵循 "按需创建、精准高效" 原则。

(1)索引基础:类型与适用场景

索引类型 适用场景 注意事项
B + 树索引(默认) 等值查询(=)、范围查询(>/-/<)、排序(ORDER BY)、分组(GROUP BY) 最左前缀匹配、避免索引失效
哈希索引 仅等值查询(Memcached/Redis 场景更优,MySQL 仅 Memory 引擎支持) 不支持范围查询、排序
全文索引(FULLTEXT) 文本内容模糊匹配(如文章内容搜索) 仅 MyISAM/InnoDB(5.6+)支持,仅适用于 CHAR/VARCHAR/TEXT
空间索引(SPATIAL) 地理坐标查询(如经纬度) 仅 MyISAM/InnoDB(5.7+)支持
联合索引 多字段组合查询(如 WHERE a=1 AND b=2) 字段顺序按 "区分度高→低" 排列,遵循最左前缀

(2)索引设计原则

  • 最左前缀匹配 :联合索引(a,b,c)仅匹配aa+ba+b+c的查询,bb+ca+c会失效;
  • 高区分度优先:区分度 = 不同值数量 / 总行数(如身份证号区分度 100%,性别仅 2%),联合索引中区分度高的字段放前面;
  • 避免冗余索引 :如已有(a,b),无需再创建(a)
  • 覆盖索引优先 :查询的字段都在索引中(无需回表),如SELECT id,name FROM user WHERE age=20,创建(age,name,id)可避免回表;
  • 慎用索引列函数 / 运算 :如WHERE DATE(create_time)='2025-01-01'WHERE id+1=100会导致索引失效,需改写为WHERE create_time BETWEEN '2025-01-01 00:00:00' AND '2025-01-01 23:59:59'
  • 短索引优先 :字符串字段(如手机号)可创建前缀索引(INDEX idx_mobile (mobile(11))),减少索引占用空间;
  • 控制索引数量:写入操作(INSERT/UPDATE/DELETE)需要维护索引,索引越多写入越慢,单表索引建议≤5 个。

(3)索引失效的常见场景

  • 使用OR且非 OR 字段都无索引(如WHERE a=1 OR b=2,仅 a 有索引则失效);
  • 使用LIKE '%xxx'(如WHERE name LIKE '%张三'LIKE '张三%'可命中索引);
  • 索引列使用函数 / 运算 / 类型转换(如WHERE mobile=13800138000,mobile 为字符串,隐式转换失效);
  • 使用NOT IN/!=/NOT EXISTS(部分场景优化器会放弃索引);
  • 数据量过小(如总行数 < 1000,优化器可能选择全表扫描);
  • 联合索引违反最左前缀原则。

(4)索引维护

  • 定期分析索引使用情况:SELECT * FROM sys.schema_unused_indexes(查看未使用的索引),删除冗余 / 无用索引;
  • 重建碎片索引:InnoDB 表可通过ALTER TABLE tbl_name ENGINE=InnoDB(无锁重建)或OPTIMIZE TABLE(有锁)整理索引碎片;
  • 避免大事务期间创建 / 删除索引:大索引创建会锁表(MySQL 8.0 支持在线 DDL,可降低影响)。

3、查询优化------从SQL降低开销

即使有索引,不合理的 SQL 仍会导致性能问题,核心是 "减少扫描行数、避免临时表 / 文件排序、降低锁竞争"。

(1)核心优化原则

  • 只查需要的字段 :避免SELECT *,减少网络传输和回表开销;
  • 限制结果集 :分页查询必须加LIMIT,避免全表扫描返回大量数据;
  • 避免大表关联 :多表关联时,小表驱动大表(InnoDB 嵌套循环连接优化),如SELECT * FROM small_tbl s JOIN big_tbl b ON s.id = b.sid
  • 减少子查询 :子查询易产生临时表,改写为 JOIN(如SELECT * FROM user WHERE id IN (SELECT user_id FROM order WHERE status=1)SELECT u.* FROM user u JOIN order o ON u.id=o.user_id WHERE o.status=1);
  • 避免临时表 / 文件排序ORDER BY/GROUP BY字段未命中索引时,会创建临时表(Using temporary)或文件排序(Using filesort),需优化索引覆盖排序字段;
  • 批量操作替代循环单条 :批量 INSERT(INSERT INTO tbl (a,b) VALUES (1,2),(3,4),(5,6))、批量 UPDATE/DELETE,减少连接和日志刷盘开销;
  • 慎用 DISTINCT/UNION:DISTINCT 可通过索引去重优化,UNION(去重)改为 UNION ALL(不去重)(如无重复数据);
  • 拆分复杂查询:将一个复杂 SQL 拆分为多个简单 SQL,降低单次查询的 CPU/IO 开销。

(2)EXPLAIN 分析执行计划(核心)

EXPLAIN SELECT ... 输出 12 列核心字段,重点关注:

字段 关键解读
id 查询执行顺序(数字越大越先执行,相同数字按顺序执行)
select_type SIMPLE(简单查询)、DERIVED(派生表)、SUBQUERY(子查询)、DERIVED(派生表)等,复杂类型需优化
type 访问类型(从优到差:system > const > eq_ref > ref > range > index > ALL),至少保证 range,避免 ALL(全表扫描)
key 实际使用的索引,NULL 表示未使用索引
rows 优化器预估扫描行数,行数越少越好
Extra 关键提示:- Using index:覆盖索引(优);- Using where:过滤条件(正常);- Using temporary:创建临时表(需优化);- Using filesort:文件排序(需优化);- Using join buffer:连接缓冲区(大表关联需调大 join_buffer_size)。

示例:

复制代码
EXPLAIN SELECT id,name FROM user WHERE age=20 AND gender=1 ORDER BY create_time;
-- 若type为ALL,key为NULL,Extra有Using filesort,需创建联合索引(age,gender,create_time)

4、配置调优

MySQL 默认配置偏保守,需根据服务器硬件(CPU / 内存 / 磁盘)和业务场景(读多 / 写多 / 混合)调整my.cnf/my.ini核心参数。

(1)核心参数(InnoDB 为主)

参数 作用 建议值(参考 8 核 16G 服务器)
innodb_buffer_pool_size InnoDB 缓冲池(缓存数据和索引),核心参数 物理内存的 50%-70%(如 16G 内存设 10G)
innodb_log_file_size 重做日志文件大小,影响事务提交性能 1-4G(总日志大小 innodb_log_file_size*innodb_log_files_in_group ≤ 8G)
innodb_log_buffer_size 重做日志缓冲区 64M-256M(写密集场景调大)
innodb_flush_log_at_trx_commit 日志刷盘策略 1:事务提交立即刷盘(最安全,性能略低);0/2:每秒刷盘(性能高,宕机可能丢 1 秒数据)
sync_binlog 二进制日志刷盘策略 1:每次事务提交刷盘(安全);100:每 100 次事务刷盘(性能高)
max_connections 最大连接数 业务峰值连接数 + 预留(如 1000-2000,避免过大导致内存溢出)
wait_timeout/interactive_timeout 连接超时时间 300 秒(避免闲置连接占用资源)
query_cache_type/query_cache_size 查询缓存(MySQL 8.0 已移除) 读多写少场景开启,设 64M-128M;写密集场景关闭(query_cache_type=0)
join_buffer_size 连接缓冲区(多表关联) 2M-8M(按需调大,避免全局设太大)
sort_buffer_size 排序缓冲区 2M-8M(每个连接独立分配,避免全局设太大)
read_buffer_size/read_rnd_buffer_size 顺序 / 随机读缓冲区 2M-8M
tmp_table_size/max_heap_table_size 临时表大小(内存临时表上限) 64M-128M(避免临时表写入磁盘)
innodb_io_capacity/innodb_io_capacity_max 磁盘 IO 能力上限 根据磁盘性能设置(SSD 设 2000,HDD 设 200)
innodb_flush_method 刷盘方式 O_DIRECT(绕过操作系统缓存,SSD 推荐)

(2)配置优化原则

  • 避免参数 "一刀切":读密集场景调大缓冲池、查询缓存;写密集场景调大日志缓冲区、刷盘策略放宽;
  • 监控参数有效性:通过SHOW GLOBAL STATUS查看参数命中率(如缓冲池命中率 = 1 - Innodb_buffer_pool_reads/Innodb_buffer_pool_read_requests);
  • 逐步调整:单次改 1-2 个参数,观察性能变化,避免批量修改导致故障。

5、存储引擎与表结构优化

(1)存储引擎选择

引擎 适用场景 注意事项
InnoDB 绝大多数场景(事务、行锁、崩溃恢复、外键) 优先选择,MySQL 5.5 + 默认引擎
MyISAM 只读 / 读多写少(如日志、统计) 无事务、表锁,崩溃恢复差,已逐步淘汰
Memory 临时数据、缓存(如会话数据) 数据易失,不支持大表

(2)表结构优化

  • 字段类型最小化:如年龄用 TINYINT(1 字节)而非 INT(4 字节),手机号用 CHAR (11) 而非 VARCHAR (20),时间用 DATETIME 而非 VARCHAR;
  • 避免 NULL 值:NULL 值会增加索引 / 存储开销,可设默认值(如空字符串、0);
  • 拆分大表:- 垂直拆分:将大字段(如 TEXT/BLOB)拆到子表(如用户表拆 user_base(基础信息)+ user_ext(简介 / 头像));- 水平拆分:按时间 / 地域 / 哈希拆分(如订单表按年拆 order_2024、order_2025);
  • 使用分区表 :对大表(千万级以上)按范围 / 列表 / 哈希分区(如按时间分区PARTITION BY RANGE (TO_DAYS(create_time))),减少扫描范围;
  • 避免使用外键:外键会增加写入开销,业务层控制关联关系;
  • 使用自增主键:InnoDB 主键为聚簇索引,自增主键可避免页分裂,提升写入性能(避免 UUID 作为主键,离散写入导致索引碎片)。

6、硬件与操作系统优化

(1)硬件选型

  • CPU:多核 CPU(MySQL 对多核支持较好,复杂查询 / 高并发需 8 核以上);
  • 内存:越大越好(优先满足 InnoDB 缓冲池);
  • 磁盘:SSD(IOPS 比 HDD 高 10 倍以上)> NVMe SSD,避免使用机械硬盘;
  • 网络:10Gbps 网卡,避免网络带宽成为瓶颈(如大数据量导出 / 导入)。

(2)操作系统优化

  • 文件系统:XFS(比 EXT4 更适合大文件、高 IO);
  • 磁盘调度策略 :SSD 设mq-deadline,HDD 设deadlineecho mq-deadline > /sys/block/sda/queue/scheduler);
  • 关闭 swap :避免内存交换(swapoff -a,永久关闭需修改 /etc/fstab);
  • 调整文件描述符限制ulimit -n 65535(避免 Too many open files 错误);
  • TCP 参数优化 :调整net.core.somaxconn(监听队列)、net.ipv4.tcp_tw_reuse(复用 TIME_WAIT 连接)等,提升网络并发。

XFS 是一个由 SGI 开发的 64 位高性能日志型文件系统 ,专为大文件、大并发、高吞吐场景设计。

7、架构层面优化

当单库单表性能达到瓶颈,需从架构层面扩展:

(1)读写分离

  • 主库(Master)负责写入,从库(Slave)负责读取,通过复制(Replication)同步数据;
  • 常用方案:ProxySQL/MaxScale/MyCat 中间件,或业务层读写分离;
  • 注意:复制延迟问题(需监控 Seconds_Behind_Master,写后读场景需特殊处理)。

(2)分库分表

  • 单表数据量超千万 / 亿级时,拆分表(水平 / 垂直)、拆分库(按业务模块);
  • 常用中间件:ShardingSphere/MyCat/TDDL;
  • 核心:分片键选择(如订单表按用户 ID 哈希分片、按时间范围分片),避免跨分片查询。

(3)缓存层引入

  • 热点数据缓存:Redis/Memcached 缓存查询结果(如商品详情、用户信息),减少数据库访问;
  • 注意:缓存穿透 / 击穿 / 雪崩问题,需配合布隆过滤器、过期时间随机化、缓存预热等策略。

(4)读写优化补充

  • 批量写入:合并小事务,减少日志刷盘次数;
  • 延迟写入:非核心数据(如日志、统计)异步写入(消息队列 + 批量入库);
  • 只读实例:针对报表 / 分析类查询,部署只读实例,避免影响主业务。
相关推荐
愚公移码2 小时前
蓝凌EKP产品:扩展Druid 数据源KmssDruidDataSource在企业级数据源初始化与连接监控实践
数据库·hibernate·蓝凌·druiddatasource
Java程序员-小白2 小时前
使用Docker安装MySQL
mysql·docker·容器
和光同尘20232 小时前
一文讲透CentOS下安装部署使用MYSQL
linux·运维·数据库·数据仓库·mysql·centos·database
深圳市恒星物联科技有限公司2 小时前
国内排水监测公司有哪些?
大数据·网络·数据库·物联网
黄焖鸡能干四碗2 小时前
什么是RPA?RPA自动流程机器人在智能制造的应用
大数据·网络·数据库·安全·制造
爱干饭的boy2 小时前
MacBook安装node.js/maven/mysql
mysql·node.js·maven
麦麦鸡腿堡2 小时前
MySQL_SELECT语句
数据库·mysql
共享家95272 小时前
MySQL -复合查询
数据库·mysql
鸿蒙开发工程师—阿辉2 小时前
HarmonyOS 5 数据持久化:关系型数据库 (RelationalStore)
jvm·数据库·harmonyos