《MySQL技术内幕 InnoDB存储引擎 》学习笔记

第1章  MySQL体系结构和存储引擎

1.3 MySQL存储引擎

  数据库和文件系统最大的区别在于:数据库是支持事务的算法

InnoDB存储引擎:sql

  MySQL5.5.8以后默认的存储引擎,主要面向OLTP(联机事务处理,面向基本的、平常的事务处理)数据库

  支持事务,支持外键、支持行锁(有的状况下也会锁住整个表)、非锁定读(默认读取操做不会产生锁)缓存

  经过使用MVCC来获取高并发性,而且实现sql标准的4种隔离级别,默认为可重复读级别数据结构

  使用一种被称成next-key locking的策略来避免幻读(phantom)现象并发

  还提供了插入缓存(insert buffer)、二次写(double write)、自适应哈希索引(adaptive hash index)、预读(read ahead)等高性能技术。分布式

  表数据采用汇集方式,每张表的存储都按主键的顺序进行存放。高并发

 

MyISAM存储引擎:性能

  不支持事务、支持全文索引,表锁设计,主要面向一些OLAP(联机分析处理,数据仓库的主要应用)。spa

  它的缓冲池只缓冲索引文件,而不缓冲数据文件.

  该存储引擎表由MYD和MYI组成,MYD用来存放数据文件,MYI用来存放索引文件.

 

NDB:

  是一个集群存储引擎,其特色是数据所有放在内存中。

  所以主键查找速度极快,并经过添加NDB数据库存储节点能够线性提升数据库性能,是高可用,高性能的集群系统。

 

Memory:

  将表中的数据存放在内存中,若是数据库重启或发生崩溃,表中的数据都将消失。

  它很是适合存储临时数据的临时表.默认采用哈希索引。

  只支持表锁,并发性较差。

 

第5章  索引与算法

5.1 InnoDB存储引擎索引概述

  Innodb存储引擎支持如下几种常见的索引:

    B+树索引

    全文索引

    哈希索引

  自适应哈希索引特性:InnoDB存储引擎会根据表的使用状况自动为表生成哈希索引,不能人为干预是否在表中生成哈希索引。

  B+树索引并不能找到一个给定键值的具体行。B+树索引能找到的只是被查找数据行所在的页。而后数据库经过把页读入到内存,再在内存中进行查找,最后获得要查找的数据。

 

5.3 B+树

  为磁盘或其余存取辅助设备设计的一种平衡查找树。

  全部记录点按大小顺序存放在同一层的叶子节点上。

  各叶子节点由指针进行链接。

 

5.4 B+树索引

  B+索引在数据库中有一个特色是高扇出性

  B+树的高度通常在2~4层,这也就是说查找某一键值的行记录时最多只须要2到4次IO。

  扇入:指直接调用该模块的上级模块的个数。

  扇出:是指该模块直接调用的下级模块的个数。

  B+树索引能够分为汇集索引(clustered index)和辅助索引(secondary index),可是不论是汇集仍是辅助索引,其内部都是B+树的,即高度平衡的,叶子节点存放着全部的数据。

  汇集索引和辅助索引不一样的是,叶子节点存放的是不是一整行的信息。

 

汇集索引:

  汇集索引就是按照每张表的主键构造一棵B+树。

  叶子节点中存放的是整张表的行记录数据,叶子节点也成称为数据页。

  索引组织表中数据也是索引的一部分。同B+树数据结构同样,每一个数据页经过一个双向链表来进行连接。

  汇集索引可以特别快的访问针对范围值的查询。

 

  不少文档写着:汇集索引按照顺序,物理地存储数据。

  可是这本书上写的是:汇集索引的存储并非物理上连续的,而是逻辑上连续的。(我也不知道哪一个是对的)

  这其中的两点:一是前面说过的页经过双向链表连接,页是按照主键的顺序排序;

  另外一点是每一个页中的记录也是经过双向链表进行维护的,物理存储上能够一样不按照主键存储。

  汇集索引的另一个好处是,它对于主键的排序查找和范围查找速度很是快。

 

辅助索引(非汇集索引):

  叶子节点并不包含行记录的所有数据。

  叶子节点除了包含键值外,每一个叶子节点中的索引行中还包含了一个书签(bookmark)。

  该书签用来告诉innodb存储引擎哪里能够找到与索引相对于的行数据。

  辅助索引的存在并不影响数据在汇集索引中的组织,所以每张表上能够有多个辅助索引。

  当经过辅助索引来寻找数据时,innodb存储引擎会遍历辅助索引并经过页基本的指针得到指向主键索引的主键,而后再经过主键索引来找到一个完整的行记录。

 

B+树索引的管理:

  ALTER  TABLE  表名  ADD   [ UNIQUE | FULLTEXT | SPATIAL ]   INDEX  索引名(属性名  [ (长度) ]  [ ASC | DESC]); 

 

  CREATE INDEX index_test2 on table_test(age);

 

建立惟一性索引

  ALTER  TABLE  index14  ADD  UNIQUE  INDEX  index14_id ( course_id(100) ) ; 

 

