MySQL存储引擎

Innodb

Innodb:支持事物,支持多版本控制(mvcc),支持行锁,B+Tree作为索引结构;

日志文件

  • 错误日志:Error Log,默认关闭,需要在启动时开启--log-error[=file_name]
  • 二进制日志:Binary Log & Binary Log Index,日志中并不仅限于query语句这么简单,还包括每一条query所执行的时间,所消耗的资源,以及相关的事务信息,所以binlog是事务安全的。
--log-bin[=file_name]”参数的显式指定才能开启
  • 慢查询日志:slow query log,--log-slow-queries[=file_name]来打开该功能,分析慢查询日志的工具程序mysqlslowdump
  • Innodb的在线redo日志:innodb redo log
Innodb是一个事务安全的存储引擎,其事务安全性主要就是通过在线redo日志和记录在表空间中的undo信息来保证的。redo日志中记录了Innodb所做的所有物理变更和事务信息,通过redo日志和undo信息,Innodb保证了在任何情况下的事务安全性。Innodb完全可以通过redo日志将数据库Crash时刻已经完成但还没有来得及将数据写入磁盘的事务恢复,也能够将所有部分完成并已经写入磁盘的未完成事务回滚并将数据还原。

MVCC的优缺点

在读取数据的时候,innodb几乎不用获得任何锁, 每个查询都通过版本检查,只获得自己需要的数据版本,从而大大提高了系统的并发度.
这种策略的缺点是,为了实现多版本,innodb必须对每行增加相应的字段来存储版本信息,同时需要维护每一行的版本信息,而且在检索行的时候,需要进行版本的比较,因而降低了查询的效率;innodb还必须定期清理不再需要的行版本,及时回收空间,这也增加了一些开销。
Innodb默认的事务隔离级别是REPEATABLE READ(可重复读),在标准的事务隔离级别定义下,REPEATABLE READ是不能防止幻读产生的。INNODB使用了2种技术手段(MVCC AND GAP LOCK)实现了防止幻读的发生

锁机制

行锁

行级锁定最大的特点就是锁定对象的颗粒度很小,由于锁定颗粒度很小,所以发生锁定资源争用的概率也最小,能够给予应用程序尽可能大的并发处理能力而提高一些需要高并发应用系统的整体性能。
由于锁定资源的颗粒度很小,所以每次获取锁和释放锁需要做的事情也更多,带来的消耗自然也就更大了。此外,行级锁定也最容易发生死锁。
Innodb的行锁分为两种类型,共享锁和排他锁:
当一个事务需要给自己需要的某个资源加锁的时候,如果遇到一个共享锁正锁定着自己需要的资源的时候,自己可以再加一个共享锁,不过不能加排他锁。但是,如果遇到自己需要锁定的资源已经被一个排他锁占有之后,则只能等待该锁定释放资源之后自己才能获取锁定资源并添加自己的锁定。

间隙锁

Innodb的锁定是通过在指向数据记录的第一个索引键之前和最后一个索引键之后的空域空间上标记锁定信息而实现的。Innodb的这种锁定实现方式被称为“NEXT-KEY locking”(间隙锁),因为Query执行过程中通过范围查找的,他会锁定整个范围内所有的索引键值,即使这个键值并不存在。
间隙锁(GAP锁)有一个比较致命的弱点,就是当锁定一个范围键值之后,即使某些不存在的键值也会被无辜的锁定,而造成在锁定的时候无法插入锁定键值范围内的任何数据。在某些场景下这可能会对性能造成很大的危害。而Innodb给出的解释是为了阻止幻读的出现,所以他们选择的间隙锁来实现锁定。
通过索引实现锁定的方式存在其他几个较大的性能隐患:
  • 当Query无法利用索引的时候,Innodb会放弃使用行级别锁定而改用表级别的锁定,造成并发性能的降低;
  • 当Query使用的索引并不包含所有过滤条件的时候,数据检索使用到的索引键所指向的数据可能有部分并不属于该Query的结果集的行列,但是也会被锁定,因为间隙锁锁定的是一个范围,而不是具体的索引键;
  • 当Query在使用索引定位数据的时候,如果使用的索引键一样但访问的数据行不同的时候(索引只是过滤条件的一部分),一样会被锁定

表锁

表级别的锁定是MySQL各存储引擎中最大颗粒度的锁定机制。该锁定机制最大的特点是实现逻辑非常简单,带来的系统负面影响最小。所以获取锁和释放锁的速度很快。由于表级锁一次会将整个表锁定,所以可以很好的避免困扰我们的死锁问题。
锁定颗粒度大所带来最大的负面影响就是出现锁定资源争用的概率也会最高,致使并发大打折扣。

意向锁

innodb的意向锁主要用户多粒度的锁并存的情况。比如事务A要在一个表上加S锁,如果表中的一行已被事务B加了X锁,那么该锁的申请也应被阻塞。如果表中的数据很多,逐行检查锁标志的开销将很大,系统的性能将会受到影响。为了解决这个问题,可以在表级上引入新的锁类型来表示其所属行的加锁情况,这就引出了“意向锁”的概念。
意向锁的主要作用是处理行锁和表锁之间的矛盾,能够显示“某个事务正在某一行上持有了锁,或者准备去持有锁”
申请意向锁的动作是数据库完成的,就是说,事务A申请一行的行锁的时候,数据库会自动先开始申请表的意向锁,不需要我们程序员使用代码来申请

如何使用锁

在数据库实现资源锁定的过程中,随着锁定资源颗粒度的减小,锁定相同数据量的数据所需要消耗的内存数量是越来越多的,实现算法也会越来越复杂。不过,随着锁定资源颗粒度的减小,应用程序的访问请求遇到锁等待的可能性也会随之降低,系统整体并发度也随之提升。
要想合理利用Innodb的行级锁定,做到扬长避短,我们必须做好以下工作:
a) 尽可能让所有的数据检索都通过索引来完成,从而避免Innodb因为无法通过索引键加锁而升级为表级锁定;
b) 合理设计索引,让Innodb在索引键上面加锁的时候尽可能准确,尽可能的缩小锁定范围,避免造成不必要的锁定而影响其他Query的执行;
c) 尽可能减少基于范围的数据检索过滤条件,避免因为间隙锁带来的负面影响而锁定了不该锁定的记录;
d) 尽量控制事务的大小,减少锁定的资源量和锁定时间长度
e) 在业务环境允许的情况下,尽量使用较低级别的事务隔离,以减少MySQL因为实现事务隔离级别所带来的附加成本;

MyISAM

MyISAM:支持三种索引,不支持事物
  • B-Tree索引:所有的索引节点都按照balance tree的数据结构来存储,所有的索引数据节点都在叶节点。
  • R-Tree索引:用于为存储空间和多维数据的字段做索引,所以目前的MySQL版本来说,也仅支持geometry类型的字段作索引。
  • Full-text索引:全文索引,他的存储结构也是b-tree。主要是为了解决like查询的低效问题。
posted @ 2022-06-13 16:41  hjy1995  阅读(25)  评论(0编辑  收藏  举报