深入解析MySQL架构

1.mysql逻辑架构

mysql最重要、最与众不同不特性是它的存储引擎架构,这种架构的设计将查询处理及其他系统任务和数据的存储/提取相分离。
  1. 存储引擎负责mysql中数据的存储和提取。服务器通过API与存储引擎进行通信。这些接口屏蔽了不同存储引擎之间的差异,使得这些差异对上层的查询过程透明。但存储引擎不会去解析SQL(除了InnoDB,它会解析外键),不同储存引擎之间也不会相互通信,而只是简单地响应上层服务器的请求。
  2. 每个客户端连接都会在服务器进程中拥有一个线程,这个连接的查询只会在这个单独的线程中执行。服务器会负责缓存线程(线程池),因此不需要为每一个新建的连接创建或销毁线程。
  3. Mysql会解析查询,并创建内部数据结构(解析树),然后对其进行各种优化,包括重写查询、决定表的读取顺序,以及选择合适的索引等。用户可以通过特殊的关键字提示优化器,影响它的决策过程。也可以请求优化器解释(explain)优化过程的各个因素。
  4. 对于SELECT语句,在解析查询之前,服务器会先检查查询缓存,如果能够在其中找到对应的查询,服务器就不必再执行查询解析、优化和执行的整个过程,而是直接返回结果集。
  5. 查询缓存:
    Mysql将缓存存放在一个引用表,通过一个哈希值索引,这个哈希值通过查询本身、当前要查询的数据库、客户端协议版本号等一些可能影响结果的信息计算得来。所以2个查询在任何字符上的不同(空格、注释),都会导致缓存不会命中。
    如果查询包含任何用户自定义函数、存储函数、用户变量、临时表、mysql库中的系统表,其查询结果都不会被缓存。
    既然是缓存,就会失效,那查询缓存何时失效呢?mysql的查询缓存系统会跟踪查询中涉及的每个表,如果这些表发生变化,那么和这张表相关的所有缓存数据都将失效。正因为如此,在任何的写操作时,mysql必须将对应表的所有缓存都设置为失效。如果查询缓存非常大或者碎片很多,这个操作就可能带来很大的系统消耗。而且查询缓存对系统的额外消耗也不仅仅在写操作,读操作也不例外:1.任何的查询语句在开始之前都必须经过检查,即使这条sql语句永远不会命中缓存。
    2.如果查询结果可以被缓存,那么执行完成后,会将结果存入缓存,也会带来额外的系统开销

2.并发控制

  1. 解决并发问题的方法就是并发控制。在处理并发读或写时,可以通过实现共享锁(读锁)和排它锁(写锁)组成的锁系统来解决问题。
  2. 一种提高共享资源并发性的方式就是让锁定对象更有选择性。尽量只锁定需要修改的部分数据,而不是所有的资源。
    问题是加锁也需要消耗资源。锁的各种操作,都会增加系统的开销。如果系统花费大量的时间来管理锁,而不是存取数据,那么系统的性能可能会因此受到影响。
    所谓的锁策略,就是在锁的开销和数据的安全性之间寻求平衡。大多数数据库系统都是在表上施加行级锁,并以各种复杂的方式来实现,以便在锁比较多的情况下尽可能提供好的性能。、
  3. 而mysql则提供了多种选择。每种mysql存储引擎都可以实现自己的锁策略和锁粒度。
  4. 表锁:表锁是mysql中最基本的锁策略,并且是开销最小的策略。它会锁定整张表。
    在特定的场景中,表锁也可能有良好的性能,例如READ LOCAL表锁支持某些类型的并发写操作。
    写锁比读锁有更高的优先级,因此一个写锁请求可能会被插入到读锁队列的前面。
    尽管存储引擎可以管理自己的锁,mysql本身还是会使用各种有效的表锁来实现不同的目的。如服务器会为ALTER TABLE之类的语句使用表锁,而忽略存储引擎的锁机制。
  5. 行级锁:可以最大程度地支持并发处理,同时也带来了最大的锁开销。行级锁只在存储引擎层实现,而mysql服务器层没有实现。

3.事务

