Mysql的理论专题

目录

1、索引

1.1 为什么使用索引可以提交搜索的性能

1.2 为什么mysql会使用B+树存储索引

1.3 索引的分类

1.3.1 聚簇索引和非聚簇索引

1.3.2 唯一索引,普通索引和组合索引

1.4 回表/索引覆盖/最左匹配原则/索引下推

1.5 设计性能优良的索引

1.6 什么情况会导致索引失效

1.7 主键为什么建议自增主键

1.8 如何查看sql是否使用索引

2、事务

2.1 什么是事务

2.2 事务的特性

2.3 事务并发会带来什么问题

2.4 事务的隔离级别

2.5 如何解决数据的读一致性问题

2.6 innodb包含哪些锁

2.7 什么是死锁,如何解决死锁问题

3、架构

3.1 mysql的整体架构的理解

3.2 存储引擎的类型

4、分库分表问题

4.1 为什么要进行分库操作

4.2 为什么要进行分表操作

4.3 如何选择分片键

4.4 非分片键如何查询

4.5 如何实现跨字节的join 关联

4.6 分库后,如何解决事务问题

4.7 如何解决分库分表的分页问题

4.8 垂直分库、水平分库、垂直分表、水平分表的区别

4.9 分表是否需要停服,操作过程?

5、Mysql的优化

5.1 慢查询问题定位

5.2 优化的方法


1、索引

1.1 为什么使用索引可以提交搜索的性能

快速查找:索引的结构是使用B+树的,这样可以快速查找到键值。

减少I/O操作:索引通常是存储在内存中的,通过索引可以减少磁盘的I/O操作

提供检索效率:对应范围查询,索引可以快速找到符合条件的第一个键值,然后遍历索引树到结束条件,索引也可以用来检查唯一键约束。

减少数据访问量:如果查询的列都存在索引中,数据库可以直接从索引中获取数据,而不需要访问实际的数据表,也可以使用索引合并来满足查询条件,减少数据的访问量。

优化器使用:数据库的查询优化器可以根据索引的存在与否选择最优的执行计划,来减少执行时间。

1.2 为什么mysql会使用B+树存储索引

本质原因:B+树可以减少I/O次数,提高查询的效率,可以保证在树高度不变的情况下存储更多的数据。

1.2.1 数据存储在磁盘中,要提高查询效率就要减少I/O的次数和 I/O的数据量。使用K-V的数据结构,K是索引,V是行记录

1.2.2 支持K-V格式的数据结构有哈希表,二叉树,BST,AVL,红黑树,B-树,B+树。

选择B+树的原因:

哈希表的本质是无序散列表,进行范围查询就必须挨个数据进行比较,效率低。

二叉树,BST,AVL,红黑树有一个共同的特点是至多只有两个分支,一个三层的数据至多可以存储7个数据结果值,存储的数据太少。

B-树和B+树可以有多个节点。B-树每个节点包含key值,指针,行记录数据,行记录数据占了很大空间。B+树 叶子节点存储行记录,非叶子节点存储key值和指针,进行检索时从根节点向下检索。相比之下,B+树可以存储更多的数据。

1.3 索引的分类

按数据结构分类:B+树索引,哈希索引,FULL TEXT 索引,R-Tree索引

按物理存储分类:聚簇索引,非聚簇索引

按逻辑分类:主键索引,唯一索引,普通索引,组合索引

1.3.1 聚簇索引和非聚簇索引

在Mysql innodb 引擎中,数据插入时必须跟一个索引列绑定一起进行存储。如果有主键,就选择主键,如果没有主键就选择唯一键,如果没有唯一键,系统就会生成一个6bite的rowId进行存储。

聚簇索引:跟数据绑定存储的索引

非聚簇索引:没有跟数据绑定存储的索引

1.3.2 唯一索引,普通索引和组合索引

 创建普通索引 SQL CREATE INDEX 语法 在表上创建一个简单的索引。允许使用重复的值:

