MySQL复习知识点总结

1.存储引擎

1.1 概念

数据库存储引擎是数据库底层软件组织,数据库管理系统(DBMS)使用数据引擎进行创建、查询、更新和删除数据,不同的存储引擎提供不同的存储机制、索引技巧、锁定水平的功能,使用不同的存储引擎可以获得特定的功能。
MySQL的存储引擎有MyISAMInnoDB

1.2 MyISAM

是MySQL的默认存储引擎,但是他没有提供对数据库事务的支持,也不支持行级锁和外键,因此insert或update(即写操作)时需要锁定整个表,效率较低。
但是ISAM 执行读取操作速度很快,而且不占用大量的内存和存储资源,它是一种静态索引结构缺点是不支持事务处理。

1.3 InnoDB

时MySQL的默认事务型引擎,用来处理大量短期事务。InnoDB 的性能和自动崩溃恢复特性使得它在非事务型存储需求中也很流行,除非有特别原因否则应该优先考虑 InnoDB。
InnoDB 的数据存储在表空间中,表空间由一系列数据文件组成。MySQL4.1 后 InnoDB 可以将每个表
的数据和索引放在单独的文件中。
InnoDB 采用 MVCC 来支持高并发,并且实现了四个标准的隔离级别。其默认级别是 REPEATABLE
READ (可重复读),并通过
间隙锁策略防止幻读
,间隙锁使 InnoDB 不仅仅锁定查询涉及的行,还会对索引中的间隙进行锁定防止幻行的插入。
InnoDB 表是基于聚簇索引建立的,InnoDB 的索引结构和其他存储引擎有很大不同,聚簇索引对主键
查询有很高的性能,不过它的二级索引中必须包含主键列,所以如果主键很大的话其他所有索引都会很
大,因此如果表上索引较多的话主键应当尽可能小。
InnoDB 的存储格式是平台独立的,可以将数据和索引文件从一个平台复制到另一个平台。
InnoDB 内部做了很多优化,包括从磁盘读取数据时采用的可预测性预读,能够自动在内存中创建加速
读操作的自适应哈希索引,以及能够加速插入操作的插入缓冲区等。
MySQL复习知识点总结_第1张图片
底层存储结构为B+树,B树的每个结点对应innodb的一个page,page大小固定,一般设为16k,其中非叶子节点只有键值,叶子节点包含完整数据。

区别:
MySQL复习知识点总结_第2张图片

1.3 Memory

也叫堆内存:使用存在内存中的内容来创建表,每个memory表只实际对应一个磁盘文件,memory类型的表访问非常快,因为他数据放在内存中并默认使用了HASH索引。 但是一旦服务关闭,表中数据就会丢失重启丢失,**Memory 同时支持散列索引和B树索引,B树索引可以使用部分查询和通配查询。

Memory 表适合的场景:查找或者映射表、缓存周期性聚合数据的结果、保存数据分析中产生的中间数据。

如果 MySQL 在执行查询的过程中需要使用临时表来保持中间结果,内部使用的临时表就是 Memory表。如果中间结果太大超出了Memory 表的限制,或者含有 BLOB 或 TEXT 字段,临时表会转换成MyISAM 表。

2.索引

2.1 概念

索引的本质是数据结构,他的目的在于提高查询效率,类似于字典。排好序的快速查找数据结构就是索引。

在数据之外,数据库系统还维护着满足待定查找算法的结构,这些数据结构以某种方式引用数据,这样就可以在这些数据结构上实现高级查找算法,这种数据结构就是索引。

优势:提高数据检索效率 降低数据排序成本

劣势:索引也是一张表,索引列也会占用空间,虽然索引提高查询速度但会降低更新表的速度,更新不仅要保存数据还要更新索引信息
索引这是提高效率的一个因素,需要花费时间优化最优索引。

2.2 索引使用原则

1 . 选择唯一性索引
唯一性索引的值是唯一的,可以更快速的通过该索引来确定某条记录。
2. 为经常需要排序、分组和联合操作的字段建立索引 ;
3 .为常作为查询条件的字段建立索引 。
4.限制索引的数目:越多的索引,会使更新表变得很浪费时间,尽量使用数据量少的索引;
6.如果索引的值很长,那么查询的速度会受到影响。
7. 尽量使用前缀来索引:如果索引字段的值很长,最好使用值的前缀来索引。
删除不再使用或者很少使用的索引
8 .最左前缀匹配原则
9. 尽量选择区分度高的列作为索引
区分度的公式是表示字段不重复的比例
10. 索引列不能参与计算,保持列“干净”:带函数的查询不参与索引。
11 . 尽量的扩展索引,不要新建索引。