事务就是一组原子性的SQL操作,或者说是一个独立的工作单元。事务内的语句,要么全部执行成功,要么全部执行失败。
  1. 可以用START TRANSACTION语句开始一个事务,然后要么使用COMMIT提交事务将修改的数据持久保留,要么使用ROLLBACK撤销所有的修改。
  2. 原子性(Atomicity):一个事务必须被视为一个不可分割的最小工作单元。不可能只执行其中的一部分操作。
  3. 一致性(consistency):数据库总是从一个一致性的状态转换到另外一个一致性的状态
  4. 隔离性(isolation):通常来说,一个事务所做的修改在最终提交以前,对其他事务是不可见的。
  5. 持久性(durability):一旦事务提交,则其所做的修改就会永久保存在数据库中。此时即使系统崩溃,修改的数据也不会丢失。实际上持久性也分很多不同的级别。而且不可能有做到100%的持久性保证
  6. 就像锁粒度的升级会增加系统开销一样,一个实现了ACID的数据库,相比没有实现的数据库,通常会需要更强的CPU处理能力、更大的内存和更多的磁盘空间。
  7. 即使存储引擎不支持事务,也可以通过LOCK TABLES语句为应用提供一个程度的保护。
  8. 隔离级别:每一种级别都规定了一个事务中所做的修改,哪些在事务内和事务间是可见的。
    1.READ UNCOMMITTED(未提交读):事务中的修改,即使没有提交,对其他事务也都是可见的。事务可以读取未提交的数据,称为脏读。会导致很多问题。从性能上来说,不会比其他的级别好太多,但却缺乏其他级别的很多好处,在实际应用中一般很少使用。
    2.READ COMMITTED(提交读、不可重复读):大多数数据库的默认隔离级别都是这个(但Mysql不是)。2次执行同样的查询,可能会得到不一样的结果。因为有可能第二次读的时候可能有别的用户提交修改了数据。
    3.REPEATABLE READ(可重复读):该级别保证了在同一个事物中多次读取同样记录的结果是一致的。(因为这个级别会保存事务开始前的一个版本,即使其他线程修改了数据也没关系),但是无法解决幻读。幻读指的是当某个事物在读取某个范围内的记录时,另外一个事务又在该范围内插入了新的记录,会产生幻行。(可重复读强调的是读读,而幻读强调的是读写,比如在事务中首先判断一个地址为空,然后执行插入却无法插入,因为这时候可能有别的线程已经添加了数据,造成虚幻的一个现象)。 可重复读是mysql的默认事务隔离级别。
    4.SERIALIZABLE(可串行化):是最高的隔离级别。它通过强制事务串行执行,避免了前面说的幻读的问题。它会在读取的每一行数据上都加锁(共享锁,可以并发读,若进行写操作,则其他线程会处于等待状态,消除幻读,即S锁和X锁),所以可能导致大量的超时和锁争用的问题。实际上也很少用到这个隔离级别,只有在非常需要确保数据的一致性而且可以接受没有并发的情况下,才考虑。
  9. 死锁:
    2个或多个事务在同一资源上相互占用,并请求锁定对方占用的资源,从而导致恶性循环的现象。
    数据库系统实现了各种死锁检测和死锁超时机制。越复杂的系统,越能检测到死锁的循环依赖,并立即返回一个错误。这种方式很有效,否则死锁会导致出现非常慢的查询。还有一种就是当查询的时间达到锁等待超时的设定后放弃锁请求。这种方式通常来说不太好。
    InnoDB目前处理死锁的方法是,将持有最少行级排他锁的事务进行回滚。
    锁的行为和顺序是和存储引擎相关的。以同样的顺序执行语句,有些储存引擎会产生死锁,有些则不会。死锁的产生有双重原因:有些是因为真正的数据冲突,有些是由于存储引擎的实现方式导致
  10. 事务日志:
    1.事务日志可以帮助提高事务的效率。使用事务日志,存储引擎在修改表的数据时只需要修改其内存拷贝,再把该修改行为记录到持久在硬盘上的事务日志中,而不用每次都将修改的数据本身持久到磁盘。
    2.事务日志采用的是追加的方式,因此写日志的操作是磁盘上一小块区域内的顺序IO,而不像随机IO需要在磁盘的多个地方移动磁头。所以采用事务日志的方式相对来说快得多。事务日志持久以后,内存中被修改的数据在后台可以慢慢地刷回到磁盘。称为预写式日志,修改数据需要写2次磁盘
    3.如果数据的修改已经记录到事务日志并持久化,但数据本身还没有写回磁盘,此时系统崩溃,存储引擎在重启时能够自动恢复这部分修改的数据。
  11. Mysql中的事务
    1.自动提交:mysql默认采用自动提交模式。如果不是显式地开始一个事务,则每个查询都被当做一个事务执行提交操作。在当前连接中,可以通过设置AUTOCOMMIT变量来启用或禁止。1或ON表示启用,0或OFF表示禁用。当为0时,所有的查询都是在一个事务中,直到显式地执行COMMIT提交或者ROLLBACK回滚,该事务结束,同时又开始了另一个新事务。
    修改AUTOCOMMIT对非事务型的表,比如 MyISAM或者内存表,不会有任何影响。
    另外还有一些命令,在执行之前会强制执行COMMIT提交当前的活动事务。在数据定义语言(DDL)中,如果是会导致大量数据改变的操作,比如ALTER TABLE就是如此。另外LOCK TABLES也会导致同样的结果。
  12. 在事务中混合使用存储引擎:
    Mysql服务器层不管理事务,事务是由下层的存储引擎实现的。如果混合使用了事务性和非事务型的表,正常提交的情况下不会有什么问题。但如果事务需要回滚,非事务型的表上的变更就无法撤销,这会导致数据库处于不一致的状态,这种情况很难修复,事务的最终结果将无法确定。
  13. 隐式和显式锁定:
    InnoDB采用的是两阶段锁定协议。在事务执行过程中,随时都可以执行锁定,锁只有在执行COMMIT或ROLLBACK的时候才会释放,并且所有的锁是在同一时刻被释放。前面描述的锁定都是隐式锁定,InnoDB会根据隔离级别在需要的时候自动加锁。
    另外,InnoDB也支持通过特定的语句进行显式锁定。如LOCK IN SHARE MODE/FORUPDATE。
    mysql也支持LOCK TABLES和UNLOCK TABLES语句,这是在服务器层实现的,和存储引擎无关。它们有自己的用途,但并不能替代事务处理。如果应用需要用到事务,还是选择事务型存储引擎。
    应用已将表从MyISAM转换到InnoDB,但还是显式地使用LOCK TABLES。这不但没有必要,还会严重影响性能,实际上InnoDB的行级锁工作得更好。
    LOCK TABLES和事务之间相互影响的话,情况会变得非常复杂,在某些Mysql版本中甚至会产生无法预料的结果。因此,除了事务中禁用了AUTOCOMMIT,可以使用外,其他任何时候都不要显式地执行LOCK TABLES,不管是什么存储引擎。

