高性能mysql 第1章 mysql架构与历史
mysql逻辑架构图:
第一层 客户端
第二层(服务层):针对所有类型的存储引擎可以公共提取的部分。将存储引擎抽离之后的其他部分都在这里。如:查询解析,分析优化,内置函数,存储过程,触发器,视图。
第三层(存储引擎层):存储引擎负责mysql数据的存储和提取。服务器通过API与存储引擎进行通信。这些API屏蔽了不同存储引擎的具体实现差异。存储引擎API包含"开始一个事务","根据主键获取一行数据"等操作。存储引擎本身不会去解析sql。
注:mongdb也有存储引擎。
数据库通过读锁和写锁,又叫共享锁和排它锁,来控制并发事务。
关于锁粒度,mysql交给存储引擎自己去管理,每种存储引擎可以实现自己的锁粒度和锁策略。
不同的锁策略,会带来不同的效果,表锁开销最小,但是并发最差。行级锁并发性能最好,但是开销最大。
尽管锁策略在存储引擎上管理,但是在执行alter table这种操作的时候,服务层会直接使用表所,而忽视存储引擎层的锁机制。
隔离级别:
mysql支持四中隔离级别:
- read uncommitted:未提交读
- read commited 提交读(Oracle的默认隔离级别)
- repeatable read 可重复读(mysql的默认隔离级别)
- serializable 串行化
注:可重复读解决了不可重复读的问题(同一个数据在两次读取的时候结果不一样)。串行化解决了幻读的问题(两次执行同一个where语句结果什么结果条数不一致)。
疑惑:关于序列化,书上说mysql对每一行读的数据都加锁。如果这样做的话,肯定能保证可重复读,但是怎么保证幻读呢,因为对读取的数据进行加锁是不能阻塞insert操作的呢。
死锁:关于死锁的原因,一种是业务场景的操作导致,另外一些,是存储引擎的实现方式导致的。
innodb能够识别到死锁现象,并回滚持有最少排它锁的事务。
事务日志:
事务日志可以提高事务的效率,mysql在update表的时候只需要修改内存中的数据,然后将修改行为记录在硬盘的事务日志中,这个事务的过程就算完了。不需要等待硬盘中的数据文件被update才返回。事务日志是硬盘上的一段顺序存储空间,可不是随机的磁盘存储,每次add都是采取追加的方式,事务日志中的内容会持久化到硬盘数据文件中。这种方式叫做预写式日志,需要写两次硬盘。
如果出现断电,在重启后,可以通过事务日志恢复数据。
注:Mongodb最新的WiredTiger存储引擎也有类似事务日志的概念,不过不叫事务日志,叫做预写日志(WAL: Write-Ahead Logging),因为mongdb没有事务么。
书上说,如果是会导致大量数据改变的DDL语句,如alter table操作,会触发事务的commit操作。另外,lock table操作或者其他语句也会导致commit。有哪些语句需要查阅mysql的官方文档。
注:这点和oracle不一样,oracle的所有DDL操作都会触发commit操作。
如果在一个事务中混合使用了事务性和非事务性的表(如Innodb和MyISAM表),在回滚的过程中,将无法回滚非事务性的表。而且mysql不会抛出错误,直接忽略了非事务性的表的回滚操作。
Innodb采用两阶段锁定协议。
mvcc:多版本并发控制
不仅mysql,大部分的数据库,如ORACLE都实现了mvcc。mvcc是行级锁的一个变种,因为它在大多数的情况下,避免了行级锁,虽然实现机制有所不同,但都大多实现了非阻塞的读操作。不论执行多长的sql,通过时间点上的快照,可以保证读取数据的一致性。
mysql的innodb的mvcc,简单的理解,可以说是在每一行加了隐藏的两列,开始时间和结束时间。当然存储的不是时间,而是系统的版本号。
mvcc只在repeatable read和read commited两个隔离级别下生效。因为另外两个隔离级别根本不需要它。
innodb的行为是非常复杂的,不容易理解,如果使用innodb引擎,笔者强烈建议阅读官方手册中"innodb实物模型和锁"一节。如果应用程序是基于innodb构建,那么了解一下innodb的mvcc架构带来的一些微妙和细节之处是非常有必要的。存储引擎为所有用户甚至包括修改数据的用户维持一致性视图,是非常复杂的工作。
在mysql 5.1之前的版本,MyISAM是默认的搜索引擎。它不支持事务和行级锁。
mysql5.5是oracle收购mysql之后的第一个版本(上一个版本就是5.1 没有 5.2 5.3之类的),它的默认存储引擎是innodb。
以下来自网络:
两种存储引擎的大致区别表现在:
1)InnoDB支持事务,MyISAM不支持,这一点是非常之重要。事务是一种高级的处理方式,如在一些列增删改中只要哪个出错还可以回滚还原,而MyISAM就不可以了。
2)MyISAM适合查询以及插入为主的应用,InnoDB适合频繁修改以及涉及到安全性较高的应用
3)InnoDB支持外键,MyISAM不支持
4)从MySQL5.5.5以后,InnoDB是默认引擎
5)InnoDB不支持FULLTEXT类型的索引
6)InnoDB中不保存表的行数,如select count(*)
from table时,InnoDB需要扫描一遍整个表来计算有多少行,但是MyISAM只要简单的读出保存好的行数即可。注意的是,当count(*)语句包含where条件时MyISAM也需要扫描整个表
7)对于自增长的字段,InnoDB中必须包含只有该字段的索引,但是在MyISAM表中可以和其他字段一起建立联合索引
8)清空整个表时,InnoDB是一行一行的删除,效率非常慢。MyISAM则会重建表
9)InnoDB支持行锁(某些情况下还是锁整表,如 update table set a=1 where user like '%lee%'
关于MyISAM与InnoDB选择使用:
MYISAM和INNODB是Mysql数据库提供的两种存储引擎。两者的优劣可谓是各有千秋。INNODB会支持一些关系数据库的高级功能,如事务功能和行级锁,MYISAM不支持。MYISAM的性能更优,占用的存储空间少。所以,选择何种存储引擎,视具体应用而定:
1)如果你的应用程序一定要使用事务,毫无疑问你要选择INNODB引擎。但要注意,INNODB的行级锁是有条件的。InnoDB行锁是通过给索引上的索引项加锁来实现的,这一点MySQL与Oracle不同,后者是通过在数据块中对相应数据行加锁来实现的。InnoDB这种行锁实现特点意味着:只有通过索引条件检索数据,InnoDB才使用行级锁,否则,InnoDB将使用表锁。
2)如果你的应用程序对查询性能要求较高,就要使用MYISAM了。MYISAM索引和数据是分开的,而且其索引是压缩的,可以更好地利用内存。所以它的查询性能明显优于INNODB。压缩后的索引也能节约一些磁盘空间。MYISAM拥有全文索引的功能,这可以极大地优化LIKE查询的效率。
关于Mysql数据库默认的存储引擎:
MyISAM和InnoDB是MySQL的两种存储引擎。
如果是默认安装,那就应该是InnoDB,你可以在my.cnf文件中找到default-storage-engine=INNODB;
当然你可以在建表时指定相应的存储引擎。
基本的差别为:
MyISAM类型不支持事务处理等高级处理,而InnoDB类型支持。
MyISAM类型的表强调的是性能,其执行数度比InnoDB类型更快,但是不提供事务支持,而InnoDB提供事务支持已经外部键等高级数据库功能。
因为我接触的系统都是事务性的,所以肯定要用InnoDB,虽然可以同时使用MyISAM和InnoDB,但是我不建议这么做。随着mysql的发展,InnoDB的性能会慢慢得到提升,作为默认的存储引擎,肯定是mysql开发的重心。一些功能也会越来越稳定。如果没有必要,不建议为了强调未出现的性能问题使用MyISAM。
关于存储引擎的接口:
官方网站了翻了好久,试图找到mysql存储引擎和应用层的交互接口(在读取数据的过程中)有哪些,可以没有找到。网上找了好久,也没有找到,只知道有这几个,以后再慢慢补充吧:
使用索引读取行。
给定索引区间范围读取行。
传递索引区间范围获取这个区间的数据条数。
获取一个索引相关信息,如基数等。