目录
1,引擎
#说明:数据库中的存储引擎其实是对使用了该引擎的表进行某种设置,数据库中的表设定了什么存储引擎,那么该表在数据存储方式、数据更新方式、数据查询性能以及是否支持索引等方面就会有不同的“效果”。
#常见种类
#InnoDB存储引擎
#特点:支持事务、行级锁和、支持外键、不支持全文搜索、不保存表的行数、缓存索引和数据
#适用场景:需要事务支持(具有较好的事务特性)、行级锁定对高并发有很好的适应能力、数据更新较为频繁的场景、数据一致性要求较高、硬件设备内存较大
#MyISAM存储引擎
#特点:不支持事务、表级锁和、不支持外键、支持全文搜索、保存表的行数、只会缓存索引
#适用场景:不需要事务支持(不支持)、并发相对较低(锁定机制问题)、读远远大于修改数据
#两种引擎所使用的索引的数据结构都是B+树
#MyIASM引擎,B+树的数据结构中存储的内容实际上是实际数据的地址值。也就是说它的索引和实际数据是分开的,只不过使用索引指向了实际数据。这种索引的模式被称为非聚集索引。
#Innodb引擎的索引的数据结构也是B+树,只不过数据结构中存储的都是实际的数据,这种索引有被称为聚集索引。
#NDBCluster存储引擎
#特点:分布式、支持事务、内存需求量巨大、可与mysqld不在一台主机、不支持临时表
#说明:具有非常高的并发需求、对单个请求的响应并不是非常的critical、查询简单,过滤条件较为固定,每次请求数据量较少,又不希望自己进行水平Sharding
#其他:Memory,Merge,CSV,Archive等存储引擎的使用场景都相对较少,这里就不一一分析了。
2,索引原理
B+树和B-树
3,事务
#定义:是指作为单个逻辑工作单元执行的一系列操作,要么完全执行,要么完全地不执行。
#ACID四个特性
#原子性(Atomicity)
#构成事务的的所有操作必须是一个逻辑单元,要么全部执行,要么全部不执行。
#为了实现原子性,需要通过日志:将所有对数据的更新操作都写入日志,如果一个事务中的一部分操作已经成功,但以后的操作,由于断电/系统崩溃/其它的软硬件错误而无法继续,则通过回溯日志,将已经执行成功的操作撤销,
##从而达到“全部操作失败”的目的。最常见的场景是,数据库系统崩溃后重启,此时数据库处于不一致的状态,必须先执行一个crash recovery的过程:读取日志进行REDO(重演将所有已经执行成功但尚未写入到磁盘的操作,保证持久性),
##再对所有到崩溃时尚未成功提交的事务进行UNDO(撤销所有执行了一部分但尚未提交的操作,保证原子性)。crash recovery结束后,数据库恢复到一致性状态,可以继续被使用。
#日志的管理和重演是数据库实现中最复杂的部分之一。如果涉及到并行处理和分布式系统(日志的复制和重演是数据库高可用性的基础),会比上述场景还要复杂得多。
#一致性(Consistency)
从一个一致的状态变到另外一个一致的状态,也就是事务执行后,并没有破坏数据库的完整性约束,一切为正确的。其他三个特性都是为了保证一致性而存在的
#隔离性(Isolation)
#隔离性是指当多个用户并发访问数据库时,比如操作同一张表时,数据库为每一个用户开启的事务,不能被其他事务的操作所干扰,多个并发事务之间要相互隔离
#保证数据的一致性,必须同时保证隔离性和原子性,实现隔离性可以加锁
#持久性(Durability)
#持久性是指一个事务一旦被提交了,那么对于数据库中的数据改变就是永久性的,即便是在数据库系统遭遇到故障的情况下也不会丢失提交事务的操作。
#并发问题
#脏读:事务A读取了事务B更新的数据,然后B回滚操作,那么A读取到的数据是脏数据
#不可重复读:在一个事务的两次查询之中数据不一致,这可能是两次查询过程中间插入了一个事务更新的原有的数据。
#幻读:在一个事务的两次查询中数据笔数不一致,例如有一个事务查询了几列(Row)数据,而另一个事务却在此时插入了新的几列数据,先前的事务在接下来的查询中,就会发现有几列数据是它先前所没有的。
#小结:不可重复读的和幻读很容易混淆,不可重复读侧重于修改,幻读侧重于新增或删除。解决不可重复读的问题只需锁住满足条件的行,解决幻读需要锁表
#隔离级别
#事务隔离级别 脏读 不可重复读 幻读
#读未提交(read-uncommitted) 是 是 是
#不可重复读(read-committed) 否 是 是
#可重复读(repeatable-read) 否 否 是
#串行化(serializable) 否 否 否
#oracle和sql server默认是不可重复读(read-committed)隔离级别,mysql默认是可重复读(repeatable-read)
4,锁机制
#说明:数据库为了维护ACID,尤其是一致性和隔离性,一般使用加锁
的方式。同时由于数据库是个高并发的应用,同一时间有大量的并发访问,如果加锁过度,会极大的降低并发处理的能力。所以对于加锁的处理,是数据库对于事务处理的精髓所在
#共享锁(又称读锁)、排它锁(又称写锁):
#InnoDB引擎的锁机制:InnoDB支持事务,支持行锁和表锁用的比较多,Myisam不支持事务,只支持表锁。
#共享锁(S):允许一个事务去读一行,阻止其他事务获得相同数据集的排他锁。
#排他锁(X):允许获得排他锁的事务更新数据,阻止其他事务取得相同数据集的共享读锁和排他写锁。
#意向共享锁(IS):事务打算给数据行加行共享锁,事务在给一个数据行加共享锁前必须先取得该表的IS锁。
#意向排他锁(IX):事务打算给数据行加行排他锁,事务在给一个数据行加排他锁前必须先取得该表的IX锁。
#说明:
#意向排他锁(IX):事务打算给数据行加行排他锁,事务在给一个数据行加排他锁前必须先取得该表的IX锁。
#对于UPDATE、DELETE和INSERT语句,InnoDB会自动给涉及数据集加排他锁(X);对于普通SELECT语句,InnoDB不会加任何锁
#这里说说Myisam:MyISAM在执行查询语句(SELECT)前,会自动给涉及的所有表加读锁,在执行更新操作(UPDATE、DELETE、INSERT等)前,会自动给涉及的表加写锁。
#InnoDB行锁是通过给索引上的索引项加锁来实现的,因此InnoDB这种行锁实现特点意味着:只有通过索引条件检索数据,InnoDB才使用行级锁,否则,InnoDB将使用表锁
#乐观锁、悲观锁:
#悲观锁:
#定义:即当前事务将所有涉及操作的对象加锁,操作完成后释放给其它对象使用。为了尽可能提高性能,发明了各种粒度(数据库级/表级/行级……)/各种性质(共享锁/排他锁/共享意向锁/排他意向锁/共享排他意向锁……)的锁。为了解决死锁问题,又发明了两阶段锁协议/死锁检测等一系列的技术。
#说明:
#使用悲观锁,我们必须关闭mysql数据库的自动提交属性,采用手动提交事务的方式,因为MySQL默认使用autocommit模式,也就是说,当你执行一个更新操作后,MySQL会立刻将结果进行提交。
#需要注意的是,在事务中,只有SELECT ... FOR UPDATE 或LOCK IN SHARE MODE 同一笔数据时会等待其它事务结束后才执行,一般SELECT ... 则不受此影响。对于UPDATE、DELETE和INSERT语句,InnoDB会自动给涉及数据集加排他锁(X)。
#使用select…for update会把数据给锁住,不过我们需要注意一些锁的级别,MySQL InnoDB默认Row-Level Lock,所以只有「明确」地指定主键(或有索引的地方),MySQL 才会执行Row lock (只锁住被选取的数据) ,否则MySQL 将会执行Table Lock (将整个数据表单给锁住)。
#乐观锁:
定义:乐观锁假设认为数据一般情况下不会造成冲突,所以在数据进行提交更新的时候,才会正式对数据的冲突与否进行检测,如果发现冲突了,则让返回用户错误的信息,让用户决定如何去做(一般是回滚事务)
#实现方式:
#使用数据版本(Version)记录机制实现,这是乐观锁最常用的一种实现方式。何谓数据版本?即为数据增加一个版本标识,一般是通过为数据库表增加一个数字类型的 “version” 字段来实现。当读取数据时,将version字段的值一同读出,数据每更新一次,对此version值加一。当我们提交更新的时候,判断数据库表对应记录的当前版本信息与第一次取出来的version值进行比对,如果数据库表当前版本号与第一次取出来的version值相等,则予以更新,否则认为是过期数据。
#乐观锁定的第二种实现方式和第一种差不多,同样是在需要乐观锁控制的table中增加一个字段,名称无所谓,字段类型使用时间戳(timestamp), 和上面的version类似,也是在更新提交的时候检查当前数据库中数据的时间戳和自己更新前取到的时间戳进行对比,如果一致则OK,否则就是版本冲突。
#锁也是数据库实现中最复杂的部分之一。同样,如果涉及到分布式系统(分布式锁和两阶段提交是分布式事务的基础),会比上述场景还要复杂得多。
5,优化
#参数配置优化
#说明:mysql配置项的优化是一件非常复杂且长期坚持的事情,因为不同的并发级别会导致某个配置项不符合当前的情况
#文章链接:http://blog.csdn.net/u014044812/article/details/78929579
#使用规范优化
#说明:遵循使用规范,可避免在使用过程中对数据库性能的降低
#文章链接:http://blog.csdn.net/u014044812/article/details/78931044