mysql性能调优与架构设计(一)商业需求与系统架构对性能的影响

这里我们就拿一个看上去很简单的功能来分析一下。


需求:一个论坛帖子总量的统计
附加要求:实时更新


在很多人看来,这个功能非常容易实现,不就是执行一条SELECT COUNT(*)的Query 就可以得到结果
了么?是的,确实只需要如此简单的一个Query 就可以得到结果。但是,如果我们采用不是MyISAM 存储
引擎,而是使用的Innodb 的存储引擎,那么大家可以试想一下,如果存放帖子的表中已经有上千万的帖
子的时候,执行这条Query 语句需要多少成本?恐怕再好的硬件设备,恐怕都不可能在10 秒之内完成一
次查询吧。如果我们的访问量再大一点,还有人觉得这是一件简单的事情么?
既然这样查询不行,那我们是不是该专门为这个功能建一个表,就只有一个字段,一条记录,就存
放这个统计量,每次有新的帖子产生的时候,都将这个值增加1,这样我们每次都只需要查询这个表就可
以得到结果了,这个效率肯定能够满足要求了。确实,查询效率肯定能够满足要求,可是如果我们的系
统帖子产生很快,在高峰时期可能每秒就有几十甚至上百个帖子新增操作的时候,恐怕这个统计表又要
成为大家的噩梦了。要么因为并发的问题造成统计结果的不准确,要么因为锁资源争用严重造成整体性
能的大幅度下降。
其实这里问题的焦点不应该是实现这个功能的技术细节,而是在于这个功能的附加要求“实时更
新”上面。当一个论坛的帖子数量很大了之后,到底有多少人会关注这个统计数据是否是实时变化的?
有多少人在乎这个数据在短时间内的不精确性?我想恐怕不会有人会傻傻的盯着这个统计数字并追究当
自己发了一个帖子然后回头刷新页面发现这个统计数字没有加1 吧?即使明明白白的告诉用户这个统计
数据是每过多长时间段更新一次,那有怎样?难道会有很多用户就此很不爽么?
只要去掉了这个“实时更新”的附加条件,我们就可以非常容易的实现这个功能了。就像之前所提
到的那样,通过创建一个统计表,然后通过一个定时任务每隔一定时间段去更新一次里面的统计值,这
样既可以解决统计值查询的效率问题,又可以保证不影响新发贴的效率,一举两得。
实际上,在我们应用的系统中还有很多很多类似的功能点可以优化。如某些场合的列表页面参与列
表的数据量达到一个数量级之后,完全可以不用准确的显示这个列表总共有多少条信息,总共分了多少
页,而只需要一个大概的估计值或者一个时间段之前的统计值。这样就省略了我们的分页程序需要在分
以前实时COUNT 出满足条件的记录数。
其实,在很多应用系统中,实时和准实时,精确与基本准确,在很多地方所带来的性能消耗可能是
几个性能的差别。在系统性能优化中,应该尽量分析出那些可以不实时和不完全精确的地方,作出一些
相应的调整,可能会给大家带来意想不到的巨大性能提升。


无用功能堆积使系统过度复杂影响整体性能


很多时候,为系统增加某个功能可能并不需要花费太多的成本,而要想将一个已经运行了一段时间
的功能从原有系统中撤下来却是非常困难的。
首先,对于开发部门,可能要重新整理很多的代码,找出可能存在与增加该功能所编写的代码有交
集的其他功能点,删除没有关联的代码,修改有关联的代码;
其次,对于测试部门,由于功能的变动,必须要回归测试所有相关的功能点是否正常。可能由于界
定困难,不得不将回归范围扩展到很大,测试工作量也很大。
最后,所有与撤除下线某个功能相关的工作参与者来说,又无法带来任何实质性的收益,而恰恰相
反是,带来的只可能是风险。
由于上面的这几个因素,可能很少有公司能够有很完善的项目(或者功能)下线机制,也很少有公
司能做到及时将系统中某些不合适的功能下线。所以,我们所面对的应用系统可能总是越来越复杂,越
来越庞大,短期内的复杂可能并无太大问题,但是随着时间的积累,我们所面对的系统就会变得极其臃
肿。不仅维护困难,性能也会越来越差。尤其是有些并不合理的功能,在设计之初或者是刚上线的时候
由于数据量较小,带来不了多少性能损耗。可随着时间的推移,数据库中的数据量越来越大,数据检索
越来越困难,对真个系统带来的资源消耗也就越来越大。
而且,由于系统复杂度的不断增加,给后续其他功能的开发带来实现的复杂度,可能很多本来很简
单的功能,因为系统的复杂而不得不增加很多的逻辑判断,造成系统应用程序的计算量不断增加,本身
性能就会受到影响。而如果这些逻辑判断还需要与数据库交互通过持久化的数据来完成的话,所带来的
性能损失就更大,对整个系统的性能影响也就更大了。

 

我们数据库中存放的数据都是适合在数据库中存放的吗?


对于有些开发人员来说,数据库就是一个操作最方便的万能存储中心,希望什么数据都存放在数据
库中,不论是需要持久化的数据,还是临时存放的过程数据,不论是普通的纯文本格式的字符数据,还
是多媒体的二进制数据,都喜欢全部塞如数据库中。因为对于应用服务器来说,数据库很多时候都是一
个集中式的存储环境,不像应用服务器那样可能有很多台;而且数据库有专门的DBA 去帮忙维护,而不
像应用服务器很多时候还需要开发人员去做一些维护;还有一点很关键的就是数据库的操作非常简单统
一,不像文件操作或者其他类型的存储方式那么复杂。

实际上,以下几类数据都是不适合在数据库中存放的:


1. 二进制多媒体数据
将二进制多媒体数据存放在数据库中,一个问题是数据库空间资源耗用非常严重,另一个问题
是这些数据的存储很消耗数据库主机的CPU 资源。这种数据主要包括图片,音频、视频和其他一些
相关的二进制文件。这些数据的处理本不是数据的优势,如果我们硬要将他们塞入数据库,肯定会
造成数据库的处理资源消耗严重。


2. 流水队列数据
我们都知道,数据库为了保证事务的安全性(支持事务的存储引擎)以及可恢复性,都是需要
记录所有变更的日志信息的。而流水队列数据的用途就决定了存放这种数据的表中的数据会不断的
被INSERT,UPDATE 和DELETE,而每一个操作都会生成与之对应的日志信息。在MySQL 中,如果是支
持事务的存储引擎,这个日志的产生量更是要翻倍。而如果我们通过一些成熟的第三方队列软件来
实现这个Queue 数据的处理功能,性能将会成倍的提升。


3. 超大文本数据
对于5.0.3 之前的MySQL 版本,VARCHAR 类型的数据最长只能存放255 个字节,如果需要存储更
长的文本数据到一个字段,我们就必须使用TEXT 类型(最大可存放64KB)的字段,甚至是更大的
LONGTEXT 类型(最大4GB)。而TEXT 类型数据的处理性能要远比VARCHAR 类型数据的处理性能低下
很多。从5.0.3 版本开始,VARCHAR 类型的最大长度被调整到64KB 了,但是当实际数据小于255
Bytes 的时候,实际存储空间和实际的数据长度一样,可一旦长度超过255 Bytes 之后,所占用的存
储空间就是实际数据长度的两倍。
所以,超大文本数据存放在数据库中不仅会带来性能低下的问题,还会带来空间占用的浪费问
题。

你可能感兴趣的:(mysql)