CREATE INDEX index_name ON table_name (column_name)

注释:“column_name” 规定需要索引的列。

创建唯一索引 SQL CREATE UNIQUE INDEX 语法 在表上创建一个唯一的索引。唯一的索引意味着两个行不能拥有相同的索引值。

CREATE UNIQUE INDEX index_name ON table_name (column_name)

可创建多列字段为唯一索引:

CREATE UNIQUE INDEX index_name ON table_name (column_name,age)

创建组合索引 假如您希望索引不止一个列,您可以在括号中列出这些列的名称,用逗号隔开:

CREATE INDEX PersonIndex ON Person (LastName, FirstName)

1.4 回表/索引覆盖/最左匹配原则/索引下推

回表:使用非聚簇索引时,数据库引擎根据普通索引找到匹配的行,然后根据叶子节点中存储的聚簇索引的值去聚簇索引树找到行记录。

有一张表有如下字段:id,name,age,gender,address,其中id是主键,name是普通索引

那么要进行如下SQL语句的查询:

select * from table where name = 'zhangsan';

上述SQL语句的查找过程是:先根据name的值去name的索引树上进行检索,找到匹配的记录之后取出id的值,然后再根据id的值去id的B+树上检索整行的记录,在这个过程中,查找了两棵树,多进行了棵树的IO,因此效率比较低,在生产环境中应该尽量避免回表

索引覆盖:一个索引包含了查询需要的所有数据,无需回表从原表中获取数据

假设有一张表,表中有以下字段:id,name,age,gender,address,其中id是主键,name是普通索引

那么要进行如下SQL语句的查询:

select id,name from table where name = 'zhangsan';

查找过程如下:在name的索引树上包含了要查询的所有字段,所以直接通过name字段去name的B+树上检索对应的记录即可,不需要找到id之后再去id的B+树上检索数据。

索引覆盖可以提高查询的性能,所以在生产环境做SQL优化的时候,可以考虑索引覆盖

最左匹配原则:主要适用于组合索引,指多个列进行匹配的时候要遵循从左到右的原则,不然会导致索引失效

假设有一张表,表中有以下字段:id,name,age,gender,address

id是主键,(name,age)是组合索引

1、Select * from table where name = 'zhangsan' and age = 10;

2、Select * from table where name = 'zhangsan';

3、Select * from table where age = 10;

4、Select * from table where age = 10 and name = 'zhangsan';

上述的四条语句中,1,2,4都可以用到组合索引,3用不到,但是很多同学会有疑问,为什么第四条会用到,明明不符合最左匹配原则的顺序,这里需要注意,如果把第四条SQL语句的条件换一下顺序,会影响最终的查询结果吗?答案是不会的,所以mysql中的优化器会进行优化,调整条件的顺序

索引下推:ICP是mysql使用索引从表中检索行情况进行优化。如果没有ICP, 存储引擎就会通过索引找到记录,将结果返回给server, 在server中对where的条件进行筛选;如果有ICP, 如果where条件的一部分可以通过索引列获取到值,mysql就会将这一部分的where条件下推到存储引擎。即下推指的是将条件的筛选从server层下推到存储引擎层。

索引下推的条件:

A.当需要访问完整的行记录时,ICP用于range、ref、eq_ref和ref_or_null访问方法

B.ICP可以用于innodb和myisam表,包括分区的innodb表和myisam表

C.对于innodb表,ICP仅用于二级索引。ICP的目标是减少整行读取的次数,从而减少IO操作

D.在虚拟列上创建的二级索引不支持ICP

E.引用子查询的条件不能下推

F.引用存储函数的条件不能下推

G.触发器条件不能下推

H.不能将条件下推到包含对系统变量引用的派生表中

假设有一张表,表中有以下字段:id,name,age,gender,address,其中id是主键,(name,age)是组合索引

select * from table where name = 'zhangsan' and age = 10;

