高性能MySQL读书摘要(一)

第一章MySQL架构与历史

用途:MySQL既可以嵌入到应用系统中(嵌入式数据库还是用sqlite比较好),也可以支持数据仓库、内容索引和部署软件、高可用的冗余系统、在线事务处理系统(OLTP)等各种应用类型。

1.1 MySQL的逻辑架构

MySQL最重要、最与众不同的特征是它的存储引擎架构,这种架构的设计将查询处理(Query Processing)及其他系统任务(Server Task)和数据的存储/提取分开。这种处理和存储分离的设计可以在使用时根据性能,特性选择数据的存储方式。
在这里插入图片描述
第一层:最上层的服务类似于大多是基于网络的客户端/服务端的工具或者服务都有类似的架构。比如连接处理、授权认证、安全等。
第二层:大多数MySQL的核心服务功能都在这一层,包括查询解析、分析、优化、缓存以及所有的内置函数(日期、时间、数学和加密函数),所有跨存储引擎的功能都在这一层实现:存储过程、触发器、视图等。
第三层:包含了存储引擎。存储引擎包含负责MySQL中数据的存储和提取。服务器通过API和存储引擎进行通信。这些接口屏蔽了不同存储引擎之间的差异,使得这些差异对上层的查询过程透明。
服务器通过API(mysql优化后的查询语句调用的API)与存储引擎进行通信。存储引擎API包含了十几个底层(操作系统操作文件的)函数。
在这里插入图片描述
每个客户端连接都会在服务器进程中拥有一个线程,建立的是TCP连接。这个连接的查询只会在这个单独的线程中执行。当客户端(应用)连接到MySQL服务器时,服务器需要对其进行认证。认证可以使用X.509证书的SSL,通过用户名,原始主机信息,密码认证。认证通过,服务器会认证该客户端是否有执行某个特定查询的权限。
MySQL默认的最大连接数为100,MySQL服务器允许的最大连接数16384。可以通过进行查询。

 show variables like 'max_connections';

对于并发较大的系统,建立一次连接然后缓存起来连续使用,直到程序结束等情况下再释放连接,就能够将系统资源集中在对数据库操作的处理上,从而大大提高性能。通常情况下将数据连接的建立和断开委托给一种能够数据库连接池的组件或服务进行管理。而DBCP, C3p0, Proxool等都是常用的开源的连接池组件。
所以,通过连接池维持应用与数据库之前的连接。

1.2 并发控制

只要有多个查询在同一时刻修改数据,都会产生并发控制的问题。Mysql在两个层面的并发控制:服务器层与存储引擎层(欠解释)
1.读写锁
在处理并发读或写时,可以通过实现一个由两种类型的锁组成的系统来解决问题。这两种类型的锁通常被称为共享锁和排他锁。也叫读锁和写锁。–类比java的读锁和写锁。出于安全的考虑,确保在给定时间内,只有一个用户能执行写入,并防止其他用户读取正在写入的同一资源。在实际的数据库系统中,每时每刻都在发生锁定,当某个用户在修改某一部分数据时,MySQL会通过锁定防止其他用户读取同一数据。
2.锁粒度
提高共享资源并发性的方式就是让锁定对象更有选择性。尽量只锁定需要修改的部分数据,而不是所有的资源。任何时刻,在给定的资源上,锁定的数据量越少,则系统的并发程度越高,只要相互之间不发生冲突即可。但问题是加锁也需要消耗资源。如果花大量时间管理锁,而不是存储数据,那么系统的性能可能会因此受到影响。所以出现了锁策略,即在锁的开销和数据的安全性之间寻求平衡。大多数商业数据库是在表上增加行级锁。而MySQL提供了多种策略。每种存储引擎都可以实现自己的锁策略和锁粒度。在上面的图中,可以看出存储引擎负责锁的管理。下面介绍MySQL两个重要的锁策略。
(1)表锁。锁定整张表,开销最小。它会锁定整张表。一个用户在对表进行写操作前,需要先获得写锁,但会阻塞其他用户对该表的所有读写操作。写锁有更高的优先级。尽管存储引擎可以管理自己的锁,MySQL本身还是会使用各种有效的表锁来实现不同的目的。比如ALTER TABLE就会使用表锁,而忽略存储引擎的锁机制。
(2)行级锁。最大程度支持并发,但是带来了最大的锁开销。InnoDB和XtraDB中实现了行级锁。

