上一篇中说到了很多存储引擎,那么我们应该如何选择呢,大部分情况下,InnoDB都是正确的选择,所以Oracle在MySQL5.5版本时终于将InnoDB作为默认的存储引擎了。对于如何选择存储引擎,可以见到的归纳为一句话:除非必须要用到某些InnoDB布局被的特性,并且没有其他更好的方式可以实现,否则都应该选择InnoDB引擎。例如,如果要用到全文索引,建议优先考虑InnoDB加上Sphinx的组合,而不是使用支持全文索引的MyISAM。当然,如果不需要用到InnoDB的特性,同时其他引擎的疼能够更好的满足需求,也可以考虑一下其他存储引擎。例如,如果不在乎可扩展能力和并发能力,也不在乎崩毁数据丢失问题,却对InnoDB占用的空间过多比较敏感,这种情况下选择MyISAM就比较合适。
但是,除非万不得已,不建议使用多种存储引擎混合使用,否则可能会带来一系列的问题,以及一些潜在的bug和边界问题。存储引擎层和服务器的交互已经比较复杂,更不用说混合使用多个了。至少,混合存储对一致性备份和服务器参数配合都带来了一些麻烦。
如果应用需要不同的存储引擎时,请先考虑以下几个因素。
① 事务:
如果引用需要事务支持,那么InnoDB或者XtraDB是目前最稳定并且经过验证的选择。如果不需要事务,并且主要是select和insert操作,那么MyISAM是不错的选择。一般日之星的应用比较符合这一特性。
② 备份:
备份的需要也会影响存储引擎的选择。如果可以定期的关闭服务器来执行备份,那么备份的因素可以忽略(但是这种情况应该不存在了吧,反正我没听说过定期关服务器备份的)。反之,如果需要在线热备份,那么选择InnoDB就是基本的要求。
③ 崩溃恢复
数据量比较大的时候,系统崩溃后如何快速的恢复是一个需要考虑的问题。相对而言,MyISAM崩溃后发生损坏的概率比InnoDB要高很多,而且恢复速度也比InnoDB要慢很多。因此,即使不需要事务支持,也有很多人选择InnoDB,这也是一个重要的原因。
④ 特有的特性
有些应用可能依赖一些村吃醋引擎所独有的特性或者优化,比如很多应用依赖聚簇索引的优化。另外,MySQL中也只有MyISAM支持地理空间搜索。如果一个村吃醋引擎拥有一些关键的特性,同时又缺乏一些必要的特性,那么不得不进行折中考虑,或者在架构设计上进行取舍。某些存储引擎无法直接支持的特性,有时候通过变通也可以满足需求。
假设你需要实时的记录大量的日志到MySQL中,或者通过Apache的mod_log_sql模块将网站的所有访问信息直接记录到表中(百度有一个访问者埋点也可以实现这类功能,还不需要自己提供服务器,有兴趣的可以自行了解下,很简单的配置就可以实现。但是不能存储到数据库中)。这一类引用的插入速度有很高的要求,数据库不能成为瓶颈。MyISAM或者Archive存储引擎对这类引用比较和二十,因为它们的开销低,插入速度非常快。
如果需要对记录的日志做分析报表,生成报表的SQL很有可能会导致插入效率明显降低,这时候怎么办?
一种解决方法是利用MySQL内置的赋值方案将数据复制一份到备库,然后在备库上执行比较消耗时间和CPU的查询。这样主库只用于高效的插入工作,而备份库上执行查询页无需担心影响到日志的插入性能。当然也可以在系统负载较低的时候执行报表查询操作,但应用在不断变化,如果依赖这个策略可能会导致后续产生问题。
另一种方法,在日志记录表的名字中包含年月的信息,比如web_logs_2019_01或者web_logs_2019_jan。这样可以在已经没有插入操作的历史表上做频繁的查询操作,而不会干扰到最新的当前表上的插入操作。
有些表的数据用于编制类目或者分类清单,这种应用场景是典型的读多写少的业务。如果不介意MyISAM的崩溃恢复问题,选用MyISAM引擎是最合适的。不过永远不要低估崩溃回复问题的重要性,有些存储引擎不会保证将数据安全的写入磁盘中,而许多用户实际上并不清楚这样有多大的风险(MyISAM只将数据写到内存中,然后等待操作系统定期将数据刷出到磁盘上)。
我们可以在一个拟真的测试环境下运行应用然后断电,以此来测试崩溃回复问题,也可以定期进行演练,以避免真正遇到问题时不知道如何处理。
不要轻易相信MyISAM比InnoDB快这样的经验之谈,这个结论并不是绝对的。在很多已知的场景中,InnoDB的速度都可以让MyISAM望尘莫及,尤其是使用到聚簇索引,或者需要访问的数据都可以放入内存的应用。
当涉及到上述类型的应用时,建议采用InnoDB。MyISAM引擎在一开始可能没有任何问题,但随着应用压力的上升,可能会迅速恶化。各种锁争用、崩溃数据丢失问题都会随之而来。
如果涉及订单处理,那么支持事务就是必要选项。半完成的订单是无法用来吸引用户的。另外一个重要考虑点是存储引擎对外键的支持情况。InnoDB是订单处理类应用的最佳选择(当然,现在我们一般情况都不会在表中指定外键这个属性了)。
对于MySQL用户,主体讨论去屎个很有意思的话题。当前有成百上千的PHP或Perl的免费系统可以支持主题讨论。其中大部分的数据库操作效率都不高,因为它们大多倾向于在一次请求中执行尽可能多的查询。另外还有部分系统设计为不采用内数据库,当然也就无法利用到数据库提供的一些方便的特性。主题讨论去一般都有更新计数器,并且会为各个主题计算访问统计信息。多数应用只涉及了几张表来保存所有的数据,所以核心表的读写压力可能非常大。为保证这些核心表的数据一致性,锁称为资源争用的主要因素。
尽管有这些设计缺陷,但大多数引用在中低负载时可以工作的很好。如果Web站点的规模迅速扩展,流量随之猛增,则数据库访问可能变得非常慢。此时一个典型的解决方案是更改为支持更高读写的存储引擎,但有时用户会发现这么做反而更慢了。
可能大家并没有意识到这是由于某些特殊查询的缘故,例如:
select count(*) from table;
这个问题在于不是所有存储引擎运行上述查询都很快,对于MyISAM确实会很快,但其他的可能斗殴不行。每种村吃醋引擎都能找出类似的例子。
如果要发布一个基于CD-ROM或者DVD-ROM并且使用MySQL数据文件的应用,可以考虑使用MyISAM表或者MyISAM压缩表,这样表之间可以隔离并且可以在不同介质上相互拷贝。MyISAM压缩表比未压缩的表要节约很多空间,但压缩表是只读的。在某些应用中这可能是个大问题。但如果数据放到只读介质的场景下,压缩表的只读特性就不是问题,就没有理由不采用压缩表了。
什么样的数据量算大?我们创建或者管理的很多InnoDB数据库的数据量在3~5TB或更大,这是单台机器上的量,不是一个分片的量(shard)。这些系统运行得还不错,要做到这一点需要合理的选择硬件,做好物理设计,并为服务器的I/O瓶颈做好规划。在这样的数据量下,如果采用MyISAM,崩溃回复就是一个噩梦。
如果数据量继续增长到10TB以上的解,可能就要建立数据仓库。Infobright是MySQL数据仓库最成功的解决方案。也有一些大数据库不适合Infobright,却可能适合使用TokuDB。