没有索引下推:mysql执行这条SQL语句的时候,会首先根据name的值去存储引擎中拉取数据,然后将数据返回到mysql server,然后在server层对age进行条件过滤,把符合条件的结果返回给客户端。

有索引下推:mysql执行这条SQL语句的时候,会直接根据name和age的值去存储引擎中拉取数据,而无需在server层对数据进行条件过滤

可以通过optizizer_switch中的index_condition_pushdown条件来是否开启,默认是开启sql

SET optimizer_switch = 'index_condition_pushdown=off';

SET optimizer_switch = 'index_condition_pushdown=on';

1.5 设计性能优良的索引

A.索引列占用的空间越小越好

B.尽量选择离散度高的列作为索引

C.Where条件字段及order by 字段条件索引

D.在join on 条件字段添加索引

E.索引的个数不用过多,增加索引的维护成本

F.频繁更新的字段不要添加索引

G.随机无序的值,不创建索引

H.索引列在设计时最好不为null

I.可以使用列前缀作为索引列

1.6 什么情况会导致索引失效

A.索引列使用函数(replace\substr\sum\count\avg),表达式

B.数据类型不匹配,数据库数据的类型和索引列的数据类型不匹配

C.组合索引,不满足最左匹配原则

D.Like条件前面带%

E.使用is not null

F.使用关键字or

G.优化器进行分析的时候觉得全表扫描比索引快

1.7 主键为什么建议自增主键

如果选择自增主键的话,每次新增数据时,都是以追加的形式进行存储,在本页索引写满之后,只需申请一个新页继续写入即可,不会产生页分裂问题

如果说采用业务字段作为主键的话,新增数据不一定是顺序的,需要挪动数据,页快满时还要去分裂页,保持索引的有序性,造成写数据成本较高

1.8 如何查看sql是否使用索引

通过执行计划 explain sql 可以查看是否使用索引,以便进行sql 优化。

2、事务

2.1 什么是事务

事务是不可分割的数据库操作序列,并发控制的基本单位,其执行的结果必须是数据库从一种一致性状态到另一种一致性状态。从逻辑上是一组操作,要么一起执行,要么都不执行。

2.2 事务的特性

2.2.1 原子性:不可再分,要么都成功,要么都是失败,不可出现部分成功部分失败的

实现原子性:innodb中通过undo log 实现,undo log 记录了数据修改前的记录,如果出现异常,可以用undo log 实现回滚

2.2.2 一致性:数据库的完整性约束没有被破坏,事务执行前后都是合法的数据状态

实现一致性:LBCC(锁的并发控制), MVCC(多版本并发控制)

2.2.3 隔离性:多个事务,对表和行的并发操作,都是透明的,互不干扰的。

实现: 设置隔离级别

2.2.4 持久性:数据库的任意操作,只有事务提交成功,结果就是永久的。

实现:通过redo log, 操作数据的时候,先写到内存的buffer pool中, 同时记录到redo log。如果在刷盘前出现异常,重启后就可以到redo log 读取记录,写入到磁盘。

2.3 事务并发会带来什么问题

2.3.1 脏读:一个事务,读取到另一个事务未提交的数据。脏读通常出现在读未提交(Read Uncommitted)的隔离级别。

2.3.2 不可重复度:在一个事务内,多次读取同一数据。在这个事务还没有结束时,另一个事务也访问了该同一数据并对其进行了修改。因此,在第一个事务中的两次读数据之间,由于第二个事务的修改,第一个事务两次读到的数据可能是不一样的。这种情况通常发生在读已提交(Read Committed)或可重复读(Repeatable Read)的事务隔离级别下。

2.3.3 幻读:当事务不是独立执行时,第一个事务对一个表中的数据进行了修改,这种修改涉及到表中的全部数据行。在第二个事务中,由于第一个事务的修改,导致第二个事务在读取数据时出现了额外的行或缺失的行。

出现的原因是:同时使用当前读(最新数据)和快照读(undo log 历史数据)

