1. MySQL

1.1. Mysql基础架构

MySQL 可以分为 Server 层和存储引擎层两部分。

Server 层包括连接器、查询缓存、分析器、优化器、执行器等。

而存储引擎层负责数据的存储和提取。其架构模式是插件式的,支持 InnoDB、MyISAM、Memory 等多个存储引擎

  • 连接器:连接器负责跟客户端建立连接、获取权限、维持和管理连接
  • 查询缓存:拿到请求后,先到查询缓存中看是否有数据,不建议使用查询缓存,失效频率非常高,一个更新操作就会使查询缓存都失效。
  • 分析器:词法分析、语法分析、判断sql语句是否正确。
  • 优化器: 存在多个索引时,决定使用哪个索引 ,join连接顺序。
  • 执行器: 执行语句,判断是否有权限查询。

1.2. Mysql 日志系统

1.2.1. 重要的日志模块:redo log

Mysql WAL(Write-Ahead Logging) 技术,它的关键点就是先写日志,再写磁盘,当更新一条记录的时候,innodb会先把记录写到redo log里,等系统比较空闲的时候再把数据写入磁盘。

1.2.2. 重要的日志模块:binlog

binlog 是mysql service 层层维护的一种二进制日志,与innodb引擎中的redo/undo log是完全不同的日志;其主要是用来记录对mysql数据更新或潜在发生更新的SQL语句,并以"事务"的形式保存在磁盘中;

binlog记录的是执行的sql语句

binlog 与redo log区别

  • redo log 是 InnoDB 引擎特有的;binlog 是 MySQL 的 Server 层实现的,所有引擎都可以使用。

  • redo log 是物理日志,记录的是“在某个数据页上做了什么修改”;binlog 是逻辑日志,记录的是这个语句的原始逻辑,比如“给 ID=2 这一行的 c 字段加 1 ”。

  • redo log 是循环写的,空间固定会用完;binlog 是可以追加写入的。“追加写”是指 binlog 文件写到一定大小后会切换到下一个,并不会覆盖以前的日志。

1.3. 事务隔离

提到事务,你肯定会想到 ACID(Atomicity、Consistency、Isolation、Durability,即原子性、一致性、隔离性、持久性),今天我们就来说说其中 I,也就是“隔离性”。

事务的隔离级别

1、读未提交(READ-UNCOMMITTED):也就是允许读到未提交的内容,这种情况下查询是不会使用锁的,可能会产生脏读、不可重复读、幻读等情况。

2、读已提交(READ-COMMITTED):读已提交就是只能读到已经提交的内容,可以避免脏读的产生,属于RDBMS中常见的默认隔离级别(比如说Oracle和SQL Server),但如果想要避免不可重复读或者幻读,就需要我们在SQL查询的时候编写带加锁的SQL语句。

3、可重复读(REPEATABLE-READ),保证一个事务在相同查询条件下两次查询得到的数据结果是一致的,可以避免不可重复读和脏读,但无法避免幻读。MySQL默认的隔离级别就是可重复读。

4、可串行化(SERIALIZABLE),将事务进行串行化,也就是在一个队列中按照顺序执行,可串行化是最高级别的隔离等级,可以解决事务读取中所有可能出现的异常情况,但是它牺牲了系统的并发性。

1.4. 事务的隔离级别,每个级别是如何解决的。

MySQL 事务隔离其实是依靠锁来实现的.而读未提交隔离级别是不加锁的,所以它的性能是最好的,没有加锁、解锁带来的性能开销。但有利就有弊,这基本上就相当于裸奔啊,所以它连脏读的问题都没办法解决.

读提交隔离级别可以解决脏读问题:但会存在幻读与不可重复读问题 在同一事务中(本例中的事务B),事务的不同时刻同样的查询条件,查询出来的记录内容是不一样的,事务A的提交影响了事务B的查询结果,这就是不可重复读,也就是读提交隔离级别。

  • 读未提交:不加任何锁
  • 串行化:读的时候加共享锁,也就是其他事务可以并发读,但是不能写。写的时候加排它锁,其他事务不能并发写也不能并发读。
  • 可重复读:为了解决不可重复读,或者为了实现可重复读,MySQL 采用了 MVVC (多版本并发控制) 的方式。
  • 幻读:解决幻读使用的是间隙锁,MySQL 把行锁和间隙锁合并在一起,解决了并发写和幻读的问题,这个锁叫做 Next-Key锁。