4.多版本并发控制

  1. Mysql的大多数事务型存储引擎实现的都不是简单的行级锁。基于提升并发性能的考虑,一般都同时实现了多版本并发系统MVCC(Multi Version Concurrent Control)。
  2. 可以认为MVCC是行级锁的一个变种,但是它在很多情况下避免了加锁操作,因此开销更低。虽然实现机制有所不同,但大都实现了非阻塞的读操作,写操作也只锁定必要的行。
  3. MVCC的实现,是通过保存数据在某个时间点的快照来实现的。不管执行多长时间,每个事务看到的数据都是一致的。根据事务开始的时间不同,每个事务对同一张表,同一时刻看到的数据可能是不一样的。
  4. InnoDB的MVCC实现过程:通过在每行记录后面保存2个隐藏的列,一个保存了行的创建时间,一个保存行的过期时间(删除时间)。存储的并不是实际的时间值,而是系统版本号。每开始一个新的事务,系统版本号都会自动递增。事务开始时刻的系统版本号会作为事务的版本号,用来和查询到的每行记录的版本号进行比较。下面是在可重复读隔离级别下,具体操作:
    SELECT:InnoDB会根据以下2个条件检查每行记录:
    1. 只查找版本早于当前事务版本的数据行(行的系统版本号小于或等于事务的系统版本号),这样可以确保事务读取的行,要么是在事务开始前已经存在的,要么是事务自身插入或者修改过的
    2. 行的删除版本要么未定义,要么大于当前事务版本号,这可以确保事务读取到的行,在事务开始之前未被删除
    只有符合上诉2个条件的记录,才能返回作为查询结果
    INSERT:为新插入的每一行保存当前系统版本号作为行版本号。
    DELETE:为删除的每一行保存当前系统版本号作为行删除标识。
    UPDATE:插入一行新纪录,保存当前系统版本号作为行版本号,同时保存当前系统版本号到原来的行作为行删除标识。
    保存这2个额外系统版本号,使大多数读操作都可以不用加锁。这样设计使得读数据操作很简单,性能很好,并且也能保证只会读取到符合标准的行。不足之处是每行记录都需要额外的存储空间,需要做更多的行检查工作,以及一些额外的维护工作。
    MVCC只在可提交读和不可重复读2个隔离级别下工作。其他2个级别都和MVCC不兼容,因为未提交读总是读取最新的数据行,而不是符合当前事务版本。而SERIALIZABLE会对所有读取的行都加锁。