解决幻读:加锁或设置 可串行化的隔离级别

2.4 事务的隔离级别

READ-UNCOMMITTED(读取未提交): 事务的修改,即使没有提交,对其他事务也都是可见的。事务能够读取未提交的数据,这种情况称为脏读。

READ-COMMITTED(读取已提交): 事务读取已提交的数据,大多数数据库的默认隔离级别。当一个事务在执行过程中,数据被另外一个事务修改,造成本次事务前后读取的信息不一样,这种情况称为不可重复读。

REPEATABLE-READ(可重复读): 这个级别是MySQL的默认隔离级别,它解决了脏读的问题,同时也保证了同一个事务多次读取同样的记录是一致的,但这个级别还是会出现幻读的情况。幻读是指当一个事务A读取某一个范围的数据时,另一个事务B在这个范围插入行,A事务再次读取这个范围的数据时,会产生幻读

SERIALIZABLE(可串行化): 最高的隔离级别,完全服从ACID的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。

2.5 如何解决数据的读一致性问题

2.5.1 LBCC(锁的并发控制): 读写数据的时候,锁定我要操作的数据,不允许其他的事务进行访问。会极大低影响数据操作的效率。

2.5.2 MVCC(多版本并发控制)

MVCC的意思是多版本并发控制。指维护一个数据的多个版本,使得读写操作没有冲突,它的底层实现主要是分为三个部分,第一个是隐藏字段,第二个是undo log日志,第三个是readView读视图

隐藏字段是指:在mysql中给每个表都设置了隐藏字段,有一个是trx_id(事务id),记录每一次操作的事务id,是自增的;另一个字段是roll_pointer(回滚指针),指向上一个版本的事务版本记录地址

undo log主要的作用是记录回滚日志,存储老版本数据,在内部会形成一个版本链,在多个事务并行操作某一行记录,记录不同事务修改数据的版本,通过roll_pointer指针形成一个链表

readView解决的是一个事务查询选择版本的问题,在内部定义了一些匹配规则和当前的一些事务id判断该访问那个版本的数据,不同的隔离级别快照读是不一样的,最终的访问的结果不一样。如果是rc隔离级别,每一次执行快照读时生成ReadView,如果是rr隔离级别仅在事务中第一次执行快照读时生成ReadView,后续复用                  

2.6 innodb包含哪些锁

记录锁表示的是给记录行所在的索引上添加的锁。例如select c1 from t where c1 = 10 for update;防止任何其他事务插入、更新或者删除c1=10的行

记录锁总是锁定索引记录,即使表没有定义索引,innodb也会创建一个隐藏的聚簇索引,并使用该索引进行记录锁定

间隙锁的锁定范围是索引记录之间的间隙,或者在第一个索引记录之前或最后一个索引记录之后的间隙,间隙锁是针对事务隔离级别为可重复读或以上级别。

临键锁是记录锁和间隙锁的组合,也就是索引记录本身加上之前的间隙,间隙锁保证在RR级别不会出现幻读问题,防止在同一个事务内得到的结果不一致。假设索引包含10,11,13,20这几个值,那么临键锁的范围就是(-∞,10],(10,11],(11,13],(13,20],(20,+∞)。对于最后一个间隔,临键锁锁定索引中最大值以上的间隙,以及值高于索引中任何实际值的supremum

2.7 什么是死锁,如何解决死锁问题

死锁是两个或多个事务在同一资源上相互占有,并请求锁定对应的资源,导致恶性循环现象

解决死锁问题:

2.7.1 如果不同程序会并发存取多个表,尽量约定以相同的顺序访问表,可以大大降低死锁的概率

2.7.2 在同一个事务中,尽可能做到一次锁定所有的资源,减少死锁产生的概率

2.7.3 对于非常容易产生死锁的业务部分,可以尝试使用升级锁粒度,通过表锁来减少死锁的概率

2.7.4 死锁和索引密不可分,合理优化索引

