Mysql之复习

138 阅读3分钟

Mysql存储引擎

Mysql常用的存储引擎分为两种,InnoDB和MyIsAM

InnoDB

InnoDB提供了ACID的事务支持,实现了Mysql的四种隔级别,提供了行锁和外键,提供了缓存池,对于写的支持更好。

MyISAM

相对简单,可以保存为文件方式,方便跨平台

事务

事务的四个性质

  • 原子性:一个事务的要么全部完成、要么全部不完成。
  • 隔离型:两个事务执行时互相不影响。
  • 一致性:事务执行前后保证数据逻辑的正确
  • 持久性:保证事务执行的操作对数据库进行永久性的改变。

事务的隔离级别

多个事务并发执行时可能导致以下常见的问题:

  • 脏读:指一个事务读取到了另一个事务未提交的数据
  • 不可重复读:指一个事务第一次读取A=1,当另一个事务更新A=2 并提交,那么第一个事务读取到的数据为A=2 ,也就是说读到了其他事务提交的数据。(重点在于update和delete)
  • 幻读:指一个事务在两次读取的间隔间进行了插入操作,再进行update操作时就可以操作到新插入的数据,因此导致了同一事务在两次查询期间数据的不一致。

Mysql的隔离级别

  • 未提交读:一个事务未提交,造成的更新可被其他事务看到,造成脏读
  • 读提交: 可以看到其他事务提交的内容
  • 可重复读:多次读取能得到一样的结果,即使其他事务提交了数据更改,也无法被看到。
  • 序列化:完全穿行化读取。
MVCC

mysql是如何实现这些隔离级别的?是通过MVCC机制。

在所有事务开始时,第一次查询会生成一个事务id。
mysql将所有活跃的事务id数组放入一个数组中。

  • 当查询的数据的事务id > 活跃数组中的最大事务id 表示 此条数据的最新更改是当前事务之后提交的,无法读取。
  • 当查询的数据的事务id < 活跃数组中的最小事务id 表示 此条数据的当前信息是当前事务之前提交的,可以读取。
  • 当活跃数组中的最小事务id < 查询的数据的事务id < 活跃数组中的最大事务id
    那么判断这条数据的事务id是否在活跃数组中,如果在则不可读取,不在则说明已经提交,可读取。

查询时会根据上面的条件根据roll_pointer找到符合条件的数据

在不可重复读中,每次select都会生成一个新的快照,也就是更新这个数组,其DB_TRX_ID 每次读都 +1(如果事务id不+1,那么会读不到在当前事务之后创建的事务提交的内容), 在可重复读中,只有第一次select会生成一个快照。

快照读

这种读取方式称作快照读,查询时会采用这种方式读取。不用加锁,效率高

当前读

当更新和删除时需要使用当前读,也可以使用特殊的select语句,因为更新时必须要知道当前这条数据的情况。

如何解决幻读

上面的方式依然没法解决幻读,插入新的数据虽然无法看到,但是仍然能更新新的数据,因此可以搭配间隙锁来解决这种问题。

什么时候用行锁,什么时候用表锁?
我们知道innoDB拥有表锁和行锁
只有通过索引进行数据操作时才会使用行锁进行锁定,其他情况会使用表锁。

索引

索引相当于一本字典的目录,通过索引可以快速定位到想查到的数据。

索引的底层数据结构

InnoDB

InnoDB 包含了如下两种索引。
聚簇索引:节点页只包含了索引列,叶子页包含了行的全部数据。聚簇索引“就是表”,因此可以不需要独立的行存储
二级索引(非主键索引):叶子节点保存的不是指行的物理位置的指针,而是行的主键值。

也就是说如果命中主键索引,就直接获取到数据,而命中到二级索引时,会根据找到的主键定位到聚簇索引获取数据

聚簇索引: 聚簇索引保证关键字的值相近的元组存储的物理位置也相近

二级索引:

MyISAM

MyISAM按照插入的顺序在磁盘上存储数据
MyISAM中只有一种索引,索引中的叶子节点只保存行号,根据行号去定位数据。

  • INNODB索引和MyISAM索引对比

MYSQL常见索引

  • 普通索引
  • 主键索引
  • 组合索引
    组合索引在B+树中,每个非叶子节点都是三个索引的组合,比如: 最左前缀索引:(a,b,c) 会先比较a的大小,再比较b的大小,再比较c的大小进行树的生成。

先保证a的大小顺序,在a相同时才能保证b的大小顺序,因此不使用最左前缀直接使用b的话,无法判断当前索引节点b的右边是否小于它,a的左边是否大于它

  • 唯一索引

什么时候索引失效

  • or语句中只要有一项没用索引
  • like语句以%开头
  • 组合索引未满足最左前缀
  • 如果列是字符串类型且没用引号开头
  • 使用全表扫描比索引快的时候
  • 在列上做计算
  • where 子句中使用!=或<>操作符
  • where 语句中第一个范围查询之后的列无法用到索引(包括最左前缀),因为范围查询会直接找到叶子节点,根据叶子结点的链表指针直接获取这个范围的数据。

索引设计

  • 尽量使用数字型,因为字符型会逐个比较字符
  • 不要让默认值为null,索引不包含null的列,并且复合索引中只要有一个为null,这个索引就不成立。
  • 前缀索引,对于很长的字符串类型尽量使用前缀索引(需要指定前缀长度),但是无法使用索引做order by 和 group by
  • 组合索引代替多列索引

问题:###

mysql分页查询到后面很慢怎么办?