《PHP核心技术与实践》-PHP与数据库基础(2)
-
MYSQL瓶颈及应对措施
1)增加MYSQL配置中buffer和cache的数值,增加服务器CPU数量和内存大小,这能很大程度上应对MYSQL的性能瓶颈,性能优化中效果最显著成本最低的当属硬件和服务器优化,就优先考虑;
2)使用第三方引擎或衍生版本;
3)迁移到其他数据库;
4)对数据库进行分区、分表操作,减少单表体积;
5)使用NoSQL等辅助解决方案,如Memcached,Redis;
6)使用中间件做数据拆分和分布式部署;
最后,一个工具能不能用好,人的因素占很大的比重。
-
数据库设计
(1)范式与反范式:为规范DB设计在DB理论发展的过程中,逐渐形成了DB范式的理论,到目前为止有五大范式。到了第三范式通常已经能够满足业务需求了,表之间的关系也比较清晰容易维护。
(2)反范式的提出:范式理论在20世纪70年代提出并在80拆借基本定型,那时候的系统的特征为:可用的存储器资源极其有限,并且网络不成熟能使用网络的人较少通常只涉及单机的计算性能,所以范式理论强调减少依赖/降低冗余;但现在内在廉价存储不再是问题同时面临高并发业务逻辑复杂低延迟的要求,所以不应一味遵循范式设计理论,应当适当降低范式,增加冗余以空间换时间是值得的,最低可降至第一范式。
(3)通常在设计数据库时需遵循以下原则:
1)核心业务使用范式。
2)弱一致性需求--反范式
3)空间换时间
4)避免不必要的冗余
-
数据库分区
所谓分区就是把一个数据表的文件和索引分散存储在不同的物理文件中,MySQL5.1以上版本才支持分区。可用SHOW VARIABLES LIKE ‘%partition%’来确认是否支持分区。MYSQL支持的分区类型包括Range/List/Hash/Key,其中Range最常用,示例:
CREATE TABLE foo (id INT NOT NULL AUTO_INCREMENT,created DATATIME,PRIMARY KEY(id,created)) ENGINE = INNODB PARTITION BY RANGE (TO_DAYS(created)) (PARTITION foo_1 VALUES LESS THAN (TO_DAYS('2009-01-01')),PARTITION foo_2 VALUES LESS THAN (TO_DAYS('2010-01-01')))
MYSQL通过分区把数据保存到不同数据文件里,同时索引也是分区的,相对未分区的表来说分区后单独的数据文件和索引文件的大小明显降低,效率明显提升。一条查询/写操作只在相应分区上执行。实际应用分区时,通过DATA DIRECTORY和INDEX DIRECTORY选项把不同分区分散到不同磁盘上进一步提高系统的IO吞吐量。使用分区后最好都用EXPLAIN PARTITIONS过一遍以确认分区是否生效。
通常使用Range分区,但在主从结构中主服务器很少使用SELECT语句在其上使用Range查询并没有太大意义,此时使用Hash类型的分区相对更好:PARTITON BY HASH(id) PARTITION 10,当插入数据时会根据ID把数据平均分散到各个分区上,由于文件小/效率高,更新操作会变得更快。通常按时间字段分区,不过具体情况还是按需求而定。
分区虽然很好,但目前的实现还有很多限制如:
主键或者唯一索引必须包含分区字段,如PRIMARY KEY (id,created),不过对InnoDB来说,大主键性能不好
很多时候使用分区就不要再使用主键否则可能影响性能
只能通过INI类型的字段或者返回INI类型的表达式来分区,通常使用YEAR或TO_DAYS等函数
每个表最多1024个分区,不可能无限制扩展分区,而且过度使用分区会消耗大量系统内存
采用分区的表不支持外键,相关的约束逻辑必须在代码里实现
分区后可能会造成索引失效,需要验证分区可行性