3、架构

3.1 mysql的整体架构的理解

整体架构包括:客户端、服务器、存储引擎

3.2 存储引擎的类型

3.2.1 MyISAM(3个文件)

特点:

支持表级别的锁(插入和更新会锁表)。不支持事务。

拥有较高的插入(insert)和查询(select)速度。

存储了表的行数(count 速度更快)。

适合:只读之类的数据分析的项目。

3.2.2 InnoDB (2个文件)

特点:

支持事务,支持外键,因此数据的完整性、一致性更高。

支持行级别的锁和表级别的锁。

支持读写并发,写不阻塞读。

特殊的索引存放方式,可以减少 IO,提升查询效率。

适合:经常更新的表,存在并发读写或者有事务处理的业务系统。

3.2.3 Memory (一个文件)

特点:

把数据放在内存里面,读写的速度很快,但是数据库重启或者崩溃,数据会全部消失。只适合做临时表。默认使用哈希索引,将表中的数据存储到内存中。

3.2.4 CSV (3个文件)

特点:

不允许空行,不支持索引。格式通用,可以直接编辑,适合在不同数据库之间导入导出。

3.2.5 Archive (2个文件)

特点:

不支持索引,不支持 update delete。适用于存储和检索大量很少引用的历史、存档或安全审计信息

4、分库分表问题

4.1 为什么要进行分库操作

分库指的是将存储在一个数据库中的数据拆分到多个数据库中进行存储。

主要原因如下:

性能提升:随着业务量的增长,单一数据库可能会面临性能瓶颈。分库可以将数据和请求分散到多个数据库上,从而提高系统的吞吐量和响应时间

容量扩展:单一数据库可能收到硬件资源(磁盘,CPU,内存)的限制,分库可以将数据分散到多个数据库上,从而突破这些限制,实现容量的线性扩展

可靠性提升:分库可以提高系统的可靠性。当某个数据库出现故障时,其他数据库仍然可以正常工作,从而保证业务的连续性

安全性提升:分库可以降低数据泄露的风险。通过将数据分散到多个数据库上,即使某个数据库被攻破,攻击者也无法获取全部数据

运维便利性:分库可以提高运维的便利性。每个数据库可以独立进行备份、恢复、监控等操作,降低了运维的复杂性和难度

4.2 为什么要进行分表操作

分表操作是指将一个大表按照一定的规则分解成多张具有独立空间的表的过程。

主要原因如下:

性能提升:随着业务的发展,数据库中的数据量会不断增长,导致单表的数据量变得非常大。当表的数据量过大时,查询和插入操作会变得非常耗时,性能低下。分表可以将数据分散到多个表中,减少单个表的数据量,从而提高查询和插入的效率。

减轻IO和CPU压力:当单表数据量过大时,查询操作可能需要扫描大量的数据,导致磁盘IO和网络IO的压力增大,同时也可能增加CPU的负担。分表可以将数据分散到多个表中,减少单次查询需要扫描的数据量,从而减轻IO和CPU的压力。

方便数据管理:随着数据量的增长,单表的数据管理可能会变得非常复杂。分表可以将数据按照一定的规则进行划分,使得数据管理变得更加简单和清晰。

避免锁竞争:在并发访问较高的情况下,单表可能会成为锁竞争的热点,导致性能下降。分表可以将数据分散到多个表中,减少锁竞争的可能性。

4.3 如何选择分片键

分片键的选择并没有啥具体的原则,重点还是结合业务和需求来进行判断。

比如可以进行如下选择和判断:

选择合适的业务逻辑主体:比如面向用户的应用,可以使用用户id作为分片键,在电商系统重,可以选择订单、卖家等作为分片键。

如果没有特别明确的业务主体,那么可以考虑数据分布和访问均衡度,尽可能的使每个分表重的数据相对均衡的分布在不同的物理分表中,比如在电商系统中,可以按照商品id和用户id将数据均衡的分布,在金融行业,可以按照用户id或者交易时间进行分表,在物流行业,可以按照订单id或者运输轨迹进行分布,在社交媒体行业,可以按照用户id或者发布时间进行分布