1.3 事务

MySQL可用START TRANSACTION语句开始一个事务,然后要么使用COMMIT提交事务将修改的数据持久保留,要么使用ROLLBACK撤销所有的修改。
一个运行良好的事务处理系统,必须具有ACID这些标准特性。
1.原子性。
2.一致性。
3.隔离性。
4.持久性。

1.3.1 隔离级别

4种不同隔离级别是对大事务性能的妥协
通过MVCC只有写写冲突
分布式系统保证了高可用和安全性,高安全,高水平扩展。
map套map==nosql
解决扩容和缩容的问题:一致性hash
7-15s不可用,用于选择主机(RAFT)
 MHA-parox-解决mysql主死从竞争

每种存储引擎实现的隔离级别不尽相同。下面简单介绍下四种隔离级别。
READ UNCOMMITTED(未提交读)
事务可以读取未提交的数据。这也被称为脏读。性能也不会比其他好很多。在实际应用中一般很少使用。
READ COMMITED(提交读)
大多数数据库系统(ORACEL,SQL SERVER,DB2)的默认隔离级别都是READ COMMITTED(但MySQL不是)。一个事务从开始直到提交之前,所做的任何修改对其他事务都是不可见的。这意味着提交后是可见的。所以会出现两次执行同样的查询,可能会得到不一样的结果。即可以读取提交的数据,即出现不可重复读现象。
REPEATABLE READ(可重复读)
可重复读解决了脏读的问题。该级别保证了在同一个事务中多次读取同样记录的结果是一致的。但是从理论上无法解决幻读的问题。所谓幻读,指的是当某个事务在读取某个范围内的记录时,另外一个事务又在该范围内插入了新的记录,当之前的事务再次读取该范围的记录时,会产生幻读,就是A事务是范围查找,B事务插入了该范围的数据,A事务再去查能查到B事务提交的内容。但是,InnoDB和XtraDB存储引擎通过多版本并发控制(MVCC)和间隙锁解决了幻读的问题。可重复读是MySQL的默认事务隔离级别。
SERIALIAZABLE(可串行化)
SERIALIAZABLE是最高的隔离级别。它通过强制事务串行执行,避免了前面说的幻读的问题,简单来说,SERIALIAZABLE会在读取的每一行数据上都加锁,所以,可能导致大量的超时和锁争用的问题。

1.3.2 死锁

死锁是指两个或者多个事务在同一资源上相互占用,并请求锁定对方占用的资源,从而导致恶性循环的现象。
为了解决死锁,数据库系统实现了各种死锁检测和死锁超时机制。越复杂的系统,比如InnoDB存储引擎,越能检测到死锁的循环依赖。并立即返回一个错误。InnoDB目前处理死锁的方法是,将持有最少行级排他锁的事务进行回滚(这是相对比较简单的死锁回滚算法)。
所以应用程序在并发情况下必须考虑如何处理死锁,即如何对异常进行处理。

1.3.3 事务日志

事务日志可以帮助提高事务的效率。使用事务日志,存储引擎在修改表的数据时只需要修改其内存拷贝,再把该修改行为记录到持久在硬盘上的事务日志中,而不是每次都将修改的数据本身持久到磁盘。事务日志采用的是追加的方式。因此写日志的操作是磁盘上一小块区域内的顺序I/O。大都数存储引擎采用预写式日志,修改数据需要写两次磁盘(第一次是顺序写事务日志,第二次是由主线程将内存中的修改慢慢刷回主线程,默认是一秒钟)。如果数据的修改已经记录到事务日志并持久化,但数据本身还没有写回磁盘,此时系统崩溃,存储引擎在重启时能够自动恢复这部分修改的数据。

