[MySQL][1][MySQL架构与历史]

第 1 章 MySQL架构与历史

和其他数据库系统相比, MySQL有点与众不同,它的架构可以在多种不同场景中应用并发挥好的作用。 MySQL并不完美,却足够灵活,能够适应高要求的环境。

MySQL最重要、最与众不同的特性是它的存储引擎架构这种架构的设计将__查询__处理( Query Processing)及其他系统任务(Server Task)和数据的__存储/提取__相分离。这种处理和存储分离的设计可以在使用时根据性能、特性来选择数据存储的方式。

1.1 MySQL逻辑架构

MySQL的逻辑架构图如下所示

最上层的服务是大多数基于网络的客户端/服务器的工具或者服务都有类似的架构。比如连接处理、授权认证、安全等等。

第二层架构是包含 MySQL的大多数核心服务功能,包括査询解析、分析、优化、缓存以及所有的内置函数,所有跨存储引擎的功能都在这一层实现:存储过程、触发器、视图等。

第三层包含了存储引擎。存储引擎负责 MySQL中数据的存储和提取。和GNU/ Linux下的各种文件系统一样,每个存储引擎都有它的优势和劣势。服务器通过API与存储引擎进行通信。这些接口屏蔽了不同存储引擎之间的差异,使得这些差异对上层的查询过程透明。存储引擎API包含几十个底层函数,用于执行诸如“开始一个事务”或者“根据主键提取一行记录”等操作。但存储引擎不会去解析SQL,不同存储引擎之间也不会相互通信,而只是简单地响应上层服务器的请求。

1.1.1 连接管理与安全性

每个客户端连接都会在服务器进程中拥有一个线程,这个连接的查询只会在这个单独的线程中执行。

当客户端连接到 MySQL服务器时,服务器需要对其进行认证。认证基于用户名原始主机信息和密码。一旦客户端连接成功,服务器会继续验证该客户端是否具有执行某个特定查询的权限。

1.1.2 优化与执行

MySQL会解析查询,并创建内部数据结构(解析树),然后对其进行各种优化,包括重写査询、决定表的读取顺序,以及选择合适的索引等。用户可以通过特殊的关键字提示(hint)优化器,影响它的决策过程。

优化器并不关心表使用的是什么存储引擎。但优化器会请求存储引擎提供容量或某个具体操作的开销信息,以及表数据的统计信息等。

对于 SELECT语句,在解析查询之前,服务器会先检查查询缓存( Query Cache),如果能够在其中找到对应的査询,服务器就不必再执行查询解析、优化和执行的整个过程,而是直接返回查询缓存中的结果集。

1.2 并发控制

只要有多个查询需要在同一时刻修改数据,都会产生并发控制的问题。

1.2.1 读写锁

在处理并发读或者写问题时,可以通过实现一个由两种类型的锁组成的锁系统来解决问题。这两种类型的锁通常被称为共享锁(shared lock)和排他锁( exclusive lock),也叫读锁( read lock)和写锁( write lock)

读锁是共享的,或者说是相互不阻塞的。多个客户在同一时刻可以同时读取同一个资源,而互不干扰。写锁则是排他的,也就是说一个写锁会阻塞其他的写锁和读锁。

在实际的数据库系统中,每时每刻都在发生锁定,当某个用户在修改某一部分数据时,MySQL会通过锁定防止其他用户读取同一数据。大多数时候,MySQL锁的内部管理都是透明的。

1.2.2 锁粒度

种提高共享资源并发性的方式就是让锁定对象更有选择性。尽量只锁定需要修改的部分数据,而不是所有的资源。在给定的资源上,锁定的数据量越少,则系统的并发程度越高,只要相互之间不发生冲突即可。

锁的各种操作,包括获得锁、检査锁是否已经解除、释放锁等,都会__增加系统的开销__。

所谓的锁策略,就是在锁的开销和数据的安全性之间寻求平衡。大多数商业数据库系统没有提供更多的选择,一般都是在表上施加行级锁(row level lock),并以各种复杂的方式来实现,以便在锁比较多的情况下尽可能地提供更好的性能。而MySQL则提供了多种选择。每种MySQL存储引擎都可以实现自己的锁策略和锁粒度。

1.2.2.1 表锁(table lock)

表锁是 MySQL中最基本的锁策略,并且是开销最小的策略。它会锁定整张表。