4.4 非分片键如何查询

当按照某一个或者某几个分片键进行分库分表之后,在一些业务场景,难免需要按照非分片键进行查询。

此时可以按照如下方式进行查询:

对所有库所有表进行遍历查询,找到符合条件的记录,此时的效率一定很低,不建议使用

将需要查询的数据信息同步到ES中,在ES中进行高效查询,此方式效率较高,但是需要进行mysql和ES的数据同步

在不同的分表中存储一些冗余数据,能够在此分表上直接进行查询,而不需要跨表查询,比如,在一个有大量用户但是活跃用户较少的系统中,可以将活跃用户的数据冗余在单独的表中,查询的时候直接查询这张表,而不需要扫描全部的表

使用基因法,比如在电商系统中,让同一个用户的所有订单全部存储到一个表中,且查询的时候既可以通过用户id,也可以通过订单id。

4.5 如何实现跨字节的join 关联

在没有分库分表的场景中,join关联多张表的时候非常简单,但是分库分表之后,相关联的表可能不再同一个数据库中,那么如何解决跨库的join操作呢?

字段冗余:把需要关联的字段放入主表中,避免关联操作;比如订单表保存了卖家ID(sellerId),你把卖家名字sellerName也保存到订单表,这就不用去关联卖家表了。这是一种空间换时间的思想。

全局表:比如系统中所有模块都可能会依赖到的一些基础表(即全局表),在每个数据库中均保存一份。

数据抽象同步:比如A库中的a表和B库中的b表有关联,可以定时将指定的表做同步,将数据汇合聚集,生成新的表。一般可以借助ETL工具。

应用层代码组装:分开多次查询,调用不同模块服务,获取到数据后,代码层进行字段计算拼装。

4.6 分库后,如何解决事务问题

分库分表后,假设两个表在不同的数据库中,那么本地事务已经无效了,此时需要考虑分布式事务。

常见的分布式事务解决方案如下:

4.6.1 两阶段提交

4.6.2 三阶段提交

4.6.3 TCC

4.6.4 saga

4.6.5 本地消息表

4.6.6 最大努力通知

4.7 如何解决分库分表的分页问题

方案1(全局视野法):

在各个数据库节点查到对应结果后,在代码端汇聚再分页。这样优点是业务无损,精准返回所需数据;缺点则是会返回过多数据,增大网络传输,也会造成空查,

方案2(业务折衷法-禁止跳页查询):

这种方案只有上一页和下一页,不允许跳页查询了。查询第一页时,是跟全局视野法一样的。但是下一页时,需要把当前最大的创建时间传过来,然后每个节点,都查询大于创建时间的一页数据,接着汇总,内存排序返回。

4.8 垂直分库、水平分库、垂直分表、水平分表的区别

垂直分库:将原本一个数据库中的表按照业务功能分布到不同的数据库中,每个数据库只包含部分表。

水平分库:将一个数据库中的表按照数据行进行拆分,分不到多个数据库中国,每个数据库都包含完成的表结构,但只包含部分数据。

垂直分表:将一个数据库中的列拆分到不同的表中,这些表具有相同的主键,但包含不同的列。

水平分表:将一个数据库表中的数据拆分到多个相同结构的表中,每个表都包含部分数据行,通常按照一定的规则拆分。

4.9 分表是否需要停服,操作过程?

不用停服。主要分五个步骤:

编写代理层,加个开关(控制访问新的DAO还是老的DAO,或者是都访问),灰度期间,还是访问老的DAO。

发版全量后,开启双写,既在旧表新增和修改,也在新表新增和修改。日志或者临时表记下新表ID起始值,旧表中小于这个值的数据就是存量数据,这批数据就是要迁移的。

通过脚本把旧表的存量数据写入新表。