1.3.4 MySQL中的事务

  1. 自动提交
    MySQL默认采用自动提交模式。也就是说,如果不是显示地开始一个事务,则每个查询都被当做一个事务执行提交操作
    通过show variables like ‘autocommit’;查看。当AUTOCOMMIT=0时,所有的查询都是在一个事务中,直到显式地执行COMMIT提交或者ROLLBACK回滚,该事务结束,同时又开始了另一个新事务。
    有一些命令,比如ALTER TABLE,LOCK TABLE会在执行之前执行COMMIT提交当前的活动事务。MySQL可以通过执行SET TRANSACTION ISOLATION LEVEL命令来设置隔离级别。
  2. 在事务中混合使用存储引擎
    MySQL服务器层不管理事务,事务是由下层的存储引擎实现的。如果在一个事务中使用了事务型和非事务型的表,如果该事务需要回滚,非事务型的表(MYISAM)上的变更就会无法撤销,这会导致数据库处于不一致的状态,这种情况很难修复,事务的最终结果将无法确定。

1.4 多版本并发控制

MySQL的大多数事务型存储引擎实现的都不是简单的行级锁。它们一般都同时实现了多版本并发控制(MVCC)。可以认为MVCC是行级锁的一个变种,但是它在很多情况下避免了加锁操作,因此开销更低。虽然实现机制有所不同,但大都实现了非阻塞的读操作,写操作也只锁定必要的行。
MVCC的实现,是通过保存数据在某个时间点的快照来实现的。MVCC的典型实现有乐观并发控制和悲观并发控制。下面同构InnoDB的简化版行为来说明MVCC是如何工作的。
InnoDB的MVCC,是通过在每行记录后面保存两个隐藏的列来实现的。这两个列,一个保存了行的创建时间,一个保存了行的过期时间(或删除时间)。当然存储的并不是实际的时间值,而是系统版本号。每开始一个事务,系统版本号都会自动递增,事务开始时刻的系统版本号会作为事务的版本号,用来查询到每行记录的版本号进行比较。这里与我们在应用系统中增加一个version字段作为乐观锁的思路是一样的。下面分析下REPEATABLE READ隔离级别下,MVCC具体是如何操作的。
SELECT
InnoDB会根据以下两个条件检查每行记录:
a. InnoDB只查找版本早于当前事务版本的数据行。

1.5MySQL的存储引擎

在存储系统中,MySQL将某个数据库(也可以称为Schema)保存为数据目录下的一个子目录。创建表时,MySQL会在数据库子目录下创建一个和表同名的.frm文件保存表的定义。

通过SHOW TABLE STATUS LIKEuser|G;

ROW_FORMAT
行的格式。对于MyISAM表,可选的值为Dynamic、Fixed或者Compressed。Dynamic的行长度是可变的。一般包含可变长度的字段,如VARCHAR或BLOG。Fixed的长度则是固定的,只包含固定长度的列,如CHAR和INTEGER。Compressed的行则只在压缩表中存在。
ROWS
表的行数。对于MyISAM和其他一些存储引擎,该值是精确的,但对于InnoDB,该值是估计值。
Max_data_length
表数据的最大容量,该值和存储引擎有关。
Data_free
对于MyISAM表,表示已分配但目前没有使用的空间。这部分空间包含了之前删除的行,以及后续可被INSERT利用到的空间。
Checksum
如果启用,保存的是整个表的实时校验和。

1.5.1 InnoDB存储引擎

InnoDB是基于聚簇索引建立的。InnoDB内部做了很多优化,包括从磁盘读取数据时采用的可预测性预读,能够自动在内存中创建hash索引以加速读操作的自适应哈希索引,以及能够加速插入操作的插入缓冲区等。

