mysql数据库引擎InnoDB和MyISAM的区别

 

InnoDB支持行级锁和表级锁(默认行级锁),支持事务,外部键等;大量的insert和update更快等。只有经过索引条件检索数据,InnoDB 才使用行级锁,不然,InnoDB 将使用表锁。mysql

MyISAM是表级锁,不支持事务,大量的SELECT查询更快等sql

BDB引擎支持页级锁和表级锁(默认页级锁)数据库

 

行级锁

行级锁是 MySQL 中锁定粒度最细的一种锁,表示只针对当前操做的行进行加锁。行级锁能大大减小数据库操做的冲突,其加锁粒度最小,但加锁的开销也最大。行级锁分为共享锁和排他锁。并发

特色性能

开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的几率最低,并发度也最高。spa

表级锁

表级锁是 MySQL 中锁定粒度最大的一种锁,表示对当前操做的整张表加锁,它实现简单,资源消耗较少,被大部分 MySQL 引擎支持。最常使用的 MyISAM 与 InnoDB 都支持表级锁定。表级锁定分为表共享读锁(共享锁)与表独占写锁(排他锁)。线程

特色设计

开销小,加锁快;不会出现死锁;锁定粒度大,发出锁冲突的几率最高,并发度最低。code

页级锁

页级锁是 MySQL 中锁定粒度介于行级锁和表级锁中间的一种锁。表级锁速度快,但冲突多,行级冲突少,但速度慢。所以,采起了折衷的页级锁,一次锁定相邻的一组记录。BDB 支持页级锁。orm

特色

开销和加锁时间界于表锁和行锁之间;会出现死锁;锁定粒度界于表锁和行锁之间,并发度通常。

 

InnoDB 中的行锁与表锁

前面提到过,在 InnoDB 引擎中既支持行锁也支持表锁,那么何时会锁住整张表?何时只锁住一行呢?

InnoDB 行锁是经过给索引上的索引项加锁来实现的,这一点 MySQL 与 Oracle 不一样,后者是经过在数据块中对相应数据行加锁来实现的。InnoDB 这种行锁实现的特色意味着:只有经过索引条件检索数据,InnoDB 才使用行级锁,不然,InnoDB 将使用表锁。

在实际应用中,要特别注意 InnoDB 行锁的这一特性,否则的话,可能致使大量的锁冲突,从而影响并发性能。

  • 在不经过索引条件查询的时候,InnoDB 确实使用的是表锁,而不是行锁。
  • 因为 MySQL 的行锁是针对索引加的锁,不是针对记录加的锁,所以虽然是访问不一样行的记录,可是若是是使用相同的索引键,是会出现锁冲突的。应用设计的时候要注意这一点。
  • 当表有多个索引的时候,不一样的事务可使用不一样的索引锁定不一样的行,另外,不管是使用主键索引、惟一索引仍是普通索引,InnoDB 都会使用行锁来对数据加锁。
  • 即使在条件中使用了索引字段,可是否使用索引来检索数据是由 MySQL 经过判断不一样的执行计划的代价来决定的。若是 MySQL 认为全表扫描效率更高,好比对一些很小的表,它就不会使用索引,这种状况下 InnoDB 将使用表锁,而不是行锁。所以,在分析锁冲突时,别忘了检查 SQL 的执行计划,以确认是否真正使用了索引。

行级锁与死锁

MyISAM 中是不会产生死锁的,由于 MyISAM 老是一次性得到所需的所有锁,要么所有知足,要么所有等待。而在 InnoDB 中,锁是逐步得到的,就形成了死锁的可能。

在 MySQL 中,行级锁并非直接锁记录,而是锁索引。索引分为主键索引和非主键索引两种,若是一条 SQL 语句操做了主键索引,MySQL 就会锁定这条主键索引;若是一条 SQL 语句操做了非主键索引,MySQL 就会先锁定该非主键索引,再锁定相关的主键索引。 在进行UPDATEDELETE操做时,MySQL 不只锁定WHERE条件扫描过的全部索引记录,并且会锁定相邻的键值,即所谓的next-key locking.

当两个事务同时执行,一个锁住了主键索引,在等待其余相关索引;另外一个锁定了非主键索引,在等待主键索引。这样就会发生死锁。

发生死锁后,InnoDB 通常均可以检测到,并使一个事务释放锁回退,另外一个获取锁完成事务。

避免死锁的方法

有多种方法能够避免死锁,这里只介绍常见的三种:

  1. 若是不一样程序会并发存取多个表,尽可能约定以相同的顺序访问表,能够大大下降发生死锁的可能性;
  2. 在同一个事务中,尽量作到一次锁定所须要的全部资源,减小死锁产生几率;
  3. 对于很是容易产生死锁的业务部分,能够尝试使用升级锁定颗粒度,经过表级锁定来减小死锁产生的几率。

死锁的解决方案:

一、先查看当前库的线程状况:show  full processlist; 目的看先有没有这在执行的慢sql线程,若是有就kill掉

二、若是没有,再去查看innodb的事务表INNODB_TRX,看下里面是否有正在锁定的事务线程,看看ID是否在show full processlist里面的sleep线程中,若是是,就证实这个sleep的线程事务一直没有commit或者rollback而是卡住了

  SELECT * FROM information_schema.INNODB_TRX G;若是有就kill掉

 

共享锁和排他锁:

一、共享锁:称为读锁,简称S锁,顾名思义,共享锁就是多个事务对于同一数据能够共享一把锁,都能访问到数据,可是只能读不能修改。

二、排他锁:又称为写锁,简称X锁,顾名思义,排他锁就是不能与其余所并存,如一个事务获取了一个数据行的排他锁,其余事务就不能再获取该行的其余锁,包括共享锁和排他锁,可是获取排他锁的事务是能够对数据就行读取和修改

对于共享锁你们可能很好理解,就是多个事务只能读数据不能改数据,对于排他锁你们的理解可能就有些差异,我当初就犯了一个错误,觉得排他锁锁住一行数据后,其余事务就不能读取和修改该行数据,其实不是这样的。排他锁指的是一个事务在一行数据加上排他锁后,其余事务不能再在其上加其余的锁。mysql InnoDB引擎默认的修改数据语句,update,delete,insert都会自动给涉及到的数据加上排他锁,select语句默认不会加任何锁类型,若是加排他锁可使用select ...for update语句,加共享锁可使用select ... lock in share mode语句。因此加过排他锁的数据行在其余事务种是不能修改数据的,也不能经过for update和lock in share mode锁的方式查询数据,但能够直接经过select ...from...查询数据,由于普通查询没有任何锁机制。

 

注意:mysql的update、delete、insert是默认加了排他锁的,而普通的selete是什么锁都没加,因此普通selete既能查共享锁的行也能查排他锁的行

相关文章
相关标签/搜索