2.3 索引分类

单值索引:一个索引只包含单个列,一个表可以有多个单列索引
唯一索引:索引列的值必须唯一,但允许有空值
复合索引:一个索引包含多个列

2.4 mysql索引结构

B-Tree索引

意味着所有的值都是按顺序存储,并且每个叶子页到根的距离相同,B-Tree索引能够加快访问数据的速度,因为存储引擎不再需要全表扫描来获取需要的数据,取而代之的是从索引的根节点开始搜索,根节点的槽中存放了指向子节点的指针,存储引擎根据这些指针向下查找。通过比较节点页的值和要查的值可以找到合适的指针进入下层子节点,这些指针实际上定义了子节点页中值的上限和下限。最终存储引擎要么找到对应值,要么不存在,叶子节点的指针指向的是被被索引的数据而不是其他节点的页。
B-Tree索引的限制:
1.如果不是按照索引的最左列开始查找,则无法使用索引。
2.不能跳过索引中的列,例如索引为 (id,name,sex),不能只使用 id 和 sex 而跳过 name。
3.如果查询中有某个列的范围查询,则其右边的所有列都无法使用索引。

Hash索引

基于哈希表实现,只有精确匹配索引所有列的查询才有效,对每一行数据,存储引擎都会对所有的索引列计算一个哈希码,哈希码是一个较小的值,并且根据不同的键值计算出的哈希码也不同,哈希索引将所有的哈希码存储在索引中,同时在哈希表中保存指向每个数据行的指针。
只有Memory引擎显示支持哈希索引,这也是Memory引擎的默认索引类型
因为索引自身只需存储对应的哈希值,所以索引的结构十分紧凑,这让哈希索引的速度非常快,但它也有一些限制:
1.哈希索引数据不是按照索引值顺序存储的,无法用于排序。
2.哈希索引不支持部分索引列匹配查找,因为哈希索引始终是使用索引列的全部内容来计算哈希值的。例如在数据列(a,b)上建立哈希索引,如果查询的列只有a就无法使用该索引。
3.哈希索引只支持等值比较查询,不支持任何范围查询。

全文索引

通过数值比较、范围过滤等就可以完成绝大多数需要的查询,但如果希望通过关键字匹配进行查询,就需要基于相似度的查询而不是精确的数值比较,全文索引就是为了这种场景设计的。
MyISAM 的全文索引是一种特殊的 B-Tree 索引,一共有两层。第一层是所有关键字,然后对于每一个关键字的第二层,包含的是一组相关的"文档指针"。全文索引不会索引文档对象中的所有词语,它会根据规则过滤掉一些词语,例如停用词列表中的词都不会被索引

聚簇索引

聚簇索引不是一种索引类型,而是一种数据存储方式。InnoDB的聚簇索引实际上在同一个结构中保存了B-Tree索引和数据行,当表有聚簇索引时,它的行数据实际上存放在索引的叶子页中,因为无法同时把数据行放在两个不同的地方,所以一个表只能由一个聚簇索引。

聚簇索引就是按照每张表的主键构造一颗B+树,同时叶子节点中存放的就是整张表的行记录数据,也将聚集索引的叶子节点称为数据页。这个特性决定了索引组织表中数据也是索引的一部分,每张表只能拥有一个聚簇索引。
优点
① 可以把相关数据保存在一起。
② 数据访问更快,聚簇索引将索引和数据保存在同一个 B-Tree中,因此获取数据比非聚簇索引要更快。
③ 使用覆盖索引扫描的查询可以直接使用页节点中的主键值。

缺点
1.插入速度严重依赖于插入顺序,按照主键的顺序插入是最快的方式,(新增行就会出现页分裂,导致每个被更新的行被重新移动)否则将会出现页分裂,严重影响性能。因此,对于InnoDB表,我们一般都会定义一个自增的ID列为主键
2.更新主键的代价很高,因为将会导致被更新的行移动。因此,对于InnoDB表,我们一般定义主键为不可更新。
3.二级索引访问需要两次索引查找,第一次找到主键值,第二次根据主键值找到行数据。

辅助索引(非聚簇索引)