5.mysql的存储引擎

在文件系统中,mysql将每个数据库(schema)保存为数据目录下的一个子目录。创建表时,mysql会在数据库子目录下创建一个和表同名的.frm文件保存表的定义。表的定义是在mysql服务层统一处理的。

可以使用SHOW TABLE STATUS命令显示表的相关信息。下面是输出每一行的含义:

Name:表名。

Engine:表的存储引擎类型。   

Row_format:行的格式。其中Dynamic的行长度是可变的,如VARCHAR或BLOB。Fixed的行长度是固定的,如CHAR和INTEGER,Compressed的行则只在压缩表中存在。   

 Rows:表中的行数。对于MyISAM和其他一些,该值是精确的,但对于InnoDB,该值是估计值

Avg_row_length:平均每行包含的字节数。

Data_length:表数据的大小      Max_data_length:表数据的最大容量,该值和存储引擎有关

Index_length:索引的大小(单位:字节)

Data_free:对于MyISAM表,表示已分配但目前没有使用的空间。包括之前删除的行,以及后续可以被						INSERT利用到的空间。

Auto_increment:下一个AUTO_INCREMENT的值。

Check_time:使用CHECK TABLE或者myisamchk工具最后一次检查表的时间

Collation:表的默认字符集和字符列排序规则

Checksum:如果启用,保存的是整个表的实时校验和。