在特定的场景中,表锁也可能有良好的性能。例如,READ LOCAL表锁支持某些类型的并发写操作。另外,写锁也比读锁有更高的优先级,因此一个写锁请求可能会被插入到读锁队列的前面

尽管存储引擎可以管理自己的锁,MYSQL本身还是会使用各种有效的表锁来实现不同的目的。例如,服务器会为诸如 ALTER TABLE之类的语句使用表锁,而忽略存储引擎的锁机制。

1.2.2.2 行级锁(row lock)

行级锁可以最大程度地支持并发处理(同时也带来了最大的锁开销)。在InnoDB和ⅹ traDB,以及其他一些存储引擎中实现了行级锁。行级锁只在存储引擎层实现,而 MySQL服务器层没有实现。所有的存储引擎都以自己的方式实现了锁机制。

1.3 事务

事务就是一组原子性的SQL查询,或者说一个独立的工作单元。如果数据库引擎能够成功地对数据库应用该组查询的全部语句,那么就执行该组查询。如果其中有任何一条语句因为崩溃或其他原因无法执行,那么所有的语句都不会执行。

可以用START TRANSACTION语句开始一个事务,然后要么使用COMMIT提交事务将修改的数据持久保留,要么使用ROLLBACK撒销所有的修改。

1
2
3
4
5
START TRANSACTION;
SELECT balance FROM checking WHERE customer_id = 1022331;
UPDATE checking SET balance = balance - 200 WHERE customer_id = 1022331;
UPDATE saving SET balance = balance - 200 WHERE customer_id = 1022331;
COMMIT;

除非系统通过严格的ACID测试,否则空谈事务的概念是不够的。ACID表示原子性(atomicity)、一致性(consistency)、隔离性(isolation)和持久性(durability)。一个运行良好的事务处理系统,必须具备这些标准特征。

  • 原子性(atomicity):一个事务必须被视为一个不可分割的最小工作单元,整个事务中的所有操作要么全部提交成功,要么全部失败回滚。
  • 一致性(consistency):数据库总是从一个一致性的状态转换到另外一个一致性的状态。
  • 隔离性(isolation):通常来说,一个事务所做的修改在最终提交以前,对其他事务是不可见的。
  • 持久性(durability):一旦事务提交,则其所做的修改就会永久保存到数据库中。此时即使系统崩溃,修改的数据也不会丢失。

但是这种事务处理过程中额外的安全性,也会需要数据库系统做更多的额外工作。一个实现了ACID的数据库,相比没有实现ACID的数据库,通常会需要更强的CPU处理能力、更大的内存和更多的磁盘空间。但这也正是MySQL的存储引擎架构可以发挥优势的地方。用户可以根据业务是否需要事务处理,来选择合适的存储引擎。对于一些不需要事务的查询类应用,选择个非事务型的存储引擎,可以获得更髙的性能。

1.3.1 隔离级别

在SQL标准中定义了四种隔离级别,每一种级别都规定了个事务中所做的修改,哪些在事务内和事务间是可见的,哪些是不可见的。较低级别的隔离通常可以执行更高的并发,系统的开销也更低。

  • READ UNCOMMITTED(未提交读):在READ UNCOMMITTED级别,事务中的修改,即使没有提交,对其他事务也都是可见的。事务可以读取未提交的数据,这也被称为脏读(Dirty Read)。

  • READ COMMITTED(提交读):大多数数据库系统的默认隔离级别都是 READ COMMITTED。它满足前面提到的隔离性的简单定义:一个事务从开始直到提交之前,所做的任何修改对其他事务都是不可见的。这个级别有时候也叫做不可重复读(nonrepeatable read),因为两次执行同样的查询,可能会得到不一样的结果

  • REPEATABLE READ(可重复读):REPEATABLE READ解决了脏读和不可重复读的问题。该级别保证了在同一个事务中多次读取同样记录的结果是一致的。但是理论上,可重复读隔离级别还是无法解决另外一个幻读(Phantom read)的问题。所谓幻读,指的是当某个事务在读取某个范围内的记录时,另外一个事务又在该范围内插入了新的记录,当之前的事务再次读取该范围的记录时,会产生幻行(Phantom row)。 InnoDB存储引擎通过多版本并发控制(MVCC, Multiversion Concurrency Control)解决了幻读的问题。可重复读是MySQL的默认事务隔离级别。

  • SERIALIZABLE(可串行化):SERIALIZABLE是最高的隔离级别。它通过强制事务串行执行,避免了前面说的幻读的问题。简单来说, SERIALIZABLE会在读取的每一行数据上都加锁,所以可能导致大量的超时和锁争用的问题。