MyISAM使用的就是非聚簇索引。辅助索引就是一个为了需找主键索引的二级索引,先找到主键索引再通过主键索引找数据;
在聚簇索引之上创建的索引称之为辅助索引,辅助索引访问数据总是需要二次查找。辅助索引叶子节点存储的不再是行的物理位置,而是主键值。通过辅助索引首先找到的是主键值,再通过主键值找到数据行的数据页,再通过数据页中的Page Directory找到数据行。

Innodb辅助索引的叶子节点并不包含行记录的全部数据,叶子节点除了包含键值外,还包含了相应行数据的聚簇索引键。

辅助索引的存在不影响数据在聚簇索引中的组织,所以一张表可以有多个辅助索引。在innodb中有时也称辅助索引为二级索引。

聚簇索引和非聚簇索引的参考文章

聚簇索引与非聚簇索引的区别
聚簇索引的叶子节点存放的是主键值和数据行支持覆盖索引二级索引的叶子节点存放的是主键值或指向数据行的指针。由于节子节点(数据页)只能按照一颗B+树排序,故一张表只能有一个聚簇索引。
辅助索引的存在不影响聚簇索引中数据的组织,所以一张表可以有多个辅助索引

覆盖索引

覆盖索引(covering index)指一个查询语句的执行只用从索引中就能够取得,不必从数据表中读取。也可以称之为实现了索引覆盖。 当一条查询语句符合覆盖索引条件时,MySQL只需要通过索引就可以返回查询所需要的数据,这样避免了查到索引后再返回表操作,减少I/O提高效率。 如,表covering_index_sample中有一个普通索idx_key1_key2(key1,key2)。当我们通过SQL语句:select key2 from covering_index_sample where key1 = ‘keytest’;的时候,就可以通过覆盖索引查询,无需回表。

优点
① 索引条目通常远小于数据行大小,可以极大减少数据访问量。
② 因为索引按照列值顺序存储,所以对于 IO 密集型防伪查询回避随机从磁盘读取每一行数据的 IO 少得多。
③ 由于 InnoDB 使用聚簇索引,覆盖索引对 InnoDB 很有帮助。InnoDB 的二级索引在叶子节点保存了行的主键值,如果二级主键能覆盖查询那么可以避免对主键索引的二次查询。

2.5 什么情况需要创建索引?

1.主键自动建立唯一索引
2.频繁作为查询条件的字段应创建索引
3.查询中与其他表关联的字段,外键关系建立索引
4.频繁更新的字段不适合创建索引
因为每次更新不单单是更新了记录,还会更新索引,加重了IO负担
5.where条件里用不到的字段不创建索引
6.单键/组合索引的选择问题?
在高并发情况下倾向创建组合索引
7.查询中排序的字段,排序字段若通过索引去访问将大大提高排序速度
8.查询中统计或分组字段

2.6 什么情况不需要创建索引?

1.表记录太少
2.经常增删改查的表
提高了查询速度,同时会降低更新表的速度,如对表进行insert、update和delete,因为更新表时mysql不仅要保存数据,还要保存索引文件。
3.数据重复且分布均匀的表字段,因为应该只为最常查询和最常排序的数据列建立索引。

2.7 如何避免索引失效?

1.全值匹配
2.最佳左前缀法则,如果索引了多列,要遵守最左前缀法则,指的是查询从索引最左前列开始并且不跳过索引中的列。
3.不在索引上做任何操作(计算、函数、类型转换等),会导致索引失效从而转向全表扫描
4.存储引擎不能使用索引中范围条件右边的列
5.尽量使用覆盖索引(只访问索引的查询,索引列和查询列一致),减少select *
6.mysql在使用不等于(!=或<>)的时候无法使用索引,导致全盘扫描
7.is null,is not null也不能使用索引
8.like 以通配符开头的(’%abc…’)mysql索引失效会变成全表扫描
9.字符串不加单引号索引失效
字符串不加单引号会导致mysql底层会进行一次自动的数据转换,从而导致索引失效
10.少用or,用它连接会导致索引失效

3.MySQL事务和读写锁

3.1 数据库三大范式