Comment:包含了一些其他的额外信息。对于MyISAM表,保存的是表在创建时带的注释。对于InnoDB						  表,保存的是剩余空间信息。如果是一个视图,则该列包含"VIEW"的文本字样。
  1. InnoDB存储引擎:
    1.它被设计用来处理大量的短期事务,短期事务大部分情况是正常提交的,很少会被回滚。InnoDB的性能和自动崩溃特性,使得它在非事务型储存的需求中也很流行。
    2.InnoDB的数据存储在表空间中,表空间是InnoDB管理的一个黑盒子,由一系列的数据文件组成。InnoDB可以将每个表的数据和索引存放在单独的文件中。
    InnoDB可将所有数据存放于ibdata*的共享表空间,也可将每张表独立存放于独立的.ibd文件的独立表空间。
    3.InnoDB采用MVCC来支持高并发,并且实现了4个标准的隔离级别,默认是可重复读,并且通过间隙锁策略防止幻读的出现。间隙锁使得InnoDB不仅仅锁定查询涉及的行,还会对索引中的间隙进行锁定,以防止幻影行的插入。
    4.间隙锁:当我们用范围条件而不是相等条件检索数据,并请求S锁或X锁时,InnoDB会给符合条件的已有数据记录的索引项加锁。对于键值在条件范围内但并不存在的记录,叫做间隙。InnoDB也会对这个间隙加锁。
    间隙锁的目的:一方面是为了防止幻读,以满足相关隔离级别的要求。另一方面是为了满足其恢复和复制的需要。
    很显然,这种加锁机制会阻塞符合条件范围内键值的并发插入,这往往会造成严重的锁等待。因此,对于并发插入比较多的应用,要尽量优化业务逻辑,尽量使用相等条件来访问更新数据,避免使用范围条件。PS:如果使用相等条件给一个不存在的记录加锁,InnoDB也会使用间隙锁。
    5.InnoDB表是基于聚簇索引建立的,聚簇索引对主键查询有很高的性能,不过它的二级索引(非主键索引)中必须包含主键列,所以如果主键列很大的话,其他的所有所以都会很大。因此,若表上的索引较多的话,主键应当尽可能的小。InnoDB的存储格式是平台独立的。
    6.InnoDB内部做了很多优化,包括从磁盘读取数据时采用的可预测性预读,能够自动在内存中创建hash索引以加速读操作的自适应哈希索引以及能够加速插入操作的插入缓冲区等。
    7.作为事务型的存储引擎,InnoDB通过一些机制和工具支持真正的热备份。而mysql的其他存储引擎不支持热备份,要获取一致性视图需要停止对所有表的写入,而在读写混合场景中,停止写入可能也意味着停止读取。
  2. MyISAM存储引擎:
    1.在mysql5.1及之前的版本,MyISAM是默认的储存引擎。MyISAM提供了大量的特性,包括全文索引、压缩、空间函数,但MyISAM不支持事务和行级锁,而且有一个毫无疑问的缺陷就是崩溃后无法安全恢复。尽管MyISAM引擎不支持事务,不支持崩溃后的安全恢复。但对于只读的数据,或者表比较小,可以忍受修复操作,则依然可以使用。
    2.MyISAM会将表存储在2个文件中:数据文件和索引文件。分别以.MYD和.MYI为扩展名。MyISAM表可以包含动态或静态行。Mysql会根据表的定义来决定采用何种行格式。MyISAM表可以存储的行记录数,一般受限于可用的磁盘空间或者操作系统中单个文件的最大尺寸。
    3.在Mysql5.0中,MyISAM表如果是变长行,则默认配置只能处理256TB的数据,因为指向数据记录的指针长度是6个字节。而在更早的版本中,指针长度默认是4字节,所以只能处理4GB的数据。而所有的mysql版本都支持8字节的指针。要改变MyISAM表指针的长度,可以通过修改表MAX_ROW和AVG_ROW_LENGTH选项的值来实现。两者相乘就是表可能达到的最大大小。修改这2个参数会导致重建整个表和表的所有索引,可能需要很长的时间。
    4.MyISAM特性:
    1.加锁与并发:MyISAM对整张表加锁,而不是针对行。读取时会对需要读到所有表加S锁,写入时则对表加X锁。但是在表有读取查询的同时,也可以往表中插入新的记录。
    2.修复:对于MyISAM表,mysql可以手工或者自动执行检查和修复操作。这里的修复和事务恢复以及崩溃修复是不同的概念。执行表的修复可能导致一些数据丢失,而且修复操作时非常慢的。可以通过CHECK TABLE mytable检查表的错误,如果有错误可以执行REPAIR TABLE mytable进行修复。另外,如果mysql服务器已经关闭,也可以通过myisamchk命令行工具进行检查和修复操作。
    3.索引特性:对于MyISAM表,即使是BLOB和TEXT等长字段,也可以基于其500个字符创建索引。MyISAM也支持全文索引,这是一种基于分词创建的索引,可以支持复杂的查询。
    4.延迟更新索引键:创建MyISAM表时,如果指定了DELAY_KEY_WRITE选项,在每次修改执行完成时,不会立刻将修改的索引数据写入磁盘,而是会写到内存的键缓冲区,只有在清理键缓冲区或者关闭表的时候才会将对应的索引块写入到磁盘。这种方式可以极大地提升写入性能,但是在数据库或者主机崩溃时会造成索引损坏,需要执行修复操作。该特性,可以在全局设置,也可以为单个表设置。
    5.MyISAM压缩表:如果表在创建并导入数据以后,不会再进行修改操作,那么这样的表或许适合采用MyISAM压缩表。
    可以使用myisampack对MyISAM表进行压缩(打包pack)。压缩表是不能进行修改的(除非先将表解除压缩,修改数据,然后再次压缩)。压缩表可以极大地减少磁盘空间占用,因此也可以减少磁盘IO,从而提升查询性能。压缩表也支持索引,但索引也是只读的。
    以现在的硬件能力,对大多数应用场景,读取压缩表数据时的解压带来的开销影响并不大,而减少IO带来的好处则要大得多。压缩时表中的记录时独立压缩的,所以读取单行的时候不需要解压整个表。
    6.性能:MyISAM引擎设计简单,数据以紧密格式存储。MyISAM有一些服务器级别的性能扩展限制,比如对索引键缓冲区的Mutex锁,MariaDB基于段的索引键缓冲区机制来避免该问题。但MyISAM最典型的性能问题还是表锁的问题。
  3. MYSQL内建的其他存储引擎
    1.Archive引擎:
    只支持INSERT和SELECT操作,在mysql5.1之前也支持索引。Archive引擎会缓存所有的写并利用zlib对插入的行进行压缩,所以比MyISAM表的磁盘IO更少。但是每次SELECT查询都需要执行全表扫描。所以该表适合日志和数据采集类应用,这类应用做数据分析时往往需要全表扫描,或者一些需要更快速INSERT操作的场景也可以使用。
    支持行级锁和专用的缓冲区,所以可以实现高并发的插入。在一个查询开始直到返回表中存在的所有行数之前,Archive引擎会阻止其他的SELECT执行,以实现一致性读。另外,也实现了批量插入在完成之前对读操作时不可见的。这种机制模仿了事务和MVCC的一些特性,但Archive引擎不是一个事务型的引擎,而是一个针对高速插入和压缩做了优化的引擎。
    2.Blockhole引擎:
    没有实现任何的存储机制,它会丢弃所有插入的数据,不做任何保存。但服务器会记录Blackhole表的日志,所以可以用于复制数据到备库,或者只是简单地记录到日志。可以在一些特殊的复制架构和日志审核时发挥作用。但并不推荐。
    3.CSV引擎:
    可以将普通的CSV文件(逗号分割值的文件)作为mysql的表来处理,但这种表不支持索引。CSV引擎可以在数据库运行时拷入或拷出文件。可以将Excel等电子表格软件中的数据存储为CSV文件,然后复制到mysql数据目录下,就能在mysql中打开使用。同样,如果将数据写入到一个CSV引擎表,其他的外部程序也能立即从表的数据文件中读取CSV格式的数据。因此CSV可以作为一种数据交换的机制,非常有用。
    4.Federated引擎
    是访问其他mysql服务器的一个代理,它会创建一个到远程mysql服务器的客户端连接,并将查询传输到远程服务器执行,然后提取或者发送需要的数据。经常有问题,因此默认是禁用的。
    5.Memory引擎:
    如果需要快速地访问数据,并且这些数据不会被修改,重启以后丢失也没有关系,那么使用Memory表是非常有用的。Memory表至少比MyISAM表要快一个数量级,因为所有的数据都保存在内存中,不需要进行磁盘IO。Memory表的结构在重启以后还会保留,但数据会丢失。
    Memory表在很多场景可以发挥好的作用:
    用于查找或者映射表。 用于缓存周期性聚合数据的结果 用于保存数据分析中产生的中间数据
    Memory表支持Hash所有,因此查找操作非常快。它是表级锁,因此并发写入的性能低。且不支持BLOB或TEXT类型的列,并且每行的长度是固定的,所以即使指定了VARCHAR列,实际存储时也会转换成CHAR,这可能导致部分内存的浪费。
    如果mysql在执行查询的过程中需要使用临时表来保存中间结果,内部使用的临时表就是Memory表。如果中间结果太大超出了Memory表的限制,或者含有BLOB或者TEXT字段,则临时表会转换成MyISAM表。
    临时表是指使用CREATE TEMPORARY TABLE 语句创建的表,它可以使用任何存储引擎,因此和Memory表不是一回事。临时表只在单个连接中可见,当连接断开时,临时表也将不复存在。
    6.Merge引擎:
    是MyISAM引擎的一个变种,是由多个MyISAM表合并而来的虚拟表。如果将mysql用于日志或者数据仓库类应用,该引擎可以发挥作用。但是引入分区功能后,已经被放弃。
    7.NDB集群引擎:
    MYSQL服务器、NDB集群存储引擎,以及分布式的、share-nothing的、容灾的、高可用的NDB数据库的组合,被称为mysql集群。
  4. 选择合适的引擎
    1.除了需要用到某些InnoDB不具备的特性,并且没有其他办法可以替代,否则都应该优先选择InnoDB引擎。
    2.不建议混合使用多种存储引擎。如果应用需要不同的存储引擎,请优先考虑:
    1.事务:如果应用需要事务支持,那么InnoDB是最好的选择。如果不需要事务,并且主要还是SELECT和INSERT操作,那么MyISAM是不错的选择。一般的日志型的应用比较符合这一特性。
    2.备份:如果可以定期地关闭服务器来执行备份,那么备份的因素可以忽略。反之,如果需要在线热备份,那么选择InnoDB就是基本的要求。
    3.崩溃恢复:数据量比较大的时候,系统崩溃后如何快速恢复是一个需要考虑的问题。MyISAM崩溃后发生损坏的概率比InnoDB要高得多,而且恢复速度也要慢。
    4.特有的特性:有些应用可能依赖一些存储引擎所占有的特性或者优化。比如很多应用依赖聚簇索引的优化。另外,mysql中也只有MyISAM支持地理空间搜索。
    日志型应用:
    对于插入速度有很高的的要求,数据库不能成为瓶颈。MyISAM或者Archive存储引擎对这类应用比较合适,因为它们开销低,而且插入速度非常快。
    如果需要对记录的日志做分析报表。生成报表的SQL很可能会导致插入效率明显降低,怎么办呢?
    一是利用mysql内置的复制方案将数据复制一份到备库,然后再备库上执行比较消耗时间和和CPU的查询。这样主库只用于高效的插入工作,而备库上执行的查询也无须担心影响到日志的插入功能。
    二是在日志记录表的名字中包含年和月的信息。这样可以在已经没有插入操作的历史表上做频繁的查询操作,而不会干扰到最新的当前表上的插入操作。
    只读或者大部分情况下只读的表:
    如果不介意MyISAM的崩溃恢复问题,选用MyISAM引擎是合适的。MyISAM只将数据写到内存中,然后等待操作系统定期将数据刷出到磁盘上。
    当设计上诉类型的应用时,建议采用InnoDB,MyISAM一开始可能没有任何问题,但随着应用压力的上升,则可能迅速恶化。各种锁争用、崩溃后的数据丢失等问题都会随之而来。
    订单处理:
    如果涉及订单处理,那么支持事务就是必要选项。InnoDB是最佳选择。
    主体讨论论坛:
    主题讨论区一般都有更新计数器,并且会为各个主题计算访问统计信息。多数应用只设计了几张表来保存所有数据,所以核心表的读写压力非常大,为保证这些核心表的数据一致性,锁成为资源争用的主要因素。
    CD-ROM(光盘只读存储器)应用:
    可以考虑使用MyISAM或MyISAM压缩表。这样表之间可以隔离并且可以在不同介质上相互拷贝。
    大数据量:
    需要合理选择硬件,做好物理设计,并为服务器的IO瓶颈做好规划。在这样的数据量下,如果采用MyISAM,崩溃后的恢复就是一个噩梦。
    如果数据量增长到10TB以上的级别,可能就需要建立数据仓库。Infobright是mysql数据仓库最成功的解决方案。
  5. 转换表的引擎:
    1.ALTER TABLE:
    这是最简单的方法修改引擎,如ALTER TABLE mytable ENGINE = InnoDB,上述语法可以适用于任何存储引擎。但需要执行很长时间。mysql会按行将数据从原表复制到一张新的表中,在复制期间可能会消耗系统所有的IO能力,同时原表上会加上读锁。所以,在繁忙的表上执行此操作要特别小心。一个替代方案是采用导出和导入的方法,手工进行表的复制。
    如果转换表的存储引擎,将会失去和原引擎相关的所有特性。
    2.导出与导入:
    为了更好地控制转换的过程,可以使用mysqldump工具将数据导出到文件,然后修改文件中CREATE TABLE语句的存储引擎选项,注意同时修改表名,因为同一个数据库不能存在相同的表名,即使它们用的是不同的存储引擎。PS:mysqldump默认会自动在CREATE TABLE语句前加上DROP TABLE语句,不注意这一点可能会导致数据丢失。
    3.创建与查询:
    这种技术综合了第一种方法的高效和第二种方法的安全。不需要导出整个表的数据,而是先创建一个新的存储引擎的表,然后用INSERT和SELECT语法来导入数据。
    数据量不大的话,这样做效果很好。但如果数据量很大,则可以考虑做分批处理,针对每一段数据执行事务提交操作,以避免大事务产生过多的undo。
    4.undo与redo
    undo日志用于存放数据修改被修改前的值。
    redo用于记录数据修改后的记录,顺序记录。当缓存池中的数据还没有刷新到磁盘的时候发生崩溃,启动服务后,可通过redo log找到需要重新刷新到磁盘的记录。
    缓冲池中的数据直接刷新到磁盘,是一个随机IO,效率较差。而把缓冲池中的数据记录到redo log,是一个顺序IO,可以提高事务提交的速度。

你可能感兴趣的:(深入解析MySQL,mysql,架构,数据库)