事务
ACID特性
-
原子性(atomicity)
一个事务必须被视为一个不可分割的最小工作单元,整个事务中的所有操作要么全部提交成功,要么全部失败回滚,对于一个事务来说,不可能只执行其中的一部分操作。 -
-
隔离性(isolation)
通常来说,一个事务所做的修改在最终提交以前,对其他事务是不可见的。 -
持久性(durability)
一旦事务提交,则其所做的修改就会永久保存到数据库中。此时即使系统崩溃,修改的数据也不会丢失。
脏读
在事务A修改数据之后提交数据之前,这时另一个事务B来读取数据,如果不加控制,事务B读取到A修改过数据,之后A又对数据做了修改再提交,则B读到的数据是脏数据,此过程称为脏读Dirty Read。
不可重复读
一个事务内在读取某些数据后的某个时间,再次读取以前读过的数据,却发现其读出的数据已经发生了变更、或者某些记录已经被删除了。
幻读
事务A在按查询条件读取某个范围的记录时,事务B又在该范围内插入了新的满足条件的记录,当事务A再次按条件查询记录时,会产生新的满足条件的记录(幻行 Phantom Row)
不可重复读与幻读的区别
-
不可重复读的重点是修改:在同一事务中,同样的条件,第一次读的数据和第二次读的「数据不一样」。(因为中间有其他事务提交了修改)
-
幻读的重点在于新增或者删除:在同一事务中,同样的条件,第一次和第二次读出来的「记录数不一样」。(因为中间有其他事务提交了插入/删除)
四个隔离级别
MySQL中哪些存储引擎支持事务?
MySQL中InnoDB和NDB Cluster存储引擎提供了事务处理能力,以及其他支持事务的第三引擎。
自动提交
MySQL默认采用自动提交AUTOCOMMIT模式。也就是说,如果不是显式地开始一个事务,则每个查询都被当作一个事务执行提交操作。
对于MyISAM或者内存表这些事务型的表,修改AUTOCOMMIT不会有任何影响。对这类表来说,没有COMMIT或者ROLLBACK的概念,也可以说是相当于一直处于AUTOCOMMIT启用的模式。
InnoDB与MyISAM对比
MVCC
Multiple Version Concurrent Control,多版本并发控制
MVCC (Multiversion Concurrency Control),即多版本并发控制技术,它使得大部分支持行锁的事务引擎,不再单纯的使用行锁来进行数据库的并发控制,取而代之的是,把数据库的行锁与行的多个版本结合起来,只需要很小的开销,就可以实现非锁定读,从而大大提高数据库系统的并发性能.
可以认为MVCC是行级锁的一个变种,但它在很多情况下避免了加锁操作,因此开销更低。虽然实现机制有所不同,但大都实现了非阻塞的读操作,写操作也只锁定必要的行。
MVCC的实现,是通过保存数据在某个时间点的快照来实现的。也就是说,不管需要执行多长时间,每个事务看到的数据都是一致的。根据事务开始时间的不同,每个事务对同一张表,同一时刻看到的数据可能是不一样的。
InnoDB的MVCC,是通过在每行后面保存两个隐藏的列来实现的。这两个列,一个保存了行的的创建时间,一个保存了行的过期时间(或删除时间)。当然,存储的并不是实际的时间,而是系统版本号。每开始一个新的事务,系统版本号会自动递增。事务开始时刻的系统版本号作为该事务的版本号,用来和查询到的行的版本号进行比较。
MVCC只在可重复读和读已提交两个隔离级别下工作。其他两个隔离级别都与MVCC不兼容,因为读未提交总是读取最新的数据行,而不是符合当前事务版本的数据行。而串行化则会对所有读取的行进行加锁。
下面分别以select、delete、 insert、 update语句来说明:
1) SELECT
对于select语句,只有同时满足了下面两个条件的行,才能被返回:
•行的被修改版本号小于或者等于该事务号
•行的被删除版本号要么没有被定义,要么大于事务的版本号:行的删除版本号如果没有被定义,说明该行没有被删除过;如果删除版本号大于当前事务的事务号,说明该行是被该事务后面启动的事务删除的,由于是repeatable read隔离等级,后开始的事务对数据的影响不应该被先开始的事务看见,所以该行应该被返回。
2) INSERT
对新插入的行,行的更新版本被修改为该事务的事务号
3) DELETE
对于删除,innodb直接把该行的被删除版本号设置为当前的事务号,相当于标记为删除,而不是实际删除
4) UPDATE
在更新行的时候,innodb会把原来的行复制一份到回滚段中,并把当前的事务号作为该行的更新版本
MVCC的优缺点
优点:在读取数据的时候,innodb几乎不用获得任何锁,,每个查询都通过版本检查,只获得自己需要的数据版本,从而大大提高了系统的并发度。
缺点:为了实现多版本,innodb必须对每行增加相应的字段来存储版本信息,同时需要维护每一行的版本信息,而且在检索行的时候,需要进行版本的比较,因而降低了查询的效率;innodb还必须定期清理不再需要的行版本,及时回收空间,这也增加了一些开销。
问题
1、为什么select count()在myisam表上很快,而在Innodb的表上很慢 ?
因为innodb采用了MVCC技术,对于相同的行,可能同时存在多个版本,innodb必须根据查询的时间来过滤掉一些行,才能得出结果,必然要执行全表扫描,而全表扫描是非常耗时的.对于myisam的表,任何行都只有一个版本,mysql甚至不需要扫描就可以直接返回精确的统计结果,我们用explain也可以看到,对于myisam的表,执行select count(*)的时候,mysql显示” Select tables optimized away”,查询直接被优化了;而对于innodb的表,可能是全表扫描,也可能是”using index”,总之,速度肯定会比myisam的表慢很多.
2、数据库只是频繁更新,没有插入新数据,但是为什么表空间占用会越来越大?

浙公网安备 33010602011771号