读提交解决了脏读问题,行锁解决了并发更新的问题。并且 MySQL 在可重复读级别解决了幻读问题,是通过行锁和间隙锁的组合 Next-Key 锁实现的。

1.5. 数据库索引

InnoDB 的索引模型:在 InnoDB 中,表都是根据主键顺序以索引的形式存放的,这种存储方式的表称为索引组织表,InnoDB 使用了 B+ 树索引模型,所以数据都是存储在 B+ 树中的。每一个索引在 InnoDB 里面对应一棵 B+ 树。

基于主键索引和普通索引的查询有什么区别?

主键索引也就是是聚簇索引,叶子节点存储了数据的行,根据主键查询,直接搜索 ID 这棵 B+ 树就拿到了数据。

普通索引查询方式,则需要先搜索索引树,得到 主键的值,再到主键索引树搜索一次。这个过程称为回表。

避免回表查询的方法:覆盖索引

最左前缀原则:最左前缀可以用于在索引中定位记录

建索引的几大原则:1、最左前缀匹配原则、mysql一直向右匹配,直到遇到范围查询就停止匹配。2、=和in可以乱序 3、尽量选择区分度高的列作为索引

1.6. 慢查询优化基本步骤

  • 先运行看看是否真的很慢,注意设置SQL_NO_CACHE
  • where条件单表查,锁定最小返回记录表
  • explain查看执行计划,是否与1预期一致(从锁定记录较少的表开始查询)
  • order by limit 形式的sql语句让排序的表优先查
  • 了解业务方使用场景
  • 加索引时参照建索引的几大原则
  • 观察结果,不符合预期继续从0分析

1.7. Mysql锁

Mysql锁可以分为 全局锁、表级锁和行锁三类

全局锁:锁的是整个数据库实例,这个库处于只读状态,任何更新删除修改、数据定义语句都会被阻塞。全局锁的使用场景主要是:做全库逻辑备份。

表级锁:表锁的语法是 lock tables … read/write,使用unlock tables 主动释放锁。

行锁:在 InnoDB 事务中,行锁是在需要的时候才加上的,但并不是不需要了就立刻释放,而是要等到事务结束时才释放。这个就是两阶段锁协议。

1.8. Mysql普通索引与唯一索引

  • 普通索引,查到满足条件的第一个记录后,继续查找下一个记录,直到第一个不满足条件的记录
  • 唯一索引,由于索引唯一性,查到第一个满足条件的记录后,停止检索 但是,两者的性能差距微乎其微。因为InnoDB根据数据页来读写的。

概念: change buffer

当需要更新一个数据页,如果数据页在内存中就直接更新,如果不在内存中,在不影响数据一致性的前提下,InnoDB会将这些更新操作缓存在change buffer中。下次查询需要访问这个数据页的时候,将数据页读入内存,然后执行change buffer中的与这个页有关的操作。

唯一索引的更新不能使用change buffer,change buffer使用场景:写多读少场景,适用于写入后不立马做查询的业务场景

字符串字段创建索引的场景:

  • 直接创建完整索引,这样可能比较占用空间
  • 创建前缀索引,节省空间,但会增加查询扫描次数,并且不能使用覆盖索引
  • 倒序存储,再创建前缀索引,用于绕过字符串本身前缀的区分度不够的问题
  • 创建 hash 字段索引,查询性能稳定,有额外的存储和计算消耗,跟第三种方式一样,都不支持范围扫描。

1.9. SQL语句性能分析

t_modified 字段有索引,以下查询是否用到了索引,答案:没有使用索引。

select count(*) from tradelog where month(t_modified)=7;

如果对字段做了函数计算,就用不上索引了,这是 MySQL 的规定。对索引字段做函数操作,可能会破坏索引值的有序性,因此优化器就决定放弃走树搜索功能。

  • 函数计算不走索引
  • 为什么有数据类型转换,就需要走全索引扫描。
  • 隐式字符编码转换不走索引
© gaohueric all right reserved,powered by Gitbook文件修订时间: 2021-12-08 23:22:22

results matching ""

    No results matching ""