建立全文索引

  ALTER  TABLE  index15  ADD  FULLTEXT  INDEX  index15_info ( info ) ; 

 

建立空间索引

  ALTER  TABLE  index18  ADD  SPATIAL  INDEX  index18_line( line ) ; 

 

建立多列索引

  ALTER  TABLE  index17  ADD  INDEX  index17_na( name, address ) ; 

 

  CREATE INDEX一个语句一次只能创建一个索引,ALTER TABLE能够在一个语句创建多个,如:
        ALTER TABLE HeadOfState ADD PRIMARY KEY (ID), ADD INDEX (LastName,FirstName);


  只有ALTER TABLE 才能建立主键

  查看索引: SHOW INDEX FROM 表名

 

 

5.6 B+树索引的使用

联合索引:

  有多个索引列

  KEY idx_a_b(a,b) where a =xxx and b=xxx  以及 where a =xxx 都能使用该索引

  可是where b =xxx 没发使用该索引,由于如图,1,2,1,4,1,2不是有序的

 

 

索引覆盖:

  Innodb存储引擎支持索引覆盖,即从辅助索引中就能够获得查询的记录,而不须要查询汇集索引中的记录。

  使用索引覆盖的一个好处是辅助索引不包含整行记录的全部信息,故其大小要远小于汇集索引,所以能够减小大量的IO操做。

 

全文检索:

  是将存储在数据库中的整篇文章中的任意内容信息查找出来的技术

  InnoDB1.2.x从开始,支持全文检索

 

 

第6章  锁

6.3 InnoDB存储引擎中的锁

锁的类型:

InnoDB存储引擎实现了以下两种标准的行级锁:

  • 共享锁(读锁 或 S LOCK),容许事务读一行数据
  • 排它锁(写锁 或 X LOCK),容许事务删除或者更新一行数据

  当一个事务已经得到了行r的共享锁,那么另外的事务能够当即得到行r的共享锁,由于读取并无改变行r的数据,咱们称这种状况为锁兼容。

  但若是有事务想得到行r的排它锁,则它必须等待事务释放行r上的共享锁——这种状况咱们成为锁不兼容。

  InnoDB存储引擎支持多粒度锁定,这种锁定容许在行级上的锁和表级上的锁同时存在。为了支持在不一样粒度上进行加锁操做,InnoDB存储引擎支持一种额外的锁方式,咱们称之为意向锁。

  意向锁是表级别的锁,其设计目的主要是为了在一个事务中揭示下一行将被请求的锁的类型。

    • 意向共享锁(IS Lock),事务想要得到一个表中某几行的共享锁。
    • 意向排它锁(IX Lock),事务想要得到一个表中某几行的排它锁。 
      由于InnoDB支持的是行级别的锁,因此意向锁其实不会阻塞除全表扫之外的任何请求。

 

一致性的非锁定读操做:

  是指InnoDB存储引擎经过行多版本并发控制(MVCC)的方式来读取当前执行时间数据库中行的数据。

  若是读取的行正在执行DELETE、UPDATE操做,这时读取操做不会所以等待行上的锁释放,相反,存储引擎会去读取一个快照数据。

快照数据是指该行以前版本的数据,该实现是经过Undo段来实现。而Undo用来在事务中回滚数据,于是快照数据自己是没有额外的开销。此外,读取快照数据是没必要要上锁的,由于没有必要对历史的数据进行修改。

 

  在Read Comitted事务隔离级别下,对于快照数据,老是读取被锁定行的最新一份快照数据。

  在Repeatable Read事务隔离级别下,对于快照数据,老是读取事务开始时的行数据版本。

  因此,对于Read Commited的事务隔离级别而言,其实违反了事务的隔离性。

 

锁定读操做:

  SELECT…FOR UPDATE 对读取的行记录加一个X锁。其余事务想在这些行上加任何锁都会被阻塞。

  SELECT…LOCK IN SHARE MODE 对读取的行记录加一个S锁。其余事务能够向锁定的记录加S锁,可是对于加X锁,则会被阻塞。

 

6.4 锁的算法

行锁的3种算法:

InnoDB存储引擎有3种行锁的算法设计:

  • Record Lock:单个行记录上的锁,锁定的对象是索引,而不是数据。
  • Gap Lock:间隙锁,锁定一个范围的索引,但不包含记录自己
  • Next-Key Lock: Gap Lock + Record Lock,锁定一个范围的索引,而且锁定记录自己。

Record Lock老是会锁住索引记录,若是InnoDB存储引擎创建的时候没有设置任何一个索引,这时InnoDB存储引擎会使用隐式的主键来进行锁定。