1.3.2 死锁

当多个事务试图以不同的顺序锁定资源时,就可能会产生死锁。多个事务同时锁定同一个资源时,也会产生死锁。

下面举一个例子

如果凑巧,两个事务都执行了第一条UPDATE语句,更新了一行数据,同时也锁定了该行数据,接着每个事务都尝试去执行第二条UPDATE语句,却发现该行已经被对方锁定,然后两个事务都等待对方释放锁,同时又持有对方需要的锁,则陷入死循环。除非有外部因素介入才可能解除死锁。

为了解决这种问题,数据库系统实现了各种死锁检测和死锁超时机制。InnoDB存储引擎,能检测到死锁的循环依赖,并立即返回一个错误。还有一种解决方式,就是当査询的时达到锁等待超时的设定后放弃锁请求,这种方式通常来说不太好。 InnoDB目前处理死锁的方法是,将持有最少行级排他锁的事务进行回滚。

1.3.3 事务日志

事务日志可以帮助提高事务的效率。使用事务日志,存储引擎在修改表的数据时只需要修改其__内存__拷贝,再把该修改行为记录到持久在硬盘上的__事务日志__中,而不用每次都将修改的数据本身持久到磁盘。事务日志持久以后,内存中被修改的数据在后台可以__慢慢地刷回到磁盘__。

1.3.4 MySQL中的事务

MySQL提供了两种事务型的存储引擎:InnoDB和NDB Cluster。

1.3.4.1 自动提交

MySQL默认采用自动提交(AUTOCOMMIT)模式。如果不是显式地开始个事务,则毎个査询都被当作一个事务执行提交操作。可以通过设置AUTOCOMMIT变量来启用或者禁用自动提交模式。

1或者ON表示启用,θ或者OFF表示禁用。当AUTOCOMMIT=0时,所有的查询都是在一个事务中,直到显式地执行提交或者回滚,该事务结束,开始一个新事务。修改AUTOCOMMIT对非事务型的表,比如MyISAM或者内存表,不会有任何影响。

另外还有一些命令,在执行之前会强制执行COMMIT提交当前的活动事务。典型的例子在数据定义语言(DDL)中,如果是会导致大量数据改变的操作,比如ALTER TABLE就是如此。

MySQL可以通过执行SET TRANSACTION ISOLATION LEVEL命令来设置隔离级别。新的隔离级别会在下一个事务开始的时候生效。

MySQL能够识别所有的4个ANSI隔离级别,InnoDB引擎也支持所有的隔离级别。

1.3.4.2 在事务中混合使用存储引擎

MySQL服务器层不管理事务,事务是由下层的存储引擎实现的。所以在同一个事务中,使用多种存储引擎是不可靠的。

如果在事务中混合使用了事务型和非事务型的表,在正常提交的情况下不会有什么问题。

但如果该事务需要回滚,非事务型的表上的变更就无法撤销,这会导致数据库处于不一致的状态,这种情况很难修复,事务的最终结果将无法确定。所以,为每张表选择合适的存储引擎非常重要。

在非事务型的表上执行事务相关操作的时候, MySQL通常不会发出提醒,也不会报错。

1.3.4.3 隐式和显式锁定

InnoDB采用的是两阶段锁定协议(two-phase locking protocol),包括显示锁定和隐式锁定。在事务执行过程中,随时都可以执行锁定,锁只有在执行COMMIT或者ROLLBACK的时候才会释放。前面描述的锁定都是隐式锁定,InnoDB会根据隔离级别在需要的时候自动加锁。

InnoDB也支持通过特定的语句进行显式锁定

1
2
SELECT ... LOCK IN SHARE MODE
SELECT ... FOR UPDATE

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

1.4 多版本控制

MySQL的大多数事务型存储引擎实现的都不是简单的行级锁。基于提升并发性能的考虑,它们一般都同时实现了多版本并发控制(MVCC)。

可以认为MVCC是行级锁的一个变种,但是它在很多情况下避免了加锁操作,因此开销更低。虽然实现机制有所不同,但大都实现了__非阻塞的读__操作,写操作也只锁定必要的行

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则会对所有读取的行都加锁。

1.5 MySQL的存储引擎

