MySQL基础知识

Posted WSYW126

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MySQL基础知识相关的知识,希望对你有一定的参考价值。

mysql基础知识

死锁

对于死锁问题,数据库系统实现了各种死锁检测和死锁超时机制。越复杂的系统,比如 Innodb存储引擎,越能检测到死锁的循环依赖,并立即返回一个错误。这种解决方式很有效,否则死锁会导致出现非常慢的查询。还有一种解决方式,就是当查询的时间达到锁等待超时的设定后放弃锁请求,这种方式通常来说不太好。 Innodb目前处理死锁的方法是,将持有最少行级排他锁的事务进行回滚(这是相对比较简单的死锁回滚算法)。

锁的行为和顺序是和存储引擎相关的。以同样的顺序执行语句,有些存储引擎会产生死锁,有些则不会。死锁的产生有双重原因:有些是因为真正的数据冲突,这种情况通常很难避免,但有些则完全是由于存储引擎的实现方式导致的。

事务日志

事务日志可以帮助提高事务的效率。使用事务日志,存储引擎在修改表的数据时只需要修改其内存拷贝,再把该修改行为记录到持久在硬盘上的事务日志中,而不用每次都将修改的数据本身持久到磁盘。事务日志采用的是追加的方式,因此写日志的操作是磁盘上一小块区域内的顺序IO,而不像随机I/O需要在磁盘的多个地方移动磁头,所以采用事务日志的方式相对来说要快得多。事务日志持久以后,内存中被修改的数据在后台可以慢慢地刷回到磁盘。目前大多数存储引擎都是这样实现的,我们通常称之为预写式日志( write - ahead logging),修改数据需要写两次磁盘。

如果数据的修改已经记录到事务日志并持久化,但数据本身还没有写回磁盘,此时系统崩溃,存储引擎在重启时能够自动恢复这部分修改的数据。具体的恢复方式则视存储引擎而定。

事务

自动提交( AUTOCOMMIT)

MYSQL默认采用自动提交( AUTOCOMMIT)模式。也就是说,如果不是显式地开始个事务,则每个查询都被当作一个事务执行提交操作。在当前连接中,可以通过设置 AUTOCOMMIT变量来启用或者禁用自动提交模式:

mysql> show variables like 'AUTOCOMMIT' ;
|variable_name | value|
|-----------------|-------|
|AUTOCOMMIT|on|
1 row in set ( 0.00 sec )
mysql> set autocommit = 1 ;

1或者ON表示启用,0或者OFF表示禁用。当 AUTOCOMMIT=0时,所有的查询都是在一个事务中,直到显式地执行 COMMIT提交或者 ROLLBACK回滚,该事务结束,同时又开始了另一个新事务。修改 AUTOCOMMIT对非事务型的表,比如 MYISAM或者内存表,不会有任何影响。对这类表来说,没有COMMIT或者 ROLLBACK的概念,也可以说是相当于一直处于AUTOCOMMIT启用的模式。

另外还有一些命令,在执行之前会强制执行COMMIT提交当前的活动事务。典型的例子,在数据定义语言(DDL)中,如果是会导致大量数据改变的操作,比如 ALTER TABLE,就是如此。另外还有LOCK TABLES等其他语句也会导致同样的结果。如果有需要,请检查对应版本的官方文档来确认所有可能导致自动提交的语句列表。

MYSQL可以通过执行 SET TRANSACTION ISOLATION LEVEL命令来设置隔离级别。新隔离级别会在下一个事务开始的时候生效。可以在配置文件中设置整个数据库的隔离级别,也可以只改变当前会话的隔离级别:
mysql > set session transaction isolation level read committed ;MYSQL能够识别所有的4个ANSI隔离级别, Innodb引擎也支持所有的隔离级别。

隐式和显式锁定

Innode采用的是两阶段锁定协议(wo- phase locking protocol)。在事务执行过程中,随时都可以执行锁定,锁只有在执行 COMMIT或者 ROLLBACK的时候才会释放,并且所有的锁是在同一时刻被释放。前面描述的锁定都是隐式锁定, Innodb会根据隔离级别在需要的时候自动加锁。

另外, Innodb也支持通过特定的语句进行显式锁定,这些语句不属于SQL规范:

  • SELECT … LOCK IN SHARE MODE
  • select . . for update

MYSQL也支持LOCK TABLES和 UNLOCK TABLES语句,这是在服务器层实现的,和存储引擎无关。它们有自己的用途,但并不能替代事务处理。如果应用需要用到事务,还是应该选择事务型存储引擎。

经常可以发现,应用已经将表从MYISAM转换到Innodb,但还是显式地使用LOCK TABLES语句。这不但没有必要,还会严重影响性能,实际上Innodb的行级锁工作得更好。

多版本并发控制(MVCC)

不同存储引擎的MVCC实现是不同的,典型的有乐观( optimistic)并发控制和悲观( pessimistic)并发控制。下面我们通过 Innodb的简化版行为来说明MVCC是如何工作的。

Innodb的MVCC,是通过在每行记录后面保存两个隐藏的列来实现的。这两个列,一个保存了行的创建时间,一个保存行的过期时间(或删除时间)。当然存储的并不是实际的时间值,而是系统版本号( system version number)。每开始一个新的事务,系统版本号都会自动递增。事务开始时刻的系统版本号会作为事务的版本号,用来和查询到的每行记录的版本号进行比较。下面看一下在 REPEATABLE READ隔离级别下,MVCC具体是如何操作的。

SELECT
Innodb会根据以下两个条件检查每行记录:

  • Innodb只查找版本早于当前事务版本的数据行(也就是,行的系统版本号小于或等于事务的系统版本号),这样可以确保事务读取的行,要么是在事务开始前已经存在的,要么是事务自身插入或者修改过的。
  • 行的删除版本要么未定义,要么大于当前事务版本号。这可以确保事务读取到的行,在事务开始之前未被删除

只有符合上述两个条件的记录,才能返回作为查询结果。

INSERT
Innodb为新插入的每一行保存当前系统版本号作为行版本号。

DELETE
Innodb为删除的每一行保存当前系统版本号作为行删除标识。

UPDATE
Innodb为插入一行新记录,保存当前系统版本号作为行版本号,同时保存当前系统版本号到原来的行作为行删除标识。

保存这两个额外系统版本号,使大多数读操作都可以不用加锁。这样设计使得读数据操作很简单,性能很好,并且也能保证只会读取到符合标准的行。不足之处是每行记录都需要额外的存储空间,需要做更多的行检查工作,以及一些额外的维护工作。

MVCC只在 REPEATABLE READ和 READ COMMITTED两个隔离级别下工作。其他两个隔离级别都和MVCC不兼容,因为READ UNCOMMITTED总是读取最新的数据行,而不是符合当前事务版本的数据行。而SERIALIZABLE则会对所有读取的行都加锁。


参考资料:
高性能MySQL(第3版)
备注:
转载请注明出处:http://blog.csdn.net/wsyw126/article/details/78205979
作者:WSYW126

以上是关于MySQL基础知识的主要内容,如果未能解决你的问题,请参考以下文章

Mysql锁一般使用

MySQL探秘 —— 恢复到任意时刻的秘诀

MySQL探秘 —— 恢复到任意时刻的秘诀

《高性能MySQL》读书笔记之 MySQL锁事务多版本并发控制的基础知识

高性能mysql读后感

使用时刻 js 将 mysql 日期中的组 concat 更改为印度尼西亚日期格式