好比:`SELECT * FROM t WHERE a < 6 lock in share mode,该语句会锁定(-oo, 6)这个数值区间的全部数值。

 

解决幻读问题:

  InnoDB存储引擎采用Next-Key Locking机制来避免幻读。

  幻读:同一事务下,连续执行两次一样的SQL语句可能致使不一样的结果。第二次SQL语句可能会返回以前不存在的行。

  假如表t由1,2,5三个值组成,  where a > 2 ,被锁住的不只是5这个值,而是(2,+∞)这个范围加了X锁

  在读提交级别下,仅采用Record Lock

 

6.5 锁问题

脏读:

  即一个事务能够读到另外一个事务中未提交的数据,违反了数据库的隔离性。发生条件:READ UNCOMMITED,这个隔离级别在Mysql中不使用。

不可重复读:

  一个事务两次读同一数据,结果不同。(另外一个事务修改了改数据并提交)

  不可重复读和脏读的区别是:脏读是读到未提交的数据;而不可重复读读到的确实是已经提交的数据,可是其违反了数据库事务一致性的要求。

  InnoDB的默认事务隔离级别是READ REPEATABLE,采用Next-Key Lock算法,解决了不可重复读(幻读)问题。

  在Next-Key Lock 算法下,不只仅是锁住扫描到的索引,并且还锁住这些索引覆盖的范围(gap)。所以对于这个范围内的插入都是不容许的。

 

6.7 死锁

  死锁是指两个或两个以上的事务在执行过程当中,因争夺锁资源而形成的一种相互等待的现象。

  超时机制:当一个事务等待超时,则对它进行回滚。可是有可能回滚的这个事务的时间要比另外一个事务要多。(就是还不如回滚另外一个没超时的)

  InnoDB采用wait-for graph(等待图)的方式来进行死锁检测。

 

6.7 锁升级

  指将当前锁的粒度下降,好比1000个行锁升级为一个页锁,或者将页锁升级为表锁。

  InnoDB不存在锁升级的问题。

  其根据每一个事务访问的每一个页对锁进行管理,采用的是位图的方式。

  无论事务锁住页中的一个记录仍是多个记录,其开销是同样的。

 

 

第7章  事务

7.1 认识事务

  事务是访问并更新数据库的一个程序执行单元。

 

ACID:

  Atomicity 原子性: 数据库事务是不可分割的工做单位, 要么都作, 要么都不作.

  Consistency 一致性: 事务不会破坏事务的完整性约束. 事务将数据库从一个一致状态转变为另外一个一致状态

  Isolation 隔离性: 事务之间相互分离, 在提交以前相互不可见.

  Durability 持久性: 事务一旦提交, 其产生的效果就是永久的

 

分类

  • 扁平事务
  • 带保存点的扁平事务
  • 链事务
  • 嵌套事务 (nested transactions)
  • 分布式事务

扁平事务

  使用最为频繁

  • 以 BEGIN [WORK] / START TRANSACTION开始
    • COMMIT [WORK] 成功提交
    • ROLLBACK [WORK] 回滚

带保存点的扁平事务

  就是能够不会滚所有,只回滚一部分

  • 使用 SAVE WORK 新增保存点
  • 扁平事务默认带着一个事务开始时的保存点

 

7.2 事务的实现

  事务的隔离性由锁实现

  原子性,一致性,持久性 由 redo log / undo log 实现

  undo log 保证事务的一致性, 逻辑日志, 根据每行记录进行记录,帮助事务回滚及MVCC

  redo log(重作日志): 保证事务的原子性和持久性, 物理日志

 

redo log:

  由两部分组成:内存中的重作日志缓冲,易失的

  重作日志文件,持久的

  事务提交时,必须将事务的的全部日志写入重作日志进行持久化。

 

 

undo log:

  记录的是 SQL, undo 以后底层物理文件格式可能会改变

  当前事务经过undo读取以前的行版本信息,来实现非锁定读

  undo log 会产生redo log,由于undo log也须要持久性的保护

 

purge:

  删除并无删除原数据,只是delete flag置为1

  若该行记录已经不被其余事务引用,则purge完成真正的删除

 

7.6 事务隔离级别

  READ UNCOMMITTED(读未提交):事务隔离最低的级别,可是存在脏读的问题

  READ COMMITED(读提交):ORACLE和SQL SERVER默认的隔离级别,解决了脏读,可是一个事务屡次读取的内容不一样,出现了不可重复读的问题。

  READ REPEATABLE(可重复读):innodb引擎的默认事务隔离级别,解决了不可重复读的问题,可是产生了幻读,innodb经过Next-key lock解决了幻读。

  SERIALIZABLE(可串行化):经过强制事务排序解决幻读问题,会下降性能。

 

  可串行化中,InnoDB会对每一个select语句后加上LOCK IN SHARE MODE,也就是为每一个读加上共享锁。该级别主要用于分布式事务。

 

7.7 分布式事务

  指容许多个独立的事务资源参与到一个全局的事务中。

  全局事务要求在其中全部参与的事务要么都提交,要么都回滚。

  InnoDB的隔离级别要设置为可串行化。

 

 

7.8 很差的习惯

  在循环中提交事务

  不要开启自动提交事务 set auto_commit = 0

  使用自动回滚,存储过程当中使用 declare exit handlerfor sqlexception rollback

相关文章
相关标签/搜索