在文件系统中,MySQL将每个数据库(也可以称之为schema)保存为数据目录下的一个子目录。创建表时,MySQL会在数据库子目录下创建一个和表同名的.frm文件保存表的定义。因为MySQL使用文件系统的目录和文件来保存数据库和表的定义,大小写敏感性和具体的平台密切相关。在Windows中,大小写是不敏感的;而在类Unxx中则是敏感的。不同的存储引擎保存数据和索引的方式是不同的,但表的定义则是在MySQL服务层统一处理的。

可以使用SHOW TABLE STATUS命令显示表的相关信息。

1.5.1 InnoDB存储引擎

InnoDB是MySQL的默认事务型引擎,也是最重要、使用最广泛的存储引擎。它被设计用来处理大量的短期(short-lived)事务,短期事务大部分情况是正常提交的,很少会被回滚。InnoDB的性能和自动崩溃恢复特性,使得它在非事务型存储的需求中也很流行。除非有非常特别的原因需要使用其他的存储引擎,否则应该优先考虑InnoDB引擎。

InnoDB的数据存储在表空间(tablespace)中,表空间是由InnoDB管理的一个__黑盒子__由一系列的数据文件组成。在MySQL4.1以后的版本中,InnoDB可以将每个表的数据和索引存放在单独的文件中。

InnoDB采用__MVCC__来支持__高并发__,并且实现了四个标准的隔离级别。其默认级别是REPEATABLE READ(可重复读),并且通过间隙锁(next-key locking)策略__防止幻读__的出现。间隙锁使得InnoDB不仅仅锁定查询涉及的行,还会对索引中的间隙进行锁定,以防止幻影行的插入。

InnoDB表是基于聚簇索引建立的。InnoDB的索引结构和MySQL的其他存储引擎有很大的不同,聚簇索引对主键查询有很高的性能。不过它的二级索引(secondary index,非主键索引)中必须包含主键列。因此,若表上的索引较多的话,主键应当尽可能的小。 InnoDB的存储格式是平台独立的,也就是说可以将数据和索引文件从Intel平台复制到 PowerPC或者Sun sparo平台。

作为事务型的存储引擎, InnoDB通过一些机制和工具支持真正的热备份。MySQL的其他存储引擎不支持热备份,要获取一致性视图需要停止对所有表的写入。

1.5.2 MyISAM存储引擎

在MySQL5.1及之前的版本, MyISAM是默认的存储引擎。MyISAM提供了大量的特性,包括全文索引、压缩、空间函数等,但MyISAM不支持事务和行级锁,而且有一个亳无疑问的缺陷就是崩溃后无法安全恢复。对于只读的数据,或者表比较小、可以忍受修复(repair)操作,则依然可以继续使用MyISAM。

1.5.2.1 存储

MyISAM会将表存储在两个文件中:数据文件和索引文件,分别以.MYD.MY为扩展名。MyISAM表可以包含动态或者静态(长度固定)行。 MySQL会根据表的定义来决定采用何种行格式。MyISAM表的最大行数,一般受限于可用的磁盘空间或者操作系统中单个文件的最大尺寸。MyISAM表如果是变长行,则默认配置只能处理256TB的数据,因为指向数据记录的指针长度是6个字节。

1.5.2.2 MyISAM特性

加锁与并发

  • MyISAM对整张表加锁,而不是针对行。
  • 读取时会对需要读到的所有表加共享锁,写人时则对表加排他锁。

修复

  • 对于MyISAM表,MySQL可以手工或者自动执行检查和修复操作
  • 执行表的修复可能导致一些数据丢失,而且修复操作是非常慢的。

索引特性

  • 对于MyISAM表,即使是BLOB和TXT等长字段,也可以基于其前500个字符创建索引。
  • MyISAM也支持全文索引,这是一种基于分词创建的索引,可以支持复杂的查询。

延迟更新索引键(Delayed Key Write)

  • 创建MyISAM表的时候,如果指定了DELAY KEY WRITE选项,在每次修改执行完成时,不会立刻将修改的索引数据写入磁盘,而是会写到内存中的键缓冲区(in-memory key buffer),只有在清理键缓冲区或者关闭表的时候才会将对应的索引块写入到磁盘。
  • 这种方式可以极大地提升写人性能,但是在数据库或者主机崩溃时会造成索引损坏,需要执行修复操作。
1.5.2.3 MyISAM压缩表

如果表在创建并导入数据以后,不会再进行修改操作,那么这样的表或许适合采用MyISAM压缩表。

可以使用myisampack对MyISAM表进行压缩。压缩表是不能进行修改的。压缩表可以极大地减少磁盘空间占用,因此也可以减少磁盘I/O,从而提升查询性能。压缩表也支持索引,但索引也是只读的。