范式是具有最小冗余的表结构
1.第一范式(列都是不可再分)
第一范式的目标是保证每列的原子性:每列都是不可再分的最小数据单元
如Address列的数据为中国北京,那就可以拆分为Country列和City列,中国,北京,这样才满足第一范式
2.第二范式(每个表只描述一件事情)
首先满足第一范式,并且表中非主键列不存在对主键的部份依赖。第二范式要求每个表只描述一件事情。
如一张表有订单编号,产品编号,订购时间,价格,这就得拆分为订购日期表和价格表。
3.第三范式(表中的列不存在对非主键列的传递依赖)
满足第二范式,表中的列不存在对非主键列的传递依赖,如
MySQL复习知识点总结_第3张图片
顾客姓名依赖于非主键顾客编号。

3.2 事务

事务是一个不可分割的工作逻辑单元,是一组原子性的SQL查询或者说是一个独立的工作单元。事务是作为单个逻辑工作单元执行的一系列操作,这些操作作为一个整体一起向系统提交,要么都执行要么都不执行。

ACID属性

事务必须具备的四个属性
1.原子性(Atomicity)
事务时一个完整的操作,事务的各步操作是不可分的,要么都执行,要么都不执行。
2.一致性(Consistency)
当事务完成时,数据必须处于一致状态。
3.隔离性(Isolation)
对数据进行修改的所有并发事务是彼此隔离的,这表明事务必须是独立的,一个事务所做的修改在最终提交之前对其他事务不可见。
4.永久性(Durability)
事务完成后,他对数据库的修改被永久保持,事务日志能够保持事务的永久性。此时即使系统崩溃修改的数据也不会丢失。

并发事务处理会带来哪些问题?

1.更新丢失
当两个或多个事务选择同一行,然后基于最初选定的值更新该行时,由于每个事务都不知道其他事务的存在,就会发生更新丢失,所以会导致最后的更新覆盖了其他事务所作的更新。

  • 如何避免?
    证一个在完成并提交事务之前,其他事务不能操作同一行。

2.脏读
一个事务正在对一条记录进行修改,在这个事务完成并提交前,这条记录的数据就处于不一致状态,这时如果另一个事务来读取这个记录,如果不加控制,第二个事务读取了这些脏数据,并对此做进一步的处理,就会产生未提交的数据依赖关系。这种现象就叫脏读
即,事务A读取到了事务B 已修改但未提交的数据,还在这个数据的基础上做了操作,此时,如果B事务回滚,A读取到的数据就是无效的,不符合一致性的要求。
3.不可重复读
一个事务在读取某些数据后的某个时间,再此读取以前读过的数据,却发现数据发生了改变,或是某些记录已被删除或修改。
就是事务A读取到了事务B已经提交的修改数据,不符合隔离性
4.幻读
一个事务按相同的查询条件重新读取以前检索过的数据,却发现其他事务插入了满足查询条件的新数据。
即 事务A读取到了事务B提交的新增数据,不符合隔离性

脏读和幻读的区别:
脏读时事务B在里面修改了数据,而幻读时事务B新增了数据。

3.3 Mysql隔离级别

1.未提交读 Read uncommitted

在该级别事务中的修改即使没有被提交,对其他事务也是可见的。
事务可以读取其他事务修改完但未提交的数据,这种问题称为脏读
这个级别还会导致不可重复读幻读,性能没有比其他级别好很多,很少使用。

2.已提交读 Read committed

多数数据库系统默认的隔离级别,已提交读满足了隔离性的简单定义:一个事务开始时只能看见已经提交的事务所做的修改。换句话说,一个事务从开始到提交前的任何修改对其他事务是不可见的。所以也叫不可重复读,因为两次执行同样的查询可能会得到不同结果,不会导致脏读但会导致幻读

3.可重复读 Repeatable read(MySQL默认隔离级别)

可重复读解决了不可重复读的问题,保证了在同一个事务中多次读取同样的记录结果一致。但还是无法解决幻读。InnoDB存储引擎通过多版本并发控制MVCC解决幻读问题。

4.可串行化 Serializable

最高的隔离级别,通过强制事务串行执行避免幻读,可串行化会在读取的每一行数据上都加锁,可能导致大量的抄视和锁征用问题。实际很少应用。

隔离级别 读数据一致性 脏读 不可重复读 幻读
未提交读 最低级别,只能保证不读取物理上损坏的数据
已提交读 语句级
可重复读 事务级
可序列化 最高级别,事务级

5.MVCC

是多版本并发控制,很多情况下避免加锁,大都实现了非阻塞的读操作,写操作也只需锁定必要的行。

