实现方案一:html
(1)直接执行select count(*)。 (2)可是此sql语句在数据量愈来愈大的时候,不一样的存储引擎会带来不一样的性能问题。 (3)myisam存储引擎是非事务性存储引擎,而且其内部存在内置的计数器,直接保存着代表细的总数目,若是执行select count(*)那么将很容易就取出,即便在数据量很大的状况下也不会出现太大的问题。 (4)可是若是是InnoDB存储引擎,其内部并无内置的计数器保存代表细总数量,每次执行select count(*)都会全表扫描 (5)因而可知,当数据量在很大的一个量级的时候,加上并发很大的状况下,很容易出现性能瓶颈。
实现方案二:mysql
(1)方案一能够适用于myisam存储引擎,可是对于innodb存储引擎就不行了。 (2)那咱们是否能够考虑为这个功能单独创建一个表,就只有一个字段一条记录,就存放这个统计量,每次有新的帖子的时候就更新一次这个统计量,到时候直接查询这个字段便可实现。 (3)这种方案也可能很好的提高查询效率,可是在咱们的系统帖子产生很快的时候,在高峰时期可能每秒就有几十个甚至上百个帖子新增操做的时候,这个统计表可能又回出现问题。 (4)要么由于并发的问题形成统计结果不许确,要么由于锁资源争用严重形成总体性能的降低。
实现方案三:web
(1)方案一和方案二都有必定的优缺点,可是若是咱们想要在它们的缺陷处尽量的完美避开性能瓶颈呢? (2)这时候咱们从新考虑实时更新的需求,用户对于这个实时更新是很容易感知的吗? (3)当一个论坛的帖子数量很大了以后,到底有多少人会关注这个数量的实时变化?我想应该不会,所以,咱们对此需求是否是能够不那么严格,是否是能够容许必定的误差,达到准实时的标准? (4)基于此考虑,那么咱们的方案三就能够建立一个统计表,而后经过定时任务隔一段时间更新一次统计表数据,这样既能够解决统计表查询的效率问题,又能够保证不影响发帖的效率,一箭双雕。
实际上,如下几类数据都是不适合在数据库中存放的:sql
(1)二进制多媒体数据: 【1】将二进制多媒体数据存放在数据库中,一个问题是数据库空间资源耗用很是严重,另外一个问题是这些数据的存储很消耗数据库主机的cpu资源。 【2】这种数据主要包括图片、音频、视频和其余一些相关的二进制文件。 【3】这些数据的处理本不是数据库的优点,若是咱们硬要将它们塞入数据库,确定会形成数据库的处理资源消耗严重。 (2)流水队列数据: 【1】咱们都知道,数据库为了保证事务的安全性以及可恢复性,都是须要记录全部变动的日志信息的。 【2】而流水队列数据的用途就决定了存放这种数据的表中的数据会不断的被INSERT、UPDATE、DELETE,而每个操做都会生成与之对应的日志信息。 【3】在mysql中,若是是支持事务的存储引擎(InnoDB),这个日志的产生量将更是翻倍。 【4】而若是咱们经过一些成熟的第三方队列软件来实现这个Queue数据的处理功能,性能将会成倍的提高。 (3)超大文本数据: 【1】对于5.0.3以前的mysql版本,varchar类型的数据最长只能存放255个字节,若是须要存储更长的文本数据到一个字段,咱们就必须使用text类型(最大可存放64KB),甚至是更大的longtext类型(最大4G)。 【2】而text类型数据的处理性能要远比varchar类型数据的处理性能低下不少。 【3】从5.0.3版本开始,varchar类型的最大长度被调整为64KB,可是当实际数据小于255Bytes时,实际存储空间和数据的实际长度同样,可一旦数据长度超过了255Bytes以后,所占用的存储空间就是实际数据长度的两倍。 【4】因此,超大文本数据存放在数据库中不只会带来性能低下的问题,还会带来空间占用的浪费问题。
是否合理的利用了应用层cache机制?数据库
(1)对于web应用,活跃数据的数据量老是不会特别大,有些活跃数据更是不多变化。 (2)对于这中类型的数据,咱们是否有必要每次须要的适合都去数据库中查询呢? (3)若是咱们可以将变化相对较少的部分活跃数据经过应用层的cache机制cache到内存中,对性能的提高确定是成数量级的,并且因为是活跃数据,对系统总体性能的影响也会很大。 (4)固然,经过cache机制成功的案例数不胜数,如何合理的经过cache技术让系统性能获得较大的提高也并非经过寥寥几笔就能说明清楚的,这里根据以往经验列举一下什么样的数据适合经过cache技术来提高系统性能: 【1】系统各类配置及规则数据:因为这些配置信息变更的频率很是低,访问几率又很高,因此很是适合使用cache。 【2】活跃用户的基本信息数据: 「1」虽然咱们常常会听到某某网站的用户量达到成百上千万,可是不多有系统的活跃用户量都能达到这个量级。 「2」也不多有用户没事干去将本身的基本信息改来改去。 「3」更为重要的一点是用户的基本信息在应用系统中的访问频率及其频繁。 「4」因此,用户基本信息的cache,很容易让整个系统的性能出现一个质的提高。 【3】活跃用户的个性化定制信息数据: 「1」虽然用户个性化定制的数据从访问频率来看,可能并无用户的基本信息那么频繁,但相对于系统总体来讲,也占了很大的比例,并且变动规律同样不会太多。 「2」从Ebay的PayPal经过mysql的memory存储引擎实现用户个性化定制数据的成功案例咱们就能看出对这部分信息进行cache的价值。 「3」虽然经过mysql的memory存储引擎并不像咱们传统意义上的cache机制,但正是对cache技术的合理利用和扩充造就了项目总体的成功。 【4】准实时的统计信息数据: 「1」所谓准实时的统计信息数据,实际上就是基于时间段的统计数据。 「2」这种数据不会实时更新,也不多须要增量更新,只有当达到从新build该统计数据的时候须要作一次全量更新操做。 「3」虽然这种数据即便经过数据库来读取效率可能也会很高,可是执行效率很高以后,一样会消耗很多资源。既然数据库资源很是珍贵,咱们为何不放在应用相关的cache中呢? 【5】其余一些访问频繁可是变动较少的数据: 「1」除了上述四种数据以外,在咱们面对的各类系统环境中确定还会有各类各样的变动较少可是访问很频繁的数据。 「2」只要合适,咱们均可以对他们的访问从数据库移到cache中。
咱们的数据层的实现都是最精简的吗?安全
(1)从以往的经验来看,一个合理的数据存取实现和一个拙劣的实现相比,在性能方面的差别常常会超出一个甚至几个数量级。 (2)咱们先来分析一个实例: 【1】在咱们的网站中,如今要实现每一个用户查看各自相册列表,假设每一个列表10张图片,可以在相片名称后边显示该相片的留言数量。 【2】实现方案一: 「1」经过“SELECT id,subject,url FROM photo WHERE user_id = ? limit 10”获得第一页的相片相关信息; 「2」经过第一步结果集中的10个相片的id循环运行十次"SELECT COUNT(*) FROM photo_comment WHERE photh_id = ?"来获得每张相片的回复数量而后再拼装展示对象。 【1】实现方案二: 「1」和方案一中的第一步同样的操做步骤; 「2」经过程序拼装上面获得的10个photo的id,再经过in查询“SELECT photo_id,count(*) FROM photo_comment WHERE photo_id in (?) GROUP BY photo_id”一次获得10个photo的全部回复数量,再组装两个结果集获得展示对象 (3)下面对两种方案作一下简单的比较: 【1】从mysql的sql执行数量来看,方案一为11条sql语句,方案二为2条sql语句; 【2】从应用程序于数据库交互来看,方案一是11次,方案二是2次; 【3】从数据库IO操做来看,简单假设每次sql为1个IO,方案一最少11次IO,方案二小于等于11次IO,并且只有当数据很是之离散的时候才会须要11次; 【4】从数据库处理的查询复杂度来看,方案一是两类很简单的查询,方案二有一条sql有group by操做,比第一种解决方案增长了排序分组操做; 【5】从应用程序结果集处理来看,方案一11次结果集的处理,方案二2次结果集的处理,可是方案二中第二次结果集数量是第一次的10倍; 【6】从应用程序数据处理来看,方案二比方案一多了一个拼装photo_id的过程。 (4)咱们从以上6点作一个性能消耗的分析: 【1】因为mysql对客户端每次提交的sql无论是相同仍是不一样,都须要进行彻底解析,这个动做主要消耗的资源是数据库主机的CPU,那么这里第一种方案和第二种方案消耗的CPU的比例是11:2。sql语句的解析动做在整个sql语句执行过程当中的总体消耗的CPU比例是比较多的; 【2】应用程序与数据库交互消耗的资源基本上都在网络方面,一样是11:2; 【3】数据库IO操做资源消耗小于或者等于1:1; 【4】方案二须要比方案一多消耗内存资源进行排序分组操做,因为数据量不大,多出的消耗在语句总体消耗中占用比例会比较小,大概不会超过20%,你们能够针对性测试; 【5】结果集处理次数为11:2,可是方案二比方案一处理数量大,总体来讲两次的性能消耗区别不大; 【6】应用程序数据处理方面所多出的这个photo_id的拼装所消耗的资源是很是小的,甚至比应用程序与mysql作一次简单的交互所消耗的资源还要少。 (5)总体分析后,得出结论,从总体消耗资源来看,方案二远远优于方案一。
过渡依赖数据库sql语句的功能形成数据库操做效率低下性能优化
(1)前面的案例是开发工程师过渡弱化SQL语句的功能形成的资源浪费案例,而这里咱们再来分析一个彻底相反的案例:在群组简介页面须要显示群名称和简介,每一个群成员的nick_name,以及群主的我的签名信息。 (2)需求中所需信息存放在如下四个表中:user,user_profile,groups,user_group (3)方案一: 【1】SELECT name,description,user_type,nick_name,sign FROM groups,user_group,user ,user_profile WHERE groups.id = ? AND groups.id = user_group.group_id AND user_group.user_id = user.id AND user_profile.user_id = user.id (4)方案二: 【1】首先取得全部须要展现的group的相关信息和全部群组员的nick_name信息和组员类别: SELECT name,description,user_type,nick_name FROM groups,user_group,user WHERE groups.id = ? AND groups.id = user_group.group_id AND user_group.user_id = user.id 【2】而后在程序中经过上面结果集中的user_type找到群主的user_id再到user_profile表中取得群主的签名信息: SELECT sign FROM user_profile WHERE user_id = ? (5)你们应该可以看出二者的区别吧,两种解决方案最大的区别在于交互次数和 SQL复杂度。 (6)而带来的实际影响是第一种解决方案对user_profile表有没必要要的访问(非群主的profile信息),形成IO访问的直接增长在20%左右。 (7)而你们都知道,IO操做在数据库应用系统中是很是昂贵的资源。尤为是当这个功能的PV较大的时候,第一种方案形成的IO损失是至关大的。
其余比较常见的架构设计实现不当带来的性能问题和资源浪费状况:服务器
(1)重复执行相同的SQL形成资源浪费 (2)Cache系统的不合理利用致使Cache命中率低下形成数据库访问量的增长,同时也浪费了Cache系统的硬件资源投入; (3)对可扩展性的过分追求,促使系统设计的时候将对象拆得过于离散,形成系统中大量的复杂Join语句,而MySQL Server在各数据库系统中的主要优点在于处理简单逻辑的查询,这与其锁定的机制也有较大关系; (4)对数据库的过分依赖,将大量更适合存放于文件系统中的数据存入了数据库中,形成数据库资源的浪费,影响到系统的总体性能,如各类日志信息; (5)过分理想化系统的用户体验,使大量非核心业务消耗过多的资源,如大量不须要实时更新的数据作了实时统计计算。
为何获得相同结果集的不一样SQL语句,在执行性能上存在差别呢?这里咱们先从sql语句在数据库中执行并获取所需数据的过程来进行分析。网络
(1)当mysql server的链接线程接收到Client端发送过来的sql请求以后,会通过一系列的分解Parse,进行相应的分析。 (2)而后mysql会经过查询优化器模块根据该sql所涉及到的数据表的相关统计信息进行计算分析,而后再得出一个mysql认为最合理最优化的数据访问方式,就是咱们平时说得“执行计划”。 (3)再根据获得的执行计划经过存储引擎接口来获取相应数据。 (4)最后再将存储引擎返回的数据进行相关处理,并以Client端要求的格式做为结果集返回给Client端的应用程序。 (5)注意:这里所说的统计数据,是mysql经过ANALYZE TABLE命令同志mysql对表的相关数据作分析以后所得到的一些数据统计量。这些统计数据对mysql优化器来讲很是重要,优化器所生成的执行计划的好坏,主要就是由这些统计数据所决定的。 (6)咱们都知道,在数据库管理软件中,最大的性能瓶颈就是在于磁盘IO,也就是数据存取操做上面。 (7)而对于同一份数据,当咱们以不一样方式去寻找某一点的数据时,所须要读取的数据量可能会有天壤之别,所消耗的资源也天然是区别深大。 (8)因此,当咱们须要从数据库中查询某个数据的时候,所消耗资源的多少主要取决于数据库以一个什么样的数据读取方式来完成咱们的查询请求,也就是取决于sql语句的执行计划。 (9)而对于惟一sql语句来讲,通过mysql Parse以后分解后的结构都是固定的,只要统计信息稳定,其执行计划基本上都是比较固定的。 (10)而不一样写法的sql语句,通过Mysql Parse以后分解的结构就可能会不一样,即便优化器使用彻底同样的统计信息来进行优化,最后所获得的执行计划也可能彻底不同。 (11)而执行计划是决定一个sql语句最终的资源消耗量的主要因素。 (12)因此,实现功能彻底同样的SQL语句,在性能上面可能会有差异巨大的性能消耗。 (13)固然,若是功能同样,并且通过 MySQL的优化器优化以后的执行计划也彻底一致的不一样SQL语句在资源消耗方面可能就相差很小了。固然这里所指的消耗主要是IO资源的消耗,并不包括 CPU的消耗。
简要分析:mysql优化
(1)须要存放用户数据的表; (2)须要存放分组信息和存放用户与组关系的表 (3)须要存放讨论信息的表;
两方案比较:
(1)咱们先来比较下两个解决方案所设计的Schema的区别。 (2)区别主要体如今两点。一个区别就是group_message表中添加了author字段来存放发帖做者的昵称,与user表的nick_name相对应,另一个就是方案二将user表和group_message表都拆分红了两个表,关系分别一一对应。 (3)方案二看起来复杂一些,首先是表的数量多2个,而后是group_message中冗余了做者的昵称。 (4)咱们试想一下,一个讨论区系统,访问最多的页面会是什么? (5)我想你们都会很清楚是帖子标题列表页面。而帖子标题列表页面最主要的信息就是都是来自 group_message表中,同时帖子标题后面的做者通常都是经过用户名(昵称)来展现。按照第一种解决方案来设计的 Schema,咱们就须要执行相似以下这样的SQL语句来获得数据: 【1】SELECT t.id, t.subject,user.id, u.nick_name FROM ( SELECT id, user_id, subject FROM group_message WHERE group_id = ? ORDER BY gmt_modified DESC LIMIT 20 ) t, user u WHERE t.user_id = u.id (6)可是方案二所需执行的sql就会简单不少: SELECT t.id, t.subject, t.user_id, t.author FROM group_message WHERE group_id = ? ORDER BY gmt_modified DESC LIMIT 20 (7)两个sql相比较,很明显能够看出方案一须要join两个表的数据,与方案二的sql相比性能相差很大,尤为是若是第一个再写的差一点,性能更是很是糟糕,二者所带来的资源消耗就更相差玄虚了。 (8)不只仅如此,因为第一个方案中的group_message表中还包含一个大字段“content”,该字段所存放的信息要占整个表的绝大部分存储空间,但在这条系统中执行最频繁的 SQL之一中是彻底不须要该字段所存放信息的,可是因为这个SQL又没办法作到不访问group_message表的数据,因此第一条SQL在数据读取过程当中会须要读取大量没有任何意义的数据。 (9)在系统中用户数据的读取也是比较频繁的,可是大多数地方所须要的用户数据都只是用户的几个基本属性,如用户的id,昵称,密码,状态,邮箱等,因此将用户表的这几个属性单独分离出来后,也会让大量的SQL语句在运行的时候减小数据的检索量,从而提升性能。 (10)可能有人会以为,在咱们将一个表分红两个表的时候,咱们若是要访问被分拆出去的信息的时候,性能不是就会变差了吗?是的,对于那些须要访问如user的sign,msn等原来只须要一个表就能够完成的SQL来讲,如今都须要两条SQL来完成,性能确实会 有所下降,可是因为两个表都是一对一的关联关系,关联字段的过滤性也很是高,并且这样的查询需求在整个系统中所占有的比例也并不高,因此这里所带来的性能损失实际上要远远小于在其余SQL上所节省出来的资源,因此彻底没必要为此担忧
三类影响数据库主机性能的最主要因素部件
(1)与IO相关的磁盘和内存: 【1】首先,数据库主机是存取数据的地方,那么其IO操做天然不会少,因此数据库主机的IO性能确定是须要最优先考虑的一个因素,这一点无论是什么类型的数据库应用都是适用的。 【2】不过,这里的IO性能并不只仅只是指物理的磁盘IO,而是主机的总体IO性能,是主机整个IO系统的整体IO性能。 【3】而IO性能自己又能够分为两类,一类是每秒可提供的IO访问次数,也就是咱们常说的IOPS数量,还有一种就是每秒的IO总流量,也就是咱们常说的IO吞吐量。 【4】在主机中决定 IO性能部件主要由磁盘和内存所决定,固然也包括各类与IO相关的板卡。 (2)CPU: 【1】其次,因为数据库主机和普通的应用程序服务器相比,资源要相对集中不少,单台主机上所须要进行的计算量天然也就比较多,因此数据库主机的CPU处理能力也不能忽视。 (3)网络设备: 【1】最后,因为数据库负责数据的存储,与各应用程序的交互中传递的数据量比其余各种服务器都要多,因此数据库主机的网络设备的性能也可能会成为系统的瓶颈。
因此后面咱们经过对各类类型的应用作一个简单的分析,再针对性的给出这三类部件的基本选型建议。
(1)典型OLTP应用系统 【1】对于各类数据库系统环境中你们最多见的OLTP系统 【2】其特色是并发量大,总体数据量比较多,但每次访问的数据比较少,且访问的数据比较离散,活跃数据占整体数据的比例不是太大。 【3】对于这类系统的数据库其实是最难维护,最难以优化的,对主机总体性能要求也是最高的。由于他不只访问量很高,数据量也不小。 【4】针对上面的这些特色和分析,咱们能够对OLTP的得出一个大体的方向: 「1」虽然系统整体数据量较大,可是系统活跃数据在数据总量中所占的比例不大,那么咱们能够经过扩大内存容量来尽量多的将活跃数据cache到内存中; 「2」 虽然IO访问很是频繁,可是每次访问的数据量较少且很离散,那么咱们对磁盘存储的要求是IOPS表现要很好,吞吐量是次要因素; 「3」 并发量很高,CPU每秒所要处理的请求天然也就不少,因此CPU处理能力须要比较强劲; 「4」 虽然与客户端的每次交互的数据量并非特别大,可是网络交互很是频繁,因此主机与客户端交互的网络设备对流量能力也要求不能太弱。 (2)典型OLAP应用系统 【1】用于数据分析的OLAP系统的主要特色就是数据量很是大,并发访问很少,但每次访问所须要检索的数据量都比较多,并且数据访问相对较为集中,没有太明显的活跃数据概念。 【2】基于OLAP系统的各类特色和相应的分析,针对OLAP系统硬件优化的大体策略以下: 「1」数据量很是大,因此磁盘存储系统的单位容量须要尽可能大一些; 「2」单次访问数据量较大,并且访问数据比较集中,那么对IO系统的性能要求是须要有尽量大的每秒IO吞吐量,因此应该选用每秒吞吐量尽量大的磁盘; 「3」虽然IO性能要求也比较高,可是并发请求较少,因此CPU处理能力较难成为性能瓶颈,因此CPU处理能力没有太苛刻的要求; 「4」虽然每次请求的访问量很大,可是执行过程当中的数据大都不会返回给客户端,最终返回给客户端的数据量都较小,因此和客户端交互的网络设备要求并非过高; 「5」此外,因为OLAP系统因为其每次运算过程较长,能够很好的并行化,因此通常的OLAP系统都是由多台主机构成的一个集群,而集群中主机与主机之间的数据交互量通常来讲都是很是大的,因此在集群中主机之间的网络设备要求很高。 (3)除了以上两个典型应用以外,还有一类比较特殊的应用系统,他们的数据量不是特别大,可是访问请求及其频繁,并且大部分是读请求。可能每秒须要提供上万甚至几万次请求,每次请求都很是简单,可能大部分都只有一条或者几条比较小的记录返回,就好比基于数据库的 DNS服务就是这样类型的服务。 「1」虽然数据量小,可是访问极其频繁,因此能够经过较大的内存来 cache住大部分的数据,这可以保证很是高的命中率,磁盘IO量比较小,因此磁盘也不须要特别高性能的; 「2」并发请求很是频繁,须要较强的CPU处理能力才能处理; 「3」虽然应用与数据库交互量很是大,可是每次交互数据较少,整体流量虽然也会较大,可是通常来讲普通的千兆网卡已经足够了。