1.5.2.4 MyISAM性能

在服务器级别,MyISAM有很大的性能限制。但MyISAM最典型的性能问题还是表锁的问题,如果你发现所有的查询都长期处于Locked状态,那么毫无疑问表锁就是罪魁祸首。

1.5.3 MySQL内建的其他存储引擎

1.5.3.1 Archive引擎

Archive存储引擎只支持INSERTSELECT操作,Archive引擎会缓存所有的写并利用zlib对插入的行进行压缩,所以比MyISAM表的磁盘I/O更少。但是每次SELECT查询都需要执行全表扫描。所以Archive表适合日志和数据采集类应用,这类应用做数据分析时往往需要全表扫描。

Archive引擎支持行级锁和专用的缓冲区,所以可以实现高并发的插入。在一个查询开始直到返回表中存在的所有行数之前,Archive引擎会阻止其他的SELECT执行,以实现一致性读。 Archive引擎不是一个事务型的引擎,而是一个针对高速插入和压缩做了优化的简单引擎。

1.5.3.2 Blackhole引擎

Blackhole引擎没有实现任何的存储机制,它会丢弃所有插入的数据,不做任何保存。但是服务器会记录 Blackhole表的日志。这种特殊的存储引擎可以在一些特殊的复制架构和日志审核时发挥作用。

1.5.3.3 CSV引擎

CSV引擎可以将普通的CSV文件(逗号分割值的文件)作为MySQL的表来处理,但这种表不支持索引。CSV引擎可以作为一种数据交换的机制,非常有用。

1.5.3.4 Federated引擎

Federated引擎是访问其他 MySQL服务器的一个代理,它会创建一个到远程MySQL服务器的客户端连接,并将查询传输到远程服务器执行,然后提取或者发送需要的数据。

1.5.3.5 Memory引擎

如果需要快速地访问数据,并且这些数据不会被修改,重启以后丢失也没有关系,那么使用Memory表是非常有用的。 Memory表至少比MyISAM表要快一个数量级,因为所有的数据都保存在内存中,不需要进行磁盘I/O。Memory表的结构在重启以后还会保留,但数据会丢失。

Memroy表是表级锁,因此并发写入的性能较低。它不支持BLOB或TEXT类型的列,并且每行的长度是固定的,所以即使指定了VARCHAR列,实际存储时也会转换成CHAR,这可能导致部分内存的浪费。

如果MySQL在执行查询的过程中需要使用临时表来保存中间结果,内部使用的临时表就是Memory表。

1.5.3.6 Merge引擎

Merge表是由多个 MyISAM表合并而来的虚拟表。如果将 MySQL用于日志或者数据仓库类应用,该引擎可以发挥作用。但是引入分区功能后,该引擎已经被放弃。

1.5.3.7 NDB集群引擎

MySQL服务器、NDB集群存储引擎,以及分布式的、 share- nothing的、容灾的、高可用的NDB数据库的组合,被称为 MySQL集群(MySQL Cluster)。

1.5.4 第三方存储引擎

MySQL从2007年开始提供了插件式的存储引擎API,从此涌出了一系列为不同目的而设计的存储引擎。

1.5.4.1 OLTP类引擎

Percona的XtraDB存储引擎是基于 InnoDB引擎的一个改进版本。它的改进点主要集中在性能、可测量性和操作灵活性方面XtraDB可以作为 InnoDB的一个完全的替代产品,甚至可以兼容地读写 InnoDB的数据文件,并支持 InnoDB的所有查询。

TokuDB引擎使用了一种新的叫做分形树(Fractal Trees)的索引数据结构。该结构是缓存无关的,因此即使其大小超过内存性能也不会下降,也就没有内存生命周期和碎片的问题。TokuDB是一种大数据存储引擎,因为其拥有很高的压缩比,可以在很大的数据量上创建大量索引。在本书写作时,这个引擎还处于早期的生产版本状态,

1.5.4.2 面向列的存储引擎

MySQL默认是面向行的,每一行的数据是一起存储的,服务器的查询也是以行为单位处理的。而在大数据量处理时,面向列的方式可能效率更高。如果不需要整行的数据,面向列的方式可以传输更少的数据。如果每一列都单独存储,那么压缩的效率也会更高。