InnoDB 的 MVCC 通过在每行记录后面保存两个隐藏列来实现,这两个列分别保存了行的创建时间过期时间。不过存储的不是实际的时间值而是系统版本号,每开始一个新的事务系统版本号都会自动递增,事务开始时刻的系统版本号会作为事务的版本号,用来和查询到的每行记录的版本号比较。

MVCC 只能在 READ COMMITTED已提交读 和 REPEATABLE READ 可重复读 两个隔离级别下工作,因为 READ UNCOMMITTED 总是读取最新的数据行,而不是符合当前事务版本的数据行,而 SERIALIZABLE 则会对
所有读取的行都加锁。

6.MySQL查询执行流程

① 客户端发送一条查询给服务器。
② 服务器先检查查询缓存,如果命中了缓存则立刻返回存储在缓存中的结果,否则进入下一阶段。
③ 服务器端进行 SQL 解析、预处理,再由优化器生成对应的执行计划。
④ MySQL 根据优化器生成的执行计划,调用存储引擎的 API 来执行查询。
⑤ 将结果返回给客户端。

3.4 数据库并发策略

1.乐观锁

乐观锁认为一个用户读数据的时候,别人不会去写自己所读的数据;悲观锁就刚好相反,觉得自己读数据库的时候,别人可能刚好在写自己刚读的数据,其实就是持一种比较保守的态度;时间戳就是不加锁,通过时间戳来控制并发出现的问题。

2.悲观锁

悲观锁就是自己修改某条数据的时候,不允许别人读取该数据,只有等自己的整个事务提交了,才释放自己加上的锁,才允许其他用户访问那部分数据。
悲观锁所说的加“锁”,其实分为几种锁,分别是:排它锁(写锁)和共享锁(读锁)

3.时间戳

时间戳就是在数据库表中单独加一列时间戳,比如“TimeStamp”,每次读出来的时候,把该字段也读出来,当写回去的时候,把该字段加1,提交之前 ,跟数据库的该字段比较一次,如果比数据库的值大的话,就允许保存,否则不允许保存,这种处理方法虽然不使用数据库系统提供的锁机制,但是这种方法可以大大提高数据库处理的并发量。

3.5 MySQL的锁策略

1.表锁(偏读)

是MySQL中最基本的锁策略,而且开销最小,表锁会锁定整张表,一个用户对表进行写操作前需先获得锁,这会阻塞其他用户对该表的所有读写操作,如果没有写锁时,其他读取的用户才能获取读锁,读锁之间不互相阻塞。
表锁的两种模式:表共享读锁表独占写锁

2.行锁(偏写)

可以最大程度支持并发,同时也带来了最大开销。
偏向InnoDB 开销大 加锁慢 会出现死锁 并发度高
InnoDB和MyISAM不同:1.支持事务2.采用行级锁

3.MySQL的读写锁

表锁的两种模式:表共享读锁表独占写锁
读锁是共享的,相互不阻塞,多个客户在同一时刻可以同时读
取同一个资源而不相互干扰。写锁则是排他的,也就是说一个写锁会阻塞其他的写锁和读锁,确保在给
定时间内只有一个用户能执行写入并防止其他用户读取正在写入的同一资源。

锁类型 可否兼容 读锁 写锁
读锁
写锁

总结:读锁会阻塞写,但是不会阻塞读,而写锁会把读和写操作都阻塞。

4.数据库死锁

死锁是指多个事务在同一资源上相互占用并请求锁定对方占用的资源而导致恶性循环的现象当多个事务试图以不同顺序锁定资源时就可能会产生死锁,多个事务同时锁定同一个资源时也会产生死锁。
为了解决死锁问题,数据库系统实现了各种死锁检测和死锁超时机制。越复杂的系统,例如InnoDB 存储引擎,能检测到死锁的循环依赖,并立即返回一个错误。这种解决方式很有效,否则死锁会导致出现非常慢的查询。还有一种解决方法,就是当查询的时间达到锁等待超时的设定后放弃锁请求,这种方式通常来说不太好。InnoDB 目前处理死锁的方法是将持有最少行级排它锁的事务进行回滚
死锁发生之后,只有部分或者完全回滚其中一个事务,才能打破死锁。对于事务型系统这是无法避免的,所以应用程序在设计时必须考虑如何处理死锁。大多数情况下只需要重新执行因死锁回滚的事务即可。

5.间隙锁

定义:当我们用范围条件查询而不是相等条件检索数据,并请求共享或排他锁时,InnoDB会给符合条件的记录数据的索引项加锁,对于键值在条件范围内但并不存在的记录,叫做”间隙GAP“。
InnoDB也会对这个间隙加锁,这就是间隙锁。