1.5.2 MyISAM存储引擎

  1. 存储
    MyISAM会将表存储在两个文件中:数据文件和索引文件,分别以.MYD(MYSQL DATA)和.MYI(MYSQL INDEX)为扩展名。MyISAM表可以包含动态或者静态(长度固定)行。MySQL会根据表的定义来决定采用何种行格式。MyISAM表可以存储的行记录数,一般受限于可用的磁盘空间,或者操作系统中单个文件的最大尺寸。
    在MySQL5.0中,MyISAM表如果是变长行,则默认配置只能处理256TB的数据,因为指向数据记录的指针长度是6个字节。而在更早的版本中,指针长度默认是4字节,所有只能处理4GB的数据。而所有的MySQL版本都支持8字节的指针。要改变MyISAM表指针的长度(调高或者调低),可以通过修改表的MAX_ROWS和AVG_ROW_LENGTH选项的值来实现,两者相乘就是表可能达到的最大大小。修改这两个参数会导致重建整个表和表的所有索引,这可能需要很长的时间才能完成。
  2. MyISAM特性
    加锁与并发
    MyISAM对整张表加锁,而不是针对行。读取时会对需要读到的所有表加共享锁,写入时则对表加排他锁。但是在表有读取查询的同时,也可以往表中插入新的记录(这被称为并发插入,CONCURRENT INSERT)。
    索引特性
    对于MyISAM表,即使是BLOG和TEXT等长字段,也可以基于其前500个字符创建索引。MyISAM也支持全文索引,这是一种基于分词创建的索引,可以支持复杂的查询。全文索引建议采用ES。
    延迟更新新索引
    创建MyISAM表的时候,如果指定了DELAY_KEY_WRITE选项,在每次修改执行完成时,不会立刻将修改的索引数据写入磁盘,而是会写到内存中的键缓存区,只有在清理键缓冲区或者关闭表的时候才会将对应的索引块写入到磁盘。这种方式可以极大地提升写入性能,但是在数据库或者主机崩溃时会造成索引损坏,需要执行修复操作,延迟更新索引键的特性,可以在全局设置,也可以为单个表设置。
  3. MyISAM性能
    MyISAM最典型的性能问题还是表锁的问题,如果你发现所有的查询都长期处于“Locked”状态,那么毫无疑问表锁就是罪魁祸首。

1.5.3 第三方存储引擎

ToKuDB引擎使用了一种新的叫做分形树的索引数据结构。TokuDB是一种大数据(Big Data)存储引擎,因此其拥有很高的压缩比,可以在很大的数据量上创建大量索引。其最适合在需要大量插入数据的分析型数据集的场景中使用。

1.5.4 选择合适的引擎

如何选择存储引擎,可以简单地归纳为一句话:“除非需要用到某些InnoDB不具备的特性,并且没有其他办法可以替代,否则都应该优先选择InnoDB引擎”。如:如果要用到全文索引,建议优先考虑InnoDB加上Sphinx的组合,而不是使用支持全文索引的MyISAM。
除非万不得已,否则建议不要混合使用多种存储引擎,否则可能会带来一系列的问题,以及一些潜在的bug和边界问题。
事务
如果应用需要支持事务,则选择InnoDB,如果不需要事务,并且主要是SELECT或INSET操作,那么MyISAM是不错的选择。一般日志型的应用比较符合这一特性。但是,现在的InnoDB与MyISAM速率相差不大,所以还是建议使用InnoDB。
备份
如果需要在线热备份,那么选择InnoDB就是基本的要求。
崩溃恢复
MyISAM崩溃后发生损坏的概率比InnoDB要高很多,而且恢复速度也要慢。因此,即使不需要事务支持,很多人也选择InnoDB引擎,这是一个非常重要的因素。
最后,有些应用可能依赖一些存储引擎所独有的特性或者优化,比如很多应用依赖聚簇索引的优化。另外,MySQL中也只有MyISAM支持地理空间搜索。
根据应用选择引擎,日志型应用要求插入速度有很高的要求,数据库不能成为瓶颈。MyISAM或者Archive存储引擎对这类应用比较合适,因为它们开销低,而且插入数据非常快。因为MyISAM是表锁,在一开始可能没有任何问题,但随着应用压力的上升,则可能迅速恶化。各种锁争用、崩溃后的数据丢失等问题都会随之而来。其次,InnoDB是订单处理类应用的最佳选择。
我们创建或者管理的很多InnoDB数据库的数据量在3~5TB之间,或者更大,这是单台机器上的量,不是一个分片的量。如果数据量继续增长到10TB以上的级别,可能就需要数据仓库了。Infobright是MySQL数据仓库最成功的解决方案。也有一些大数据库不适合Infobright,却可能很适合TokuDB。
导出和导入
注意mysqldump默认会自动在CREATE TABLE语句前加上DROP TABLE语句,不注意这点可能会导致数据丢失。

猜你喜欢

转载自blog.csdn.net/gonghaiyu/article/details/107029940