Infobright是最有名的面向列的存储引擎。在非常大的数据量(数十TB)时,该引擎工作良好。Infobright是为数据分析和数据仓库应用设计的。数据高度压缩,按照块进行排序,每个块都对应有一组元数据。在处理查询时,访问元数据可决定跳过该块,甚至可能只需要元数据即可满足查询的需求。但该引擎不支持索引,不过在这么大的数据量级,即使有索引也很难发挥作用,而且块结构也是一种准索引。

1.5.5 选择合适的引擎

InnoDB都是正确的选择。除非需要用到某些InnoDB不具备的特性,并且没有其他办法可以替代,否则都应该优先选择 InnoDB引擎。例如,如果要用到全文索引,建议优先考虑InnoDB加上Sphinx的组合,而不是使用支持全文索引的 MyISAM。

除非万不得已,否则建议不要混合使用多种存储引擎,否则可能带来一系列复杂的问题,以及一些潜在的bug和边界问题。存储引擎层和服务器层的交互已经比较复杂,更不用说混合多个存储引擎了。至少,混合存储对一致性备份和服务器参数配置都带来了一些困难。

如果应用需要选择存储引擎,通常从如下几个角度考虑

事务

  • 如果应用需要事务支持,那么InnoDB是目前最稳定并且经过验证的选择。
  • 如果不需要事务,并且主要是SELECTINSERT操作,那么MyISAM是不错的选择。一般日志型的应用比较符合这一特性。

备份

  • 如果可以定期地关闭服务器来执行备份,那么备份的因素可以忽略。
  • 反之,如果需要在线热备份,那么选择InnoDB就是基本的要求。

崩渍恢复

  • MyISAM崩溃后发生损坏的概率比InnoDB要高很多,而且恢复速度也要慢。
  • 因此,即使不需要事务支持,很多人也选择InnoDB引擎。

下面从不同应用类型的角度考虑存储引擎的选择

日志型应用

  • 假设你需要实时地记录一台中心电话交换机的每一通电话的日志到MySQL中。
  • 这一类应用的插入速度有很高的要求,数据库不能成为瓶颈。
  • MyISAM或者Archive存储引擎对这类应用比较合适,因为它们开销低,而且插入速度非常快。

只读或者大部分情况下只读的表

  • 有些表的数据用于编制类目或者分列清单(如工作岗位、竞拍、不动产等),这种应用场景是典型的读多写少的业务。
  • 如果不介意MyISAM的崩溃恢复问题,选用MyISAM引擎是合适的。

订单处理

  • 如果涉及订单处理,那么支持事务就是必要选项。半完成的订单是无法用来吸引用户的。
  • 另外一个重要的考虑点是存储引擎对外键的支持情况。
  • InnoDB是订单处理类应用的最佳选择。

大数据量

  • 什么样的数据量算大?我们创建或者管理的很多InnoDB数据库的数据量在3~5TB之间,或者更大,这些系统运行得还不错
  • 如果数据量继续增长到10TB以上的级别,可能就需要建立数据仓库。
  • Infobright是MySQL数据仓库最成功的解决方案。也有一些大数据库不适合Infobright,却可能适合TokuDB

1.5.6 转换表的引擎

我们将讲述其中的三种方法将表的存储引擎转换成另外一种引擎。

1.5.6.1 ALTER TABLE

将表从一个引擎修改为另一个引擎最简单的办法是使用 ALTER TABLE语句。

1
ALTER TABLE mytable ENGINE = InnoDB

上述语法可以适用任何存储引擎。但需要执行很长时间。 MySQL会按行将数据从原表复制到张新的表中,在复制期间可能会消耗系统所有的I/O能力,同时原表上会加上读锁。所以,在繁忙的表上执行此操作要特别小心。

1.5.6.2 导出与导入

为了更好地控制转换的过程,可以使用mysqldump工具将数据导出到文件,然后修改文件中CREATE TABLE语句的存储引擎选项,注意同时修改表名。\

1.5.6.3 创建与查询(CREATE和SELECT)

不需要导出整个表的数据,而是先创建一个新的存储引擎的表,然后利用INSERT… SELECT语法来导数据

1
2
3
CREATE TABLE innodb table LIKE myisam table; 
ALTER TABLE innodb table ENGINE=InnoDB;
INSERT INTO innodb table SELECT FROM mmyisam table;

1.6 MySQL的开发模式

MySQL依然遵循GPL开源协议,全部的源代码都会开放给社区。现在Oracle为付费用户提供了一些服务器插件,但是没有这些插件,MySQL也是功能完整的数据库。