危害:因为query执行过程中通过范围查找会给整个范围内所有索引键值加锁,即使这个键值并不存在。这就会造成在锁定的时候无法插入锁定键值范围内的任何数据。

3.6 数据类型

1.VARCHAR 和 CHAR 的区别

VARCHAR用于存储可变字符串,是最常见的字符串数据类型。它比 CHAR 更节省空间,因为它仅使用必要的空间。VARCHAR 需要 1 或 2 个额外字节记录字符串长度,如果列的最大长度不大于 255 字节则只需要 1 字节。VARCHAR 不会删除末尾空格。
VARCHAR 适用场景:字符串列的最大长度比平均长度大很多、列的更新很少、使用了 UTF8 这种复杂字符集,每个字符都使用不同的字节数存储。
CHAR 是定长的,根据定义的字符串长度分配足够的空间。CHAR 会删除末尾空格。
CHAR 适合存储很短的字符串,或所有值都接近同一个长度,例如存储密码的 MD5 值。对于经常变更的数据,CHAR 也比 VARCHAR更好,因为定长的 CHAR 不容易产生碎片。对于非常短的列,CHAR 在存储空间上也更有效率,例如用 CHAR 来存储只有 Y 和 N 的值只需要一个字节,但是 VARCHAR 需要两个字节,因为还有一个记录长度的额外字节.

2.DATETIME 和 TIMESTAMP 的区别

DATETIME 能保存大范围的值,从 1001~9999 年,精度为秒。把日期和时间封装到了一个整数中,与时区无关,使用 8 字节存储空间。
TIMESTAMP 和 UNIX 时间戳相同,只使用 4 字节的存储空间,范围比 DATETIME 小得多,只能表示1970 ~2038 年,并且依赖于时区。

3.数据类型优化策略

1.更小的通常更好
一般情况下尽量使用可以正确存储数据的最小数据类型,更小的数据类型通常也更快,因为它们占用更少的磁盘、内存和 CPU 缓存。
2.尽可能简单
简单数据类型的操作通常需要更少的 CPU 周期,例如整数比字符操作代价更低,因为字符集和校对规则使字符相比整形更复杂。应该使用 MySQL 的内建类型 date、time 和 datetime 而不是字符串来存储日期和时间,另一点是应该使用整形存储 IP 地址。
3.尽量避免 NULL
通常情况下最好指定列为 NOT NULL,除非需要存储 NULL值。因为如果查询中包含可为 NULL 的列对MySQL 来说更难优化,可为 NULL 的列使索引、索引统计和值比较都更复杂,并且会使用更多存储空间。当可为 NULL 的列被索引时,每个索引记录需要一个额外字节,在MyISAM 中还可能导致固定大小的索引变成可变大小的索引。
如果计划在列上建索引,就应该尽量避免设计成可为 NULL 的列

4.MySQL优化

1.定位低效 SQL

可以通过两种方式来定位执行效率较低的 SQL 语句。一种是通过慢查询日志定位可以通过慢查询日志定位那些已经执行完毕的 SQL 语句。另一种是使用 SHOW PROCESSLIST 查询,慢查询日志在查询结束以后才记录,所以在应用反应执行效率出现问题的时候查询慢查询日志不能定位问题,此时可以使用 SHOW PROCESSLIST 命令查看当前 MySQL 正在进行的线程,包括线程的状态、是否锁表等,可以实时查看 SQL 的执行情况,同时对一些锁表操作进行优化。找到执行效率低的 SQL 语句后,就可以通过 SHOW PROFILE、EXPLAIN 或 trace 等丰富来继续优化语句。

慢查询如何处理??
1.开启慢查询日志找出那些语句慢了
2.使用explain进行分析
3.show profile
4.进行数据库参数调优

2.show profile

通过 SHOW PROFILE 可以分析 SQL 语句性能消耗,例如查询到 SQL 会执行多少时间,并显示 CPU、内存使用量,执行过程中系统锁及表锁的花费时间等信息。例如 SHOW PROFILE CPU/MEMORY/BLOCKIO FOR QUERY N 分别查询 id 为 N 的 SQL 语句的 CPU、内存以及 IO 的消耗情况。

3.trace