停读旧表改读新表,此时新表已经承载了所有读写业务,但是这时候不要立刻停写旧表,需要保持双写一段时间。

当读写新表一段时间之后,如果没有业务问题,就可以停写旧表。

5、Mysql的优化

5.1 慢查询问题定位

5.1.1、慢查询原因:

聚合查询/多表查询/表数据量过大查询/深度分页查询

表现:页面加载慢、接口无响应,或者响应时间过长(超过1s)

5.1.2、如何定位慢查询

方案一:开源工具

调试工具:Arthas

运维工具:Prometheus 、Skywalking

方案二:MySQL自带慢日志

慢查询日志记录了所有执行时间超过指定参数(long_query_time,单位:秒,默认10秒)的所有SQL语句的日志 如果要开启慢查询日志,需要在MySQL的配置文件(/etc/my.cnf)中配置如下信息:

开启MySQL慢日志查询开关

slow_query_log=1

设置慢日志的时间为2秒,SQL语句执行时间超过2秒,就会视为慢查询,记录慢查询日志

long_query_time=2    

定义慢查询日志存放位置                                           

slow_query_log_file = /data/mysql/logs/slow.log

慢日志是否开启和日志文件位置sql语句

show variables like '%slow_query_log%';

5.1.3 一个SQL语句执行很慢, 如何分析

语法:

直接在select语句之前加上关键字explain/desc

EXPLAIN SELECT 字段列表 FROM 表名 WHERE 条件;

possible_key: 当前sql可能会使用到的索引

key:当前sql实际命中的索引

key_len: 索引占用的大小

Extra: 额外的优化建议

type: 这条sql的连接的类型

注意:性能由好到差为NULL、system、const、eq_ref、ref、range、 index、all

type 类型介绍说明
system查询系统中的表
const根据主键查询
eq_ref主键索引查询或唯一索引查询
ref索引查询
range范围查询
index索引树扫描
all全盘扫描

5.2 优化的方法

5.2.1 SQL查询优化
避免使用select* :只选取需要的列,减少数据传输量。
使用覆盖索引:设计索引以涵盖查询中所有列,减少回表查询。
利用EXPLAIN分析查询:理解查询执行计划,优化索引使用。
减少子查询:尽可能用连接查询(JOIN)替代复杂的子查询。
使用LIMIT进行分页:避免一次性加载大量数据,特别是在网页分页场景中。
优化IN操作:IN操作符中元素过多会影响性能,考虑使用JOIN或临时表。


5.2.2 索引优化
合理添加索引:对经常用于查询条件的列添加索引,尤其是主键和外键。
索引类型选择:根据数据分布选择合适的索引类型,如B-Tree、Hash等。
定期分析和优化索引:使用ANALYZE TABLE和OPTIMIZE TABLE命令保持索引的最新状态。
避免冗余索引:删除不必要的重复索引,减少写操作的开销。


5.2.3 表结构设计
合适的数据类型:选择最合适的字段类型,避免不必要的空间占用和处理时间。
分区表:对于大型表,可以考虑使用分区提高查询效率。


5.2.4. 硬件与配置优化
内存:增加内存,扩大InnoDB缓冲池(innodb_buffer_pool_size),让热点数据尽可能驻留在内存中。
CPU:根据负载情况考虑增加CPU核心数。
磁盘:使用SSD提高I/O速度,或配置RAID以提高可靠性或性能。
配置调整:根据实际负载调整MySQL配置文件中的各项参数,如线程池大小、连接数限制等。


5.2.5. 日常维护
定期备份:制定备份策略,使用mysqldump或mysqlhotcopy等工具。
监控与日志:使用工具(如MySQL Enterprise Monitor、Prometheus+Grafana)监控数据库状态,分析慢查询日志。
清理和归档:定期归档或删除不再需要的历史数据,减少数据库体积。
安全维护:定期检查权限分配,避免过度使用root账户,及时更新安全补丁。

  • 12
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值