从 MySQL5.6 开始,可以通过 trace 文件进一步获取优化器是是如何选择执行计划的,在使用时需要先打开设置,然后执行一次 SQL,最后查看 information_schema.optimizer_trace 表的内容,该表为联合表,只能在当前会话进行查询,每次查询后返回的都是最近一次执行的 SQL 语句。

4.explain字段

可以模拟优化器执行SQL语句从而知道SQL怎么执行语句,从而进行分析。
字段:
在这里插入图片描述
1.id:select查询的一组序列号,数字构成,表示操作的顺序
①id相同 执行顺序由上至下
​ ②id不同,如果是子查询,id序号递增,id越大优先级越高,越先被执行
​ ③id相同不同,以上两种方式同时存在
2.select_type
类型:MySQL复习知识点总结_第4张图片
说明了查询类型,主要是用于查询普通查询、联合查询、子查询等复杂查询。
MySQL复习知识点总结_第5张图片
3.type:表示访问性能,性能排序:
system>const>eq_ref>ref>range>index>All

All:全表扫描
index:索引全扫描
range:范围索引扫描,只检索给定范围的行,使用一个索引来选择行,比全局扫描好,他从索引的某一点开始,有范围。
ref:非唯一性索引扫描,返回匹配某一个值的所有行,查找扫描的混合体
eq_ref:唯一性索引扫描,表中只有一条记录匹配
const:通过一次索引就找到,常出现在主键索引或unique索引,只匹配一行数据,如将主键置于where列表中,mysql就能把它转化为一个常量
system:系统表,表中只有一行记录

SQL 性能优化的目标:至少要达到 range 级别,要求是 ref 级别,如果可以是consts 最好。

4.possible_keys:可能应用在这张表中的索引,一个或多个,但不一定被查询实际使用

5.key: 显示 MySQL 在查询时实际使用的索引,如果没有使用则显示为 NULL。

6.key_len
索引中使用的字节数,最大可能长度,可通过这个计算索引使用长度,越少越好,并非实际使用长度,是根据表结构计算出来的。

7.ref:显示索引那一列被使用了,最好是一个常数
8.rows:根据表统计信息和索引选用情况,估算找到记录所需读取的行数
9.Extra
①​ using filesort:表示无法利用索引完成的文件排序,这是ORDER BY 的结果,可以通过合适的索引改进性能
②using temporary:使用临时表查询中间结果,常见于排序order by和分组查询group by
​③using index:表示相应select操作使用了索引覆盖,避免访问了表的数据行 出现了using where表明索引用来执行索引键值的查找 没有则表示索引用来读取数据而并非执行查找动作

5.优化 SQL

1.优化count查询

COUNT 是一个特殊的函数,它可以统计某个列值的数量,在统计列值时要求列值是非空的,不会统计NULL 值。如果在 COUNT 中指定了列或列的表达式,则统计的就是这个表达式有值的结果数,而不是NULL。
COUNT 的另一个作用是统计结果集的行数,当 MySQL 确定括号内的表达式不可能为 NULL 时,实际
上就是在统计行数。当使用 COUNT() 时, 不会扩展成所有列,它会忽略所有的列而直接统计所有行数。

某些业务场景并不要求完全精确的 COUNT 值,此时可以使用近似值来代替,EXPLAIN 出来的优化器估算的行数就是一个不错的近似值,因为执行 EXPLAIN 并不需要真正地执行查询。
通常来说 COUNT 都需要扫描大量的行才能获取精确的结果,因此很难优化。在 MySQL 层还能做的就只有覆盖扫描了,如果还不够就需要修改应用的架构,可以增加汇总表或者外部缓存系统。

2.优化关联查询

确保 ON 或 USING 子句中的列上有索引,在创建索引时就要考虑到关联的顺序。
确保任何 GROUP BY 和 ORDER BY 的表达式只涉及到一个表中的列,这样 MySQL 才有可能使用索引来优化这个过程。
在 MySQL 5.5 及以下版本尽量避免子查询,可以用关联查询代替,因为执行器会先执行外部的 SQL 再执行内部的 SQL。

3.优化group by

group by 实质是先排序后进行分组,遵循索引的最佳左前缀。
where高于having,能在where写的限定条件就不要写在having中。
如果没有通过 ORDER BY 子句显式指定要排序的列,当查询使用 GROUP BY 时,结果集会自动按照分组的字段进行排序,如果不关心结果集的顺序,可以使用 ORDER BY NULL 禁止排序。

4.优化order by

order by子句尽量使用index方式排序(扫描索引本身完成排序),避免使用filesort方式排序。
尽可能在索引列上完成排序操作,遵循最佳左前缀原则。
如果排序不在索引列上,filesort就有两种排序算法
1.双路排序:扫两次磁盘得到数据,从磁盘取排序字段,在buffer进行排序,再从磁盘取其他字段。所以IO操作非常耗时。
2.单路排序:从磁盘读取查询所需的所有列,按照order by 列在buffer对其排序然后扫描排序后的列表后输出,把随机IO变成顺序IO,避免了第二次读取数据,但会使用更多空间,他爸每一行都保存在了内存中。

5.优化 LIMIT 分页

在偏移量非常大的时候,需要查询很多条数据再舍弃,这样的代价非常高。要优化这种查询,要么是在页面中限制分页的数量,要么是优化大偏移量的性能。最简单的办法是尽可能地使用覆盖索引扫描,而
不是查询所有的列,然后根据需要做一次关联操作再返回所需的列。
还有一种方法是从上一次取数据的位置开始扫描,这样就可以避免使用 OFFSET。其他优化方法还包括使用预先计算的汇总表,或者关联到一个冗余表,冗余表只包含主键列和需要做排序的数据列。

6.优化 INSERT

需要对一张表插入很多行数据时,应该尽量使用一次性插入多个值的 INSERT 语句,这种方式将缩减客户端与数据库之间的连接、关闭等消耗,效率比多条插入单个值的 INSERT 语句高。也可以关闭事务的自动提交,在插入完数据后提交。当插入的数据是按主键的顺序插入时,效率更高。

7.优化 UNION 查询

MySQL 通过创建并填充临时表的方式来执行 UNION 查询,除非确实需要服务器消除重复的行,否则一定要使用 UNION ALL,如果没有 ALL 关键字,MySQL 会给临时表加上 DISTINCT 选项,这会导致对整个临时表的数据做唯一性检查,这样做的代价非常高。

5.MySQL主从复制

1.作用

复制解决的基本问题是让一台服务器的数据与其他服务器保持同步,一台主库的数据可以同步到多台备库上,备库本身也可以被配置成另外一台服务器的主库。主库和备库之间可以有多种不同的组合方式。
MySQL 支持两种复制方式:基于行的复制基于语句的复制,基于语句的复制也称为逻辑复制,从MySQL 3.23 版本就已存在,基于行的复制方式在 5.1 版本才被加进来。这两种方式都是通过在主库上记录二进制日志在备库重放日志的方式来实现异步的数据复制。因此同一时刻备库的数据可能与主库存在不一致,并且无法包装主备之间的延迟。
MySQL 复制大部分是向后兼容的,新版本的服务器可以作为老版本服务器的备库,但是老版本不能作为新版本服务器的备库,因为它可能无法解析新版本所用的新特性或语法,另外所使用的二进制文件格式也可能不同。
复制解决的问题:数据分布、负载均衡、备份、高可用性和故障切换、MySQL 升级测试。

2.步骤

① 在主库上把数据更改记录到二进制日志中。
② 备库将主库的日志复制到自己的中继日志中。
③ 备库读取中继日志中的事件,将其重放到备库数据之上。

第一步是在主库上记录二进制日志,每次准备提交事务完成数据更新前,主库将数据更新的事件记录到二进制日志中。MySQL 会按事务提交的顺序而非每条语句的执行顺序来记录二进制日志,在记录二进制日志后,主库会告诉存储引擎可以提交事务了。

下一步,备库将主库的二进制日志复制到其本地的中继日志中。备库首先会启动一个工作的 IO 线程,IO 线程跟主库建立一个普通的客户端连接,然后在主库上启动一个特殊的二进制转储线程,这个线程会读取主库上二进制日志中的事件。它不会对事件进行轮询。如果该线程追赶上了主库将进入睡眠状态,直到主库发送信号量通知其有新的事件产生时才会被唤醒,备库 IO 线程会将接收到的事件记录到
中继日志中。

备库的 SQL 线程执行最后一步,该线程从中继日志中读取事件并在备库执行,从而实现备库数据的更新。当 SQL 线程追赶上 IO 线程时,中继日志通常已经在系统缓存中,所以中继日志的开销很低。SQL线程执行的时间也可以通过配置选项来决定是否写入其自己的二进制日志中。

你可能感兴趣的:(数据结构,数据库,mysql,java,索引)